summaryrefslogtreecommitdiffstats
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/hl1-demofile-spec.txt299
1 files changed, 299 insertions, 0 deletions
diff --git a/doc/hl1-demofile-spec.txt b/doc/hl1-demofile-spec.txt
index e69de29..930b20b 100644
--- a/doc/hl1-demofile-spec.txt
+++ b/doc/hl1-demofile-spec.txt
@@ -0,0 +1,299 @@
+Half-Life 1 Demofile Specifications
+--------------------------------------------------------------------------------
+
+The Half-Life Demofile format has it's roots in the Quake 1 Demo format and is
+basically just an extension to it. Thus it contains only basic descriptors which
+rapidly points into raw recorded network data.
+
+It requires a lot of game engine related logic to be used for parsing such a
+file in a non-game client application. This explains the lack of any
+documentation or examples in the SDK as it would require to heavily open up
+game engine sources.
+
+
+General Fileformat Data Hiarchy:
+
+DemoFile {
+ DemoHeader
+
+ DemoSegment {
+ DemoMacroBlock {
+ DemoMacroHeader
+ DemoMacroData {
+
+ }
+ }
+ ...
+ }
+ ...
+
+ DemoDirectoryEntry
+ ...
+}
+
+
+Demofile Header
+--------------------------------------------------------------------------------
+The header starting at the beginning of the file contains the magic and further
+global game related information.
+
+DemoHeader->directory_offset points to a table of DemoDirectoryEntry structs
+prefixed by a count and suffixed by a file offset to the end of table.
+
+The location of the entries is usually somewhere at the end of the demo file,
+which is often a cause for "corrupt" demofiles if the data inbetween got
+altered/wrongly written by the game itself (raw network stream insanity or
+crash) thus resulting in a wrong offset.
+
+This can be fixed by parsing the end of the file for directory entries and
+fixing the proper offset value which allows playback in the game again.
+
+Known network_version -> Half-Life version mappings:
+
+ 40 = '1.0.1.6'
+ 42 = '1.1.0.1'
+ 43 = '1.1.0.4/6'
+ 45 = '1.1.0.8'
+ 46 = '1.1.1.x'
+ 47 = '1.1.1.x'
+
+struct DemoHeader
+{
+ char[8] magic;
+ uint32 demo_version;
+ uint32 network_version;
+ char[260] map_name;
+ char[260] game_dll;
+ uint32 map_crc;
+ uint32 directory_offset {
+ uint32 dir_count; // 1 to 1024
+ DemoDirectoryEntry* entries;
+ uint32 dir_end;
+ }
+}
+
+
+Demofile Directory Entries
+--------------------------------------------------------------------------------
+
+A directory entry is used to define a series of data segments of the recording
+which contain the game data. Usually this is used to split data of the
+"Loading..." part and the actual game recording part.
+
+DemoDirectoryEntry->offset points to the start of a data segment within the
+demofile.
+
+struct DemoDirectoryEntry
+{
+ uint32 number;
+ char[64] title;
+ uint32 flags;
+ int32 play;
+ float32 time;
+ uint32 frames;
+ uint32 offset; // points to a DemoSegment
+ uint32 length; // length of the DemoSegment at offset
+}
+
+
+Demofile Data Segments
+--------------------------------------------------------------------------------
+
+Each segment is of variable size and contains a sequence of numbered macro
+blocks. We use it here purely as a virtual container.
+
+struct DemoSegment
+{
+ DemoMacro* macros;
+}
+
+
+Demofile Macro Blocks
+--------------------------------------------------------------------------------
+
+Each macro block is "stamped" with time and frame information from the
+recording and is followed by the individual macro type data which has to be
+parsed individually. This relates to the game engine's status information at
+a specific time.
+
+The game uses 10 macro types:
+
+ 0 = 'Game Data'
+ 1 = 'Game Data'
+ 2 = 'N/A' // unused, skip
+ 3 = 'Client Command' // string
+ 4 = 'N/A' // string
+ 5 = 'Last in segment'
+ 6 = 'N/A'
+ 7 = 'N/A'--------------------------------------------------------------------------------
+ 8 = 'Play Sound'
+ 9 = 'N/A' // delta data
+
+struct DemoMacroHeader
+{
+ uint32 file_offset;
+ uint8 type;
+ float32 time;
+ uiint32 frame;
+ ...
+}
+
+Demofile Macro Types
+--------------------------------------------------------------------------------
+
+Each macro type has it's own structure closely related to the game engine and
+it's parsing differs among the demo's network version.
+
+# 0 and 1 / Game Data:
+
+struct DemoMacro_GameData
+{
+ if(network_version = 42)
+ {
+ uint8[560] extinfo;
+ }
+ else
+ if(network_version >= 45)
+ {
+ uint8[220] extinfo;
+ uint16 recorded_resolution_width;
+ uint16 recorded_resolution_height;
+ uint16 recorded_resolution_depth;
+ uint8[238] extinfo;
+ }
+
+ int32 chunklength; // size of following DemoServerMessage
+ ...
+}
+
+A server message follows the game data information and is parsed dynamically.
+
+struct DemoServerMessage
+{
+ uint8 id;
+ ...
+}
+
+List of Server Message IDs:
+
+{0} 'bad',
+{1} 'nop',
+{2} 'disconnect',
+{3} 'event',
+{4} 'version',
+{5} 'setview',
+{6} 'sound',
+{7} 'time',
+{8} 'print',
+{9} 'stufftext',
+{10} 'setangle',
+{11} 'serverinfo',
+{12} 'lightstyle',
+{13} 'updateuserinfo',
+{14} 'deltadescription',
+{15} '',
+{16} 'stopsound',
+{17} '',
+{18} '',
+{19} '',
+{20} '',
+{21} '',
+{22} '',
+{23} 'temp_entity',
+{24} 'setpause',
+{25} '',
+{26} '',
+{27} '',
+{28} '',
+{29} 'spawnstaticsound',
+{30} 'intermission',
+{31} '',
+{32} 'cdtrack',
+{33} '',
+{34} '',
+{35} 'weaponanim',
+{36} '',
+{37} 'roomtype',
+{38} 'addangle',
+{39} 'newusermsg',
+{40} '',
+{41} '',
+{42} '',
+{43} '',
+{44} '',
+{45} 'classinfo',
+{46} '',
+{47} '',
+{48} '',
+{49} '',
+{50} 'hltv',
+{51} 'director',
+{52} '',
+{53} '',
+{54} 'sendextrainfo',
+{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} ''
+
+# 2 / Unknown
+
+This is an unused macro type in Half-Life and should never be encountered.
+
+# 3 / Client Command
+
+A null-terminated string corresponding to a client command such as "+weapon".
+
+# 4 / Unknown
+
+A null-terminated string.
+
+# 5 / Last in segment
+
+This macro type marks the end of this segment for verification and switch to the
+next one.
+
+# 6 / Unknown
+