Friday Facts #149 - Deep down in multiplayer
I have been deep down in the multiplayer internals the whole time since the last Friday facts. I think about multiplayer when I eat, I think about it when I ride my bike, I even have dreams about packets travelling from place to place, when my wife asks me what do I think about, I'm almost afraid to tell the truth. So obviously there is nothing else I could write about than the multiplayer in this Friday facts. This is going to be somewhat technical.
The connection - the Router layer
This is the old way of connecting to the game.
The first problem is the possible abuse of the server to ddos someone. As it is possible to send packets with fake sender IP. The "hacker" can just send the connection request to the server, where the IP is the target . The server will eventually connect the target of the ddos attack to the game, and it will send him heartbeats until it gets disconnected. It takes 10 seconds to disconnect a peer so the attacker can flood the target with 700 packets by sending a single packet to the server.
So the new way of connecting is like this:
The client first generates (randomly) his id, and sends it to the server as part of the request. The server generates his unique random id as well, and sends it back to the client. The first response from the server is very small packet containing just the two ids and application version, so the reply is not effective for the ddos.
The server then waits for the reply from the client, if the IP of the connection request was hacked to not be real, the client will simply not respond and the connection ends. The serverID is required as proof, that the sender of the ConnectionReplyConfirm is really the source of connection request.
Several smaller problems of the connection logic were solved as well, such as possibility that the server connected a client twice (even without any hacking) and others.
Synchronisation - the Synchronizer layer
Once the player is connected, he will receive heartbeat packets from the server, and is expected to send his own.
In the old multiplayer model that was based on the peer-to-peer
, we had something called network-tick. It was a number used to identify sequential heartbeat messages. It could be used as a means of identification when packets where lost and when when peers needed to synchronize during connection/disconnection/map upload etc.
As the peer-to-peer
network model is being removed, this is not needed anymore and every communication has it's own numbering, I call it a sequence number. This allows players with big latency and lower internet connection speed to send their messages less often while sending more user actions in one message. It can be also used in the state where client is trying to catch up the game without making his own actions (more later).
A Side effect of redoing the synchronisation logic is better resistance to hacking. There was thing called "session magic"; a randomly generated number given to players as they connected to the game. Every packet sent to the server needed to provide this number as a key. But once it was shared, it was possible to send message as it was from a different player. This is now (almost) not possible as the session magic is different for every client.
Multiplayer states - the Multiplayer manager layer
The trying to catch up
mentioned in previous multiplayer post is now fully functional. Map upload is done in in the background, while others are playing the game. The new player is also receiving all the player input, that is saved for the next phase. Once the client downloads and loads the map, it tries to update it as fast as possible to catch up with the server. If he can't catch up or his upload is too slow and he decides to cancel the connection, other clients are not bothered.
Overall progress update
I have already added+removed more than 20 000 lines of code in my git branch called "fixed-multiplayer", so the changes are quite huge, but it feels good to dive into something completely new to me (networking), and get an understanding of it. As we have some nicely written tests for the multiplayer already, I could just make them work one by one from the lower layers (router, synchronizer) up to the higher layer (multiplayer manager). All the lower level tests are now working flawlessly, the higher level is being worked on, but simple connection to the game with 3 players was just fixed today. Because the multiplayer network model is far easier to understand and doesn't contain as many weird corner case issues I think it will be possible to have the finished version in weeks instead of months which makes me very positive.
To give you better idea of how much is happening under the hood, this is the diagram of the action path from when a key is pressed until it's applied on the local peer in a multiplayer game.
As always, let us know what you think on our forums