Replay

The replay feature should allow people to watch a race they've just finished, but also to save a race to be able to load it later, perhaps share it with friends etc. It is not supposed to be a frame by frame history, which might be needed to debug certain bugs (e.g. kart falling through track, problems with physics, AI, ...), it should only give the same (or a very close) visual recreation of a race. Mid term these files can be utilised for an online highscore lists: having people to submit a complete replay of the race makes sure other people can have a look at the races, and cheating (e.g. a patched STK program, changed physics) will be detected.

Another usage would be to allow a 'ghost opponent' (as apparently in Moorhuhn Kart): you can use a (downloaded) replay file and race with that kart on the same track. The downloaded kart would be a 'ghost' (e.g. slightly foggy?), and you can't interact with the kart. But it might be fun trying to beat a certain highscore, or learn from other players. Perhaps we would need a kind of filter to extract a single kart from a replay file(?).

And we should consider replay of Grand Prixs as well, e.g. a collection of races. Perhaps the right approach would be that a replay file is a collection of single race data (this would then include a single race, but would also be prepared to do Grand Prix as well).

Replaying should enable people to switch camera positions, e.g. select the karts, or a view from high above, or perhaps even to fly around(?).

The data files saved should be rather small, so I would suggest not to use any existing formats like XML, since they could easily double the file size, instead define a simple STK only ASCII file format. ASCII might be a bit bigger than a binary format (e.g. in binary a floating point number for STK can be saved in 4 bytes, while an ASCII representation might be 6 bytes (limited precision would be enough), but it has a few advantages:

Some design ideas for the file format:


An example file format might be (using # to indicate comments):

...                                                     # preamble, to be defined
...                                                     # containing information about what race, 
                                                        # number of karts, difficulty, numer of laps, ...
POS   @10.1    k 1  1.0,2.0,3.0,4.0,5.0,6.0 7.0,8.,9.   # position and velocity for kart 1 at time 10.1
               k 2  1.0,2.0,3.0,4.0,5.0,6.0 7.0,8.,9.   # dito for kart 2, indentation is optional
POS   @10.13   k 1 ...                                  # information for timestep 10.13
               k 2  ...
COLL  @10.14   k 1 zipper
CRASH @10.145  k 2 track  1.0,1.0,1.0                   # where it crashed, perhaps specify triangle?
POS   @10.16   k 1  ...
               k 2  ...
USE   @10.17   k 1 rocket 2                             # rockets etc. would get an internal number, so that: 
EXPL  @10.18   rocket 1                                 # the right rocket can be exploded and replaced

We need events like explode and collide, since (because of minor error in the physics engine depending on time step size) an event like this might not occur 'naturally': while in the original game a rocket just hit a kart, in the play it might otherwise just miss the kart. And the final file format should be easy to parse.

Comments welcome! --hiker 03:59, 8 May 2007 (CEST)



First decision would be: do we interpolate, or not? My preferences would be not to interpolate, since this is less implementation work. This way we could quickly see how big files can become etc. --hiker 05:49, 10 May 2007 (CEST)




today i take the challenge and start implementing it .. ;)


1. memory-requirements for recording a game / memory-management

for the beginning i'm experimenting with an array of allocated buffers

simplified it looks like this:

struct Frame
{
    // absolute time of frame
    float     time;
    // this will be an array with number of karts, pointing to another buffer
    // for simplication here it is just one kart
    sgCoord   kart;
};

// buffers of frames
Frame  **m_pp_blocks_frames;

before we start recording the game, we initialize the first element of the array pointing to an allocated buffer:

// we start with one buffer
m_pp_blocks_frames = new Frame*[ 1 ];
// number of frames stored in one buffer
// assuming 10 minutes with 50 frames per second
const int BUFFER_PREALLOCATE_FRAMES = 10 * 50 * 60;
m_pp_blocks_frames[ 0 ] = new Frame[ BUFFER_PREALLOCATE_FRAMES ];


if that buffer is not big enough for one game, here is how we allocate a new buffer without copying all the old frames to the new alloated buffer

Frame **pp_blocks_frames_old = m_pp_blocks_frames;
m_pp_blocks_frames = new Frame*[ 2 ];
// copy pointer(s) to old frame-buffer
for( tmp = 0; tmp < 1; ++tmp )
{
    m_pp_blocks_frames[tmp] = pp_blocks_frames_old[tmp];
}
// create new buffer of frames
m_pp_blocks_frames[1] = new Frame[ BUFFER_PREALLOCATE_FRAMES ];


this *memory-code* is gonna be hidden in templates, since we need different buffers, and it's gonna look like we are working with usual arrays, which have a self-growing-mode for recording, if an index is bigger than the array-size.

2. Replay-Files

I'm gonna make experiments with both human readable and binary files, if we decide to use binary-files, we have to take care of little/big endians.

What do you think about a new folder to store replays?


3. Compiler-Switch to activate replay while deveopment

As long as its not implemented in a usable way, i'm gonna put ifdef's called HAVE_GHOST_REPLAY. that way the trunk is not gonna be unusable ..


4. Sample-Frequency

for the time being i start recording with the normal frame-rate, but i guess for *good* results we can define a lower frequency later.


i'm curious about your ideas and feedback ..

--Ike 14:09, 18 Sep 2007

Retrieved from "http://supertuxkart.sourceforge.net/Replay"

User Tools