code wiki / (root) / nx_sim_snapshot.nx

nx_sim_snapshot.nx

buildroot/runtime/nx_sim_snapshot.nx

14794 B351 linesdepth 2pulls 2 transitivereach 1 importersview sourcekind tooltopic sim
docsdependenciesstructsconstsfunctions

about

nx_sim_snapshot.nx -- generic simulation state save/restore. Foundation primitive for: - Rollback netcode (GGPO model, Cannon 2006): save last N frames, roll back when remote input correction arrives, re-simulate. - Turn-based replay (XCOM 2 / Into the Breach honestmode model): save state at turn boundary, replay deterministically. - VN save-anywhere (Ren'Py model): full-VM state snapshot for load/quicksave/rollback over the last ~128 statements. - Desync recovery (RTS lockstep): when frame_hash mismatches across clients, roll back to last known-good snapshot and re-simulate from authoritative input log. Two layers: 1. Flat byte-buffer save/restore (memcpy semantics). Caller owns the byte layout of their simulation state. 2. Ring buffer of N snapshots indexed by frame number with wraparound. Sized for rollback budget (default 8 frames at 60Hz = 133ms maximum prediction window per GGPO standard). Honest scope: this primitive does NOT serialize POINTERS. Caller is responsible for flattening pointer-graph state into a byte block before save and rebuilding pointers after restore. This matches how GGPO's `save_game_state` callback works. Source references (open): - GGPO Rollback SDK: https://github.com/pond3r/ggpo (MIT) - Tony Cannon "GGPO Inside Out": ggpo.net/file/Inside_GGPO.pdf - Skullgirls/Killer Instinct postmortems (GDC vault open) - Bernier "Latency Compensating Methods" (Valve PDF, open) genealogy_id: ggpo_2006_rollback + xcom_honestmode_replay + renpy_rollback_log lineage_id: simulation_state_persistence

dependencies 2 imports · 1 importers

nx_syscalls.nx nx_tier.nx nx_sim_snapshot.nx nx_rollback_session.nx

imports: nx_syscalls.nxnx_tier.nx

imported by: nx_rollback_session.nx

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main sys_mmap nx_sim_snapshot_save nx_sim_snapshot_eq nx_sim_snapshot_restore nx_sim_snapshot_save ↻ nx_snapshot_ring_alloc sys_mmap ↻ _ss_slot_frame_ptr nx_snapshot_ring_newest nx_snapshot_ring_oldest nx_snapshot_ring_has _ss_slot_for_frame _ss_slot_frame_ptr ↻ nx_snapshot_ring_save _ss_slot_for_frame ↻ _ss_slot_bytes_ptr _ss_bytes_base nx_sim_snapshot_save ↻ _ss_slot_frame_ptr ↻ nx_snapshot_ring_restore _ss_slot_for_frame ↻ _ss_slot_frame_ptr ↻ _ss_slot_bytes_ptr ↻ nx_sim_snapshot_restore ↻

structs

none

consts

46const NX_SS_DEFAULT_RING_DEPTH: nx_int = 8
49const NX_SS_FRAME_INVALID: nx_int = -1
103const NX_SS_HDR_STATE_SIZE: nx_int = 0
104const NX_SS_HDR_RING_DEPTH: nx_int = 1
105const NX_SS_HDR_NEWEST_FRAME: nx_int = 2
106const NX_SS_HDR_OLDEST_FRAME: nx_int = 3
107const NX_SS_HDR_BASE: nx_int = 4

functions

58func nx_sim_snapshot_save(dst: *u8, src: *u8, n: nx_int) -> nx_int
71func nx_sim_snapshot_restore(dst: *u8, src: *u8, n: nx_int) -> nx_int
78func nx_sim_snapshot_eq(a: *u8, b: *u8, n: nx_int) -> nx_int
called by 1: main
109func _ss_slot_for_frame(ring: *i64, frame: nx_int) -> nx_int
117func _ss_slot_frame_ptr(ring: *i64, slot: nx_int) -> *i64
123func _ss_bytes_base(ring: *i64) -> *u8
called by 1: _ss_slot_bytes_ptr
130func _ss_slot_bytes_ptr(ring: *i64, slot: nx_int) -> *u8
141func nx_snapshot_ring_alloc(state_size: nx_int, ring_depth: nx_int) -> *i64
167func nx_snapshot_ring_save(ring: *i64, frame: nx_int, src: *u8) -> nx_int
201func nx_snapshot_ring_restore(ring: *i64, frame: nx_int, dst: *u8) -> nx_int
220func nx_snapshot_ring_oldest(ring: *i64) -> nx_int
226func nx_snapshot_ring_newest(ring: *i64) -> nx_int
called by 1: main
233func nx_snapshot_ring_has(ring: *i64, frame: nx_int) -> nx_int
245func main() -> i64