The advantage of virtual connections and game-ids (virtual connections are actually the generalized version of using game-ids) is that we don’t need to bother with multiple logins.

For each method there are advantages and disadvantages. For example, game-ids are simple, but force you to push that id with every packet, and while managing multiple connections adds complexity, it also means less packets to handle unsubscribing or leaving tables.

There are many nuances that depend on the requirements of your particular game, but we don’t really have the time to explore them here. For now we’re just going to pretend that you can only join a single game (even though in practice we usually don’t want that restriction).

Creating our packets

The client packet is simple, it only needs to hold the game id, since we’ve already logged in and the server knows our player id.

The response though, will need to return the entire state of the table in order to render it on the client:

Here the client needs to keep a lot of logic in order to make sense of the incoming data. For example, when the PLAYER_BET is received, the client needs to understand that the current player should no longer be active, and the next active player should be the next player that is still in the game, same with PLAYER_FOLD.

This is extremely error prone. What if the protocol had looked like this instead:

Working like this is especially useful if you have a rich state with many types of updates.

Handling updates

To automate the update packets we can use something similar to the object views discussed in this Gamasutra article. The most straightfoward thing is to keep an object with a data structure identical to the full GAME_STATE sent at connect.

Whenever we update the server model, we make sure we send an update to this object, which then can broadcast the delta changes to everyone viewing the game.

One problem we encounter though, is that we get a lot of different update packet types this way. However, nothing prevents us from generalizing them (this is slightly less pleasant with static packets):

There are obviously more details to this implementation, but the main idea is to defer update delta and notifications to when the packet have processed and send it as a single update. Interestingly, this allows us to surpress the queued notifications and updates if we want to. This can be useful for when errors occur during processing.

When is the the ad-hoc solution better?

Removing the need to duplicate game logic in the client is the greatest advantage to pure update deltas. This makes updates very simple in the client, and this is appropriate to use when it is important and expected that the game model is always in sync with the server.

If you have a fairly rich, but well defined, state – like in poker – updates of a player view makes good sense, but that doesn’t mean it’s universally applicable. Starting out with an ad-hoc solution can often be a good idea while prototyping or starting out.

The player game state

For our poker table we’ll want to know what players are participating, the cards on the table, the pot, active players etc. (It’s likely this object is missing a few fields, but you get the general idea)