Field Decoders
To parse entity updates, we need to map the fields of the send-table to their respective types within an update. To do this, we create a "field decoder" for each field which can be initialised from the parameters found from the send-table.
Note: Within this guide, we will refer to the 'field type' as a "decoder".
Decoder Types
First, let's define the possible types of decoders:
We've listed all the decoders we currently support, along with their wire type and the type they decode to.
| Decoder Name | Wire Type | Type | Description |
|---|---|---|---|
Boolean | bit_bool | bool | |
Signed | bit_varint_32 | int32 | |
Unsigned | bit_varuint_32 | uint32 | |
Component | bit_component_uint | uint32 | |
AmmoCount | bit_ammocount | uint32 | |
Unsigned64 | bit_varuint_64 | uint64 | |
FixedUnsigned64 | bit_uint64_le | uint64 | |
String | bit_string_null_term | string | |
NoScale | bit_float32_noscale | float32 | |
Coord | bit_float32_coord | float32 | |
SimTime | bit_simulation_time | float32 | |
RuneTime | bit_rune_time | float32 | |
Qfloat | quantised_float * | float32 | *maps to a quantised float decoder |
QAnglePrec | bit_qangle_precise | float32 | |
QAngleFixed | bit_qangle_fixed | float32 | |
QAngleCoord | bit_qangle_coord | float32 | |
Vector3Normal | bit_vec3_normal | float32[3] | |
Vector2[F] | F x2 * | float32[2] | *calls the float factory, creates a vector of degree 2 |
Vector3[F] | F x3 * | float32[3] | *calls the float factory, creates a vector of degree 3 |
Vector4[F] | F x4 * | float32[4] | *calls the float factory, creates a vector of degree 4 |
Vector6[F] | F x6 * | float32[6] | *calls the float factory, creates a vector of degree 6 |
Matching Decoders
When matching a field to a decoder, there are three methods:
- Factory: A decoder with logical mapping and parameter initialisation
- Overrides: A overridden type, controlled by another parameter (such as
var_name) - Mapping: A simple name to decoder mapping
Factories
As stated before, not all field types map to a decoder one-to-one. Factories map a type to multiple types of decoders depending on their parameters.
Factories can also be called other factories. For example, the float factory can call the Quantised Float factory, or the vector factory calls the float factory.
Quantised Float Factory
- If
bit_count != nilandbit_count < 32:NoScale
- Otherwise, create a quantised float decoder from the parameters:
bit_count(if not present then default to 0)encode_flags(if not present then default to 0)low_valuehigh_value
Float Factory
- If
encoder == "coord":CoordType
- If
encoder == "simtime":SimTime
- If
encoder == "runetime":RuneTime
- If
bit_count == nilorbit_count < 32:NoScale
- Otherwise, call Quantised Float Factory
Unsigned64 Factory
- If
encoder == "fixed64"Vector3[Normal]
- Otherwise
Unsigned64
QAngle Factory
- If
encoder == "qangle_precise"QAnglePrec
- If
bits != nilandbits != 0:QAngleFixed
- Otherwise
QAngleCoord
Vector3 Factory
- If
encoder == "normal"Vector3Normal
- Otherwise call VectorN Factory
vector(3)
VectorN Factory
In this documentation, we reference the vector factory as Vector[N] Factory
where N dictates the degree (size) of the vector.
The vector factory calls Float Factory to create its inner type,
and on the wire reads this N times to get a resulting vector.
Overrides
Some field types can be overridden, there is currently one case:
| Condition | Decoder |
|---|---|
| `var_name == "m_iClip1" | AmmoCount |
Mapping
This table contains a mapping to a field's decoded type to its respective factory or decoder.
This table should be applied in sequential order to prevent any issues with overlap between factories and mappings.
| Base Type | Factory | Decoder |
|---|---|---|
float32 | Float | |
CNetworkedQuantizedFloat | Quantised Float | |
uint64 | Unsigned 64 | |
CStrongHandle | Unsigned 64 | |
Vector | Vector3 | |
Vector2D | Vector[2] | |
Vector4D | Vector[4] | |
Quaternion | Vector[4] | |
CTransform | Vector[6] | |
QAngle | QAngle | |
bool | Boolean | |
int8 | Signed | |
int16 | Signed | |
int32 | Signed | |
HSequence | Signed | |
CEntityIndex | Signed | |
NPC_STATE | Signed | |
AmmoIndex_t | Signed | |
TakeDamageFlags_t | Signed | |
StanceType_t | Signed | |
RagdollBlendDirection | Unsigned | |
BeamType_t | Unsigned | |
EntityDisolveType_t | Unsigned | |
PrecipitatonType_t | Unsigned | |
BeamClipStyle_t | Unsigned | |
SharpSolid_t | Unsigned | |
ShatterPanelMode | Unsigned | |
gender_t | Unsigned | |
item_definition_index_t | Unsigned | |
uint8 | Unsigned | |
uint16 | Unsigned | |
uint32 | Unsigned | |
CHandle | Unsigned | |
Color | Unsigned | |
CUtlStringToken | Unsigned | |
EHandle | Unsigned | |
CEntityHandle | Unsigned | |
CGameSceneNodeHandle | Unsigned | |
CStrongHandle | Unsigned | |
AttachmentHandle_t | Unsigned | |
MoveCollide_t | Unsigned | |
MoveType_t | Unsigned | |
RenderMode_t | Unsigned | |
RenderFx_t | Unsigned | |
SolidType_t | Unsigned | |
SurroundingBoundsType_t | Unsigned | |
ModelConfigHandle_t | Unsigned | |
WeaponState_t | Unsigned | |
DoorState_t | Unsigned | |
ValueRemapperInputType_t | Unsigned | |
ValueRemapperOutputType_t | Unsigned | |
ValueRemapperHapticsType_t | Unsigned | |
ValueRemapperMomentumType_t | Unsigned | |
ValueRempapperRatchetType_t | Unsigned | |
PointWorldTextJustifyHorizontal_t | Unsigned | |
PointWorldTextJustifyVertical_t | Unsigned | |
PointWorldTextReorientMode_t | Unsigned | |
PoseController_FModType_t | Unsigned | |
itemid_t | Unsigned | |
style_index_t | Unsigned | |
attributeprovidertypes_t | Unsigned | |
DamageOptions_t | Unsigned | |
MaterialModifyMode_t | Unsigned | |
CSWeaponMode | Unsigned | |
ESurvivalSpawnTileState | Unsigned | |
SpawnStage_t | Unsigned | |
ESurvivalGameRuleDecision_t | Unsigned | |
RelativeDamagedDirection_t | Unsigned | |
CSPlayerState | Unsigned | |
MedalRank_t | Unsigned | |
CSPlayerBlockingUseAction_t | Unsigned | |
MoveMountingAmount_t | Unsigned | |
QuestProgress::Reason | Unsigned | |
tablet_skin_state_t | Unsigned | |
ScreenEffectType_t | Unsigned | |
char | String | |
CUtlString | String | |
CUtlSymbolLarge | String | |
GameTime_t | NoScale | |
CBodyComponent | Component | |
CPhysicsComponent | Component | |
CLightComponent | Component | |
CRenderComponent | Component |
Lookup Methodology
Mapping a field type to a decoder is done by a lookup method. There are two variants of this:
Lookup Field Decoder
This is the most common use of decoding a field type. It is implemented as such:
- Check factories
- Check overrides
- Check mapping
- Otherwise,
Unsigned
This will be referenced as lookup_field_decoder
Lookup Field Inner Decoder
This is the less often used decoder, are used for decoding the inner child elements of an array.
Unlike Field Type, Base Type is actually the inner GENERIC type,
not the outer type (because it will always be an array)
It is implemented as such:
- Check if we have a generic type.
- Fatally Error if this is not the case.
- Check factories
- Check mapping.
- Otherwise,
Unsigned
Note: we do not need to check overrides in this implementation.
This will be referenced as lookup_field_inner_decoder