urt-rs / docs /research /USERCMD_ACCEPTANCE.md
nmarshall's picture
Analyze native QVM usercmd retrieval and game time prefix
e15838a
|
Raw History Blame Contribute Delete
7.1 kB
# Server usercmd acceptance and game-VM boundary
RE-401–403 / F-160–162. [usercmd-acceptance.json](usercmd-acceptance.json) retains four verified native graphs across the Linux ELF64 engines. Reproduce with `python3 scripts/analyze_usercmd_acceptance.py`; verify with `python3 scripts/test_usercmd_acceptance.py`.
This follows [usercmd caller and bundle evidence](USERCMD_CALLERS.md). The script evaluates bounded instructions against supplied server/client state and already-decoded command records. Original processes, native callees and the game VM never run. Gates stop at external calls. Timestamp-loop VM calls have supplied return zero, retained caller registers and **no VM side effects**. Full packet, input generation, callback effects and runtime conformance remain open.
## ACCEPT-001 — Post-decode connection and purity gates (RE-401)
The inspected gate starts after the decode loop and frame acknowledgement metadata. At client-engine `0x4716e7` / dedicated `0x406d97`, the native path loads `sv_pure` and reads its integer slot at +0x30. Client fields +0x24ed4 and +0x24ed8 are provisionally authentication and received-pure-result flags; producer semantics are not established here.
| Supplied condition | Observed stopped boundary |
| --- | --- |
| Pure nonzero, +0x24ed4 zero, +0x24ed8 zero, state 4 | Diagnostic then SV_SendClientGameState |
| Same pure/flag combination, state 2 or 3 | Return without timestamp processing |
| Above early gate does not apply, state 3 | SV_ClientEnterWorld |
| After the state-3 branch, pure nonzero and +0x24ed4 zero | SV_DropClient |
| Remaining state 4 | Timestamp loop |
| Remaining other tested state | Set client +0x20d28 to 0xffffffff, then return |
48 probes (24 per engine) cover states 2/3/4 and all Boolean pure/flag combinations. External calls are not executed. In particular, stopping at SV_ClientEnterWorld does not establish its resulting state, callback effects or the outcome of the subsequent purity recheck. Sending game state or dropping a client is a recorded request, not an action taken by the analysis.
The sampled +0x20d28 value starts at 77 and is retained on the other tested boundaries. These findings do not cover the earlier delta-mode argument, packet decoding, count/EOF checks, or complete connection lifecycle.
## ACCEPT-002 — Signed time filtering and baseline updates (RE-402)
The time slice starts at client-engine `0x4717e4` / dedicated `0x406e94`, after upstream gates, with supplied state 4, count and records. Native signed 32-bit comparisons apply the following rule sequentially:
1. Skip a command whose timestamp is greater than the **last command's timestamp in this bundle**.
2. Skip a command whose timestamp is less than or equal to client +0x2081c, the stored previous command time.
3. Otherwise copy all 24 command bytes into client +0x2081c, then reach the game-VM boundary when the state remains 4.
The stored time advances after each accepted command, so duplicate or older entries are skipped relative to the latest accepted record. The bundle's final timestamp is the cap; it is not a maximum computed over all entries. A descending fixture therefore accepts only its final command. No comparison with a server-clock value is present in this bounded loop; upstream generation and downstream game-side clamping remain open.
Per engine, 92 probes cover every ordered count 1–32 and sampled counts 1/2/3/4/5/7/8/16/31/32 for duplicates, descending, unordered, stale, negative and signed-boundary times. Independent sequential signed arithmetic predicts exact records at each VM boundary and the complete final stored record. Each engine produces 685 stopped VM requests. Command memory remains unchanged, and adjacent stored-record canaries remain intact.
Negative and sign-boundary probes describe supplied instruction behavior, not legitimate multiplayer timestamps or verified clock wrapping. The earlier short-delta anomaly in [CMD-001](MESSAGE_USERCMD.md) is not declared unreachable or resolved: time generation, codec composition and real traffic must still be traced.
## ACCEPT-003 — Standalone copy and VM request contract (RE-403)
`SV_ClientThink` entries: dedicated `0x403a16`, client-engine `0x46e366`. This separate native function unconditionally copies three 64-bit words from the supplied command into client +0x2081c/+0x20824/+0x2082c. It requests a tail transfer to `VM_Call` only when client state equals 4; other tested states return after the copy. This is distinct from the upstream timestamp loop's filtering. The same copy and selector operations are inlined in SV_UserMove.
The observed VM request has arguments `(gvm, 7, client_index)`. No usercmd pointer is forwarded in these registers. Selector 7 is an observed native boundary; this batch does not execute or fully characterize its QVM callback or the callback's command-retrieval syscall.
Index arithmetic subtracts the file-backed `svs+0x10` client-array pointer, arithmetic-shifts the difference by six, then multiplies by 0x352f43fb794105d5 modulo 64 bits. That multiplier is the modular inverse of 0xb7d. Thus **0x2df40 is a candidate client stride**: aligned supplied addresses `base + index*0x2df40` recover indices 0/1/7/63. This is not proof of allocation size, valid maximum clients, arbitrary-pointer division or bounds safety. Array allocation/iteration evidence must confirm the stride independently.
32 standalone probes (16 per engine) cover states 0/2/3/4 and those four indices. Native stop locations determine whether a VM request exists; an independent oracle checks that only state 4 dispatches and all states copy the full record. Inlined requests independently recover the same selector/index and show copied bytes already present before the stopped VM call.
## Validation and remaining work
Eight tests verify connection/purity gates and sentinel mutation, signed sequential timestamps and final-bundle cap, every ordered count, record copy before VM requests, standalone state behavior, reciprocal/stride arithmetic, canaries/source retention, paired engine outcomes and source/disassembly identities. The report records instruction graphs, trace lengths/hashes, complete supplied/accepted records and requested VM arguments.
RE-400 remains open for complete producer and packet/runtime work. RE-404 must confirm purity/state-field meanings and client stride through producers/allocation, trace command generation and server/game-side time clamping, connect selector 7 through the QVM callback and command-retrieval syscall, compose actual decoded bundles with acceptance, characterize VM mutation effects and validate real traffic/all-platform behavior. Higher-level entity/player/snapshot codecs, Rust compatibility and Bevy/Solari rendering remain open.
Follow-up: [native/QVM retrieval and time prefix](QVM_USERCMD.md) confirms explicit stride0x2df40 in retrieval paths, connects selector7/trap36 and recovers bounded game-side time clamping. Allocation, producer domains, address translation, remaining callback effects and runtime validation remain open.