WebSocket Documentation

  • Values determined by the Server Stack are referred to as [from METHOD /endpoint]
  • Values determined by the player are referred to as [from client]
  • Send requests to: wss://w1ws57hjh0.execute-api.eu-central-1.amazonaws.com/prod/
If at any point you need to see what a given player’s object looks like, you can always send this query: {"action":"check","type":"redis","method":"player","pid":"00001","gid":"18062024-2210"} where pid is playerID and gid is gameID.

createGame

createGame creates an object in the elasticache-tax-game cache, with the key ${gameID}. It also creates the first empty planet in the planets array (in the elasticache-tax-game cache with the key planets).

Required data

{
    action: string, //MUST BE "game"
    type: string, //MUST BE "createGame"
    gameID: string, //[from RestAPI]
    stageTime: number, //in seconds (eg: 20 = 20s | so a round will be 1m 20s)
    auditChance: number, //decimal (eg: 20% = 0.20)
    finePercent: number, //decimal (eg: 20% = 0.20)
    planetCollectionMultiplier: number, //decimal (eg: 1.7) | planet collection multiplier
    taxRate: number, //decimal (eg: 20% = 0.20)
    declaredIncomePercent: number,
    incomeMax: number,
    incomeMin: number,
    bankruptcyThreshold: number,
    generateNewIncomeEachRound: boolean
}

example: {"action":"game","type":"createGame","gameID":"18062024-1845","stageTime":20,"auditChance":0.25,"finePercent":0.15,"planetCollectionMultiplier":1.7,"taxRate":0.30, "declaredIncomePercent": 0.40, "incomeMax":1200, "incomeMin":600, "bankruptcyThreshold": 0, "generateNewIncomeEachRound": false}

Elasticache

`${gameID}`: {
    hostID: string,
    gameID: string,
    gameConfiguration: {
        stageTime: number,
        auditChance: number,
        finePercent: number,
        pcm: number,
        defaultRate: number,
        decIP: number,
        incomeMax: number,
        incomeMin: number,
        bankruptcyThreshold: number,
        gNIEC: boolean
      }
}

`${planetID}-${gameID}`: {
    planetID: "planet1",
    planetName: `${AI generated}`,
    taxRate: data.taxRate,
    players: [{
        connectionID: string, //player's connection id
        playerID: string,
        playerName: string,
        role: string // one of ["A" || "B" || "C"]
    }],
  };

`planets-${gameID}` : "1";

Returns

    statusCode: 200,
    body: `{"type":"createGame","message":["OK","OK","OK","OK","OK","OK"]}`

joinGame

joinGame creates an object in the elasticache-tax-game cache, with the key ${gameID}---${playerID}. It will return a generated role and planet to each connection (once the planet is established), and update the host with the new player (playerID and name).

When WebSockets receives the request, it scans DynamoDBStack-WebsocketConnections87C62C57-1H8H09K1YWXHY table. If there is a record in the table with the same connectionId & gameID, it gets that object from Elasticache and returns the full item to the user.

Required data

action: string, //MUST BE "game"
type: string, //MUST BE "joinGame"
gameID: string,
playerID: string, //from RestAPI [ POST /joinGame]
name: string //from client

example: {"action":"game","type":"joinGame","gameID":"game-c3b4i7ybc","playerID":"001a","name":"Emma"}

New Connection

Elasticache: Role A

`${gameID}---${playerID}`: {
    connectionId: string,
    playerID: string,
    name: string,
    role: string, // "A"
    wealth: Array<number>, //starts as [0]
    rank: Array<number>, //starts as [0]
    planet: string, //`${planetID},${planetName}`,
    taxRate: Array<number>, // ONLY A | starts as [defaultRate]
    redistributedWealth: Array<number>, // ONLY A | amount they redistributed to B and C players in a round
    playerCount: Array<number>, // ONLY A | number of players on the planet they are currently on
    bankrupt: Array<boolean>, // - true if they went bankrupt in a round
}

Role B

`${gameID}---${playerID}`: {
    connectionId: string,
    playerID: string,
    name: string,
    role: string, // "B"
    wealth: Array<number>, //starts as [0]
    rank: Array<number>, //starts as [0]
    planet: `${planetID},${planetName}`,
    income: Array<number>, // - income they recieve in a round
    declaredIncome: Array<number>, // - income they declared in a round
    audit: Array<number>, // - amount they were fined in an audit in a round
    bankrupt: Array<boolean>, // - true if their planet went bankrupt in a round
}

Role C

${gameID}---${playerID}: {
    connectionId: string,
    playerID: string,
    name: string,
    role: string, // "C"
    wealth: Array<number>,
    rank: Array<number>,
    planet: Array<string>, //only an array for role C [`${planetID},${planetName}`]
    income: Array<number>, // - income they recieve in a round
    declaredIncome: Array<number>, // - income they declared in a round
    audit: Array<number>, // - amount they were fined in an audit in a round
    bankrupt: Array<boolean>, // - true if they went bankrupt in a round
}

Returns

    statusCode: 200,
    body: `{"type":"joinGame","message":{"options":{"stageTime":20,"auditChance":0.1,"finePercent":0.5,"planetCollectionMultiplier":1.7,"taxRate":0.3,"declaredIncomePercent":0,"incomeMax":1200,"incomeMin":600,"bankruptcyThreshold":0,"generateNewIncomeEachRound":false}}}`

Each time a player sends a joinGame request, the host will receive the following string: {"type":"startGame","message":[{"planetID":"planet1","planetName":"Terralus","players":[{"connectionID":"ZqGUhc8pliACFpw=","playerID":"00001","playerName":"Emma","role":"A"},{"connectionID":"ZqGWHc1-FiACETQ=","playerID":"00002","playerName":"Jules","role":"B"},{"connectionID":"ZqGXndKyFiACEXA=","playerID":"00003","playerName":"Stevie","role":"C"}]}]}

Existing Connection DEPRECIATED

    statusCode: 200,
    body: "{\"connectionId\":\"Zg2C4e7uliACEsg= \",\"playerID\":\"00001 \",\"name\":\"Emma \",\"role\":\"A\",\"wealth\":[0],\"rank\":[0],\"planet\":\"planet1,Quintaris\",\"taxRate\":[],\"redistributedWealth\":[],\"playerCount\":[],\"bankrupt\":[]}"

startGame

startGame goes through all of the planets in the elasticache-tax-game cache, ensures that there are no planets with an awkward amount of players (checks the last planet), and then sends each player their planet (name and ID) and role.

  • If there are two or less players, startGame reassigns each of them to an existing planet with the “B” role
    • The existing planets are determined by the player’s position in the player array: planetsObject[newestPlanet.players.indexOf(player)].players.push

Required data

action: string, //MUST BE "game"
type: string, //MUST BE "startGame"
gameID: string

Each player receives:

The players array includes this player {"type":"startGame","message":{{"planetID":"planet1","planetName":"Soralia","playerRole":"C","players":["Emma","Jules","Steve","Thomas","Kelvin","Dana"]}}

startRound

It should be sent by the Host. Creates an array of items in DynamoDBStack-WebsocketConnections87C62C57-1H8H09K1YWXHY with the given gameID, and then sends each connection the response message.

Required data

action: string, //MUST BE "game",
type: string, //MUST BE "startRound"
gameID: string,
round: number

Returns

To Host

    statusCode: 200,
    body: `{"type":"startRound","message":{{"round":1,"stage":1,"stageStartTime":"2024-06-17T18:17:49.544Z","stageDuration":20}}`

To Players

    statusCode: 200,
    body: `{"type":"startRound","message":{"round":1,"stage":1,"stageStartTime":"2024-06-17T17:48:58.380Z","stageDuration":20}}`

stageChanges, handleStage, & startStage

  • stageChanges is sent by a player that needed to make an action during that stage:
    • At the end of stage 1, all “A” players should send a stageChanges request
    • At the end of stage 2, all “B” and “C” players should send a stageChanges request
    • At the end of stage 3, all players should send a stageChanges request
    • At the end of stage 4, “C” players should send a stageChanges request
  • handleStage should be sent by the Host when the stage is up (stageDuration has elapsed). All players will be alerted that they must send their stageChanges request
    • This way, only one system is managing the time, and the WebSockets aren’t using up a massive amount of processing power while each connection waits for stageDuration to elapse before sending a response.
The WebSockets don’t check if the stage duration is up. The response to stageChanges is sent in handleStage.
If players don’t make a change, the request they send needs to have the default values in it. WebSockets will apply the logic to what is sent (so if the player sends 0, it will use 0 as the value), or send a 401 BAD REQUEST if it’s missing

stageChanges

Response: {"type":"stageChanges","message":"OK"}

Stage 1

//ONLY SENT BY ROLE A PLAYERS
action: string, //MUST BE "game",
type: string, //MUST BE "stageChanges",
gameID: string,
playerID: string
round: number,
stage: number, //MUST BE 1
taxRate: number,
planetID: string

Stage 2

//ONLY SENT BY ROLE B/C PLAYERS
action: string, //MUST BE "game",
type: string, //MUST BE "stageChanges",
gameID: string,
playerID: string
round: number,
stage: number, //MUST BE 2
income: number,
declaredIncome: number

Stage 3

action: string, //MUST BE "game",
type: string, //MUST BE "stageChanges",
gameID: string,
playerID: string
round: number,
stage: number, //MUST BE 3
role: string, //VERY IMPORTANT!!!!!!!!!
redistributed: number, //ONLY PLAYER A: the amount they chose to redistribute
remainder: number //ONLY PLAYER A: redistributable-redistributed
audit: number //ONLY B+C PLAYERS

Stage 4

action: string, //MUST BE "game",
type: string, //MUST BE "stageChanges",
gameID: string,
playerID: string
round: number,
stage: number, //MUST BE 4
newPlanetID: string,
newPlanetName: string,

eg : {"action":"game","type":"stageChanges","gameID":"18062024-2210","round":1,"stage":1,"playerID":"00001","planetID":"planet1","taxRate":0.7}

handleStage

Required Data

action: "game",
type: "handleStage",
gameID: string,

Returns to Host

statusCode: 200,
body: `{"type":"handleStage","message":{"value":"OK"}}`

Returns to Client

{"type":"handleStage","message":{"value":"TIME UP"}}

startStage

Required Data

action: "game",
type: "startStage",
gameID: string,
round: number,
stage: number //this should be the current stage | if handleStage() is being sent after stage 1, it should be 1

To Host

    statusCode: 200,
    body: `{"type":"startStage","message":{"round":1,"stage":2,"stageStartTime":"19/06/2024, 12:11:11","stageDuration":20}}`

After the last stage of the round (automatically calls endRound)

    statusCode: 200,
     body: `{
       "type":"endRound",
       "message":{
       "A":[
          {"connectionId":"Zru4medkliACEXA=","playerID":"00001","name":"Emma","role":"A","wealth":[0],"rank":[0],"planet":"planet1,Xerion","taxRate":[0.3],"redistributedWealth":[0],"playerCount":[5],"bankrupt":[false]}
        ],
          "B":[
            {"connectionId":"Zru5EcnpFiACHEQ=","playerID":"00002","name":"Jules","role":"B","wealth":[0],"rank":[0],"planet":"planet1,Xerion","income":[0],"declaredIncome":[0],"audit":[0],"bankrupt":[false]}
        ],
        "C":[
          {"connectionId":"Zru5Ve4rliACEeg=","playerID":"00003","name":"Stevie","role":"C","wealth":[0],"rank":[0],"planet":["planet1,Xerion"],"income":[0],"declaredIncome":[0],"audit":[0],"bankrupt":[false]}
        ]
      }
    }`

To Players - after stage 1

{"type":"startStage","message":{"round":1,"stage":2,"stageStartTime":"19/06/2024, 12:11:11","stageDuration":20,"taxRate":0.15}}

To Players - after stage 2

{"type":"startStage","message":{"round":1,"stage":3,"stageStartTime":"19/06/2024, 16:21:12","stageDuration":20,"bankrupt":false,"declared":[800,1100,600,600],"redistributable":3689}}

A Players | Bankrupt {"type":"startStage","message":{"round":1,"stage":3,"stageStartTime":"19/06/2024, 16:21:12","stageDuration":20,"bankrupt":true}}

Other Players {"type":"startStage","message":{"round":1,"stage":3,"stageStartTime":"19/06/2024, 16:21:12","stageDuration":20}}

To Players - after stage 3

A Players {"type":"startStage","message":{"round":1,"stage":4,"stageStartTime":"20/06/2024, 12:04:48","stageDuration":20,"updatedWealth":3850,"auditPool":850}}

B+C Players {"type":"startStage","message":{"round":1,"stage":4,"stageStartTime":"20/06/2024, 12:04:48","stageDuration":20,"updatedWealth":137.8,"rebate":137.8}}

To Players - after stage 4

{"type":"endRound",
"message":{
  "playerData":{
    "connectionId":"Zru5Ve4rliACEeg=",
    "playerID":"00003",
    "name":"Stevie",
    "role":"C",
    "wealth":[674.5],
    "rank":[0],
    "planet":["planet1,Zoroxia"],
    "income":[1100],
    "declaredIncome":[1100],
    "audit":[250],
    "bankrupt":[false]
  },
  "planetData":{
    "planetID":"planet1",
    "planetName":"Zoroxia",
    "taxRate":0.7,
    "bankruptThisRound":false,
    "players":[
      {"connectionID":"Zru4medkliACEXA=",
      "playerID":"00001",
      "playerName":"Emma",
      "role":"A"},
      {"connectionID":"Zru5EcnpFiACHEQ=",
      "playerID":"00002",
      "playerName":"Jules",
      "role":"B"},
      {"connectionID":"Zru5Ve4rliACEeg=",
      "playerID":"00003",
      "playerName":"Stevie",
      "role":"C"}
      ]
    }
  }
}```