add protocol

This commit is contained in:
stryan 2021-10-01 14:34:10 -04:00
parent f42b7773ce
commit 4710c51e25
1 changed files with 173 additions and 0 deletions

173
PROTOCOL.md Normal file
View File

@ -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:
<PlayerID> <Type> <Command>
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 <x>: 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 <x> <y>: 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 <x> <y>: 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 <x> <y>: 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