nx_pets_netstate.nx source
↩ module page · 82 lines · 3264 B
1// nx_pets_netstate.nx -- sovereign player-state codec for multiplayer pixelmon.
2// Packs a player snapshot into a compact 28-byte frame for the server-relay
3// (nx_room_relay): each player POSTs its frame, reads the roster of OTHER players,
4// unpacks their frames -> renders peer avatars. Pure buffer ops, NO syscalls ->
5// wasm-friendly (compiles via nxc2 --target wat, same path as the game) AND reusable
6// by the native relay daemon. Versioned + magic-guarded = forward/backward compatible
7// (mirrors gi_save discipline: a peer's short/older frame still decodes its fields;
8// the layout is APPEND-ONLY so newer frames decode their known prefix on older readers).
9//
10// Frame layout (PS_LEN = 28 bytes):
11// [0]=0x50 'P' [1]=0x4D 'M' [2]=version(1) [3]=flags
12// [4..7]=x [8..11]=y [12..15]=z [16..19]=yaw [20..23]=pitch (i32 LE, voxel fixed-pt)
13// [24]=species_held [25]=caught_count [26]=action [27]=anim
14// Fields array f[10] (caller-owned): x,y,z,yaw,pitch, species,caught,action,anim, flags
15// license_tier: ORIGINAL
16
17const PS_MAGIC0: i64 = 0x50
18const PS_MAGIC1: i64 = 0x4D
19const PS_VER: i64 = 1
20const PS_LEN: i64 = 28
21
22// little-endian i32 write
23func ps_wr32(buf: *u8, off: i64, v: i64) -> i64 {
24 buf[off] = (v & 0xff) as u8
25 buf[off+1] = ((v >> 8) & 0xff) as u8
26 buf[off+2] = ((v >> 16) & 0xff) as u8
27 buf[off+3] = ((v >> 24) & 0xff) as u8
28 return 0
29}
30
31// little-endian i32 read, sign-extended to i64 (positions can be negative in an
32// infinite world west/south of origin)
33func ps_rd32(buf: *u8, off: i64) -> i64 {
34 var v: i64 = (buf[off] as i64)
35 v = v | ((buf[off+1] as i64) << 8)
36 v = v | ((buf[off+2] as i64) << 16)
37 v = v | ((buf[off+3] as i64) << 24)
38 let HIBIT: i64 = 1 << 31
39 let WRAP: i64 = 1 << 32
40 if (v & HIBIT) != 0 { v = v - WRAP }
41 return v
42}
43
44// pack fields f[0..9] -> 28-byte frame; returns byte length
45func ps_pack(buf: *u8, f: *i64) -> i64 {
46 buf[0] = PS_MAGIC0 as u8
47 buf[1] = PS_MAGIC1 as u8
48 buf[2] = PS_VER as u8
49 buf[3] = (f[9] & 0xff) as u8
50 ps_wr32(buf, 4, f[0])
51 ps_wr32(buf, 8, f[1])
52 ps_wr32(buf, 12, f[2])
53 ps_wr32(buf, 16, f[3])
54 ps_wr32(buf, 20, f[4])
55 buf[24] = (f[5] & 0xff) as u8
56 buf[25] = (f[6] & 0xff) as u8
57 buf[26] = (f[7] & 0xff) as u8
58 buf[27] = (f[8] & 0xff) as u8
59 return PS_LEN
60}
61
62// unpack a frame of n bytes -> f[0..9]; returns 1 if magic valid, else 0 (reject,
63// caller keeps prior state = no data loss). Missing tail bytes keep DEFAULT 0
64// (backward-compatible). Any version with valid magic is accepted (append-only layout).
65func ps_unpack(buf: *u8, n: i64, f: *i64) -> i64 {
66 if n < 4 { return 0 }
67 if (buf[0] as i64) != PS_MAGIC0 { return 0 }
68 if (buf[1] as i64) != PS_MAGIC1 { return 0 }
69 var i: i64 = 0
70 while i < 10 { f[i] = 0; i = i + 1 }
71 f[9] = (buf[3] as i64)
72 if n >= 8 { f[0] = ps_rd32(buf, 4) }
73 if n >= 12 { f[1] = ps_rd32(buf, 8) }
74 if n >= 16 { f[2] = ps_rd32(buf, 12) }
75 if n >= 20 { f[3] = ps_rd32(buf, 16) }
76 if n >= 24 { f[4] = ps_rd32(buf, 20) }
77 if n >= 25 { f[5] = (buf[24] as i64) }
78 if n >= 26 { f[6] = (buf[25] as i64) }
79 if n >= 27 { f[7] = (buf[26] as i64) }
80 if n >= 28 { f[8] = (buf[27] as i64) }
81 return 1
82}