code wiki / _hdl_build / nx_lagcomp_gate.nx
nx_lagcomp_gate.nx source
↩ module page · 48 lines · 3274 B
1// nx_lagcomp_gate.nx -- proves server-side lag compensation (nx_lagcomp): a correctly-aimed action on what the client
2// SAW connects when the server rewinds to that moment, but MISSES if the server naively checks the target's current
3// (already-moved) position. And a genuinely-wrong aim still misses (it's fair adjudication, not auto-hit).
4import "nx_syscalls.nx"
5import "nx_gate_emit_lib.nx"
6import "nx_lagcomp.nx"
7import "nx_gate_verdict.nx"
8
9func main() -> i64 {
10 g_puts("nx_lagcomp gate (server rewinds history so a catch/hit connects despite RTT, MEASURED)\n" as *u8)
11 var pass: i64 = 0; var total: i64 = 0
12
13 // a target creature moving +2 / server-tick; 1s history ring (60 ticks). now = tick 50.
14 let hist: *i64 = sys_mmap(64*8) as *i64
15 var t: i64 = 0; while t < 64 { hist[t] = t * 2; t = t + 1 }
16 let now: i64 = 50
17 let radius: i64 = 4
18 let cur_pos: i64 = hist[now] // target's CURRENT server position = 100
19
20 // the acting client: latency 7 ticks + interpolation delay 5 ticks = sees the target 12 ticks in the past
21 let rewind: i64 = 7 + 5
22 let seen_pos: i64 = lc_rewind(hist, now, rewind) // hist[38] = 76 -- what the client aimed at
23 let aim: i64 = seen_pos // a CORRECT throw at the seen position
24
25 let hit_naive: i64 = lc_hit(aim, cur_pos, radius) // server checks current pos -> miss
26 let hit_lagcomp: i64 = lc_hit(aim, lc_rewind(hist, now, rewind), radius) // server rewinds -> connect
27
28 // a genuinely-wrong aim (somewhere the target never was at the seen time) must still miss even with lag comp
29 let bad_hit: i64 = lc_hit(seen_pos + 40, lc_rewind(hist, now, rewind), radius)
30
31 g_puts(" [measure] target now=" as *u8); g_pn(cur_pos); g_puts(" client saw it at=" as *u8); g_pn(seen_pos); g_puts(" (rewind " as *u8); g_pn(rewind); g_puts(" ticks) aim=" as *u8); g_pn(aim); g_puts("\n" as *u8)
32 g_puts(" [measure] naive (check current pos)=" as *u8); g_pn(hit_naive); g_puts(" lag-compensated (rewind)=" as *u8); g_pn(hit_lagcomp); g_puts(" wrong-aim w/ lagcomp=" as *u8); g_pn(bad_hit); g_puts("\n" as *u8)
33
34 pass = pass + g_check("correct aim CONNECTS with lag compensation (rewind to what the client saw)" as *u8, hit_lagcomp == 1); total=total+1
35 pass = pass + g_check("same aim MISSES without lag comp (target already moved) -- the unfair case lag-comp fixes" as *u8, hit_naive == 0); total=total+1
36 pass = pass + g_check("a genuinely-wrong aim still misses (fair adjudication, not auto-hit)" as *u8, bad_hit == 0); total=total+1
37
38 g_puts("---- lagcomp gate: passed " as *u8); g_pn(pass); g_puts(" / " as *u8); g_pn(total); g_puts(" ----\n" as *u8)
39 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check
40 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled
41 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify.
42 let ctr__dry: *i64 = gv_ctr()
43 ctr__dry[0] = pass
44 ctr__dry[1] = total
45 let rc__dry: i64 = gv_verdict("LAGCOMP-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8)
46 sys_exit(rc__dry)
47 return rc__dry
48}