1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
|
/**
@file demofile.h
@author Tobi Vollebregt
@brief Defines the Spring demofile format
This file defines the Spring demofile format and which parts of it are supposed
to be stable (can be used safely by 3rd party applications) or unstable (format
may change every Spring release without notice).
*/
#ifndef DEMOFILE_H
#define DEMOFILE_H
#include "Platform/byteorder.h"
#include <boost/cstdint.hpp>
/** The first 16 bytes of each demofile. */
#define DEMOFILE_MAGIC "spring demofile"
/** The current demofile version. Only change on major modifications for which
appending stuff to DemoFileHeader is not sufficient. */
#define DEMOFILE_VERSION 4
#pragma pack(push, 1)
/**
@brief Spring demo file main header
Demo file layout is like this:
- DemoFileHeader
- Data chunks:
- Startscript (scriptSize)
- Demo stream (demoStreamSize)
- Player statistics, one PlayerStatistic for each player
- Team statistics, consisting of:
- Array of numTeams dwords indicating the number of
CTeam::Statistics for each team.
- Array of all CTeam::Statistics (total number of items is the
sum of the elements in the array of dwords).
The header is designed to be extensible: it contains a version field and a
headerSize field to support this. The version field is a major version number
of the file format, if this changes, anything may have changed in the file.
It is not supposed to change often (if at all). The headerSize field is a
minor version number, which happens to be equal to sizeof(DemoFileHeader).
If Spring didn't cleanup properly (crashed), the demoStreamSize is 0 and it
can be assumed the demo stream continues until the end of the file.
*/
struct DemoFileHeader
{
char magic[16]; ///< DEMOFILE_MAGIC
int version; ///< DEMOFILE_VERSION
int headerSize; ///< Size of the DemoFileHeader, minor version number.
char versionString[16]; ///< Spring version string, e.g. "0.75b2", "0.75b2+svn4123"
boost::uint8_t gameID[16]; ///< Unique game identifier. Identical for each player of the game.
boost::uint64_t unixTime; ///< Unix time when game was started.
int scriptSize; ///< Size of startscript.
int demoStreamSize; ///< Size of the demo stream.
int gameTime; ///< Total number of seconds game time.
int wallclockTime; ///< Total number of seconds wallclock time.
int numPlayers; ///< Number of players for which stats are saved.
int playerStatSize; ///< Size of the entire player statistics chunk.
int playerStatElemSize; ///< sizeof(CPlayer::Statistics)
int numTeams; ///< Number of teams for which stats are saved.
int teamStatSize; ///< Size of the entire team statistics chunk.
int teamStatElemSize; ///< sizeof(CTeam::Statistics)
int teamStatPeriod; ///< Interval (in seconds) between team stats.
int winningAllyTeam; ///< The ally team that won the game, -1 if unknown.
/// Change structure from host endian to little endian or vice versa.
void swab() {
version = swabdword(version);
headerSize = swabdword(headerSize);
// FIXME endian: unixTime = swabqword(unixTime);
scriptSize = swabdword(scriptSize);
demoStreamSize = swabdword(demoStreamSize);
gameTime = swabdword(gameTime);
wallclockTime = swabdword(wallclockTime);
numPlayers = swabdword(numPlayers);
playerStatSize = swabdword(playerStatSize);
playerStatElemSize = swabdword(playerStatElemSize);
numTeams = swabdword(numTeams);
teamStatSize = swabdword(teamStatSize);
teamStatElemSize = swabdword(teamStatElemSize);
teamStatPeriod = swabdword(teamStatPeriod);
winningAllyTeam = swabdword(winningAllyTeam);
}
};
/**
@brief Spring demo stream chunk header
The demo stream layout is as follows:
- DemoStreamChunkHeader
- length bytes raw data from network stream
- DemoStreamChunkHeader
- length bytes raw data from network stream
- ...
*/
struct DemoStreamChunkHeader
{
float modGameTime; ///< Gametime at which this chunk was written/should be read.
boost::uint32_t length; ///< Length of the chunk of data following this header.
/// Change structure from host endian to little endian or vice versa.
void swab() {
modGameTime = swabfloat(modGameTime);
length = swabdword(length);
}
};
#pragma pack(pop)
#endif // DEMOFILE_H
|