Rollback netcode on the NES, the gory details
Hey folks! Ready for a really technical one?
Super Tilt Bro. ALPHA 5 just hit the public, and with it the ability to play online with any character on any stage. Time to take a step back, see how the netcode works, and what where the biggest challenges.
As you know it from reading the precedent technical entry (or at least the illustrated part), Super Tilt Bro. Implements a rollback netcode on the NES. It means that the game is always smooth, when the messages from the other NES take time to transit, the game just predicts it and continue. Sometimes it happens that the prediction was wrong, the game has to revert predicted frames, and re-compute the real ones.
How the protocol works
Rollback netcodes are notoriously hard to implement. Browsing the internet, you will see very long posts explaining that the Switch is not powerful enough to do it. How the heck can it run on the NES?! (Spoiler: of course, by cheating!)
A very big pain point in traditional implementation of such a netcode is the memory management. The game has to keep a list of its previous states to be able to rollback from any of them. With only 2 KB of very slow memory, Super Tilt Bro. has to avoid it. The solution is to make the server smarter.
When you press a button, a message is sent to the server. This message is tiny, it contains just the button pressed and a timestamp. In turn, the server computes the state of the game when you pressed the button, so it can send an enhanced message to the other NES. The enhanced message contains the button pressed, a timestamp, and the state of the game at this point. The NES receiving such a message now has everything at hand. It just replaces its current state by the received one, and rollback enough frames to compensate for transit time.
The good point of this approach is that memory management on the NES is completely removed. Of course, there are drawbacks. The server must be smart, it actually has to incorporate an emulator to compute game's state. Worst, there is no way to switch to a peer-to-peer protocol. Time will tell if this rollback netcode is better than peer-to-peer input-lag netcodes.
Introducing the main foo: the CPU
Now the NES has an old state received from the server, and must simulate missing frames. It has to be speedy. We don't want to see characters moving in fast-motion to catch-up, that would destroy the timing of player's inputs, and make them miss combos. The goal is to rollback immediately, so the game is at the same point in time it was before the message's reception. We have exactly 20 milliseconds to do it without missing a video frame (on PAL.)
The first thing to do is to be able to simulate a frame in “rollback mode”. In this mode, nothing has to be displayed, so the engine can safely skip placing sprites on the screen, updating the background, and anything visual.
That done, simulating a frame in rollback mode take 25% of the 20 milliseconds. It would be enough to rollback four frames, and compensate 80 milliseconds of ping, if the rest of the game did not take 60% of the time. Notably, it has to simulate a frame in normal mode, to show sprites and other visual effects. All in all, it allows for almost no rollback.
Next step is to optimize everything that is done multiple times per frame. Collision detection is where we get the biggest gains. It was an old code, mostly implemented while learning 6502, and is run for both players, for each platform, multiple times. With this code rewrote, it is finally possible to play online even on complex stages.
Another big win is the optimization of the animation code. While in rollback we don't care about animating sprites on screen, in Super Tilt Bro. hitboxes are stored in animation data. Parsing all meta-sprites to extract an hitbox is time-consuming. Here the trick is to always put hitboxes at the beginning of such data, and stop reading there. Plus some low level optimization, it is always good to take.
Optimizing gave space to rollback around three frames. The work is not over :)
We are not yet fast enough to compensate big latencies. Thankfully, the server is smart. It can itself predict frames, and does just that to compensate for the minimal latency ever seen between players. That way, the NES just has to handle the variable part of it. Let's say your ping oscillate between 100 and 140 milliseconds, the server will predict for 100 ms, so in the worst case the NES will have to predict only two frames.
First and foremost, this code needs to be battle tested. For sure, it is not yet perfect. The only solution is to try it, play with it, and report anything strange. The more it is used, the more we can find issues. Super Tilt Bro. needs you! Please bring some friends, play together, and send your feedback. It really helps! Your journey begins here: https://sgadrat.itch.io/super-tilt-bro
If the online mode should work, it is still very light. There is only a very simple matchmaking available, and the user interface is the ugliest you can imagine. I guess I will now focus on the things around the netcode, beginning with a ranking system. Wouldn't it be nice to go to the official ranking page and find that you are the best player in the world?
Get Super Tilt Bro. for NES
Leave a comment
Log in with itch.io to leave a comment.