Peer 2 Peer Networking and State Buffers

A discussion came up on the Discord channel about how to manage state in multiplayer games. I described how it was solved “back in the day” during my time developing ArmyMen RTS.

Yes, its old (2002) but the multiplayer Peer2Peer networking methods we used were a moving window state buffer. I’ll describe how it works, and over the coming weeks I’ll add a little Defold sample people can use.

State Machines
To be able to properly “know” what a game is doing at any point in time it is good to use a state machine. This is a broad term and can come in many implementations, but fundamentally a state machine allows developers to know what state the game is in at any specific time or step.

We will ignore the machine part of this discussion, and simplify to talk about pure state within a game frame.

An example is collecting the input value for all possible key presses and record any changed state. This might be encoded into a bitstream or bytestream ie:
First byte: Id of the event that caused it
Second byte: State info for the event - 1 bit for key up/down, 1 bit for shift held
and a series of these for all the events that occurred during a single frame.
Additionally this “state” would be usually preceded with a header with properties like timestamp, frame id, and others.

Together this all represents the “state” of input over the frame.

State Buffer Management

The states are sent over the network and other peers collate them. They put them into a buffer.
This is usually a time ordered or frame ordered buffer.
The buffer is often large enough to have a second (in time) or more of updates within it.
The game with the incoming states applies them to the game if the game is at the same timestep and the actions the player applies will look correct.

A little trick with this, is all game states run a little “behind”. So that the states that the player sees can often be slightly behind what the latest state that is in the buffer. The reason for this is to cater for slower network connections allowing states in the buffer to not be too far infront of faster players.

To ensure state is consistent, one of the peers is usually nominated the “master”. The master does validation checking on the states. Usually some form of encryption or crc hashing is used to align the masters own gamestate with the state buffer. If a specific state comes in, and it doesnt match for a specific timestep, then the master can drop that peer from the game.

Also, we had peer promotion. Which allows the master to leave the game, and another peer will be promoted to master and start validating the state buffer.

Implementation

So far I have really only been talking about simple state - like keyboard input. For more complex state and state machines it is best to use a FSM - Finite State Machine (there are others, but I like FSMs :slight_smile: ).

Im not going into detail about FSM’s here, there is alot on google - although very few good articles or Id link them :). I have some samples already with FSM’s in them (Cairo and a couple of others). I’ll make a specific example for this thread.

Put simply, a finite state machine allows you to record state of a property and easily change it via events or methods. A hierarchical one, can contain an entire gamestate for interactive objects which can then be serialized into a bitstream or bytestream and you have a “known state” for a game in a frame.

That is the general description of how you can use state machines and be able to share state between peers in a P2P networked game. This is quite an old technique games like Quake and earlier used similar mechanisms along with prediction methods to minimize the amount of data needed to be sent.

I’ll expand on this over the coming weeks. If you have questions, ideas or would like to see specific examples let me know and I’ll try to integrate it into the example.

Cheers,
Dave

20 Likes

Finally an Defold 3D game!
I think it will be more outstanding if realtime shadows added.

I will be extremely interested in reading your future posts!

I have done much research into multiplayer, but insights from a developer who has really done it will be quite valuable.

Just dropping in to say I absolutely loved this game way back in the day. Played the heck out of it on the GameCube. Unfortunately there was no netplay on GC.

2 Likes

Hi @COCO Im not really proposing a 3D game here :slight_smile: … Although I have a number of samples that will help you make 3D games. Shadows are on my list - @britzl and @jcash and others have already done some great work in the 3D realtime shadows in Defold (theres posts on the forums here).

For 3D samples:

There are many many more too. Ive also got a simulation and game system working 3D quite nicely. Im sure this will become more prominent in Defold over the coming months/years. Its a big job to “get it right” in an editor, so if you need just roll it yourself - its not too bad to do.

3 Likes

Thanks. I loved playing and working on it. Only 9 of us - 3 coders, 3 artists, 2 designers and 1 business dev made the PC & PS2 version within 12 months at Pandemic Studios. Honestly, it was the best team Ive worked with. Sooo amazing to even be involved (btw they were all the old Dark Reign guys :slight_smile: ).
Would love to make something similar again… not necessarily ArmyMen, but just a fun and interesting RTS. Anyway… good ol days :slight_smile:

4 Likes

Thanks.
I did some research in … other engines but
bandicam 2021-06-04 17-13-20-479

I really really would like to see 3Ds in Defold.
I think 3D is the future.

Hi @COCO - not sure if you saw the link to the 3d and shadows examples in Defold?
I’ll paste the whole link:

image
This is using Defold.
And rather than subverting other threads, maybe talk about what specific problem you are having in the appropriate thread, or better still create a new thread? The discussion of 3D here is derailing the aim of this thread. This thread is aimed at network and state buffers (as the title states).

4 Likes

Yes, I see. Look forward for your p2p network articles.

1 Like

Thanks for this awesome writeup :heart:

1 Like

Short update. I haven’t forgotten about this, life has gotten in the way again. I hope to start putting up examples over this coming week using a new Defold-web gui setup - allows me to display info, and various other bits in simple html (faster dev).

4 Likes

So. This has all gone a little bit sad. I was going to do a nice project using Nakama, but ran into various issues with all sorts of things. I’ll post a Nakama sample sometime over the coming weeks, but I will be going back to making a pure luajit “servlet” using sockets and a Defold app as “simple game clients”.
I hope this shouldnt take more than another week to do so - since I already have my own luajit server setup and Defold should easily work with it… Ha… famous last words… :slight_smile: Will see.

2 Likes

A bit of cross posting here. Theres a dev blog here about doing the above.
https://forum.defold.com/t/building-a-multiplayer-server/

The server and client system I built has a state buffer system (very rudimentary). I was hoping to use Nakama but there were issues (as noted above).

The state buffer system in SWAMPY is simple - it has been implemented in the warbattlesmp module using websockets.
Operation is:

  • Clients connect using http and if there is no game, one is created.
  • Other clients join (using http) and then are given a websocket port to communicate on once joined.
  • During init of a client, it is sent the tanks starting positions, other players and initial start info.
  • Client has a tank “pathing system” that uses start positions and game.frame time to set position of tanks during the game. No state buffer here - all algorithm based tank positions (much simpler).
  • Client starts sending changes in player movement and any shoot events
  • Server puts events into a list which is regularly parsed and sent to all players - this is the state buffer.
  • Clients receive the state buffer from the server and apply to “other” players in their game.
  • Rockets are also sent in state buffers (from the shoot event) and are replicated in the clients.

Again, this is a very simple implementation of such a system. Normally the state buffer would be frame or time “keyed”. This allows the server to sync checks to validate things like:

  • who killed a tank first (who gets the points)
  • whether the players positions are valid for the time/frame on the server
  • check if any incoming data is not spoofed or fake. Usually time/frame + checksum or code.

While not currently implemented, this is relatively easy to add, and I will hopefully put something like this on before xmas.

Otherwise it should give people an idea of how this sort of system works.

7 Likes