Replays 2: Replay’s Revenge

Last week I said I needed a vacation, and I almost took one! Instead, I worked on something I find infinitely exciting — implementing a replay system in Bleed 2! This will be a continuation of the replays post I made a few months back. It will also be very wordy, sorry about that!

 

Implementing Replays

A quick refresher: I’m storing the user’s inputs every frame and saving them in a file. When it comes time to watch a replay, the game uses the saved inputs to reproduce the playthrough. I call each frame of input ReplayData.

I need to make sure there’s no difference between the player controlling Wryn and a replay file controlling her. So, even when you play the game your inputs are converted into ReplayData before they go to Wryn. When you watch a replay, the ReplayData comes from the recorded file instead of the player. Either way, Wryn is getting the exact same kind of information at the exact same time.

Highly technical diagram of the two ways Wryn can receive ReplayData

 

Problems

Once I re-coded everything to work this way, I started running into problems. A big one was handling menus — menus aren’t part of replay files so they aren’t controlled by ReplayData, and ReplayData isn’t created while they are active.

An example of when this is an issue: the game is paused. You select ‘return to game’ by pressing the jump button. You weren’t pressing the jump button before you paused, and since Wryn hasn’t gotten any new ReplayData since then, as far as she knows the jump button is up. As soon as you un-pause, fresh ReplayData is created telling her the jump button is now down, causing Wryn to jump or air-dash when you didn’t intend her to.

The solution was to add another bool (a true/false flag) to the ReplayData, letting Wryn know if she was just in a menu so she can ignore jump button presses immediately after resuming play. The bool has to be stored in the ReplayData — if it was just part of the pause menu, you could mess up playback by pausing/un-pausing during replays.

This is what a frame of ReplayData looked like after the fix.

 

Optimizing Stored Inputs

This created another problem — the additional bool means every frame of ReplayData takes up about 10% more space. I want to keep replay files as small as possible, and this is where my wonderful coder father came in with some slick optimizations.

This is a bit technical, and I can only explain it as well as I understand it, but here goes:

Everything in code takes up bytes of memory. So, in my ReplayData: the bool for “is the jump button down?” uses one byte. The bool for “was the player just using the menu?” uses another byte. Every true/false value I store takes up another byte in memory.

Now here’s a secret: a byte is actually made up of 8 smaller units, called bits. Bits are super simple: they can only be 0 or 1. So for example:

A byte storing the number 1, in bits, is: 00000001
A byte storing the number 20, in bits, is: 00010100
And so on. They’re all eight 0’s and 1’s, in different combinations!

What does all this have to do with anything? Well, I’ve got a lot of bools taking up space in my ReplayData. If you’ll notice, a bool is just a value holding true/false, which is kind of like… a bit, that only holds 0/1?

Yes! So if you know what you’re doing (as my pops does) you can use the 8 bits in a single byte to act as 8 true/false flags! So instead of my ReplayData using 4 bools (one byte each), I now have one byte to store them all, which even leaves 4 bits left over if I ever need more flags!

The new, ultra-compressed ReplayData!

Before, every frame of ReplayData was 10 bytes — now it’s 7! Worst case, even an hour-long co-op replay will only use 3Mb, where before it would take almost 4.5Mb! I really like these numbers.

 

The End (For Now…)

Soooooo yeah! That’s what I did this week! It was kind of a break from usual work, but still potentially helped the game! Replays aren’t fully working yet, and they aren’t tested at all, but they’re starting to get in there and things seem promising for now, so I’m excited!

If you made it all the way to the end, thank you for reading! I hope maybe you learned something! Here’s a shot of the replays in action to close things out.

Yeah, I understand I could have faked this with a pre-recorded video, but please take my word for it. The game is replaying my inputs back to me!

NOW I’m on vacation for real. Peace!!

Update: More replay work is detailed in this post.