Skip to content

CS2: fields sharing a name under different send_node collapse last-wins — m_vecVelocity unreachable on player pawns #673

Closed

Description

@cariogit

What happens

In sendtablescs2, class.collectFieldsEntries builds a field's name as prefix + field.serializer.name + "." + varName, which discards the wire's send_node. serializer.addField then indexes fieldIndexes[f.varName], last-wins.

CCSPlayerPawn declares m_vecX / m_vecY / m_vecZ twice, and the wire distinguishes them only by send_node:

send_node bit_count low / high
m_vecVelocity 18 −4096 / 4096
m_vecViewOffset 10 −64 / 64 (z: 20 bits, high 128)

The view offset wins, so m_vecVelocity cannot be read. Same on CCSPlayerPawnBase, CBasePlayerPawn and CCSObserverPawn.

Measured

One retail demo, CCSPlayerPawn entities only:

m_vecX   n=  4,060   min=  -3.94   max=   4.44
m_vecY   n=  4,020   min=  -4.44   max=   4.19
m_vecZ   n=503,544   min=  14.00   max=  73.45

m_vecZ spanning 14–73 is eye height. No m_vec* value anywhere exceeds 200, against a declared ±4096.

Both registrations still dispatch, so a consumer sees each (tick, entity, name) twice carrying the same value — 255,812 of 255,812 on that demo.

Reading the raw CSVCMsg_FlattenedSerializer off CDemoSendTables on the same file: 264 serializers, 17,111 (serializer, field) rows, and 132 (serializer, field_name) groups collide this way — all differing in send_node, 12 of them with genuinely different declared encodings. So this is not specific to velocity.

Why there seems to be no workaround through the public API

Every exported Entity accessor keys by name — Property, PropertyValue, Get, Exists, BindProperty, PropertyValueMust.

Map() looked like the exception: it iterates real field paths and calls state.get(fp) path-wise. But it keys the result by getNameForFieldPath(fp), so the collision reappears and the later path overwrites the earlier one. Verified by type-asserting to *sendtablescs2.Entity — Map() and Get() return the same value on every sample (48.2, 61.6, 64, all view offset).

Both values are decoded into entity state at distinct paths; the loss is purely the key.

Suggested direction

Either include send_node in the generated name, or expose a path-based accessor so a shadowed declaration stays reachable. Both change name strings for affected fields, so it is a breaking change and how to stage it is your call.

Environment: v5.2.0, CS2 retail demos.

Activity

  1. akiver commented on Aug 27, 2026

    @akiver
    Collaborator

    Nice catch!
    I opened this PR to fix it and be able to do for example PropertyValueMust("m_vecVelocity.m_vecX").

    It also means that the player's velocity is actually networked since the AnimGraph2 update https://store.steampowered.com/news/app/730?emclan=103582791432902485&emgid=529853121068793939 and so I added it back in the PR.

  2. added a commit that references this issue on Aug 30, 2026
  3. markus-wa commented on Aug 31, 2026

    @markus-wa
    Owner

    merged the fix - please reopen if the issue persists

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions