Conceptually, how does replay work in a game?

Design Patterns

Design Patterns Problem Overview


I was kind of curious as to how replay might be implemented in a game.

Initially, I thought that there would be just a command list of every player/ai action that was taken in the game, and it then 're-plays' the game and lets the engine render as usual. However, I have looked at replays in FPS/RTS games, and upon careful inspection even things like the particles and graphical/audible glitches are consistent (and those glitches are generally inconsistent).

So How does this happen. In fixed camera angle games I though it might just write every frame of the whole scene to a stream that gets stored and then just replays the stream back, but that doesn't seem like enough for games that allow you to pause and move the camera around. You'd have to store the locations of everything in the scene at all points in time (No?). So for things like particles, that's a lot of data to push which seems like a significant draw on the game's performance whilst playing.

Design Patterns Solutions


Solution 1 - Design Patterns

I think your initial thought was correct. To create a replay, you store all input received from the user (along with the frame number at which it was received) along with the initial seeds of any random number generators. To replay the game, you reset your PRNGs using the saved seeds and feed the game engine the same sequence of input (synchronized to the frame numbers). Since many games will update the game state based on the amount of time that passes between frames, you may also need to store the length of each frame.

Solution 2 - Design Patterns

Starcraft and Starcraft: Brood War had a replay feature. After a match was completed, you could choose to save the replay to view later. While replaying, you could scroll around the map and click on units and buildings, but not change their behaviors.

I remember once watching a replay of a match that had been played in the original game, but the replay was being viewed in Brood War. For those unfamiliar, Brood War contains all of the original units and buildings, as well as a variety of new ones. In the original game, the player had defeated the computer by creating units that the computer could not easily counter. When I played the replay in Brood War, the computer had access to different units, which it created and used to defeat the player. So the exact same replay file resulted in a different winner depending on which version of Starcraft was playing the file.

I always found the concept fascinating. It would seem that the replay feature worked by recording all of the inputs of the player, and assumed that the computer would respond to those stimuli in the exact same way each time. When the player inputs were fed into the original Starcraft replayer, the game played out exactly as it did in the original match. When the same exact input was fed into the Brood War replayer, the computer reacted differently, created stronger units, and won the game.

Something to keep in mind if you're writing a replay engine.

Solution 3 - Design Patterns

There are two major methods:

  1. Storing events (such as player/ai actions) -- just as you say.
  2. Storing state (full game state, f.e. locations of objects, in consecutive moments).

It depends on what you want to do. Sometimes storing events is better, because this takes usually much less memory. On the other side if you want to provide replays which can be played at different speeds and from different starting points, it is better to store states. When storing states you can also decide whether store them after every event or f.e. only 12 or 25 times per second -- this might reduce size of your replay and make it easier to rewind/fast forward them.

Note that "state" does not mean graphical state. More something like unit positions, state of resources and so on. Things like graphics, particle systems and so on is usually deterministic and can be stored as "animation X, time Y:Z".

Sometimes replays are used as anticheating scheme. Then storing events is probably the best here.

Solution 4 - Design Patterns

Technically you should write your engine to be deterministic, that is no randomness. Assuming a character in the game is aiming at the arm of an opponent, and fires a weapon, then the same amount of damage should be applied to the opponent in all cases.

Assuming a bomb detonates at location X, the particles produced by that explosion should always result in the same visual result. If you need randomness, create a set of random numbers, select a seed value when the game is played, and save that seed value in the replay.

In general having randomness in a game is a bad idea. Even for things like multiplayer, you can't have half your players able to see around an explosion while the others can't simply because they didn't get the right random value.

Make everything deterministic, and you should be fine.

Solution 5 - Design Patterns

Given the initial state and a series of actions with timestamps, simply go through the sequence as the recorded actions are supposed to happen have a replay.

In order to get random events to re-occur exactly the same, use seeded pseudo-random numbers and save the seed in the replay file.

So long as you use the same algorithm to generate the random numbers from the seed, you can recreate all the events just as they occurred in the live game without needing full snapshots of the game state.

This will require replays to be watched sequentially, but that's pretty normal for game replays (see Starcraft 2). If you want to allow random-access to the timeline, you can take full state snapshots at set intervals (say every minute), to jumping around the timeline at a set granularity.

Solution 6 - Design Patterns

NVidia PhysX (a physics simulation engine that is often used in games) is capable of recording the full state of the physical scene over time. This incorporates any driving inputs from the game engine, which means you don't need to track random number seeds as others have suggested. If you take this scene dump, you can replay it in an outside tool (provided by NVidia), which is very handy for tracking down problems with your physical models. However, you could also use the same physics stream to drive your graphics engine, which would then allow you to have normal camera control, since only the physics driving the graphics have been recorded. In many games, this includes the particle effects (PhysX includes some very sophisticated particle systems.) As for sound, I'm guessing that's recorded verbatim (as a sound stream), but I'm not sure.

Solution 7 - Design Patterns

Your original idea is right, and for the really complex effects, they aren't remembered exclusively. For example, the Warcraft 3 replay system doesn't store the state of animations, or particle effects in the case of random effects, etc. Besides, MOST things can be computationally computed from a starting point in a deterministic way, so for most systems that use random variables (a particle explosion that gives a random offset, for example), all you would need is the time of the effect, and the random seed. You could then re-generate the effect without really knowing what it will end up looking like.. knowing that it is going through a deterministic code path.

Thinking of it purely conceptually, to replay a timeline of events, all you need are the user actions. The program will react exactly the same way, except in the case of random variables. In this scenario, you could either ignore the randomness (does it REALLY matter if the effects look EXACTLY the same, or can they be randomly re-generated), or store the seed value and fake the randomness.

Solution 8 - Design Patterns

Throw my two pence in.

Depends on what you want, replay may be accomplished via

  1. Recording video buffer and replaying later,
  2. Capturing object state every frame and replaying later,

Most of the time, people want an interactive replay, so 2. is the way to go. Then depending on your constraints there are a number of ways to optimize this process

  • ensure system is a deterministic simulation *, such that every input generates a consistent and expected output
  • if randomicity is required, ensure random numbers may be reproduced exactly at a later time [look at seeding with Pseudo Random Number Generators PRNG, or use canned random sets]
  • divide game elements into "mechanic" and "aesthetic" elements. mechanic elements affect outcome [eg column falling over and blocking path], aesthetic elements are for show and do not influence any decision making process in the system [eg visual particle effects like sparks].

It really is a fascinating topic. I remember that one launch title for original Xbox Wreckless had a good playback feature. Unfortunately, on more than one occasion the replay would screw up ;)

oh yeah, how could anyone forget Blinx Time Sweeper! great interactive replay that was incorporated into actual game mechanic!


*= seems there are some comments regarding time stepping. i am using "simulation" here to capture this feature. at the core, your engine needs to be able to produce discrete frames of time. even if a replay frame takes longer or shorter to process than the original, the system must perceive that the same time delta has passed. this means recording the frame time-step with each recorded input, and supplying this delta to your engine clock.

Solution 9 - Design Patterns

Perhaps you could Simply save a stack of commands being sent by each player. So instead of saving that a bomb detonates at a certain point and time, or that a certain car is destroyed, you simply save the key presses sent by each player. Then, in the replay, you simply simulate the game as it would have happened with those presses. I feel like that has the potential to take up less space, but I've never worked on a replay system like that.

Interesting question, though. I'd be interested in how it's done in professional games.

Solution 10 - Design Patterns

Dan Bryant

> Further, recording random seeds would not be sufficient for rewind > support, since random progression is not a reversible procedure > without special support in all of the logic relying on the randomness. > It's more flexible to record the results of the random operations as > part of the event stream.

That's exactly What I thought at first when I was trying to figure out how did they make it so that the game replays always the same each time. With Doom I thought at how random the shoots went :D. Store any random number got used, I found out it could be a solution. That was before I came across a pdf paper about Crysis technology. Some textures noise there and grass or tree disposition, seemed to be using pseudorandomization with fixed reversible seed to make it so you didn't see altered disposition of noise, trees and grass anytime you look!

Avoiding at the same time, to store millions of trees and grass shafts position. Apparently pseudo random sequence can replay the same anytime, as the logic is fixed, to just make a fake statistically random sequence of numbers.

Solution 11 - Design Patterns

The problem of having a consistent replay is the same (well, easier) like have a consistent multiplayer game.

As others mentioned before, replays in RTS games are stored by recording all input (that has an effect. Scrolling has no effect.) Multiplayer transmits all input, too

Recording all input not just a guess - there is a library for reading Warcraft3 replays with reveals this.

input includes timestamps for this answer.

Solution 12 - Design Patterns

I would believe that at certain increments the game would take a snapshot of the state of everything (EVERYTHING). Then when the replay is happening simple usage of linear-interpolation can be used to fill in the "holes". At least that is how i think it would be done.

You are correct that recording the inputs would be unreliable/not guarantee the same output. The game definitely has to keep track of the state of all the objects (or at least the important ones)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSteven EversView Question on Stackoverflow
Solution 1 - Design PatternsPeter RudermanView Answer on Stackoverflow
Solution 2 - Design PatternsBobwiseView Answer on Stackoverflow
Solution 3 - Design PatternslioriView Answer on Stackoverflow
Solution 4 - Design PatternsTimothy BaldridgeView Answer on Stackoverflow
Solution 5 - Design PatternsBen SView Answer on Stackoverflow
Solution 6 - Design PatternsDan BryantView Answer on Stackoverflow
Solution 7 - Design PatternsStefan ValianuView Answer on Stackoverflow
Solution 8 - Design Patternsjohnny gView Answer on Stackoverflow
Solution 9 - Design PatternsThirdD3greeView Answer on Stackoverflow
Solution 10 - Design PatternsAntonymousView Answer on Stackoverflow
Solution 11 - Design PatternsFrankyView Answer on Stackoverflow
Solution 12 - Design PatternsBob FincheimerView Answer on Stackoverflow