nx_state_delta_codec.nx
buildroot/runtime/nx_state_delta_codec.nx
about
nx_state_delta_codec.nx -- quantized bit-packed entity state delta codec.
Foundation for poor-internet multiplayer. The naive "serialize full
entity state every frame" approach uses ~32 bytes/entity (x,y,z,yaw,
pitch,health,id,flags as i64). At 60Hz x 100 entities = 192 KB/s.
On a 56 kbps dial-up link (7 KB/s ceiling) that's 27x over budget.
Delta-quantize-bitpack collapses this to typical 1-4 bytes per
entity per frame:
- Bit cursor over a byte buffer (write_bits / read_bits).
- Signed N-bit delta encoding (twos-complement) for position +
velocity changes between adjacent frames.
- Unsigned N-bit absolute encoding for angles (256-step yaw =
~1.4 deg precision; the GGPO/Skullgirls choice).
- Varint (7-bit continuation, identical wire format to Protobuf
varint / LEB128) for sparse integer fields.
Bandwidth budget on a typical FPS frame:
per entity: 1 byte change-mask + ~3 bytes delta = 4 bytes
100 entities at 60Hz = 24 KB/s
Compare: full-state baseline 192 KB/s -> 8x reduction.
On 56 kbps dial-up, area-of-interest culling brings the entity count
down to ~20 in-view -> 4.8 KB/s, fits under the 7 KB/s ceiling.
Source references (all open):
- GGPO bit-packed input frames (Cannon 2006, pond3r/ggpo)
- Slither.io / Agar.io quantized state protocols (ClitherProject reverse-eng)
- Protobuf varint / LEB128 (developers.google.com/protocol-buffers/docs/encoding)
- Quake 3 delta-compressed entity protocol (Carmack .plan)
genealogy_id: ggpo_bitpacked_inputs + protobuf_varint + quake3_delta_entities
lineage_id: bandwidth_quantize_entity_state
dependencies 3 imports · 0 importers
imports: nx_syscalls.nxnx_tier.nxnx_zigzag_varint.nx
imported by: nobody (leaf or entry point)
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 44 | const NX_MAGIC_2047: i64 = 2047 |
| 45 | const NX_MAGIC_2048: i64 = 2048 |
| 46 | const NX_MAGIC_16383: i64 = 16383 |
| 47 | const NX_MAGIC_16384: i64 = 16384 |
| 48 | const NX_MAGIC_1000000: i64 = 1000000 |
| 57 | const NX_DC_OFF_BUF: nx_int = 0 |
| 58 | const NX_DC_OFF_BYTE: nx_int = 1 |
| 59 | const NX_DC_OFF_BIT: nx_int = 2 |
| 60 | const NX_DC_OFF_CAP: nx_int = 3 |
| 61 | const NX_DC_HDR_SIZE: nx_int = 4 |
functions
| 63 | func nx_delta_writer_new(cap_bytes: nx_int) -> *i64 |
| 79 | func nx_delta_writer_bytes_used(w: *i64) -> nx_int called by 1: main |
| 86 | func nx_delta_writer_buf(w: *i64) -> *u8 |
| 93 | func nx_delta_write_bits(w: *i64, value: i64, n_bits: nx_int) |
| 128 | func nx_delta_write_signed(w: *i64, value: i64, n_bits: nx_int) |
| 143 | func nx_delta_write_varint(w: *i64, value: i64) |
| 161 | func nx_delta_reader_new(buf: *u8, n_bytes: nx_int) -> *i64 |
| 170 | func nx_delta_read_bits(r: *i64, n_bits: nx_int) -> i64 |
| 207 | func nx_delta_read_signed(r: *i64, n_bits: nx_int) -> i64 |
| 222 | func nx_delta_write_zigzag_varint(w: *i64, value: i64) |
| 228 | func nx_delta_read_varint(r: *i64) -> i64 |
| 243 | func nx_delta_read_zigzag_varint(r: *i64) -> i64 |
| 250 | func main() -> i64 |