code wiki / (root) / nx_pets_netstate.nx

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}