benjivers/val Public Public: anyone can read this; the crew can change it.

Above two players, every enemy is drawn 42ms further in the past than it needs to be #29

Closed opened this has it
opened this

broadcastEvery halves the snapshot rate as soon as a third seat fills, and the reason it gives has stopped being true. I measured before filing; the numbers are yours to check and then improve on.

What the rule costs. interp.js sets the render delay at LAG = 1.3 x the interval snapshots actually arrive at, floored at 45ms:

seatscadencerateintervaldelay other bodies are drawn at
1-2every tick30Hz33ms45ms (the floor)
3+every other tick15Hz67ms87ms

So the moment a third person joins, every enemy position everybody sees gets ~42ms older. In a game about peeking a corner first, that is the wrong thing to be saving.

What the rule saves. Almost nothing, and that is the change since it was written. It says "the payload is a couple of kilobytes a seat" and "the cost multiplies by seats", which was fair when a snapshot was ~3.8KB and unfiltered. Measured on main today, in a live round:

one snapshot: 0.008ms to build (vision filter included)
one world tick: 0.026ms
 2 seats: every tick = 1.3ms of CPU per second (0.1% of a core)
 5 seats: every tick = 2.0ms per second (0.2%)
10 seats: every tick = 3.2ms per second (0.3%)

Bandwidth at a live-round snapshot (~1.6KB, which is what production actually sends): 10 seats at 30Hz is ~480 kB/s out of the box and ~48 kB/s to each player. On a droplet that is nothing, and the arena only runs while somebody is connected.

That measurement is on my machine, not the box. Assume the box's vCPU is several times slower and it is still under 2% of a core at ten seats. Check that assumption rather than taking it from me — if the box is genuinely the constraint, I would rather know than double the rate on a guess.

What I want.

  1. The cadence raised to every tick for the room sizes val actually sees, with the threshold you can defend from measurement rather than the one I guessed. If the honest answer is "every tick always, the rule can go", say that.
  2. The feel numbers before and after, at 4 and at 8 seats, from the harness in src/feel.test.ts: per-frame step spread for other bodies, jumps, and the delay actually in force. The claim to confirm or destroy is that other players get ~40ms closer to the present with no new jitter.
  3. What it costs, measured on the box if you can reach it and on yours if you cannot: CPU per second and bytes per second at those seat counts.
  4. Keep the rule a function of the room. A comment that says why the threshold is where it is, with today's numbers in it, so the next person does not have to re-derive this.

Two things not to break: the client already follows the rate it measures rather than being told it (interp.js says so explicitly), so this should need no client change at all — if you find yourself editing the client, stop and say why. And do not touch src/engine/ to do it: broadcastEvery is engine, so if the threshold needs to become a parameter, pass it in from the game rather than teaching the engine about val.

commented

Done in #31 (merged 2026-09); closing — that merge predates closing-on-merge.

closed this
Sign in to join this conversation.

↑↓ navigate ↵ open esc close

Keyboard shortcuts