Sign in to follow this  
paic

recording / replaying

Recommended Posts

paic    645
Hi, I'm wondering how can we record datas in order to replay something in a game. My first idea is to store for each frame the position / quaternion of each entity, so that I can easily go to any frame later. But that would create enourmous replay files ... The other idea is to only store the inputs. But in order to do that, I need a really deterministic engine (don't know if "deterministic" is the correct word. I mean an engine which would always have the same result for the same set of inputs) And the problem is to go back during the replay ... Do you know any method that would easily allow replay (forward and backward) without storing huge files ?? Thx in advance.

Share this post


Link to post
Share on other sites
Galapaegos    277
Paic,

You could always save those inputs and timestamp them when they occur, then play them back in a different thread playing those inputs at their specified offseted time.

When you seek, you can replay through all the events as fast as possible and not perform any rendering. I don't know how many assumptions you can make, but there might be some to help speed up seeking.

-brad

Share this post


Link to post
Share on other sites
drakostar    224
What you describe certainly could be possible. You'd need to store the initial seed of your random number generator, but that's about it. Other than that pseudo-randomness, the only possible influence is player input, right? Computer programs are inherently "deterministic" (I'm not sure if that's the right word either).

If that doesn't work out for you, try storing the initial state, and then just the changes at every tick. But that could be nearly as verbose as dumping the entire state at each tick, depending on what kind of game you have.

Share this post


Link to post
Share on other sites
paic    645
The problem of storing inputs, is floating point numbers, and rounding errors. If I replay using only the user inputs, a very small rounding error could lead to really different results, especially with collisions ...
And the problem of seeking is that even if I do not render anything, doing every updates since the first frame would take quite a lot of time with all the physics used in the engine :/
I thought maybe the first solution (store all the needed informations for any entity to render it at a given frame) with a good compression / decompression algorithm would work, but before, I wanted to know how people do this :-)

Share this post


Link to post
Share on other sites
caffiene    237
You dont necessarily have to store the exact user inputs...

If your system posts events for each user input, then you can simply record those events instead, eactly as they are posted.

But you're correct... in order to be able to reliably record and replay with any efficiency, you really need a deterministic engine, with only seeded random number generators providing "randomness". If you have major operations in the game logic which give different behaviour due to floating point and rounding errors, then youre going to have a hard time managing a replay feature.


One sidenote: If you do manage to overcome that problem, and use the method of storing input and seeds - if you have a threaded program, make sure you have a thread-safe random number generator!

Share this post


Link to post
Share on other sites
syedhs    122
Well storing position+quaternion for each object in each frame is the most straightforward method.

1) Why dont you just do it, and see if the file is indeed as big as you think?

2) If the file is indeed big, here are the steps that I can think of to reduce the size:-
a) Quaternion compression (16 bytes down to approximately 7 bytes)
b) Vector3d compression (12 bytes to maybe 10 bytes)
c) Interpolation. Let say that a car is moving from one point to another in a straight line, you can just store the start point+ending point and the timestamp itself.
d) Lastly, you can use a good compression library eg 7zip to further compress the file.

I would say, do (a), (b) and followed by (d) as they are the most straighforward.

Share this post


Link to post
Share on other sites
Kylotan    9872
Quote:
Original post by caffiene
If you have major operations in the game logic which give different behaviour due to floating point and rounding errors, then youre going to have a hard time managing a replay feature.


Floating point and rounding errors are just lack of precision - they're still 100% deterministic. The CPU doesn't just get values randomly wrong.

Share this post


Link to post
Share on other sites
paic    645
Quote:
Original post by Kylotan
The CPU doesn't just get values randomly wrong.


Yes, you're right, but I forgot to say that a replay file can be replayed on any plateform supported by the program ... and maybe different kind of processors can lead to errors ?

syedhs > imagine a car : you have 5 objects (the body, and 4 wheels) -> 140B each frame (without storing lights states, and other effects)
take 20 vehicles, run the program at 50FPS, and replay 15 minutes ...120MB of data. I'll need a really good compression algorithm (which needs to run at 50FPS)

The more I think about it, the more I think I'll try to store inputs.

Thx for the inputs :-)

Share this post


Link to post
Share on other sites
Brother Bob    10344
Quote:
Original post by paic
syedhs > imagine a car : you have 5 objects (the body, and 4 wheels) -> 140B each frame (without storing lights states, and other effects)
take 20 vehicles, run the program at 50FPS, and replay 15 minutes ...120MB of data. I'll need a really good compression algorithm (which needs to run at 50FPS)

Do you really need to sample at every single frame? Why not, say, 10 samples a second, or even 2-3 times a second could be enough? During playback, interpolate values for higher playback rates.

If you fix it to the frame rate, you also need to time stamp every frame so you know how fast to playback, as framerate could vary over time. At a fixed rate, you know when each sample is taken, and the increased resolution you get from 50 samples a second compared to 10, or 2-3 samples a second, may not make a noticable difference in practice.

Share this post


Link to post
Share on other sites
paic    645
Ah, I forgot to ask a question : when you store inputs, and just replay the scene replacing user inputs by the ones you saved, it's fine. But how can you seek backward ? The physic engine can't run backward, right ? And if I have 15 minutes of replay, I can't replay from the first frame, it would be too long (even without displaying)

Nobody ever coded this kind of stuff and could give me a hint ? :-)

Share this post


Link to post
Share on other sites
oliii    2196
I did, both deterministic and non-deterministic.

You can't play backwards with deterministic. You will have to replay from the start to the seek time. Deterministic engine don't work with multithreading very well (or at all).

To reduce size in non-deterministic replay systems, I used delta-compression. Only a small portion of the game state will change from frame to frame. You need to record that. You can even reduce it further is you limit the replays to what the player can see. Typically, for a 3rd person shooter, I recorded at 100 kb/min, 200 kb/min.

Again, playing backwards isn't really possible with delta-compressed frames, unless you do like Prince Of Persia, and record in an extra buffer and not delta-compress them. You can record keyframes though, where the game state is not delta compressed, and delta from that point onwards. Then you can jump around the replays.

Share this post


Link to post
Share on other sites
implicit    504
Floating point is a mess. If you need to support more than a single build on a single platform you'll just have to go with fixed point and avoid floating point in the game logic. Just a tiny change which makes to optimizer reorder some instructions would be enough to make things go out of sync, and in a system like .NET where the JITer may decide to switch from using the 80-bit FPU to SSE/3dNow instructions you're truly fucked.

In our game we handled replays by storing full states (key frames) every couple of seconds and recorded input in between. Simple and effective really, as long as you're willing to put up with all the fixed-point crap. Oh and if you're going attempt to write deterministic game logic then do yourself a favor and add checksums and other debugging tools to make it easier to find synchronization bugs.

Share this post


Link to post
Share on other sites
syedhs    122
Quote:
Original post by paic
syedhs > imagine a car : you have 5 objects (the body, and 4 wheels) -> 140B each frame (without storing lights states, and other effects)
take 20 vehicles, run the program at 50FPS, and replay 15 minutes ...120MB of data. I'll need a really good compression algorithm (which needs to run at 50FPS)


Instead of storing position + quaternion for 5 bodies (car chassis + 4 tires), you store these instead:-
a) Car body orientation + position (you can store it as 'lossy' quaternion + vector so the bytes stored is 10(Position)+7(Quaternion).
b) All car tires instead, store the 'suspension travel' so you can store it as unsigned short (2 bytes each)
c) car velocity (2 bytes) - used to roll all the four tires
d) car steering (2 bytes) - used to steer the front tire
So the result is 17+2*4+2+2 = 29 instead of 140B.

And if the game/app is running at 50FPS, you dont necessarily store every frame. As I said earlier, if the car is moving predictably you can interpolate the frame between. Consider developing offline tool against the file to remove the 'unnecessary' frames (frames to be interpolated). This easily result in additional 20% compression (I didn't do a study though, just a rough guess ;)).

So a scene of 20 cars running for 15 minutes at 60FPS will result in
29*20*60*60*15=31320000 bytes or 31.32MB. Further 20% compression ~ 25MB.

And yes, you can fast-foward or jump to any timeline you wish. ;)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this