nx_relchan.nx source
↩ module page · 42 lines · 2217 B
1// nx_relchan.nx -- sovereign RELIABLE, ORDERED, EXACTLY-ONCE channel for CRITICAL game events
2// (creature captured, block placed/broken, trade) over the unreliable relay. Position is unreliable-
3// frequent (interp/extrapolate cover its loss); events must never be lost OR double-applied. Sender
4// keeps an unacked window + retransmits; receiver dedups by seq + delivers strictly in order +
5// cumulative-acks. 100% nx, no syscalls -> wasm-friendly; the host just moves the bytes.
6//
7// Receiver state r[*i64]: [0]=expected (next in-order seq) [1]=delivered_total then [2 + seq] = received-bit
8// (capacity seqcap). Cumulative ack = expected-1 (highest contiguous delivered).
9// Sender state s[*i64]: [0]=acked_upto (cumulative, -1 = none) [1]=n (event count). Resends seqs > acked_upto.
10// license_tier: ORIGINAL
11
12func rc_rinit(r: *i64, seqcap: i64) -> i64 {
13 r[0] = 0; r[1] = 0
14 var i: i64 = 0
15 while i < seqcap { r[2 + i] = 0; i = i + 1 }
16 return 0
17}
18func rc_expected(r: *i64) -> i64 { return r[0] }
19func rc_delivered(r: *i64) -> i64 { return r[1] }
20func rc_ack_value(r: *i64) -> i64 { return r[0] - 1 } // cumulative ack to send back
21
22// receive event `seq`; returns the number of NEWLY in-order-delivered events (0 = duplicate/out-of-range,
23// >=1 = this arrival drained one or more contiguous events). Idempotent: a duplicate returns 0, no re-delivery.
24func rc_recv(r: *i64, seqcap: i64, seq: i64) -> i64 {
25 if seq < r[0] { return 0 } // already delivered -> dup
26 if seq >= seqcap { return 0 } // out of range
27 if r[2 + seq] == 1 { return 0 } // already buffered -> dup
28 r[2 + seq] = 1
29 var nd: i64 = 0
30 var go: i64 = 1
31 while go == 1 {
32 if r[0] >= seqcap { go = 0 } else {
33 if r[2 + r[0]] == 1 { r[0] = r[0] + 1; r[1] = r[1] + 1; nd = nd + 1 } else { go = 0 }
34 }
35 }
36 return nd
37}
38
39func rc_sinit(s: *i64, n: i64) -> i64 { s[0] = 0 - 1; s[1] = n; return 0 }
40func rc_ack(s: *i64, a: i64) -> i64 { if a > s[0] { s[0] = a } return 0 }
41func rc_unacked_lo(s: *i64) -> i64 { return s[0] + 1 } // first seq still needing (re)send
42func rc_all_acked(s: *i64) -> i64 { if s[0] >= s[1] - 1 { return 1 } return 0 }