Open dixonary opened 4 years ago
See #5 for some existing comments regarding this!
So its probably time to start having a look at the network element, there's a few different ways I can think of (though my knowledge of networks isn't amazing so I almost certainly will get something wrong):
Server/Client:
Platform Agnostice P2P
Discord/Slack Bot
Plus whatever else I've missed
I think the best way to go about this is to implement the game mechanics independently of whatever communications method is used. We can then add those on top as needed (incl. multiple).
One problem with P2P is that if clients get out of sync then things can start to go wrong. If there is an authoritative server, then it can communicate the game state to all clients.
As far as I know the clients would have to keep checking the API for updates
With websockets, you can avoid the need to poll the server - the server can push updates to the game state.
A downside of websockets is that you need to manually deal with disconnecting / reconnecting clients though, so a RESTful approach (with HTTP, and server polling) might be simpler. Making an HTTP request for updates every second or so wouldn't be too demanding.
A slack/discord bot would be simple but I'm not sure how that would integrate with a UI?
In terms of a simple protocol, something like this would be sufficient:
/makeMove
- a POST request to tell the server that the client has made a move. Details of the move encoded in JSON body, for example. When the server receives this it should validate the move to check it makes sense in context, and perform the state transformation if yes.
/getState
- a GET request which returns the current state of the game (encoded as a JSON body) if it's changed since the last request, otherwise it returns HTTP202 or similar.
Plus some metagame stuff like /connect
to connect to the game, if there's space.
Making that API support >1 game at a time can be a stretch goal.
Thoughts?
Yeah a RESTful API with servant
was my preferred choice. I'll open a PR for that later this evening. The server will obviously validate the input syntactically okay, although I thing making sure its logically okay is more likely to be a library function than in the server module
Endpoints: Endpoint | Method | Description |
---|---|---|
/connect |
POST |
This attempts to connect the user to a game. It must be passed the users deck and it will return a gameID and a player number which is used in future requests |
/gameReady/#gameID |
GET |
This returns a Bool of whether the game is ready or not - ie whether the 2nd player has joined yet |
/state/#gameID/#player?update=#time |
GET |
This returns the Board of the current game. If there has been no change since the time stated in the update parameter then HTTP304: Not Modified is returned |
/state/#gameID/#player |
PATCH |
This takes the [Card] representing the cards the player wishes to play and attempts to play it. If the cards are not valid then HTTP400: Bad Request is returned |
So the single game server has been merged, the next step is supporting multiple concurrent games. There's a couple of ways to implement this:
gameID
would be the primary key in the database. The advantage of this is it would be neater than the current IORef
system, the disadvantage is it would be harder for people to run the server on their local machines as they'd require a databaseIORef
to STM
which is similar but more thread-safe for concurrent operations, and use something like Data.Map
to store the ongoing games. The advantage is it doesn't require any extra software, the disadvantage is the code may not be as nice and we may have to keep track of what the newest ID should be manually unlike in a databaseI don't know much about efficiency, using a Data.Map
to store the game states may be more efficient then reading from a DB constantly as with the DB it has to read the data from a string to the data type, however I don't know how well Data.Map
would handle large numbers of elements. (Again I want to make it very clear this is very uninformed speculation)
Thoughts?
I'm going the try using a database, if it turns out to be horrible I'll use STM
If the game is to be played online, there will need to be a server component which takes moves from the clients and translates that into changes in game state (which are then propagated back to the client).
Dealing with multiple ongoing games is a stretch goal!