views:

5680

answers:

11

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 *in*consistent).

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.

A: 

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)

Bob Fincheimer
No, feeding the same inputs will result in exactly the same result as the first time. You just have to make sure that you get the timing correct, feeding the input inbetween the same frames where it was originally received. Saving the entire game state periodically could require a colossal amount of memory and produce inconsistent results as well.
Peter Ruderman
-1 this is *not* how it's done
BlueRaja - Danny Pflughoeft
@Peter, "feeding the same inputs will result in exactly the same result" : no. There is a random element in many games, which could be different each time the replay is played. You need to keep track of more than the inputs.
houbysoft
That's true. You also need to store the seeds of your PRNGs (see my answer to this question).
Peter Ruderman
i know it is performance and memory consuming, but if you miss 1 little thing as far as the input or the random generators...or really anything, the replay will go off on a horrible tangent!
Bob Fincheimer
@BlueRaja, Bob's memory snapshot idea is not necessarily that far-fetched, though a good engine can record state 'deltas' rather than encoding all memory for every iteration. This is probably easier to support at an engine level. 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.
Dan Bryant
+9  A: 

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.

Timothy Baldridge
What about AI? Is AI not random?
Jesse J
That's really not necessary. Use seeded pseudo-random numbers for all random events and save the seed in the replay file. That way the same "random" numbers will be generated during replay.
Ben S
-1 for clear misunderstanding of how "randomness" works in computers
BlueRaja - Danny Pflughoeft
Like he said, if you need randomness seed the PRNG and then save the seed value. This lets you recreate the same "randomness"
Ibrahim
um....no....I'm perfectly aware that there's no such thing as "true" randomness. However most people try to get around this by setting their random seed to something like the system time. However what I'm saying is that such a thing shouldn't be done. I don't care if he uses the system API or a predefined table of random numbers. What I originally said was correct. Every function in his engine should produce the same result based on its inputs. Time should never be a factor.
Timothy Baldridge
Also, I still recommend a lookup table, since if he ever plans to port his game to a new platform he has no assurances that the random function he's using won't change. random() with a seed of 20 could very well be different on a Mac/Windows/Linux machine. A pre-defined table will produce the best result. Or better yet, some sort of third-party random function portable across all the platforms.
Timothy Baldridge
@Timothy: They store the PRNG-seed. It does not matter how it was generated. If porting is a concern, they use a fixed-PRNG rather than the OS-provided one.
BlueRaja - Danny Pflughoeft
Time being a factor in a game because of frame rate is a technical decision. Implementing the game engine so that this is the case has many advantages, including making replays easier to generate (storing the seed doesn't cut it if your game's algorithm varies things a tiny bit because of frame rate), but it also has disadvantages. As for whether it is OK to use time to generate a PRNG seed, doing so is fine.
Brian
AI should not be (pseudo)random by definition: the same well defined strategy should be triggered given the same input. Nonetheless, complex AI opponents as expected may learn by errors (a neuronal network?) or alike, and so behave differently even with the same inputs... in this case again it is enough to store last N "snapshots" of the "net" that produced the behaviour, and let the net evolve again until the desired point.
ShinTakezou
If particles have no interaction with game mechanics in any meaningful way, then it doesn't really matter if the RNGs are different for them. This would help in the case of a network-synced simulation (as is the case in most RTS games, and a lot of other genres of games), as it's a little less the simulation has to sync every frame (the particle effects just get updated individually).
RCIX
+32  A: 

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.

Peter Ruderman
Frame numbers might not be a good reference since the replay might run at a different framerate than the live game.
Ben S
@Ben: Framerate doesn't make a difference, since the frame numbers will still be the same. This is the correct answer.
BlueRaja - Danny Pflughoeft
Nothing should really deal with the frames at all. Instead the data should be stored as: (at 10 sec player A fired). In this way the game can be replayed at any speed.
Timothy Baldridge
@Timothy: Except that many game loops begin by calculating the time since the last frame, and use that to update the game state (by calculating how far objects should move, and so on). If you store just the input _time_ and the replay framerate differs from the original, you could get inconsistent results due to math errors.
Peter Ruderman
Graphical frames and engine 'frames' (or iterations) are not necessarily the same. In many older games, the engine updated at the same rate as the graphics, in one master loop. With modern engines, the graphics are often allowed to update as fast as the GPU allows, with the engine ticking along at the level required for good, consistent resolution of the game dynamics (often a physics engine).
Dan Bryant
i think states must be stored somewhere, because in a game, at some time a randomness is needed. and randomness may or may not be created at top level but deep inside some AI algorithm. So ideal strategy is to save every state. saving user input is only possible in boardgames games like chess.
iamgopal
@iamgopal: if you know the state of the pseudo-random number generator, then that problem is already solved. Another method may be to treat random numbers as another form of input and save those alongside keypresses and the like.
Kylotan
I'd like to ad that this approach necessitates that your game engine is deterministic and that it operates with a fixed time step. I believe all Blizzard's RTS games have been built this way. Non-deterministic games would include additional synchronization data to ensure consistency in the long run.
John Leidegren
+12  A: 

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.

liori
+2  A: 

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.

ThirdD3gree
+8  A: 

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.

Ben S
If you re-seed every certain number of seconds (say 5 or 10) it'd be easy enough to record in your replay stream and also allow for jumping ahead or backward (to PRNG "key frames" essentially).
Wedge
+3  A: 

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.

johnny g
+5  A: 

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.

Dan Bryant
+3  A: 

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.

Stefan Valianu
+7  A: 

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.

Bobwise
+1: Very interesting. I hadn't ever heard about that. Provides some good insight into how they developed it.
SnOrfus
+1  A: 

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.

Franky