# Network sync: rollback / lockstep (deterministic) (net.rollback) ## What it is for Synchronises peers by inputs only: they run the same deterministic simulation, either predicting remote inputs and re-simulating on a misprediction (rollback) or waiting for every input of a frame (lockstep). It needs `net.transport`, `input.actions`, `game.engine`; installing it brings them in. ## Turn it on Install the kit in a project, then change a setting (the values shown are its defaults): ```text gripforge_gamekit_install { project_id: "gkp_…", id: "net.rollback" } gripforge_gamekit_configure { project_id: "gkp_…", id: "net.rollback", config: { "mode": "rollback", "players": 2 } } ``` ## First example This is the body of the passing test `input_actions_feed_the_arena_bits_when_no_input_is_set`; the helper functions it calls are defined at the top of the same test file. ```rust #[test] fn input_actions_feed_the_arena_bits_when_no_input_is_set() { let mut s = online(json!({})); commands(&mut s); s.apply(&json!({ "op": "key", "code": "Space", "down": true })) .unwrap(); step(&mut s, 1); let sent = inputs(&mut s); assert_eq!( sent[0]["v"].as_u64().unwrap() & 16, 16, "jump is bit 16: {sent:?}" ); s.apply(&json!({ "op": "key", "code": "Space", "down": false })) .unwrap(); step(&mut s, 1); assert_eq!( inputs(&mut s).last().unwrap()["v"].as_u64().unwrap() & 16, 0 ); } ``` ## Settings and defaults Descriptions come from the kit manifest and stay in English. | Setting | Type | Default | Range or values | Meaning | |---|---|---|---|---| | `mode` | string | `"rollback"` | `rollback`, `lockstep` | rollback = predict + re-simulate; lockstep = wait for every input. | | `players` | integer | `2` | 1–8 | Slots of a match; it starts when all are filled. | | `frameHz` | integer | `60` | 10–120 | Simulation frames per second. | | `inputDelay` | integer | `2` | 0–30 | Local inputs apply this many frames later (hides latency, fewer rollbacks). | | `maxRollback` | integer | `8` | 0–30 | Never predict further than this past the last confirmed frame (stall instead). | | `maxBehindFrames` | integer | `30` | 1–600 | A peer more than this many frames behind the match clock catches up without rendering the frames in between. | | `hashEvery` | integer | `60` | 0–6000 | Frames between state hash checks (0 = off). | | `maxPendingHashes` | integer | `64` | 1–4096 | State hashes waiting for comparison per peer. | | `hashWindowFrames` | integer | `600` | 60–100000 | Relay: frames of state hashes kept for comparison. | | `inputLogFrames` | integer | `36000` | 600–1000000 | Relay: frames of input kept for resumed peers. | | `maxAheadFrames` | integer | `120` | 10–6000 | Relay: inputs further ahead of the match clock are refused. | | `relayMs` | integer | `50` | 5–1000 | Relay: resend period of unacknowledged inputs. | | `orderResendMs` | integer | `30` | 5–1000 | Peer: pending orders are batched and sent at most every max(2 frames, orderResendMs) (orders ride the reliable channel). | | `resyncGapMs` | integer | `2000` | 100–60000 | A peer that received nothing for this long asks the relay for a resync. | | `seed` | integer | `0` | 0–2147483647 | Match seed (0 = random). | | `game` | string | `"arena"` | `arena`, `physics` | The deterministic game every peer runs inside the core: the integer arena, or the net.physics arena (needs physics: shared). | | `physics` | string | `"none"` | `none`, `shared` | none, or shared = net.physics (engine physics is not deterministic across machines, so native is not offered). | | `inputTimeoutMs` | integer | `0` | 0–600000 | Relay: a connected player that sends no input for this long is declared left and disconnected (0 = off). | | `orders` | boolean | `true` | | Relay: offer the structured orders channel (RTS commands, `r.ord`); gfnet-core peers only. | | `maxOrderBytes` | integer | `1024` | 64–1024 | Largest order (canonical JSON bytes). | | `maxOrdersPerFrame` | integer | `4` | 1–32 | Orders per player and per frame. | | `orderDelay` | integer | `0` | 0–120 | Orders apply at least this many frames ahead (never earlier than inputDelay). | | `turnMs` | | `0` | | Turn-based lockstep (RTS style): turn length in ms (typically 100–200; 50–1000), 0 = off. | | `turnDelay` | integer | `2` | 1–10 | Turns between issuing an order and running it. | | `adaptiveTurn` | boolean | `false` | | Relay: stretch the turn to the slowest round trip (never below turnMs, at most adaptiveTurnMaxMs). | | `adaptiveTurnMaxMs` | integer | `500` | 50–2000 | Adaptive turns never grow past this (ms). | | `adaptiveTurnPeriodMs` | integer | `1000` | 100–60000 | Relay: the adaptive turn is re-evaluated this often. | | `adaptiveTurnRttFactor` | number | `1.2` | 1–4 | Relay: the adaptive turn covers the slowest round trip × this. | ## Services, events, variables - Service `net.sync`: The project replication model (one per project: the net.* sync kits conflict with each other). - Service `net.rollback`: register(game), setInput(bits), state(), frame(); rollback / desync events. - Service `net.lockstep`: The same session in strict lockstep (`mode: lockstep`). - Events emitted: - `net.match_started` (`slot`, `players`, `seed`) — All slots filled; frame 0 starts. - `net.desync` (`frame`) — State hashes differ between peers (non-deterministic game code). - `net.slot_left` (`slot`, `frame`) — A player left; its input is neutral from `frame`. - `net.connected` (`id`, `resumed`, `transport`) — Welcome received on a session reopened by register(game) (the first session reports it through the shared session mirror, as net.transport declares). - `net.peer` (`id`, `on`) — Another peer joined or left a session reopened by register(game). - `net.refused` (`code`, `msg`) — 1.4: the handshake of a session reopened by register(game) was refused (the core's code; mods: the server runs other mods, net.transport 1.3). - Variables: - `net.status` (string) — Network status - `net.rtt` (number) — Ping (ms) - `net.peers` (number) — Players online - `net.frame` (number) — Frame - `net.rollbacks` (number) — Rollbacks ## Hooks and modding This kit declares no hook and no collection to mod. ## Engines Declared targets: `web`, `godot`, `unity`, `unreal`. `gripforge kit api net.rollback` lists the exact settings and services of your version. ## Versions Kit version 1.4.0.