mirror of
https://github.com/fluencelabs/assemblyscript-dice
synced 2025-04-25 16:12:14 +00:00
request handling and parsing, join and roll logic
This commit is contained in:
parent
5bfcb32352
commit
a8d0da3879
@ -1,5 +1,5 @@
|
|||||||
import { JSONDecoder } from "../node_modules/assemblyscript-json/assembly/decoder";
|
import {JSONEncoder} from "../node_modules/assemblyscript-json/assembly/encoder";
|
||||||
import { JSONEncoder } from "../node_modules/assemblyscript-json/assembly/encoder";
|
import {ErrorResponse, GetBalanceResponse, JoinResponse, Response, RollResponse} from "./response";
|
||||||
|
|
||||||
const PLAYERS_MAX_COUNT: usize = 1024;
|
const PLAYERS_MAX_COUNT: usize = 1024;
|
||||||
const SEED: u64 = 12345678;
|
const SEED: u64 = 12345678;
|
||||||
@ -7,8 +7,66 @@ const SEED: u64 = 12345678;
|
|||||||
const INIT_ACCOUNT_BALANCE: u64 = 100;
|
const INIT_ACCOUNT_BALANCE: u64 = 100;
|
||||||
// if win, player receives bet_amount * PAYOUT_RATE money
|
// if win, player receives bet_amount * PAYOUT_RATE money
|
||||||
const PAYOUT_RATE: u64 = 5;
|
const PAYOUT_RATE: u64 = 5;
|
||||||
|
const DICE_LINE_COUNT: u8 = 6;
|
||||||
|
|
||||||
export function handler(input: string): string {
|
export class GameManager {
|
||||||
|
|
||||||
return "";
|
registeredPlayers: u64 = 0;
|
||||||
|
playerIds: u64[] = [];
|
||||||
|
playerBalance: Map<u64, u64> = new Map<u64, u64>();
|
||||||
|
encoder: JSONEncoder = new JSONEncoder();
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
NativeMath.seedRandom(SEED);
|
||||||
|
}
|
||||||
|
|
||||||
|
join(): Response {
|
||||||
|
// delete the oldest player, if maximum players reach
|
||||||
|
if (this.playerIds.length >= PLAYERS_MAX_COUNT) {
|
||||||
|
let lastPlayer = this.playerIds.pop();
|
||||||
|
this.playerBalance.delete(lastPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.playerIds.push(this.registeredPlayers);
|
||||||
|
this.playerBalance.set(this.registeredPlayers, INIT_ACCOUNT_BALANCE);
|
||||||
|
|
||||||
|
let response = new JoinResponse(this.registeredPlayers);
|
||||||
|
|
||||||
|
this.registeredPlayers += 1;
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
roll(playerId: u64, betPlacement: u8, betSize: u32): Response {
|
||||||
|
|
||||||
|
if (betPlacement > DICE_LINE_COUNT) {
|
||||||
|
return new ErrorResponse("Incorrect placement, please choose number from 1 to 6")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.playerBalance.has(playerId)) {
|
||||||
|
return new ErrorResponse("There is no player with such id: " + playerId.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
let balance = this.playerBalance.get(playerId);
|
||||||
|
|
||||||
|
if (betSize > balance) {
|
||||||
|
return new ErrorResponse(`Player hasn't enough money: player's current balance is ${balance.toString()} while the bet is ${betSize.toString()}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
let outcome = ((NativeMath.random() * 1000000000) % DICE_LINE_COUNT - 1) as u8;
|
||||||
|
|
||||||
|
if (betPlacement === outcome) {
|
||||||
|
balance = balance + (betSize * PAYOUT_RATE);
|
||||||
|
} else {
|
||||||
|
balance = balance - betSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.playerBalance.set(playerId, balance);
|
||||||
|
|
||||||
|
return new RollResponse(outcome, balance);
|
||||||
|
}
|
||||||
|
|
||||||
|
getBalance(playerId: u64): Response {
|
||||||
|
return new GetBalanceResponse(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
25
assembly/game_handler.ts
Normal file
25
assembly/game_handler.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import {decode, GetBalanceRequest, JoinRequest, RollRequest, UnknownRequest} from "./request";
|
||||||
|
import {ErrorResponse} from "./response";
|
||||||
|
import {GameManager} from "./dice";
|
||||||
|
|
||||||
|
let gameManager = new GameManager();
|
||||||
|
|
||||||
|
// returns string, because serialization to a byte array is not compatible with our invoke handlers
|
||||||
|
export function handler(requestBytes: Uint8Array): string {
|
||||||
|
|
||||||
|
let request = decode(requestBytes);
|
||||||
|
|
||||||
|
if (request instanceof JoinRequest) {
|
||||||
|
return gameManager.join().serialize();
|
||||||
|
} else if (request instanceof RollRequest) {
|
||||||
|
return gameManager.roll(request.playerId, request.betPlacement, request.betSize).serialize();
|
||||||
|
} else if (request instanceof GetBalanceRequest) {
|
||||||
|
return gameManager.getBalance(request.playerId).serialize();
|
||||||
|
} else if (request instanceof UnknownRequest) {
|
||||||
|
return new ErrorResponse("").serialize();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
// import "allocator/tlsf";
|
import "allocator/tlsf";
|
||||||
import {handler} from "./dice";
|
|
||||||
import {JSONDecoder, JSONHandler} from "../node_modules/assemblyscript-json/assembly/decoder";
|
|
||||||
//import "allocator/buddy";
|
//import "allocator/buddy";
|
||||||
//import "allocator/arena";
|
//import "allocator/arena";
|
||||||
|
|
||||||
|
import {handler} from "./game_handler";
|
||||||
|
|
||||||
export function allocate(size: i32) :i32 {
|
export function allocate(size: i32) :i32 {
|
||||||
return memory.allocate(size);
|
return memory.allocate(size);
|
||||||
}
|
}
|
||||||
@ -20,12 +20,7 @@ export function invoke(ptr: i32, size: i32): i32 {
|
|||||||
bb[i] = load<u8>(ptr + i)
|
bb[i] = load<u8>(ptr + i)
|
||||||
}
|
}
|
||||||
|
|
||||||
let jsonHandler = new ToDictJSONEventsHandler();
|
let result = handler(bb);
|
||||||
let decoder = new JSONDecoder<ToDictJSONEventsHandler>(jsonHandler);
|
|
||||||
|
|
||||||
decoder.deserialize(bb);
|
|
||||||
|
|
||||||
let result = jsonHandler.strings.get("test");
|
|
||||||
|
|
||||||
let strLen: i32 = result.length;
|
let strLen: i32 = result.length;
|
||||||
let addr = memory.allocate(strLen + 4);
|
let addr = memory.allocate(strLen + 4);
|
||||||
@ -42,84 +37,3 @@ export function invoke(ptr: i32, size: i32): i32 {
|
|||||||
|
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
class JoinRequest {}
|
|
||||||
class RollRequest {
|
|
||||||
public player_id: u64;
|
|
||||||
public bet_placement: u8;
|
|
||||||
public bet_size: u32;
|
|
||||||
constructor(player_id: u64 ,bet_placement: u8, bet_size: u32) {
|
|
||||||
this.player_id = player_id;
|
|
||||||
this.bet_placement = bet_placement;
|
|
||||||
this.bet_size = bet_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class GetBalanceRequest {
|
|
||||||
public player_id: u64;
|
|
||||||
constructor(player_id: u64) {
|
|
||||||
this.player_id = player_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class JoinResponse {
|
|
||||||
player_id: u64;
|
|
||||||
constructor(player_id: u64) {
|
|
||||||
this.player_id = player_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class RollResponse {
|
|
||||||
public outcome: u8;
|
|
||||||
public player_balance: u64;
|
|
||||||
constructor(outcome: u64 ,player_balance: u8, bet_size: u32) {
|
|
||||||
this.outcome = outcome;
|
|
||||||
this.player_balance = player_balance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class GetBalanceResponse {
|
|
||||||
public player_balance: u64;
|
|
||||||
constructor(player_balance: u64) {
|
|
||||||
this.player_balance = player_balance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class ErrorResponse {
|
|
||||||
message: string;
|
|
||||||
constructor(message: string) {
|
|
||||||
this.message = message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ToDictJSONEventsHandler extends JSONHandler {
|
|
||||||
|
|
||||||
public strings: Map<string, string> = new Map();
|
|
||||||
public booleans: Map<string, bool> = new Map();
|
|
||||||
public integers: Map<string, i64> = new Map();
|
|
||||||
|
|
||||||
setString(name: string, value: string): void {
|
|
||||||
this.strings.set(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
setBoolean(name: string, value: bool): void {
|
|
||||||
this.booleans.set(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
setNull(name: string): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
setInteger(name: string, value: i64): void {
|
|
||||||
this.integers.set(name, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
pushArray(name: string): bool {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
popArray(): void {
|
|
||||||
}
|
|
||||||
|
|
||||||
pushObject(name: string): bool {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
popObject(): void {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
81
assembly/request.ts
Normal file
81
assembly/request.ts
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import {JSONDecoder, JSONHandler} from "../node_modules/assemblyscript-json/assembly/decoder";
|
||||||
|
|
||||||
|
export abstract class Request {}
|
||||||
|
|
||||||
|
export class UnknownRequest extends Request {}
|
||||||
|
export class JoinRequest extends Request {}
|
||||||
|
export class RollRequest extends Request {
|
||||||
|
public readonly playerId: u64;
|
||||||
|
public betPlacement: u8;
|
||||||
|
public betSize: u32;
|
||||||
|
constructor(playerId: u64, betPlacement: u8, betSize: u32) {
|
||||||
|
super();
|
||||||
|
this.playerId = playerId;
|
||||||
|
this.betPlacement = betPlacement;
|
||||||
|
this.betSize = betSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class GetBalanceRequest extends Request {
|
||||||
|
public playerId: u64;
|
||||||
|
constructor(playerId: u64) {
|
||||||
|
super();
|
||||||
|
this.playerId = playerId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function decode(bytes: Uint8Array): Request {
|
||||||
|
let jsonHandler = new RequestJSONEventsHandler();
|
||||||
|
let decoder = new JSONDecoder<RequestJSONEventsHandler>(jsonHandler);
|
||||||
|
|
||||||
|
decoder.deserialize(bytes);
|
||||||
|
|
||||||
|
let action = jsonHandler.action;
|
||||||
|
|
||||||
|
if (action === "Join") {
|
||||||
|
return new JoinRequest();
|
||||||
|
} else if (action === "Roll") {
|
||||||
|
return new RollRequest(jsonHandler.playerId, jsonHandler.betPlacement, jsonHandler.betSize)
|
||||||
|
} else if (action === "GetBalance") {
|
||||||
|
return new GetBalanceRequest(jsonHandler.playerId)
|
||||||
|
} else {
|
||||||
|
return new UnknownRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class RequestJSONEventsHandler extends JSONHandler {
|
||||||
|
|
||||||
|
public action: string;
|
||||||
|
public playerId: u64;
|
||||||
|
public betPlacement: u8;
|
||||||
|
public betSize: u32;
|
||||||
|
public outcome: u8;
|
||||||
|
public playerBalance: u64;
|
||||||
|
|
||||||
|
setString(name: string, value: string): void {
|
||||||
|
if (name === "action") {
|
||||||
|
this.action = value;
|
||||||
|
}
|
||||||
|
// json scheme is not strict, so we won't throw an error on excess fields
|
||||||
|
}
|
||||||
|
|
||||||
|
setInteger(name: string, value: i64): void {
|
||||||
|
|
||||||
|
if (name == "playerId") {
|
||||||
|
this.playerId = value as u64;
|
||||||
|
} else if (name === "betPlacement") {
|
||||||
|
this.betPlacement = value as u8;
|
||||||
|
} else if (name === "betSize") {
|
||||||
|
this.betSize = value as u32;
|
||||||
|
} else if (name === "outcome") {
|
||||||
|
this.outcome = value as u8;
|
||||||
|
} else if (name === "playerBalance") {
|
||||||
|
this.playerBalance = value as u64;
|
||||||
|
}
|
||||||
|
|
||||||
|
// json scheme is not strict, so we won't throw an error on excess fields
|
||||||
|
}
|
||||||
|
|
||||||
|
pushObject(name: string): bool {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
73
assembly/response.ts
Normal file
73
assembly/response.ts
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
import {JSONEncoder} from "../node_modules/assemblyscript-json/assembly/encoder";
|
||||||
|
|
||||||
|
export abstract class Response {
|
||||||
|
serialize(): string {
|
||||||
|
unreachable();
|
||||||
|
return "";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class JoinResponse extends Response {
|
||||||
|
playerId: u64;
|
||||||
|
constructor(playerId: u64) {
|
||||||
|
super();
|
||||||
|
this.playerId = playerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
serialize(): string {
|
||||||
|
let encoder = new JSONEncoder();
|
||||||
|
encoder.setString("action", "Join");
|
||||||
|
encoder.setInteger("playerId", this.playerId);
|
||||||
|
|
||||||
|
return encoder.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class RollResponse extends Response {
|
||||||
|
public outcome: u8;
|
||||||
|
public playerBalance: u64;
|
||||||
|
|
||||||
|
constructor(outcome: u64, playerBalance: u8) {
|
||||||
|
super();
|
||||||
|
this.outcome = outcome;
|
||||||
|
this.playerBalance = playerBalance;
|
||||||
|
}
|
||||||
|
|
||||||
|
serialize(): string {
|
||||||
|
let encoder = new JSONEncoder();
|
||||||
|
encoder.setString("action", "Roll");
|
||||||
|
encoder.setInteger("outcome", this.outcome as i32);
|
||||||
|
encoder.setInteger("playerBalance", this.playerBalance as i32);
|
||||||
|
|
||||||
|
return encoder.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class GetBalanceResponse extends Response {
|
||||||
|
public playerBalance: u64;
|
||||||
|
constructor(playerBalance: u64) {
|
||||||
|
super();
|
||||||
|
this.playerBalance = playerBalance;
|
||||||
|
}
|
||||||
|
|
||||||
|
serialize(): string {
|
||||||
|
let encoder = new JSONEncoder();
|
||||||
|
encoder.setString("action", "GetBalance");
|
||||||
|
encoder.setInteger("playerBalance", this.playerBalance as i32);
|
||||||
|
|
||||||
|
return encoder.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export class ErrorResponse extends Response {
|
||||||
|
message: string;
|
||||||
|
constructor(message: string) {
|
||||||
|
super();
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
serialize(): string {
|
||||||
|
let encoder = new JSONEncoder();
|
||||||
|
encoder.setString("action", "Error");
|
||||||
|
encoder.setString("message", this.message);
|
||||||
|
|
||||||
|
return encoder.toString();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user