What is best practice for managing boardgame move commands in Nakama? RPC or send_match_state_asyc() or something else?

Hello Heroic Labs!

I am making a turn-based boardgame and would appreciate advice on best Nakama practices.

  • The active player should be able to make the moves that comprise their turn, issuing at most one move command every few seconds.
  • Other players when online should be able to watch the active player making moves in real time.
  • The active player should be able to take up to 24 hours to complete their turn.

After reading through the Nakama docs, it seems I should use Authoritative Multiplayer and create one Match per game. I’d very much appreciate advice on how to best manage player’s move commands:

On one hand, if the client sends moves with socket.send_match_state_asych() , it seems the server needs to wait for match_loop() to tick to process them. But I’d expect I’d set this loop to a very long tick for performance, since it only has to check for time-out forfeits, and I hope to support many simultaneous matches.

On the other hand, if I register a client RPC to send the moves, which seems the most natural way, I can’t see how I declare the RPC in a way that calls into the Match module (so it has access to the Match tick, state, and presences for example)

How should handle this? Am I on the right track? What would be the best practice here?

Also, in general is it best practice to have a Match persist for days like this, or is there another idea you’d advise?

Thank you very much,
Matt

Hello @MattW,

There’s a Match Signal API to allow RPCs to send data into a match, however I’d avoid using this unless absolutely needed, ideally you’d just connect to the match and use realtime messages to modify its state - that’s the recommended pattern.

The lowest tick-rate supported is 1 (one tick per second). As you state the server processes incoming messages received up to that point at each tick. The match can outlive and exist even without players connected - it updates its state by processing the received messages at each tick and send state updates to all connected players in realtime (as participants or as observers). Players that reconnect to an ongoing match can get the current state upon joining.

Matches are very lightweight, so if your game logic doesn’t require high tick-rate or CPU intensive calculations, you should be able to spin up many of them without issue even on modest hardware.

Long-lived matches are no issue, but you’ll need to account for server restarts by storing and restoring the state of ongoing matches if needed. Have a look at: Match Handler API - Heroic Labs Documentation .

Our project template may help you get started.

Hope this helps.

Thank you, that helped. I now have a server up creating Authoritative Matches and exchanging messages with clients. I have another question (should I start another topic?).

I occasionally need to send a data package bigger than 1500 bytes. For example, the server needs to send a one-time 10-15k full game state to any player who joins a game in-progress or who just needs to re-synch for whatever reason. (Also, it would be convenient for the player to be able to occasionally send their 10-15k game state to the server for debugging.) What’s best practice for this?

Thanks! -Matt

You may need to increase the max message size but otherwise it should be ok as long as it’s only done once to sync the initial state and deltas are exchanged going forward.

That seems to do the trick, thank you.

Worth mentioning that the config.yml templates offered in the doc here use a different nakama/data volume map than the map used in the template docker-compose.yml located immediately above it. Reconciling the two might reduce config file set-up confusion for new users.

Thanks again.