Summary
Measured, not estimated — netSummary reports it every online run:
| room |
avg snapshot |
downstream, per client |
| duel (2 fighters) |
~800 B |
~16 KB/s |
| deathmatch (16) |
~3.4 KB |
~66 KB/s |
That is after the packed wire format, which already cut a verbatim
PlayerPosition from ~400 bytes to nineteen numbers. Without it, sixteen fighters
would be ~128 KB/s and a datagram past any sane MTU.
66 KB/s down per client is fine on a LAN and fine on broadband. It is not fine on
a phone tether or a bad hotel connection, and it is entirely wasted bandwidth for
fighters that have not moved.
Why nothing has been done yet
Every snapshot currently contains every fighter, in full, at 20Hz. Both obvious
savings were deliberately skipped:
- Interest management is correct to skip: the arena is 800x600 and every
fighter is always on screen, so there is nobody to cull. This only becomes
relevant with a larger map.
- Delta encoding — sending only what changed since the last acknowledged
snapshot — is the real saving and was skipped for time. Most fields of most
fighters are unchanged between two 50ms snapshots.
Caution
Delta encoding on an unreliable transport is where netcode bugs live: a delta
against a baseline the client never received is a desync, and the failure is
silent. It needs per-client acknowledged baselines, not just a diff against the
last thing sent. The existing RELIABLE split in online/types.ts is the right
mental model — this would be the first thing that genuinely needs acknowledgement.
Definition of done
netSummary.avgSnapshotBytes materially down at sixteen fighters, reported in
the same place it is reported now.
rollback.avgErrorPx and jitterSummary unchanged — a bandwidth saving that
costs prediction accuracy is not a saving.
- The wire round-trip tests extended to cover a delta against a stale baseline,
because that is the case that breaks.
Out of scope
- Interest management, until there is a map big enough to need it.
Summary
Measured, not estimated —
netSummaryreports it every online run:That is after the packed wire format, which already cut a verbatim
PlayerPositionfrom ~400 bytes to nineteen numbers. Without it, sixteen fighterswould be ~128 KB/s and a datagram past any sane MTU.
66 KB/s down per client is fine on a LAN and fine on broadband. It is not fine on
a phone tether or a bad hotel connection, and it is entirely wasted bandwidth for
fighters that have not moved.
Why nothing has been done yet
Every snapshot currently contains every fighter, in full, at 20Hz. Both obvious
savings were deliberately skipped:
fighter is always on screen, so there is nobody to cull. This only becomes
relevant with a larger map.
snapshot — is the real saving and was skipped for time. Most fields of most
fighters are unchanged between two 50ms snapshots.
Caution
Delta encoding on an unreliable transport is where netcode bugs live: a delta
against a baseline the client never received is a desync, and the failure is
silent. It needs per-client acknowledged baselines, not just a diff against the
last thing sent. The existing
RELIABLEsplit inonline/types.tsis the rightmental model — this would be the first thing that genuinely needs acknowledgement.
Definition of done
netSummary.avgSnapshotBytesmaterially down at sixteen fighters, reported inthe same place it is reported now.
rollback.avgErrorPxandjitterSummaryunchanged — a bandwidth saving thatcosts prediction accuracy is not a saving.
because that is the case that breaks.
Out of scope