diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/hl1-demofile-spec.txt | 299 |
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 + |