From 4710c51e25a6dcfd8c7ce63e9e274fcc9dfd323e Mon Sep 17 00:00:00 2001 From: Steve Date: Fri, 1 Oct 2021 14:34:10 -0400 Subject: [PATCH] add protocol --- PROTOCOL.md | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 PROTOCOL.md diff --git a/PROTOCOL.md b/PROTOCOL.md new file mode 100644 index 0000000..cca79d1 --- /dev/null +++ b/PROTOCOL.md @@ -0,0 +1,173 @@ +# So You Wanna Write a Snengame client or server + +## High level considerations + +Snengame is written under the following assumptions: + +1. Everything is calculated server side +2. A client does not have to poll the server or use a stateful connection +3. Game actions are ultimately implemented using the GameCommand format + +The default server and clients are written using JSON over Websockets. + +## GameCommand + +Go Struct representation: + + type Command struct { + PlayerID int `json:"player_id"` + Type CmdType `json:"type"` + Cmd string `json:"cmd"` + } + +Plaintext Representation: + + + +Example Command: + + 2 a p 0 + +PlayerID represents which player is issuing the command. It can be either 1 (for "Sentinal") or 2 (for "Scourge") + +Type is the command type. The following are accepted: + a: Action Command + s: State Command + d: Debug command + +The remainder of the GameCommand is a string containing the actual command. The following are valid commands: + +State Commands: + +State commands always return a "player-safe" view of the board known as a GameView. This will be described shortly. + + b: ready up or begin the game + s: start turn + e: end turn + g: return the current GameView. + +Debug Commands: + +Client-server specific. + + d: If enabled, run a debug function + +Action Commands: + +Action commands return either an empty list of cards or the relevant list of cards affected (i.e. the current players hand) + + s: Look at the top X cards of the current players deck, where x is their Life total. Returns nothing if unable to scry (i.e. the player can not currently draw a card). Otherwise return a list of zero to three cards representing what was seen. + d : Draw the the card at position X in the result return from a Scry. Returns nothing if the player is unable to draw. Otherwise return the current players hand + p : Play the card at position X in the current players hand to position Y on the current player's side of the board. Return nothing if the card cannot be played, otherwise return the current players side of the board. + m : Move the card at position X to position Y, with both positions being on the current players side of the board. Return nothing if the card cannot be moved, otherwise return the current players side of the board. + a : Attack with the card at position X on the current players side of the board at position Y on the opponents side of the board. Returns nothing if the attack can not be made, or the current players side of the board. + +### GameView + +A "GameView" is a player-safe version of the current game state. It contains all the information a client needs to show the current game state, without revealing any unwanted information about the players opponent. + +TODO: Describe all the options available in a GameView. Until then, see internal/game/game_view.go + + +### GameCommand Results + +The results of a GameCommand are returned in the following format: + +Go struct representation: + + type CommandResult struct { + PlayerID int `json:"player_id"` + ResultType CmdType `json:"result_type"` + StateResult *GameView `json:"state_result,omitempty"` + ActionResult *Deck `json:"action_result,omitempty"` + DebugResult *Game `json:"debug_result,omitempty"` + } + +PlayerID is the same as in a GameCommand +ResultType is the same as in a GameCommand, with the addition of the "e" type. This indicates an error handling the command +StateResult contains a GameView as described above. +ActionResult is a structure containing a list of Cards, which represent the result of the action command +DebugResult can be implemented however the client prefers. + + +See internal/game/cmd.go for more details on GameCommands. + +## Session Commands + +Session commands are used by the default server and client to communicate actions and game state. They are implemented as JSON structures over Websockets + +Go struct representation: + + type SessionCommand struct { + ID uuid.UUID `json:"player_id"` + MatchID uuid.UUID `json:"match_id"` + Command SessionCmd `json:"command"` + GameCommand *game.Command `json:"game_command,omitempty"` + } + +ID is the player ID in standard UUID format. It is generated by the client, however in the future it may be generated by some type of authentication system + +MatchID is the UUID of the match being played. It is NOT generated by the client; the server returns it when a game is found. All SessionCommands except for "query" MUST have a MatchID + +Command is a string representing a command from the following list: + + query: Tell the server you are looking for a game. Blocks until the server responds with a found game. + join: Attempt to join the game with the attached MatchID + leave: Attempt to leave the game with the attached MatchID. If no game is found and the player is queueing, remove from queue. Always succeeds. + poll: Check if the server has any "broadcast" responses. Opts into polling. + play: Attempt to run the attached GameCommand + ready: Check if both players have joined the game with attached MatchID + +GameCommand is a game command following the conventions described above. + + +### Session Command results + +The server responds with JSON in the following format: + +Go struct representation + + type SessionCommandResult struct { + ID uuid.UUID `json:"player_id"` + MatchID uuid.UUID `json:"match_id"` + Result SessionResp `json:"result"` + GameResult *game.CommandResult `json:"game_result,omitempty"` + } + +ID is the player ID of the sender, as described above. + +MatchID is the match ID of the sender, as described above. + +GameResult is the result of the GameCommand (if one was sent) as described above + +Result is a string representing the result of the SessionCommand. The following are valid Results that are expected to be acted upon by the client + + + "found": A game has been created on the server. The client should use the attached MatchID + "joined p1": The client was succesful in joining the game as Player 1 ("Sentinal") + "joined p2": The client was succesful in joining the game as Player 2 ("Scourge") + "left": The client was succesful in leaving the game + "played": The server recognized a game command was sent. This does NOT mean the command was succesful; the client should check the GameResult for that information + "game ready": Both players have joined the game and game commands can be sent + "generic error": An error has occured. + +The following Results are called "Broadcasts" and are sent by the server to ease the work done by the clients. None of them are required to be handled, but it will most likely be useful for clients to handle at least some of them. + +If a client opt's into polling it is expected to poll constantly. Clients can feel free to discard any Broadcasts they don't want to handle. + +All of the following are returned from the "poll" session command. + + "Sentinal turn": Player 2 has ended their turn. + "Scourge turn": Player 1 has ended their turn + "Scourge wins": Player 2 has won + "Sentinal wins": Player 1 has won + "update": An action has been taken that has altered the board or game state in some way, besides starting or ending a turn. + "Sentinal joined": Player 1 has joined the game + "Scourge joined": Player 2 has joined the game + "Sentinal player is ready": Player 1 is ready to play the game + "Scourge player is ready": Player 2 is ready to play the game + "Sentinal player has left": Player 1 has left the game + "Scourge player has left": Player 2 has left the game + + +For more information on session commands, see internal/coordinator/session.go