Ping, Which Had Read Zero
Moving geometry, lag-compensated hit registration, a menu that became the front door, player accounts opened by key, and the first matches that count.
Ping, Measured
LagCompensation had existed since v0.9.0 — and was wired only into a CLI harness. Every shot on the live server resolved against the present.
It now rewinds to the view the shooter actually had, using a tick the client was already reporting and the server was already throwing away. 100ms maxCompensationMs.
Two instruments came with it:
npm run test:lifts walks every lift on every installed map and fails if one
cannot be called -> found four dead lifts on wctf6
npm run net:viewlag holds frames in both directions over a real socket
-> found the interpolation assumption double-countingAnd ping, which had read 0 for every player since the field was introduced, is measured.
Movable Geometry
func_plat and vertical func_door are simulated, collided, predicted, heard, and crush whoever blocks them — one fixed-step system shared by server, client prediction and single-player, so "a rider is carried by the same code everywhere".
A Networking Audit, Not A Feature
Snapshots never said which state they were deltaed against, so a dropped datagram — or merely an ACK still in flight — could leave a component silently wrong until it happened to change again. Fixed at the protocol level. Snapshots are now message 0x0B; 0x04 is the old envelope, kept only for reading old data.
One shape behind a family of replay bugs:
something that should have been a function of which simulation step this is was
instead counted per call, and reconciliation counts the same steps more than once.
Knockback drag never ran on a live client at all.
Drawing Less
World culled by compiled PVS, players culled and quieted with it, autosprites stop rewriting vertices nothing moved.
Spatial batching was cut. It removes a third to a half of the triangles and costs about 20% more frame time, so r_bsp_cellsize stays off — with 36 captures behind the decision.
One thing was added rather than trimmed: tiered impact sparks, so a machinegun round stays quiet and the flourish is kept for weapons that hit once and hard.
The Menu Became The Front Door
A gold rail, one stage beside it, and rooms you can actually get into.
Player accounts opened by a key rather than a password, so a name belongs to somebody. Rooms can be private, with an invite only a link carries. Rooms have their own chat.
Amphi arrives as the mode the lobby leads with: 1v1, three rounds, a kit you pick and live with.
Matches that count. A seat is a signed ticket, the child server signs the result it reports, the lobby stores it once, and the leaderboard counts only matches most of whose room was people.
The Seven-Bot Bug Hunt
docs/research/v0.9.23-bughunt.md — mostly about other players. They were the only bodies in the map exempt from culling, dead-reckoned through walls when a packet arrived late, shared a single skeleton between them, and the trail on the rocket you fired at them collapsed to a flat sliver "in the one case that matters — shooting along the axis you are looking down."
Known Unverified Items
Long, and mostly unflattering, so here is the shape of it:
- The lobby has never been used by two people at once, and no ranked result
between two humans has ever appeared on the board in front of anyone.
- The menu has had no accessibility or real-display pass.
- The placement bug is "believed fixed, not proven fixed" — no controlled
reproduction was ever built. cl_remotehitbox 1 is the cheap discriminating test still worth running.
- Two fixes failed to hold: the lower-floor rocket launcher and the tab-return
camera were both reported still broken. "Each fix closed a real defect … but neither was the cause of what was reported."
- A player froze mid-match while the server ran on and "What stalls the connection is
not known."
- Only hitscan is rewound — projectiles still spawn against the present.
- Bots do not use ladders; ladder climbing is unreachable on 35 of 39 installed
maps.
- Client presentation is frame-rate dependent; uncapped frame rates are not a
supported configuration.
- Babylon's per-frame CPU counters cannot be trusted as totals. 9.17
PerfCounter.endMonitoring(false) assigns its current duration rather than accumulating; cpuRenderMs reads 0-0.1ms and activeMeshes reads zero.
One Deliberate Choice
Under-compensating a jittery connection is intentional, "since erring high punishes the player who took cover."