Serializers¶
Serializers (historically called “send tables” in Source 1) define the field schema for each entity class. They describe what fields an entity has, their types, and how they are encoded in the bit stream.
Source Data¶
Serializer definitions arrive in the DEM_SendTables command, which contains a
CsvcMsgFlattenedSerializer protobuf message. This message has three main parts:
Symbols — a string table of all type names, field names, and encoder names
Fields — a flat list of field definitions, each referencing symbols by index
Serializers — a list of serializer definitions, each referencing a subset of fields by index
Serializer Structure¶
A serializer is a named collection of fields:
Serializer "CCitadelPlayerController"
fields:
[0] m_iTeamNum: U64
[1] m_iszPlayerName: String
[2] m_steamID: U64
[3] m_PlayerDataGlobal: (nested serializer)
[0] m_nHeroID: U64
[1] m_bAlive: Bool
[2] m_iPlayerKills: I64
...
Fields can be nested — a field may reference another serializer, creating a
hierarchy. This is how dotted paths like m_PlayerDataGlobal.m_iPlayerKills work.
Field Properties¶
Each field carries:
Property |
Description |
|---|---|
|
Type string (e.g., |
|
Field name (e.g., |
|
Number of bits for quantized encoding |
|
Range for quantized floats |
|
Flags affecting encoding behavior |
|
Special encoder name ( |
|
Nested serializer for compound types |
Decoders¶
Each field is assigned a decoder based on its type, encoder, and bit count. The main decoder types are:
Decoder |
Used For |
|---|---|
|
Boolean fields |
|
Integer fields (varint encoded) |
|
Raw 32-bit IEEE floats |
|
Floats stored as N-bit values mapped to a [low, high] range |
|
Source coordinate encoding (14-bit integer + 5-bit fraction) |
|
Tick count converted to seconds via |
|
Variable-length byte strings |
|
Component-wise float vectors |
|
Euler angles with various precision encodings |
Special Field Types¶
Fixed arrays:
Type[N]— decoded as N sequential valuesDynamic arrays:
CNetworkUtlVectorBase<T>— prefixed with a varint length, then that many elementsPointers:
Type*— a single boolean (present/absent)
Field Resolution¶
Serializers support resolving dotted field paths to packed 64-bit keys:
# Internally, this walks the serializer hierarchy:
key = serializer.resolve_field_key("m_PlayerDataGlobal.m_iPlayerKills")
# key is a packed u64 encoding the path [3, 2] (field indices at each level)
The packed key is what gets stored in the entity’s field map and used for O(1) lookup.