demoparser package

Submodules

demoparser.bitbuffer module

class demoparser.bitbuffer.Bitbuffer(data)

Bases: object

Parse a stream of bits from a series of bytes.

Data is cast to unsigned int* and read one unsigned int at a time. As an unsigned int is 32 bits this has the effect of reading 4 bytes at once. Reads can span integer boundaries and the consecutive integers will be merged correctly.

Parameters:data (bytes) – Data to parse bit-by-bit
Example:
>>> buf = Bitbuffer(b'\x11\x22')
>>> buf.read_uint_bits(8)
17
>>> buf.read_uint_bits(8)
34
next_dword(self) → unsigned int

Move to the next 32-bit integer in the stream.

Returns:unsigned int
read_bit(self) → unsigned char

Read a single bit.

Returns:one bit
read_bit_cell_coord(self, unsigned int bits, unsigned int coord_type) → float

Read a cell coordinate.

A cell coordinate is a float which has been compressed. The number of bits indicates maximum value.

Parameters:
  • bits (unsigned int) – number of bits to read
  • coord_type (unsigned int) – level of precision
Returns:

float

read_bit_coord(self) → float

Read a float and treat as a world coordinate.

Returns:float
read_bit_normal(self) → float
read_sint_bits(self, unsigned int bits) → int

Read a signed integer of bits bits.

First an unsigned integer is read then a two’s complement integer is computed.

Parameters:bits (unsigned int) – Number of bits to read
Returns:int
read_string(self, int length=-1) → str

Read a string.

If length is not provided characters are read until \0 is reached. If length is provided then exactly length bytes will be read and the string may not be zero-terminated.

Returns:str
read_uint_bits(self, unsigned int bits) → unsigned int

Read the unsigned integer represented by bits bits.

If the number of bits remaining in the current word is not enough then the next word will be read.

Parameters:bits (unsigned int) – Number of bits to read
Returns:unsigned int
read_user_data(self, unsigned int bits) → bytes

Read user data.

Parameters:bits (unsigned int) – Number of bits to read
Returns:bytes
read_var_int(self) → unsigned int

Read a variable length integer.

Returns:unsigned int

demoparser.bytebuffer module

class demoparser.bytebuffer.Bytebuffer(data)[source]

Bases: object

Parse a stream of bytes from a .DEM file.

This class provdes convenience methods for parsing .DEM files. It handles unpacking bytes to different data types, reading variable-length integers, reading strings, and creating Bitbuffers.

Parameters:data (bytes) – Buffer data
Example:
>>> b = Bytebuffer(b'\x00\xf1\xaa')
>>> b.read(1)
0
>>> b.read_short()
43761
read(num_bytes)[source]

Read num_bytes bytes from buffer.

read_bitstream()[source]

Create a Bitbuffer from a number of bytes.

The numbers of bytes to include in the Bitbuffer is read. Then that number of bytes is used to instantiate a Bitbuffer instance.

Returns:Bitbuffer instance
read_command_data()[source]

Read command info structure.

This is not used by the parser.

Returns:bytes
read_command_header()[source]

Read the 6 byte command header.

See CommandHeader description for more details.

Returns:CommandHeader instance
read_packet_data()[source]

Read a demo packet.

Each packet consists of a command and data. The command is an ID that references either a NET_ or SVC_ class defined in netmessages.proto.

The data is used to instantiate the class referred to by command.

Returns:Tuple (command, data)
read_raw_data()[source]

Read number of bytes specified by a signed int.

First a 32-bit signed integer is read, then that number of bytes is read from the stream.

Returns:Tuple (bytes_read, bytes)
read_sequence_data()[source]

Read two integers.

This data is not used by the parser.

Returns:Tuple of integers
read_short()[source]

Read a 16-bit unsigned short.

read_string()[source]

Read a zero-terminated string.

Reads characters until \0 is encountered.

Returns:str
read_user_command()[source]

Read a user command.

read_var_bytes()[source]

Read number of bytes specified by a varint.

First a varint is read and then the number of bytes specified by the varint are read.

Returns:bytestring
read_varint()[source]

Read a variable-length integer.

Returns:Integer

demoparser.consts module

demoparser.demofile module

exception demoparser.demofile.ClassNotFoundError

Bases: Exception

exception demoparser.demofile.CommandError

Bases: Exception

class demoparser.demofile.DemoFile

Bases: object

add_callback(self, event, func)

Register a callback function for an event.

class_by_message_name(self, str name)

Find a Protobuf class for the given message.

The generated Protobuf modules create classes like C<type>Msg_<name>. For a given message name this method will convert the name to a Protobuf class name and return it.

Returns:Protobuf class
collect_exclusions(self, table) → list
collect_props(self, table, list exclusions) → list

Collect table properties which are not excluded.

If a property is part of an array or is flagged as excluded it will not be returned. Otherwise all properties are collected and data table entries are recursively collected.

Returns:Flat list of all table properties
create_string_table(self, msg) → void

Create a string table.

A string table consists of a name and a list of entries. The maximum number of entries is created and initialized to None. This is done because future messages that update or reference string table entries do so by index.

Each entry is a dictionary with two keys, entry and user_data. Entry is the name of the entry and user_data contains binary data related to the entry. In the ‘user_info’ string table user_data describes a UserInfo object.

current_tick

current_tick: ‘unsigned int’

data_table_by_name(self, str name)
emit(self, str event, args=None) → void

Run callback functions for an event.

Each time an event is trigged each registered callback will be called with the arguments provided to this method.

entities

entities: object

flatten_data_table(self, table)

Flatten a data table.

Data tables can contain other data tables as entries. This method collects all properties and sorts them by priority.

Returns:Flattened data table
handle_data_table(self, cmd_header) → void

Create data tables.

Each entity class maintains a data table that describes how to encode each of its properties. These tables are called Send Tables and and genrally have names like DT_EntityClassName (DT_CSPlayer, DT_Weapon, etc.)

Emits:baseline_create, datatable_ready.
handle_demo_packet(self, cmd_header) → void

Handle demo packet.

Demo packets are of type SVC_ or NET_. This method instantiates the appropriate protobuf class and triggers an event.

Emits:demo_packet.
handle_game_event(self, msg) → void

Handle game event.

A game event message just contains an event ID. The corresponding event can be found in self.game_events. An event is then triggered for the game event itself.

Emits:game_event.
handle_game_event_list(self, msg) → void

Create game event list.

This message contains a list of game events present in this replay. Later, when a game event occurs its ID can be used to get a game event object.

handle_packet_entities(self, msg) → void

Create or update an entity.

Entities represent in-game objects and are networked (i.e. their state is maintained on the server and updates are sent to one or more clients).

Entities have a class ID which defines the type of entity it is. The class ID is also used to find the correct instance baseline. Instance baselines serve as default values when entities are created.

handle_string_table(self, str table_name, Bitbuffer buf) → void

Populate a string table.

Emits:string_table_update.
handle_string_tables(self, cmd_header) → void
handle_user_message(self, msg) → void

Handle user message.

A user message is stuff like text chat, voice chat, radio messages, etc.

Emits:user_message
instance_baselines

instance_baselines: object

parse(self) → void

Parse the demofile.

Emits:tick_start, tick_end, end
Raises:CommandError
parse_instance_baseline(self, Bitbuffer buf, unsigned int class_id)

Parse baseline.

Baselines serve as default data for entities of type class_id.

Parameters:
  • buf (Bitbuffer) – Data to read
  • class_id (unsigned int) – Server class ID
Returns:

baseline for class_id.

parse_string_table_update(self, Bitbuffer buf, table, unsigned int num_entries, unsigned int max_entries, unsigned int user_data_bits, bool user_data_fixed_size) → void

Update a string table.

A single update message can update multiple table entries. Both the entry name and the user data can be updated.

Emits:string_table_update.
read_new_entity(self, Bitbuffer buf, entity) → void

Read entity data.

A list of updates is computed and for each one of those the appropritate property of the entity instance is updated.

Emits:change
table_by_name(self, str name)
table_updated(self, table, index, entry, user_data) → void

Update an instance baseline.

Each time a string table is updated this method is called. If a baseline doesn’t exist yet it is added to the list of pending baselines which are handled later when the correct server class is created. Server classes are created by DATATABLES commands.

update_string_table(self, msg) → void

demoparser.fields module

class demoparser.fields.FixedLengthString(length, **kwargs)[source]

Bases: suitcase.fields.BaseField

A string of a fixed number of bytes.

The specified number of bytes are read and then any null bytes are stripped from the result.

Parameters:length (Integer) – Number of bytes to read.
bytes_required

Number of bytes to read from stream.

pack(stream)[source]
unpack(data)[source]
class demoparser.fields.SLFloat32(**kwargs)[source]

Bases: suitcase.fields.BaseStructField

Signed Little Endian 32-bit float field.

PACK_FORMAT = b'<f'
UNPACK_FORMAT = b'<f'
unpack(data, **kwargs)[source]
class demoparser.fields.UBInt32Sequence(length, **kwargs)[source]

Bases: suitcase.fields.BaseFixedByteSequence

A sequence of unsigned, big-endian 32 bit integers.

Parameters:length (Integer) – Number of 32-bit integers in sequence.

demoparser.props module

class demoparser.props.Decoder

Bases: object

Decode a property.

Properties of server classes are encoded differently depending on the type of the property.

Parameters:
  • buf (Bitbuffer) – Raw buffer data used for decoding
  • prop (object) – Property to decode
decode(self)
decode_array(self) → list

Decode array.

Arrays contain one or more elements (including arrays) which are recursively decoded.

decode_float(self) → float

Decode a floating point value.

First the value is decoded as a special float. If that returns NaN then a normal floating point value is calculated.

decode_int(self) → long

Decode an integer.

Reads the number of bits specified in the num_bits field of the property. If the property has the SPROP_UNSIGNED flag set the number will be read as an unsigned int.

decode_int64(self)

Decode a 64-bit integer.

CS:GO demos don’t appear to contain 64-bit ints.

decode_special_float(self) → float

Decode a float

A special float is a float which is interpreted in some special way. The treatement is determined by the property’s flags.

Flag Explanation
COORD Treat the float or vector as a world coordinate.
COORD_MP Like COORD but special handling for multi-player games.
COORD_MP_LOWPRECISION Like COORD_MP but the fractional component uses 3 bits instead of 5.
COORD_MP_INTEGRAL Like COORD_MP but coordinates are rounded to integral boundaries.
NOSCALE Don’t scale floating-point value to a range.
NORMAL Treat vector as a normal.
CELL_COORD Like COORD but has special encoding for cell coordinates which can’t be negative.
CELL_COORD_LOWPRECISION Like CELL_COORD but fractional part uses 3 bits instead of 5.
CELL_COORD_INTEGRAL Like CELL_COORD but coordinates are rounded to integral boundaries.
decode_string(self) → str

Decode a string.

A fixed number of bits are read which may be more than the string’s length (i.e. some bits are read after a 0 is encountered).

Returns:str
decode_vector(self) → dict

Decode a vector.

Returns:vector
decode_vector_xy(self) → dict

Decode a two-element vector.

This only reads the X and Y coordinates for the vector and sets the Z coordinate to 0.0

Returns:vector

demoparser.structures module

class demoparser.structures.CommandHeader(**kwargs)[source]

Bases: suitcase.structure.Structure

Header for each command packet.

The header has the following format:

Byte Description
0 Command ID
1-4 Current tick
5 Player ID
class demoparser.structures.CommandInfo(**kwargs)[source]

Bases: suitcase.structure.Structure

class demoparser.structures.DemoHeader(**kwargs)[source]

Bases: suitcase.structure.Structure

1072 Byte header for .DEM file.

This header has the following format:

Byte Description
0-7 Fixed string ‘HL2DEMO0’.
8-11 Demo file protocol version.
12-15 Network protocol version.
16-275 Server name.
276-535 Name of client who recorded the demo.
536-795 Map name.
796-1055 Game directory.
1056-1059 Playback time in seconds.
1060-1063 Number of ticks in demo.
1064-1067 Number of frames in demo.
1068-1071 Length of signon data.
class demoparser.structures.OriginViewAngles(**kwargs)[source]

Bases: suitcase.structure.Structure

class demoparser.structures.QAngle(**kwargs)[source]

Bases: suitcase.structure.Structure

class demoparser.structures.SplitCommandInfo(**kwargs)[source]

Bases: suitcase.structure.Structure

class demoparser.structures.UserInfo(**kwargs)[source]

Bases: suitcase.structure.Structure

Player data.

This structure has the following format:

Byte Description
0-7 Version. Same for all players.
8-15 xuid. Some sort of unique ID.
15-142 Player name.
143-146 Local server user ID.
147-179 GUID
180-183 Friend’s ID.
184-312 Friend’s Name.
313 Is player a bot?
314 Is player an HLTV proxy?
314-329 Custom files CRC.
330 Numbre of files downloaded by server.
331-335 Entity index.
336-340 No idea.
class demoparser.structures.Vector(**kwargs)[source]

Bases: suitcase.structure.Structure

demoparser.util module

demoparser.util.parse_entity_update(Bitbuffer buf, server_class) → list

Parse entity updates.

First a list of all property indices is generated. For each property referenced by those indices the property’s value is decoded. The list of properties and their decoded values are collected and returned.

Returns:List of updated properties
demoparser.util.read_field_index(Bitbuffer buf, int last_index, bool new_way) → int

Read index.

This method determines the next index into the property list for a server class.

Returns:Next index or -1 if no more indices

Module contents