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

The client should not re-derive the server's movement speed #26

Closed opened this has it
opened this

A small change that removes a whole class of future desync, learned from a second game built on our engine (benjivers/skirmish #2).

Today static/val.js rebuilds the server's speed decision from four snapshot fields:

const speed = moveSpeed({
  haste: snap.me.haste > 0,
  slow: snap.me.slow > 0,
  stopped: snap.me.planting > 0 || snap.me.defusing || snap.phase === "end" || snap.phase === "over",
  heavy: snap.me.weapon === "operator",
});

That is src/match.ts:363 written twice. Every one of those four conditions is a rule the server owns, and the copy is only correct until somebody adds a fifth — a new slow, a new heavy weapon, a new phase where nobody moves. Then the prediction is wrong for exactly as long as it takes someone to notice, and the symptom is the one we spent days chasing: the drawn body creeping away from the server's answer and being pulled back.

Instead send the number. The other game does this and it worked: me.speed on the snapshot, Math.round(moveSpeed(...)) server-side, and the client passes it straight into stepLocal. A rule that stops you moving arrives as a zero and the guess stops with it, with no client-side knowledge of WHY.

What I want back.

  1. me.speed on the snapshot; the client's moveSpeed call and its four conditions deleted; stepLocal fed the server's number.
  2. A test that a body the server has stopped predicts at zero — one that fails if the client goes back to guessing.
  3. The feel numbers you would normally give me: per-frame step spread for your own body, and corrections per minute, before and after. This should be a no-op for feel; I want to see that it is, not be told.
  4. The snapshot grows by one small integer per seat. Say what it costs in bytes.

If you find the client needs to know a reason and not just a number, say so rather than keeping both.

commented

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

closed this
Sign in to join this conversation.

↑↓ navigate ↵ open esc close

Keyboard shortcuts