I implemented the most horribly hacked-up version of rollback-based networked multiplayer.
But it actually works! Or at least, it works during regular gameplay...
Cutting to the Chase
Much of my recent performance work has been oriented towards making rollback net-code1 feasible, so that performance doesn't slow to a crawl from having to re-simulate the past world as a result of inputs arriving from remote players.
But in the best case, where two players are physically in the same city (or room!), connected via reliable2 internet connections, maybe the game would already be playable over the network?
I decided to find out.
Call Me Victor
In theory, I had a lot of the groundwork already laid, so adding rollback should be easy.
In practice, I had to do some major surgery.3
Still, after lopping off a limb here, reattaching that arm there, adding some forehead stitches for effect, attaching a little metal knob on either side of the neck, and waiting for a convenient lightning strike...
Yay! Each player can run, jump and (not shown but trust me it works) cast spells to kill enemies.
And all that is correctly synchronized4 between the 4 separate copies of the game running on my computer. That means my earlier efforts to ensure determinism in game logic has worked! (so far...) 5
Caveats
But outside of that core gameplay, most things are still unimplemented; the game breaks in various ways when:
- Anyone reaches the end of a level, or
- All players die, or
- Anyone tries to do any level editing,6 or
- Particular debug options are switched on, or
- A local player is added or removed.
There's also no concept of an "offline" mode right now, which means the web build - where networked multiplayer is a whole different kettle of fish7 - is entirely broken too. So there is no playable web build this week. Sorry!
My testing thus far has also been with all game clients running on the same computer, which is the best possible situation with respect to network connectivity. Testing to see what performance is like in practice on bad connections is still on the todo list.
That is a lot of todos and unanswered questions! So I am still not sure whether online multiplayer support will be included in the game.
If rollback net-code means nothing to you, here are some previous updates covering it:
- Multiplayer Fever Dreams: high level overview.
- Rollback Performance: simulating the impact of rollbacks.
- Nondeterminism and You: why deterministic execution is crucial.
"Reliable" = wired via Cat 5/6/etc ethernet cables!
If you play online multiplayer games, please, for the love of all that is holy, connect to your router via a regular ethernet cable.
Not via wireless! Not via a router that's communicating over a wireless mesh! Not via powerline-based networking!
Tape a 50m cable to the floor if you have to.
I'm using GGRS to implement rollback, and it has its own way of doing things:
- I already store a ring buffer of my own past game states, inputs and checksums, but GGRS wants to own all 3.
- The features I added for simulating and counting rollbacks are superseded by its own versions of those.
- GGRS has strong rules for inputs, like requiring them to be a fixed size.
- GGRS doesn't support adding local or remote players during a game.
- And it doesn't have any support for synchronizing one-off events derived from player inputs.
Anyway, most of these things I can work around eventually, and the others I have sent in some pull requests for - but they still necessitated some serious hackery in my codebase.
Actually if you look really closely, you can see that the game client on the top left is initially a tiny bit ahead, but the other clients eventually catch up. The starting difference comes down to the exact timing of when each client finishes connecting to all other clients (currently the network architecture is fully "peer to peer").
Then, clients keep track of where they're at relative to other clients, and if a client is running faster than others it occasionally skips an update to slow down a little.
It's not really noticeable to humans, but this kind of slowdown is necessary to handle a player's computer being more powerful than others' computers - otherwise one game client gets too far ahead and has to completely stop for a bit to wait for others to catch up!
Although somewhat ironically, I did find non-deterministic behavior in my checksumming logic, of all places; I had taken a shortcut for performance reasons when calculating the checksum of the atom world, and that shortcut evidently resulted in me checksumming uninitialized memory - doh.
Level editing might not strictly need to be multiplayer, but it could be cool? If it's easy to get working then I'll add it.
I am not certain whether I will get networked multiplayer working on the web build.
I would like to, and I think it is possible to do so.
But it requires a bit of extra effort (using matchbox as net transport and coding and/or setting up some kind of matchmaking server), and that may not be warranted given that I am not planning to ship the game on the web in the long run.