game recording

Whats a good strategy to record a sequence of gamestates?

Kinda like a playback for a race game, I guess I’d need a fixed timestep to increment my gamelogic with, fx each 10ms between gamelogic updates indepenand of framerate. But what would be a good way to store the gamestate variables each 10ms? I know serialisation is overkill, write them in a dataoutputstream? And maybe wrap this around a zipstream to compress it a bit?

I guess it’s also closely related to networking games, that also need to send gamestate updates regulary but then over the network…

Another strategy is keeping the game state deterministic and only recording input (key presses). Take a look at

to see what I mean. Make sure to use strictfp if your game state involves floating point operations.

  • elias

The deterministisc approach, if it matters to you, is used by Blizzard in StarCraft to reply its matches. You can tell this if you play a game without the expansion, but then load the reply inside an expansion game (or vice versa). The units will act completely differently because they now have a different technology tree available to them that wasn’t there whent he match took place.

[quote]Another strategy is keeping the game state deterministic and only recording input (key presses). Take a look at


[/quote]
Nice read!
But I guess for my racing game, I’d better stick to state updates… (with networking in mind)
Because if I’d loose a packet containing a keypress, it would fail the next update (out of sync). I think the easiest way to overcome that is to send a state update each x ms? For each packet thats öut of sync" I could then interpolate to the right pos. But that would mean writing to a dataoutputstream? Any expirience using a zipoutputstream in such a realtime app?

I think you are either going to have to keep it all in memory or, if your average frequency of update is not high, queue up a window of udpates and write them on a seperate thread.

Any fileio in the middle of your game loop is likely to kill your frame rate. Thats why thy call it “secondary storage.”

If your game state is very small, you could get away with just writing it out on a buffered stream. In Tribal Trouble we write out all input to a event log file to be uploaded in case a crash happens. We found that it didn’t affect performance at all, so we kept it on even though we’re done with beta testing. I don’t think writing on a separate thread as Jeff suggests would make much difference, since the operating system already buffers disk writes, effectively flushing them from a separate thread itself. YMMV of course, and a racing game is more sensitive to “hiccups” than a RTS.

  • elias

[quote]…if I’d loose a packet containing a keypress, it would fail the next update (out of sync)
[/quote]
Actually, I don’t think that’s what the article is saying. If a packet is lost, you perform retransmission, and if a command (and its acknowledgement) arrive too late, you skip the input, or push it back to a later game tick. The system is built to handle identical simultaneous game simulations, and be robust enough to deal with networking problems such as you mentioned.

The “out of sync” thing was to check to make sure all simulations are the same at all times - essentially a debugging tool that allowed the developers to track down why it happened (assuming normal, non-cheating or code modifying elements), and make the changes necessary so that a player would never see an out of sync message. If they were at all common in Age of Empires, I’m sure you would have heard about it, because (as you alude to) if the game fails an “out of sync” check, the simulation must be halted - which would really ruin the player experience. :slight_smile:

Now, it would be interesting to see this: Since your game is being developed it in Java, the same bytecode might run slightly differently on various OS/VM combinations, and therefore make trying this in a cross-platform scenario especially difficult. Of course, if anyone has any practical knowledge (or counter argument) feel free to chime in here. I mean, in a precompiled environment, you at least know that the same machine code is being run on all computers at once. From one platform to another (say Intel to PowerPC), you actually get different machine code, guaranteed.

Now, again, I make the call for someone who actually knows about this stuff to chime in. I certainly don’t mean to scare you off from the idea, but I certainly don’t know the inner workings of a JVM.

I have some experience with it, since Tribal Trouble is implemented with synchronized game states. It works pretty well even with game clients from all the three platforms (linux, windows and mac os x) playing against each other. The only ‘trick’ you need to know is the strictfp keyword which will make your floating point game state (if any) be perfectly synchronized (another feature of java that you won’t find in C). Other than that, you just need to control all input (including time).

We even went so far and made the entire game session deterministic, not just the game state that is shared between clients. That way, we can very quickly and easily reproduce even the most obscure bugs.

  • elias

[quote]Actually, I don’t think that’s what the article is saying. If a packet is lost, you perform retransmission, and if a command (and its acknowledgement) arrive too late, you skip the input, or push it back to a later game tick. The system is built to handle identical simultaneous game simulations, and be robust enough to deal with networking problems such as you mentioned.
[/quote]
Ah sorry, I forgot to mention I’ll be using UDP for network transmission. I don’t feel to comfortable with creating a reliable delivery wrapper around UDP (my understanding is that it is very difficult to do right). So if i lose a packet i’d lose a keypress which was what i was reffering to with out of sync…

Also, as my game will be a race game, I dont think the model they described is very suitable for such a game, as it pretty much runs lockstep, and has an artificial lag and RTT which is not acceptable for a realtime racing game.

Good thing about pointing out the potential differences on different machine’s. Strictfp will ensure same floating point results on all plafforms? But this could only differ a fraction would it? Do I need to bother if I only need a fraction of 2 digits?