code wiki / _hdl_build / nx_netpredict_gate.nx

nx_netpredict_gate.nx source

↩ module page · 52 lines · 3636 B

1// nx_netpredict_gate.nx -- proves the prediction+reconciliation core (nx_netpredict): (1) local prediction gives the 2// player's own position IMMEDIATELY from local inputs (RTT hidden, zero input-to-feedback latency); (2) when the 3// server agrees, reconciliation replays pending inputs and lands EXACTLY on the predicted position (no rubber-band); 4// (3) when the server diverges on an event the client couldn't predict, reconciliation converges the client to the 5// authoritative truth. The warzone "fun realtime, not laggy" feel across a 150ms ocean. 6import "nx_syscalls.nx" 7import "nx_gate_emit_lib.nx" 8import "nx_netpredict.nx" 9import "nx_gate_verdict.nx" 10 11func main() -> i64 { 12 g_puts("nx_netpredict gate (client prediction + server reconciliation, RTT hidden, MEASURED)\n" as *u8) 13 var pass: i64 = 0; var total: i64 = 0 14 15 // client issues 10 move inputs (+1 each); start at 0. RTT means the server is several inputs behind. 16 let inputs: *i64 = sys_mmap(16*8) as *i64 17 var i: i64 = 0; while i < 10 { inputs[i] = 1; i = i + 1 } 18 let TOTAL: i64 = 10 19 20 // (1) PREDICTION: local-only, available at input tick 10 (not tick 10 + RTT) 21 let predicted: i64 = np_predict(0, inputs, TOTAL) 22 23 // (2) HAPPY PATH: server has processed 6 inputs (4 in flight across the ocean), agrees -> auth = 0 + 6 = 6 24 let acked: i64 = 6 25 let auth_happy: i64 = 6 26 let reconciled_happy: i64 = np_reconcile(auth_happy, acked, inputs, TOTAL) 27 28 g_puts(" [measure] predicted(local, immediate)=" as *u8); g_pn(predicted); g_puts(" server acked=" as *u8); g_pn(acked); g_puts(" auth=" as *u8); g_pn(auth_happy); g_puts(" reconciled=" as *u8); g_pn(reconciled_happy); g_puts("\n" as *u8) 29 30 pass = pass + g_check("prediction is local-only (RTT hidden: own creature responds immediately)" as *u8, predicted == 10); total=total+1 31 pass = pass + g_check("server agrees -> reconciled == predicted (no rubber-band correction)" as *u8, reconciled_happy == predicted); total=total+1 32 33 // (3) DIVERGENCE: at input 8 the server applied a knockback of -3 the client couldn't predict -> auth(after 8) = 8-3 = 5 34 let acked2: i64 = 8 35 let auth_div: i64 = 5 // authoritative truth includes the server-only event 36 let reconciled_div: i64 = np_reconcile(auth_div, acked2, inputs, TOTAL) // 5 + replay inputs[8..10) = 5 + 2 = 7 37 g_puts(" [measure] divergence: server knockback -3 -> auth=" as *u8); g_pn(auth_div); g_puts(" naive-predicted=" as *u8); g_pn(predicted); g_puts(" reconciled=" as *u8); g_pn(reconciled_div); g_puts(" (converges to authoritative truth + pending)\n" as *u8) 38 39 pass = pass + g_check("divergence -> reconciliation corrects toward authoritative (server authority holds)" as *u8, reconciled_div == 7); total=total+1 40 pass = pass + g_check("corrected state differs from the wrong naive prediction (the server event is honored)" as *u8, reconciled_div != predicted); total=total+1 41 42 g_puts("---- netpredict gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8) 43 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 44 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 45 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 46 let ctr__dry: *i64 = gv_ctr() 47 ctr__dry[0] = pass 48 ctr__dry[1] = total 49 let rc__dry: i64 = gv_verdict("NETPREDICT-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8) 50 sys_exit(rc__dry) 51 return rc__dry 52}