code wiki / (root) / nx_wasm_mineworld.nx

nx_wasm_mineworld.nx source

↩ module page · 1194 lines · 56246 B

1// nx_wasm_mineworld.nx -- MINECRAFT-LEVEL PROC GEN: an INFINITE deterministic voxel world (the noise function 2// IS the world -- no fixed array). Multi-octave integer value-noise terrain + CONTINUOUS biome blend (plains/ 3// forest/desert/snow: colors, tree density, hill amplitude -- amplitude blended so biome borders have no cliff), 4// 3D-noise CAVES with unbreakable bedrock at y=0, water, trees. World state = a SLIDING 32x32 height/biome cache 5// window around the camera (refreshed per frame; terrain is a pure fn of (x,z,seed) so roaming is unbounded) + 6// a SPARSE GLOBAL EDIT TABLE (open-address hash, global coords) so dig/place edits PERSIST when you roam away 7// and return (the fixed 48x48 grid of nx_wasmvox3d could not leave its box). Same base-relative pattern + export 8// surface as nx_wasmvox3d (render/terrain_at/break_at/place_at/ww/hh/fb_off) -> same JS shim contract. 9// Scoped 192x144 / VDIST 14 for software-raster speed (the proven envelope). license_tier: ORIGINAL 10import "nx_f32_hw.nx" 11import "nx_pets_netstate.nx" 12const PI2_MAGIC_4096: i64 = 4096 13const PI2_MAGIC_374761393: i64 = 374761393 14const PI2_MAGIC_668265263: i64 = 668265263 15const PI2_MAGIC_1442695041: i64 = 1442695041 16const PI2_MAGIC_1274126177: i64 = 1274126177 17const PI2_MAGIC_65536: i64 = 65536 18const PI2_MAGIC_2246822519: i64 = 2246822519 19const PI2_MAGIC_16777216: i64 = 16777216 20const PI2_MAGIC_2654435761: i64 = 2654435761 21const PI2_MAGIC_3900: i64 = 3900 22const PI2_MAGIC_9999: i64 = 9999 23const PI2_MAGIC_5734: i64 = 5734 24 25const W: i64 = 256 26const H: i64 = 192 27const HW: i64 = 128 28const HH: i64 = 96 29const ZFAR: i64 = 1073741824 30const FOCAL: i64 = 200 31const YMAX: i64 = 28 32const WSEED: i64 = 7 33const WWATER: i64 = 4 34const VDIST: i64 = 18 35const WWIN: i64 = 40 36const BIAS: i64 = 1048576 37const EBIAS: i64 = 67108864 38const ECAP: i64 = 4096 39const PI4096: i64 = 12868 // pi in 4096-scale radians (integer trig -- NO JS Math on the game path) 40const PI2_4096: i64 = 6434 41const FOG0: i64 = 12 // fog starts (blocks); full at FOG0+8 -> the horizon fades into sky 42 43const O_FB: i64 = 0 44const O_ZB: i64 = 393216 // W*H*8 (256x192) 45const O_R: i64 = 786432 46const O_RY: i64 = 786560 47const O_RX: i64 = 786688 48const O_V: i64 = 786816 49const O_RV: i64 = 786848 50const O_SX: i64 = 786880 51const O_SY: i64 = 786944 52const O_SD: i64 = 787008 53const O_SOK: i64 = 787072 54const O_PJ: i64 = 787136 55const O_HCORG: i64 = 787200 // sliding-window origin: [0]=orgx [1]=orgz [2]=valid 56const O_HC: i64 = 787224 // height cache, WWIN*WWIN i64 (40x40 covers VDIST 18 + neighbors) 57const O_HB: i64 = 800024 // biome cache, WWIN*WWIN i64 58const O_HT: i64 = 812824 // tree-presence cache, WWIN*WWIN i64 (trees are SOLID blocks now) 59const O_EDIT: i64 = 825624 // sparse edit table: ECAP * (key,val) i64 pairs 60const O_ECNT: i64 = 891160 // live edit count 61// --- multiplayer (GTA-online rung 1): peer table + netstate buffers; protocol logic ALL in-wasm --- 62const MAXPEERS: i64 = 8 63const O_PEERS: i64 = 891224 // MAXPEERS x {active,x256,y256,z256,yaw1000} i64 64const O_NETF: i64 = 891544 // ps_pack/ps_unpack scratch fields f[10] 65const O_NETOUT: i64 = 891624 // packed self frame (28B) -- JS memcpy's this to the /pstate POST body 66const O_NETIN: i64 = 891656 // roster body in ([len:1][frame] records) -- JS memcpy's /roster here 67// --- SOVEREIGN TICK: the ENTIRE player sim lives here (camera, physics, input) -- JS sends only raw input --- 68const O_CAM: i64 = 895752 // [0]x256 [1]y256(eye) [2]z256 [3]yaw4096rad [4]pitch4096rad [5]vy256 [6]fly [7]onground [8]prevkeys [9]invY [10]invX [11]sens 69const MW_SENS: i64 = 13 // default mouse gain (rad*4096 per pixel); the client owns it as data (c[11]) 70// ---- BLOCK DATA REGISTRY: blocks are DATA, not const (operator: games as data-io + logic, loosely coupled). 71// A block record = 4 i64 {top_rgb, side_rgb, style, flags}. A DATA PACK (or a MOD overlay) loads records via 72// pack_block() at RUNTIME -- no recompile. tex() READS this table -> a mod that changes a color/style re-skins 73// the world live. blk[0*4+0] = the "pack loaded" marker (0 = load the built-in default pack lazily). ---- 74const O_BLK: i64 = 895848 // MAXBLK * 4 i64 block records (starts right after O_CAM's 96 bytes) 75const O_STAT: i64 = 896872 // [0] = terrain pixels DRAWN this frame (ground truth for gates; reset per render) 76const MAXBLK: i64 = 32 77const ST_PLAIN: i64 = 0 78const ST_GRASS: i64 = 1 79const ST_STONE: i64 = 2 80const ST_WOOD: i64 = 3 81const ST_LEAF: i64 = 4 82const ST_WATER: i64 = 5 83const ST_ORE: i64 = 6 // stone body (side color) with mineral flecks (top color) -- the harvested ores 84// --- block kinds (per-face PROCEDURAL textures, integer hash, zero assets) --- 85const K_GRASS: i64 = 1 86const K_DIRT: i64 = 2 87const K_STONE: i64 = 3 88const K_SAND: i64 = 4 89const K_SNOW: i64 = 5 90const K_ROCK: i64 = 6 91const K_WATER: i64 = 7 92const K_WOOD: i64 = 8 93const K_LEAF: i64 = 9 94const K_PLANK: i64 = 10 95// HARVESTED from the minecraftclone block registry (nishi-engine packages/voxel-blocks/src/blocks.nx -- 96// already NishiLang data): the ore/cobble vocabulary, as data-pack records + deterministic underground veins. 97const K_COBBLE: i64 = 11 98const K_COAL: i64 = 12 99const K_IRON: i64 = 13 100const K_GOLD: i64 = 14 101const K_EMER: i64 = 15 102const K_DARKWOOD: i64 = 16 103 104func imin(a: i64, b: i64) -> i64 { if a < b { return a } return b } 105func imax(a: i64, b: i64) -> i64 { if a > b { return a } return b } 106func min3(a: i64, b: i64, c: i64) -> i64 { return imin(a, imin(b, c)) } 107func max3(a: i64, b: i64, c: i64) -> i64 { return imax(a, imax(b, c)) } 108func clamp255(v: i64) -> i64 { if v < 0 { return 0 } if v > 255 { return 255 } return v } 109func fratio(num: i64, den: i64) -> i64 { return f32_div(f32_of(num), f32_of(den)) } 110// floor-division by 256 (correct for negative world coords; plain / truncates toward zero) 111func mw_fd256(v: i64) -> i64 { var q: i64 = v / 256; if v < 0 { if q * 256 != v { q = q - 1 } } return q } 112// integer sine: x in 4096-scale radians -> 4096-scale result. Range-reduce to [0,pi/2] by symmetry, then a 113// 5th-order Taylor (max err ~0.5% at the quarter-turn edge). Deterministic, no float, no JS Math. 114func mw_sin4096(x0: i64) -> i64 { 115 var x: i64 = x0 % (2 * PI4096) 116 if x > PI4096 { x = x - 2 * PI4096 } 117 if x < 0 - PI4096 { x = x + 2 * PI4096 } 118 var s: i64 = 1 119 if x < 0 { s = 0 - 1; x = 0 - x } 120 if x > PI2_4096 { x = PI4096 - x } 121 let x2: i64 = x * x / PI2_MAGIC_4096 122 let t3: i64 = x * x2 / PI2_MAGIC_4096 123 let t5: i64 = t3 * x2 / PI2_MAGIC_4096 124 return s * (x - t3 / 6 + t5 / 120) 125} 126func mw_cos4096(x: i64) -> i64 { return mw_sin4096(x + PI2_4096) } 127 128// ---- deterministic integer noise (pure fn of coords + seed = the infinite world) ---- 129func mw_h2(ix: i64, iz: i64, s: i64) -> i64 { 130 var n: i64 = ix * PI2_MAGIC_374761393 + iz * PI2_MAGIC_668265263 + ix * iz * 31 + s * PI2_MAGIC_1442695041 131 n = (n >> 13) ^ n 132 n = n * PI2_MAGIC_1274126177 133 n = (n >> 16) ^ n 134 var v: i64 = n % 256 135 if v < 0 { v = v + 256 } 136 return v 137} 138// bilinear value-noise octave, coords pre-biased positive; returns 0..255 139func mw_o2(bx: i64, bz: i64, lat: i64, s: i64) -> i64 { 140 let ix: i64 = bx / lat 141 let iz: i64 = bz / lat 142 let fx: i64 = (bx % lat) * 256 / lat 143 let fz: i64 = (bz % lat) * 256 / lat 144 let h00: i64 = mw_h2(ix, iz, s) 145 let h10: i64 = mw_h2(ix + 1, iz, s) 146 let h01: i64 = mw_h2(ix, iz + 1, s) 147 let h11: i64 = mw_h2(ix + 1, iz + 1, s) 148 let a: i64 = h00 * 256 + (h10 - h00) * fx 149 let b: i64 = h01 * 256 + (h11 - h01) * fx 150 return (a * 256 + (b - a) * fz) / PI2_MAGIC_65536 151} 152// biome class 0=plains 1=forest 2=desert 3=snowy (large patches, lattice 96) 153func biome_of(gx: i64, gz: i64) -> i64 { 154 let v: i64 = mw_o2(gx + BIAS, gz + BIAS, 96, WSEED * 7 + 5) 155 if v < 88 { return 0 } 156 if v < 152 { return 1 } 157 if v < 200 { return 2 } 158 return 3 159} 160// natural surface height: continental + biome-amplitude-blended hills + roughness (1..20, sea=WWATER) 161func terrain_h0(gx: i64, gz: i64) -> i64 { 162 let bx: i64 = gx + BIAS 163 let bz: i64 = gz + BIAS 164 let cont: i64 = mw_o2(bx, bz, 48, WSEED) 165 let hill: i64 = mw_o2(bx, bz, 12, WSEED + 11) 166 let rough: i64 = mw_o2(bx, bz, 5, WSEED + 23) 167 let bv: i64 = mw_o2(bx, bz, 96, WSEED * 7 + 5) // same channel as biome_of -> amplitude is CONTINUOUS 168 let hmul: i64 = 3 + bv * 7 / 256 // desert-ish low -> snowy mountains high, no border cliff 169 var h: i64 = 1 + cont * 9 / 256 + hill * hmul / 256 + rough * 2 / 256 170 if h < 1 { h = 1 } 171 if h > 20 { h = 20 } 172 return h 173} 174// 3D cave noise: trilinear value-noise, carved where dense (1 = air pocket) 175func mw_h3(ix: i64, iy: i64, iz: i64, s: i64) -> i64 { 176 var n: i64 = ix * PI2_MAGIC_374761393 + iy * PI2_MAGIC_2246822519 + iz * PI2_MAGIC_668265263 + ix * iz * 31 + iy * ix * 17 + s * PI2_MAGIC_1442695041 177 n = (n >> 13) ^ n 178 n = n * PI2_MAGIC_1274126177 179 n = (n >> 16) ^ n 180 var v: i64 = n % 256 181 if v < 0 { v = v + 256 } 182 return v 183} 184func cave3(gx: i64, gy: i64, gz: i64) -> i64 { 185 let bx: i64 = gx + BIAS 186 let bz: i64 = gz + BIAS 187 let ix: i64 = bx / 9 188 let iz: i64 = bz / 9 189 let iy: i64 = gy / 6 190 let fx: i64 = (bx % 9) * 256 / 9 191 let fz: i64 = (bz % 9) * 256 / 9 192 let fy: i64 = (gy % 6) * 256 / 6 193 let c000: i64 = mw_h3(ix, iy, iz, WSEED + 31) 194 let c100: i64 = mw_h3(ix + 1, iy, iz, WSEED + 31) 195 let c010: i64 = mw_h3(ix, iy + 1, iz, WSEED + 31) 196 let c110: i64 = mw_h3(ix + 1, iy + 1, iz, WSEED + 31) 197 let c001: i64 = mw_h3(ix, iy, iz + 1, WSEED + 31) 198 let c101: i64 = mw_h3(ix + 1, iy, iz + 1, WSEED + 31) 199 let c011: i64 = mw_h3(ix, iy + 1, iz + 1, WSEED + 31) 200 let c111: i64 = mw_h3(ix + 1, iy + 1, iz + 1, WSEED + 31) 201 let x00: i64 = c000 * 256 + (c100 - c000) * fx 202 let x10: i64 = c010 * 256 + (c110 - c010) * fx 203 let x01: i64 = c001 * 256 + (c101 - c001) * fx 204 let x11: i64 = c011 * 256 + (c111 - c011) * fx 205 let z0: i64 = x00 * 256 + (x01 - x00) * fz 206 let z1: i64 = x10 * 256 + (x11 - x10) * fz 207 let v: i64 = (z0 * 256 + (z1 - z0) * fy) / PI2_MAGIC_16777216 208 if v > 197 { return 1 } 209 return 0 210} 211 212// ---- sparse global edit table (0=untouched 1=placed-solid 2=dug-air), persists across roaming ---- 213func mw_key(gx: i64, gy: i64, gz: i64) -> i64 { return ((gx + EBIAS) << 33) | ((gz + EBIAS) << 6) | gy } 214func mw_ehash(k: i64) -> i64 { 215 var n: i64 = k ^ (k >> 29) 216 n = n * PI2_MAGIC_2654435761 217 n = n ^ (n >> 17) 218 n = n % ECAP 219 if n < 0 { n = n + ECAP } 220 return n 221} 222func mw_eget(base: i64, gx: i64, gy: i64, gz: i64) -> i64 { 223 let t: *i64 = (base + O_EDIT) as *i64 224 let k: i64 = mw_key(gx, gy, gz) 225 var i: i64 = mw_ehash(k) 226 var probes: i64 = 0 227 while probes < ECAP { 228 let sk: i64 = t[i * 2] 229 if sk == 0 { return 0 } 230 if sk == k { return t[i * 2 + 1] } 231 i = i + 1 232 if i >= ECAP { i = 0 } 233 probes = probes + 1 234 } 235 return 0 236} 237func mw_eset(base: i64, gx: i64, gy: i64, gz: i64, v: i64) -> i64 { 238 let cnt: *i64 = (base + O_ECNT) as *i64 239 let t: *i64 = (base + O_EDIT) as *i64 240 let k: i64 = mw_key(gx, gy, gz) 241 var i: i64 = mw_ehash(k) 242 var probes: i64 = 0 243 while probes < ECAP { 244 let sk: i64 = t[i * 2] 245 if sk == k { t[i * 2 + 1] = v; return 0 } 246 if sk == 0 { 247 if cnt[0] >= PI2_MAGIC_3900 { return 0 - 1 } // honest capacity bound, never corrupt 248 t[i * 2] = k 249 t[i * 2 + 1] = v 250 cnt[0] = cnt[0] + 1 251 return 0 252 } 253 i = i + 1 254 if i >= ECAP { i = 0 } 255 probes = probes + 1 256 } 257 return 0 - 1 258} 259 260// is (gx,gy,gz) solid? hcol = natural column height (pass -1 to compute fresh). Edits override nature; 261// bedrock y=0 always solid; caves carve the interior [1, h-2] so mouths show on hillsides + digs break through. 262func solid_h(base: i64, gx: i64, gy: i64, gz: i64, hcol: i64) -> i64 { 263 if gy < 0 { return 1 } 264 if gy >= YMAX { return 0 } 265 let e: i64 = mw_eget(base, gx, gy, gz) 266 if e == 1 { return 1 } 267 if e == 2 { return 0 } 268 var h: i64 = hcol 269 if h < 0 { h = terrain_h0(gx, gz) } 270 if gy >= h { return 0 } 271 if gy == 0 { return 1 } 272 if gy <= h - 2 { if cave3(gx, gy, gz) == 1 { return 0 } } 273 return 1 274} 275// column info packed into ONE i64 (no scratch buffers on the hot path): h | bio<<6 | tree<<8. 276// Window-cached when the camera window covers the column; fresh (pure noise fns) otherwise. 277func col_pack(base: i64, gx: i64, gz: i64) -> i64 { 278 let orgp: *i64 = (base + O_HCORG) as *i64 279 if orgp[2] == 1 { 280 let wx: i64 = gx - orgp[0] 281 let wz: i64 = gz - orgp[1] 282 if wx >= 0 { if wx < WWIN { if wz >= 0 { if wz < WWIN { 283 let hc: *i64 = (base + O_HC) as *i64 284 let hb: *i64 = (base + O_HB) as *i64 285 let ht: *i64 = (base + O_HT) as *i64 286 return hc[wz * WWIN + wx] | (hb[wz * WWIN + wx] << 6) | (ht[wz * WWIN + wx] << 8) 287 } } } } 288 } 289 let h: i64 = terrain_h0(gx, gz) 290 let bio: i64 = biome_of(gx, gz) 291 return h | (bio << 6) | (has_tree(gx, gz, h, bio) << 8) 292} 293// the BLOCK KIND at a cell (0 = air): terrain body w/ caves + bedrock, sea filled to WWATER, SOLID trees 294// (trunk + plus-shaped canopy), and player edits (dug = air, placed = planks). solid() = kind != 0. 295func kind_c(base: i64, gx: i64, gy: i64, gz: i64) -> i64 { 296 if gy < 0 { return K_STONE } 297 if gy >= YMAX { return 0 } 298 let e: i64 = mw_eget(base, gx, gy, gz) 299 if e == 1 { return K_PLANK } 300 if e == 2 { return 0 } 301 let cp: i64 = col_pack(base, gx, gz) 302 let h: i64 = cp & 63 303 let bio: i64 = (cp >> 6) & 3 304 let tr: i64 = (cp >> 8) & 1 305 if gy < h { 306 if gy == 0 { return K_STONE } 307 if gy <= h - 2 { if cave3(gx, gy, gz) == 1 { return 0 } } 308 if gy == h - 1 { 309 if h <= WWATER + 1 { return K_SAND } 310 if gy >= 16 { return K_SNOW } 311 if bio == 3 { return K_SNOW } 312 if bio == 2 { return K_SAND } 313 return K_GRASS 314 } 315 if gy >= 16 { return K_ROCK } 316 if bio == 2 { return K_SAND } 317 if gy >= h - 4 { return K_DIRT } // topsoil band under the surface block 318 // STONE body with deterministic ORE VEINS (harvested from the minecraftclone vocabulary; deeper = rarer) 319 let ov: i64 = mw_h3(gx, gy, gz, WSEED + 47) 320 if ov == 0 { if gy <= 4 { return K_EMER } } 321 if ov >= 1 { if ov <= 3 { if gy <= 6 { return K_GOLD } } } 322 if ov >= 4 { if ov <= 9 { if gy <= 9 { return K_IRON } } } 323 if ov >= 10 { if ov <= 21 { if gy <= 12 { return K_COAL } } } 324 return K_STONE 325 } 326 if h <= WWATER { if gy <= WWATER { return K_WATER } } 327 if tr == 1 { if h > WWATER { 328 if gy >= h { if gy <= h + 3 { return K_WOOD } } 329 if gy >= h + 4 { if gy <= h + 5 { return K_LEAF } } 330 } } 331 // cardinal neighbors' canopies (plus-shaped crown around each trunk top) 332 var k: i64 = 0 333 while k < 4 { 334 var dx: i64 = 0 335 var dz: i64 = 0 336 if k == 0 { dx = 1 } 337 if k == 1 { dx = 0 - 1 } 338 if k == 2 { dz = 1 } 339 if k == 3 { dz = 0 - 1 } 340 let np: i64 = col_pack(base, gx + dx, gz + dz) 341 let ntr: i64 = (np >> 8) & 1 342 if ntr == 1 { 343 let nh: i64 = np & 63 344 if nh > WWATER { if gy >= nh + 3 { if gy <= nh + 4 { return K_LEAF } } } 345 } 346 k = k + 1 347 } 348 return 0 349} 350func solid(base: i64, gx: i64, gy: i64, gz: i64) -> i64 { if kind_c(base, gx, gy, gz) != 0 { return 1 } return 0 } 351// PHYSICS solidity: water is render-solid but permeable to the body (swimmable); everything else matches render 352func phys_solid(base: i64, gx: i64, gy: i64, gz: i64) -> i64 { 353 let k: i64 = kind_c(base, gx, gy, gz) 354 if k == 0 { return 0 } 355 if k == K_WATER { return 0 } 356 return 1 357} 358// the highest phys-solid cell top AT/BELOW start_gy in this column -- the true FLOOR (cave/overhang correct) 359func floor_y(base: i64, gx: i64, gz: i64, start_gy: i64) -> i64 { 360 var gy: i64 = start_gy 361 if gy > YMAX - 1 { gy = YMAX - 1 } 362 while gy >= 0 { 363 if phys_solid(base, gx, gy, gz) == 1 { return gy + 1 } 364 gy = gy - 1 365 } 366 return 0 367} 368func rgb(r: i64, g: i64, b: i64) -> i64 { return r + g * 256 + b * PI2_MAGIC_65536 } 369// ---- block-data-registry access ---- 370func blk_ptr(base: i64) -> *i64 { return (base + O_BLK) as *i64 } 371func blk_set(base: i64, id: i64, top: i64, side: i64, style: i64) -> i64 { 372 if id < 1 { return 0 - 1 } 373 if id >= MAXBLK { return 0 - 1 } 374 let b: *i64 = blk_ptr(base) 375 b[id * 4 + 0] = top; b[id * 4 + 1] = side; b[id * 4 + 2] = style; b[id * 4 + 3] = 1 376 return 0 377} 378// the built-in BASE data pack (10 blocks). A MOD calls pack_begin then pack_block to override/extend at runtime. 379func pack_default_at(base: i64) -> i64 { 380 let b: *i64 = blk_ptr(base) 381 var i: i64 = 0 382 while i < MAXBLK * 4 { b[i] = 0; i = i + 1 } 383 blk_set(base, K_GRASS, rgb(92, 168, 74), rgb(126, 92, 54), ST_GRASS) 384 blk_set(base, K_DIRT, rgb(126, 92, 54), rgb(126, 92, 54), ST_PLAIN) 385 blk_set(base, K_STONE, rgb(120, 118, 112), rgb(120, 118, 112), ST_STONE) 386 blk_set(base, K_SAND, rgb(215, 196, 123), rgb(215, 196, 123), ST_PLAIN) 387 blk_set(base, K_SNOW, rgb(231, 235, 244), rgb(231, 235, 244), ST_PLAIN) 388 blk_set(base, K_ROCK, rgb(145, 141, 135), rgb(145, 141, 135), ST_STONE) 389 blk_set(base, K_WATER, rgb(74, 127, 211), rgb(74, 127, 211), ST_WATER) 390 blk_set(base, K_WOOD, rgb(113, 81, 46), rgb(94, 66, 37), ST_WOOD) 391 blk_set(base, K_LEAF, rgb(45, 115, 49), rgb(45, 115, 49), ST_LEAF) 392 blk_set(base, K_PLANK, rgb(163, 128, 81), rgb(163, 128, 81), ST_PLAIN) 393 // harvested minecraftclone vocabulary: cobble + the ore family (fleck color in top, stone base in side) 394 blk_set(base, K_COBBLE, rgb(104, 102, 98), rgb(104, 102, 98), ST_STONE) 395 blk_set(base, K_COAL, rgb(38, 38, 40), rgb(116, 114, 108), ST_ORE) 396 blk_set(base, K_IRON, rgb(206, 166, 128), rgb(116, 114, 108), ST_ORE) 397 blk_set(base, K_GOLD, rgb(244, 204, 62), rgb(116, 114, 108), ST_ORE) 398 blk_set(base, K_EMER, rgb(52, 210, 106), rgb(116, 114, 108), ST_ORE) 399 blk_set(base, K_DARKWOOD, rgb(74, 52, 30), rgb(62, 43, 25), ST_WOOD) 400 b[0] = 1 // marker: a pack is loaded (0 => render lazily loads the default) 401 return 0 402} 403func ensure_pack(base: i64) -> i64 { let b: *i64 = blk_ptr(base); if b[0] == 0 { pack_default_at(base) } return 0 } 404// clamp helper to keep brightness modulation from overflowing a channel into the next 405func tbr(v: i64) -> i64 { if v > 255 { return 255 } if v < 0 { return 0 } return v } 406// DATA-DRIVEN block texture: read the block record (color + style) and apply the style's procedural detail as 407// a brightness modulation of the record's base color. Same integer-hash patterns as before, but the COLORS are 408// DATA -> a mod re-skins by changing records. base carries the block table. 409func tex(base: i64, kind: i64, fk: i64, tu: i64, tv: i64) -> i64 { 410 let b: *i64 = blk_ptr(base) 411 if kind < 1 { return rgb(200, 60, 200) } 412 if kind >= MAXBLK { return rgb(200, 60, 200) } 413 if b[kind * 4 + 3] == 0 { return rgb(200, 60, 200) } // undefined block = loud magenta (never silent) 414 let top: i64 = b[kind * 4 + 0] 415 let side: i64 = b[kind * 4 + 1] 416 let style: i64 = b[kind * 4 + 2] 417 var c: i64 = top 418 if fk != 0 { c = side } 419 let sp: i64 = mw_h2(tu * 7 + 1, tv * 13 + 3, kind * 57 + fk) % 4 420 if style == ST_GRASS { 421 if fk == 0 { return packc(c, tbr(232 + sp * 7)) } 422 if tv <= 1 { return packc(top, 236) } // green lip: the TOP color bleeds onto the side rim 423 return packc(c, tbr(230 + sp * 7)) 424 } 425 if style == ST_STONE { 426 let bl: i64 = mw_h2(tu / 2, tv / 2, 91) % 3 427 return packc(c, tbr(224 + bl * 14)) 428 } 429 if style == ST_WOOD { 430 if fk == 0 { if ((tu & 2) ^ (tv & 2)) != 0 { return packc(c, 250) } return packc(c, 222) } 431 if (tu & 3) == 0 { return packc(c, 208) } 432 return packc(c, 246) 433 } 434 if style == ST_LEAF { return packc(c, tbr(214 + sp * 12)) } 435 if style == ST_WATER { if ((tv + tu / 3) & 3) == 0 { return packc(c, 255) } return packc(c, 230) } 436 if style == ST_ORE { 437 // mineral flecks (the TOP color) embedded in a stone body (the SIDE color) 438 let fl: i64 = mw_h2(tu, tv, kind * 13 + 5) % 8 439 if fl <= 1 { return packc(top, 250) } 440 let bl2: i64 = mw_h2(tu / 2, tv / 2, 91) % 3 441 return packc(side, tbr(224 + bl2 * 14)) 442 } 443 return packc(c, tbr(234 + sp * 6)) // ST_PLAIN: gentle speckle 444} 445func shade(lnx: i64, lny: i64, lnz: i64) -> i64 { 446 var d: i64 = lnx * 2 + lny * 3 + lnz * 1 447 if d < 0 { d = 0 } 448 return clamp255(110 + d * 38) 449} 450func packc(col: i64, bright: i64) -> i64 { 451 let r: i64 = (col & 0xff) * bright / 255 452 let g: i64 = ((col >> 8) & 0xff) * bright / 255 453 let b: i64 = ((col >> 16) & 0xff) * bright / 255 454 return r + g * 256 + b * PI2_MAGIC_65536 455} 456func fill_z(base: i64, x0: i64, y0: i64, d0: i64, x1: i64, y1: i64, d1: i64, x2: i64, y2: i64, d2: i64, col: i64) -> i64 { 457 let fb: *i64 = (base + O_FB) as *i64 458 let zb: *i64 = (base + O_ZB) as *i64 459 let area: i64 = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0) 460 if area == 0 { return 0 } 461 let minx: i64 = imax(0, min3(x0, x1, x2)) 462 let maxx: i64 = imin(W - 1, max3(x0, x1, x2)) 463 let miny: i64 = imax(0, min3(y0, y1, y2)) 464 let maxy: i64 = imin(H - 1, max3(y0, y1, y2)) 465 var py: i64 = miny 466 while py <= maxy { 467 var px: i64 = minx 468 while px <= maxx { 469 let e0: i64 = (x2 - x1) * (py - y1) - (y2 - y1) * (px - x1) 470 let e1: i64 = (x0 - x2) * (py - y2) - (y0 - y2) * (px - x2) 471 let e2: i64 = (x1 - x0) * (py - y0) - (y1 - y0) * (px - x0) 472 var ins: i64 = 0 473 if area > 0 { if e0 >= 0 { if e1 >= 0 { if e2 >= 0 { ins = 1 } } } } 474 if area < 0 { if e0 <= 0 { if e1 <= 0 { if e2 <= 0 { ins = 1 } } } } 475 if ins == 1 { 476 let d: i64 = (d0 * e0 + d1 * e1 + d2 * e2) / area 477 let idx: i64 = py * W + px 478 if d < zb[idx] { 479 zb[idx] = d 480 let stz: *i64 = (base + O_STAT) as *i64 481 stz[0] = stz[0] + 1 482 // distance fog: beyond FOG0 blocks, blend toward the sky color (the horizon fades out) 483 var fc: i64 = col 484 let fd: i64 = d / 64 485 if fd > FOG0 { 486 var f: i64 = (fd - FOG0) * 255 / 8 487 if f > 255 { f = 255 } 488 let r: i64 = col & 0xff 489 let g: i64 = (col >> 8) & 0xff 490 let b: i64 = (col >> 16) & 0xff 491 fc = (r + (142 - r) * f / 255) + (g + (186 - g) * f / 255) * 256 + (b + (228 - b) * f / 255) * PI2_MAGIC_65536 492 } 493 fb[idx] = fc 494 } 495 } 496 px = px + 1 497 } 498 py = py + 1 499 } 500 return 0 501} 502// TEXTURED z-buffered triangle: barycentric-interpolated UVs (affine -- faces are small on screen) sample the 503// procedural block texture per pixel; per-VERTEX LIGHT (smooth ambient occlusion, harvested pattern from the 504// minecraftclone's baked-AO mesher) interpolates the same way; then face brightness + distance fog apply. 505// ⚠ 16-PARAM LIMIT: the WAT emitter silently DROPS call arguments beyond 16 (found 2026-07-02 -- the browser 506// rejects the module at validation). Each vertex packs (light<<16 | u<<8 | v) into ONE arg = still 16 params. 507func fill_zt(base: i64, x0: i64, y0: i64, d0: i64, uv0: i64, x1: i64, y1: i64, d1: i64, uv1: i64, x2: i64, y2: i64, d2: i64, uv2: i64, kind: i64, fk: i64, bright: i64) -> i64 { 508 let u0: i64 = (uv0 >> 8) & 255 509 let v0: i64 = uv0 & 255 510 let l0: i64 = (uv0 >> 16) & 255 511 let u1: i64 = (uv1 >> 8) & 255 512 let v1: i64 = uv1 & 255 513 let l1: i64 = (uv1 >> 16) & 255 514 let u2: i64 = (uv2 >> 8) & 255 515 let v2: i64 = uv2 & 255 516 let l2: i64 = (uv2 >> 16) & 255 517 let fb: *i64 = (base + O_FB) as *i64 518 let zb: *i64 = (base + O_ZB) as *i64 519 let area: i64 = (x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0) 520 if area == 0 { return 0 } 521 let minx: i64 = imax(0, min3(x0, x1, x2)) 522 let maxx: i64 = imin(W - 1, max3(x0, x1, x2)) 523 let miny: i64 = imax(0, min3(y0, y1, y2)) 524 let maxy: i64 = imin(H - 1, max3(y0, y1, y2)) 525 var py: i64 = miny 526 while py <= maxy { 527 var px: i64 = minx 528 while px <= maxx { 529 let e0: i64 = (x2 - x1) * (py - y1) - (y2 - y1) * (px - x1) 530 let e1: i64 = (x0 - x2) * (py - y2) - (y0 - y2) * (px - x2) 531 let e2: i64 = (x1 - x0) * (py - y0) - (y1 - y0) * (px - x0) 532 var ins: i64 = 0 533 if area > 0 { if e0 >= 0 { if e1 >= 0 { if e2 >= 0 { ins = 1 } } } } 534 if area < 0 { if e0 <= 0 { if e1 <= 0 { if e2 <= 0 { ins = 1 } } } } 535 if ins == 1 { 536 let d: i64 = (d0 * e0 + d1 * e1 + d2 * e2) / area 537 let idx: i64 = py * W + px 538 if d < zb[idx] { 539 zb[idx] = d 540 let stz: *i64 = (base + O_STAT) as *i64 541 stz[0] = stz[0] + 1 542 var tu: i64 = (u0 * e0 + u1 * e1 + u2 * e2) / area 543 var tv: i64 = (v0 * e0 + v1 * e1 + v2 * e2) / area 544 var tl: i64 = (l0 * e0 + l1 * e1 + l2 * e2) / area 545 if tu < 0 { tu = 0 } 546 if tu > 255 { tu = 255 } 547 if tv < 0 { tv = 0 } 548 if tv > 255 { tv = 255 } 549 if tl < 100 { tl = 100 } 550 if tl > 255 { tl = 255 } 551 let col: i64 = packc(tex(base, kind, fk, tu >> 5, tv >> 5), bright * tl / 255) 552 var fc: i64 = col 553 let fd: i64 = d / 64 554 if fd > FOG0 { 555 var f: i64 = (fd - FOG0) * 255 / 8 556 if f > 255 { f = 255 } 557 let r: i64 = col & 0xff 558 let g: i64 = (col >> 8) & 0xff 559 let b: i64 = (col >> 16) & 0xff 560 fc = (r + (142 - r) * f / 255) + (g + (186 - g) * f / 255) * 256 + (b + (228 - b) * f / 255) * PI2_MAGIC_65536 561 } 562 fb[idx] = fc 563 } 564 } 565 px = px + 1 566 } 567 py = py + 1 568 } 569 return 0 570} 571func project(base: i64, camx: i64, camy: i64, camz: i64, iwx: i64, iwy: i64, iwz: i64) -> i64 { 572 let v: *i64 = (base + O_V) as *i64 573 let r: *i64 = (base + O_RV) as *i64 574 let R: *i64 = (base + O_R) as *i64 575 let pj: *i64 = (base + O_PJ) as *i64 576 v[0] = f32_sub(f32_of(iwx), camx) 577 v[1] = f32_sub(f32_of(iwy), camy) 578 v[2] = f32_sub(f32_of(iwz), camz) 579 v[3] = f32_of(0) 580 m4_vec4(R, v, r) 581 let pz: i64 = r[2] 582 if (pz & 0x80000000) != 0 { pj[3] = 0; return 0 } 583 let zi: i64 = f32_int(f32_mul(pz, f32_of(64))) 584 if zi <= 0 { pj[3] = 0; return 0 } 585 pj[0] = HW + f32_int(f32_div(f32_mul(r[0], f32_of(FOCAL)), pz)) 586 pj[1] = HH - f32_int(f32_div(f32_mul(r[1], f32_of(FOCAL)), pz)) 587 pj[2] = zi 588 pj[3] = 1 589 return 0 590} 591func corners(base: i64, camx: i64, camy: i64, camz: i64, x0: i64, y0: i64, z0: i64) -> i64 { 592 let SX: *i64 = (base + O_SX) as *i64 593 let SY: *i64 = (base + O_SY) as *i64 594 let SD: *i64 = (base + O_SD) as *i64 595 let SOK: *i64 = (base + O_SOK) as *i64 596 let pj: *i64 = (base + O_PJ) as *i64 597 var k: i64 = 0 598 while k < 8 { 599 project(base, camx, camy, camz, x0 + (k & 1), y0 + ((k >> 1) & 1), z0 + ((k >> 2) & 1)) 600 SX[k] = pj[0]; SY[k] = pj[1]; SD[k] = pj[2]; SOK[k] = pj[3] 601 k = k + 1 602 } 603 return 0 604} 605func face(base: i64, a: i64, b: i64, c: i64, dd: i64, lnx: i64, lny: i64, lnz: i64, col: i64) -> i64 { 606 let SX: *i64 = (base + O_SX) as *i64 607 let SY: *i64 = (base + O_SY) as *i64 608 let SD: *i64 = (base + O_SD) as *i64 609 let SOK: *i64 = (base + O_SOK) as *i64 610 if SOK[a] == 0 { return 0 } 611 if SOK[b] == 0 { return 0 } 612 if SOK[c] == 0 { return 0 } 613 if SOK[dd] == 0 { return 0 } 614 let fc: i64 = packc(col, shade(lnx, lny, lnz)) 615 fill_z(base, SX[a], SY[a], SD[a], SX[b], SY[b], SD[b], SX[c], SY[c], SD[c], fc) 616 fill_z(base, SX[a], SY[a], SD[a], SX[c], SY[c], SD[c], SX[dd], SY[dd], SD[dd], fc) 617 return 0 618} 619// smooth-AO corner light from the classic 3-sample rule (two edge neighbors + the diagonal, all in the face's 620// air plane): both edges solid = full occlusion regardless of the diagonal. 255/215/175/135 steps. 621func ao3(s1: i64, s2: i64, sc: i64) -> i64 { 622 var ao: i64 = s1 + s2 + sc 623 if s1 == 1 { if s2 == 1 { ao = 3 } } 624 return 255 - ao * 40 625} 626// TEXTURED quad with PER-VERTEX LIGHT: corner UV convention a=(0,0) b=(255,0) c=(255,255) dd=(0,255); 627// la..ld = smooth-AO corner lights (packed light<<16|u<<8|v per vertex); bright = sun-normal x voxel hash. 628func face_t(base: i64, a: i64, b: i64, c: i64, dd: i64, lnx: i64, lny: i64, lnz: i64, kind: i64, fk: i64, vbr: i64, la: i64, lb: i64, lc: i64, ld: i64) -> i64 { 629 let SX: *i64 = (base + O_SX) as *i64 630 let SY: *i64 = (base + O_SY) as *i64 631 let SD: *i64 = (base + O_SD) as *i64 632 let SOK: *i64 = (base + O_SOK) as *i64 633 if SOK[a] == 0 { return 0 } 634 if SOK[b] == 0 { return 0 } 635 if SOK[c] == 0 { return 0 } 636 if SOK[dd] == 0 { return 0 } 637 let br: i64 = shade(lnx, lny, lnz) * vbr / 255 638 let pa: i64 = (la << 16) 639 let pb: i64 = (lb << 16) | (255 << 8) 640 let pc: i64 = (lc << 16) | (255 << 8) | 255 641 let pd: i64 = (ld << 16) | 255 642 fill_zt(base, SX[a], SY[a], SD[a], pa, SX[b], SY[b], SD[b], pb, SX[c], SY[c], SD[c], pc, kind, fk, br) 643 fill_zt(base, SX[a], SY[a], SD[a], pa, SX[c], SY[c], SD[c], pc, SX[dd], SY[dd], SD[dd], pd, kind, fk, br) 644 return 0 645} 646func draw_voxel(base: i64, camx: i64, camy: i64, camz: i64, gx: i64, gy: i64, gz: i64, kind: i64) -> i64 { 647 let up: i64 = solid(base, gx, gy + 1, gz) 648 // per-voxel brightness hash: block-to-block variation on top of the per-face texture 649 let vh: i64 = mw_h2(gx * 3 + gy * 7, gz * 5 + gy * 11, 999) % 21 650 let vbr: i64 = 234 + vh 651 corners(base, camx, camy, camz, gx, gy, gz) 652 if up == 0 { 653 var tb: i64 = vbr 654 // water SHORE: a water top touching land brightens (shallow/foam edge) 655 if kind == K_WATER { 656 var shore: i64 = 0 657 let e1: i64 = kind_c(base, gx + 1, gy, gz) 658 let e2: i64 = kind_c(base, gx - 1, gy, gz) 659 let e3: i64 = kind_c(base, gx, gy, gz + 1) 660 let e4: i64 = kind_c(base, gx, gy, gz - 1) 661 if e1 != 0 { if e1 != K_WATER { shore = 1 } } 662 if e2 != 0 { if e2 != K_WATER { shore = 1 } } 663 if e3 != 0 { if e3 != K_WATER { shore = 1 } } 664 if e4 != 0 { if e4 != K_WATER { shore = 1 } } 665 if shore == 1 { tb = tb + 24 } 666 } 667 if tb > 255 { tb = 255 } 668 // SMOOTH per-vertex AO, top face quad (2,3,7,6) -> corners (cx,cz) = (0,0),(1,0),(1,1),(0,1) 669 let txm: i64 = solid(base, gx - 1, gy + 1, gz) 670 let txp: i64 = solid(base, gx + 1, gy + 1, gz) 671 let tzm: i64 = solid(base, gx, gy + 1, gz - 1) 672 let tzp: i64 = solid(base, gx, gy + 1, gz + 1) 673 let la: i64 = ao3(txm, tzm, solid(base, gx - 1, gy + 1, gz - 1)) 674 let lb: i64 = ao3(txp, tzm, solid(base, gx + 1, gy + 1, gz - 1)) 675 let lc: i64 = ao3(txp, tzp, solid(base, gx + 1, gy + 1, gz + 1)) 676 let ld: i64 = ao3(txm, tzp, solid(base, gx - 1, gy + 1, gz + 1)) 677 face_t(base, 2, 3, 7, 6, 0, 1, 0, kind, 0, tb, la, lb, lc, ld) 678 } 679 // +x face quad (1,5,7,3) -> corners (cy,cz) = (0,0),(0,1),(1,1),(1,0); air plane x = gx+1 680 if solid(base, gx + 1, gy, gz) == 0 { 681 let xym: i64 = solid(base, gx + 1, gy - 1, gz) 682 let xyp: i64 = solid(base, gx + 1, gy + 1, gz) 683 let xzm: i64 = solid(base, gx + 1, gy, gz - 1) 684 let xzp: i64 = solid(base, gx + 1, gy, gz + 1) 685 let xa: i64 = ao3(xym, xzm, solid(base, gx + 1, gy - 1, gz - 1)) 686 let xb: i64 = ao3(xym, xzp, solid(base, gx + 1, gy - 1, gz + 1)) 687 let xc: i64 = ao3(xyp, xzp, solid(base, gx + 1, gy + 1, gz + 1)) 688 let xd: i64 = ao3(xyp, xzm, solid(base, gx + 1, gy + 1, gz - 1)) 689 face_t(base, 1, 5, 7, 3, 1, 0, 0, kind, 1, vbr, xa, xb, xc, xd) 690 } 691 // -x face quad (0,2,6,4) -> corners (cy,cz) = (0,0),(1,0),(1,1),(0,1); air plane x = gx-1 692 if solid(base, gx - 1, gy, gz) == 0 { 693 let mym: i64 = solid(base, gx - 1, gy - 1, gz) 694 let myp: i64 = solid(base, gx - 1, gy + 1, gz) 695 let mzm: i64 = solid(base, gx - 1, gy, gz - 1) 696 let mzp: i64 = solid(base, gx - 1, gy, gz + 1) 697 let ma: i64 = ao3(mym, mzm, solid(base, gx - 1, gy - 1, gz - 1)) 698 let mb: i64 = ao3(myp, mzm, solid(base, gx - 1, gy + 1, gz - 1)) 699 let mc: i64 = ao3(myp, mzp, solid(base, gx - 1, gy + 1, gz + 1)) 700 let md: i64 = ao3(mym, mzp, solid(base, gx - 1, gy - 1, gz + 1)) 701 face_t(base, 0, 2, 6, 4, 0 - 1, 0, 0, kind, 1, vbr, ma, mb, mc, md) 702 } 703 // +z face quad (4,5,7,6) -> corners (cx,cy) = (0,0),(1,0),(1,1),(0,1); air plane z = gz+1 704 if solid(base, gx, gy, gz + 1) == 0 { 705 let zxm: i64 = solid(base, gx - 1, gy, gz + 1) 706 let zxp: i64 = solid(base, gx + 1, gy, gz + 1) 707 let zym: i64 = solid(base, gx, gy - 1, gz + 1) 708 let zyp: i64 = solid(base, gx, gy + 1, gz + 1) 709 let za: i64 = ao3(zxm, zym, solid(base, gx - 1, gy - 1, gz + 1)) 710 let zb2: i64 = ao3(zxp, zym, solid(base, gx + 1, gy - 1, gz + 1)) 711 let zc: i64 = ao3(zxp, zyp, solid(base, gx + 1, gy + 1, gz + 1)) 712 let zd: i64 = ao3(zxm, zyp, solid(base, gx - 1, gy + 1, gz + 1)) 713 face_t(base, 4, 5, 7, 6, 0, 0, 1, kind, 1, vbr, za, zb2, zc, zd) 714 } 715 // -z face quad (0,1,3,2) -> corners (cx,cy) = (0,0),(1,0),(1,1),(0,1); air plane z = gz-1 716 if solid(base, gx, gy, gz - 1) == 0 { 717 let wxm: i64 = solid(base, gx - 1, gy, gz - 1) 718 let wxp: i64 = solid(base, gx + 1, gy, gz - 1) 719 let wym: i64 = solid(base, gx, gy - 1, gz - 1) 720 let wyp: i64 = solid(base, gx, gy + 1, gz - 1) 721 let wa: i64 = ao3(wxm, wym, solid(base, gx - 1, gy - 1, gz - 1)) 722 let wb: i64 = ao3(wxp, wym, solid(base, gx + 1, gy - 1, gz - 1)) 723 let wc: i64 = ao3(wxp, wyp, solid(base, gx + 1, gy + 1, gz - 1)) 724 let wd: i64 = ao3(wxm, wyp, solid(base, gx - 1, gy + 1, gz - 1)) 725 face_t(base, 0, 1, 3, 2, 0, 0, 0 - 1, kind, 1, vbr, wa, wb, wc, wd) 726 } 727 return 0 728} 729// tree presence from hash, density by biome (desert none, forest dense); trees are SOLID blocks via kind_c 730func has_tree(gx: i64, gz: i64, h: i64, bio: i64) -> i64 { 731 if h <= WWATER { return 0 } 732 if h >= 16 { return 0 } 733 if bio == 2 { return 0 } 734 var n: i64 = (gx * 131 + gz * 197 + gx * gz * 7 + 13) % 1021 735 if n < 0 { n = n + 1021 } 736 var den: i64 = 41 737 if bio == 1 { den = 19 } 738 if bio == 3 { den = 31 } 739 if n % den == 0 { return 1 } 740 return 0 741} 742func render_at(base: i64, camx: i64, camy: i64, camz: i64, cgx: i64, cgz: i64) -> i64 { 743 ensure_pack(base) // lazy-load the built-in block DATA pack (a mod may already have overridden records) 744 let fb: *i64 = (base + O_FB) as *i64 745 let zb: *i64 = (base + O_ZB) as *i64 746 let stp: *i64 = (base + O_STAT) as *i64 747 stp[0] = 0 748 // ---- SKY: vertical gradient + the SUN projected from the actual light direction (2,3,1) + procedural 749 // clouds (value-noise band anchored to the sun's screen position -> pans with the view). Integer per-pixel. 750 let sv: *i64 = (base + O_V) as *i64 751 let rv: *i64 = (base + O_RV) as *i64 752 let R: *i64 = (base + O_R) as *i64 753 sv[0] = f32_of(2); sv[1] = f32_of(3); sv[2] = f32_of(1); sv[3] = f32_of(0) 754 m4_vec4(R, sv, rv) 755 var sunx: i64 = 0 - PI2_MAGIC_9999 756 var suny: i64 = 0 - PI2_MAGIC_9999 757 if (rv[2] & 0x80000000) == 0 { if f32_int(f32_mul(rv[2], f32_of(64))) > 0 { 758 sunx = HW + f32_int(f32_div(f32_mul(rv[0], f32_of(FOCAL)), rv[2])) 759 suny = HH - f32_int(f32_div(f32_mul(rv[1], f32_of(FOCAL)), rv[2])) 760 } } 761 var py: i64 = 0 762 var i: i64 = 0 763 while py < H { 764 let t: i64 = py * 256 / H 765 var px: i64 = 0 766 while px < W { 767 var r: i64 = 88 + 92 * t / 256 768 var g: i64 = 140 + 72 * t / 256 769 var b: i64 = 230 + 10 * t / 256 770 let dx: i64 = px - sunx 771 let dy: i64 = py - suny 772 let d2: i64 = dx * dx + dy * dy 773 if d2 < 36 { r = 255; g = 246; b = 205 } 774 else { if d2 < 620 { 775 let hb2: i64 = (620 - d2) * 44 / 620 776 r = r + hb2 777 g = g + hb2 * 3 / 4 778 b = b + hb2 / 4 779 } } 780 if py < H * 2 / 5 { 781 let cn: i64 = mw_o2(px + sunx * 2 + PI2_MAGIC_65536, py * 3 + PI2_MAGIC_65536, 24, 77) 782 if cn > 150 { 783 var wgt: i64 = (cn - 150) * 2 784 if wgt > 110 { wgt = 110 } 785 r = r + (255 - r) * wgt / 255 786 g = g + (255 - g) * wgt / 255 787 b = b + (255 - b) * wgt / 255 788 } 789 } 790 if r > 255 { r = 255 } 791 if g > 255 { g = 255 } 792 if b > 255 { b = 255 } 793 fb[i] = r + g * 256 + b * PI2_MAGIC_65536 794 zb[i] = ZFAR 795 px = px + 1 796 i = i + 1 797 } 798 py = py + 1 799 } 800 // slide the height/biome cache window to the camera (world is infinite; the window is just a cache) 801 let orgp: *i64 = (base + O_HCORG) as *i64 802 let hc: *i64 = (base + O_HC) as *i64 803 let hb: *i64 = (base + O_HB) as *i64 804 let ox: i64 = cgx - 19 805 let oz: i64 = cgz - 19 806 orgp[0] = ox 807 orgp[1] = oz 808 orgp[2] = 1 809 let ht: *i64 = (base + O_HT) as *i64 810 var wz: i64 = 0 811 while wz < WWIN { 812 var wx: i64 = 0 813 while wx < WWIN { 814 let ch: i64 = terrain_h0(ox + wx, oz + wz) 815 let cb: i64 = biome_of(ox + wx, oz + wz) 816 hc[wz * WWIN + wx] = ch 817 hb[wz * WWIN + wx] = cb 818 ht[wz * WWIN + wx] = has_tree(ox + wx, oz + wz, ch, cb) 819 wx = wx + 1 820 } 821 wz = wz + 1 822 } 823 var gz: i64 = cgz - VDIST 824 while gz <= cgz + VDIST { 825 var gx: i64 = cgx - VDIST 826 while gx <= cgx + VDIST { 827 var gy: i64 = 0 828 while gy < YMAX { 829 let kk: i64 = kind_c(base, gx, gy, gz) 830 if kk != 0 { draw_voxel(base, camx, camy, camz, gx, gy, gz, kk) } 831 gy = gy + 1 832 } 833 gx = gx + 1 834 } 835 gz = gz + 1 836 } 837 // (decorative tree pass removed -- trees are SOLID textured voxels via kind_c now) 838 // peer avatars (multiplayer): z-buffered against the world like everything else 839 var pi: i64 = 0 840 while pi < MAXPEERS { 841 let pp: *i64 = peer_ptr(base, pi) 842 if pp[0] == 1 { draw_peer(base, camx, camy, camz, pp[1], pp[2], pp[3], pi) } 843 pi = pi + 1 844 } 845 return 0 846} 847func build_R(base: i64, ycos: i64, ysin: i64, pcos: i64, psin: i64) -> i64 { 848 let Ry: *i64 = (base + O_RY) as *i64 849 let Rx: *i64 = (base + O_RX) as *i64 850 let R: *i64 = (base + O_R) as *i64 851 // NEGATED ysin: the VIEW transform is the INVERSE of the camera orientation. With raw +ysin the view 852 // rotated OPPOSITE the walk heading -> mouse-right turned the view LEFT while movement went right = the 853 // operator's "left is right" mirror (proof: heading (sin yaw, cos yaw) through m4_roty(c, +s) maps to 854 // 2*yaw off-center; through m4_roty(c, -s) it maps to screen center). Look/move/aim now agree. 855 m4_roty(fratio(ycos, 1000), f32_neg(fratio(ysin, 1000)), Ry) 856 // RAW psin (NO f32_neg): in this m4_rotx convention r2 = s*vy + c*vz, so negative psin = pitch DOWN 857 // (found 2026-07-02 via the edit-visibility gate + nx_mw_f32_probe). 858 m4_rotx(fratio(pcos, 1000), fratio(psin, 1000), Rx) 859 m4_mul(Rx, Ry, R) 860 return 0 861} 862func mem_bytes() -> i64 { return O_STAT + 64 + 64 } 863func drawn_px_at(base: i64) -> i64 { let s: *i64 = (base + O_STAT) as *i64; return s[0] } 864func drawn_px() -> i64 { return drawn_px_at(0) } 865// ---- SOVEREIGN TICK: camera + physics + input decoding + aim rays ALL in-wasm. The JS shim may only 866// capture raw input (key bitmask, mouse deltas), memcpy net bytes, and blit -- zero game logic outside. ---- 867// keys bitmask: 1=W 2=S 4=A 8=D 16=Space/Up 32=Shift/Down 64=F(fly toggle, edge-detected here) 868func cam_ptr(base: i64) -> *i64 { return (base + O_CAM) as *i64 } 869func start_at(base: i64) -> i64 { 870 let c: *i64 = cam_ptr(base) 871 c[0] = 30 * 256 + 128 872 c[2] = 30 * 256 + 128 873 c[1] = surface_y(base, 30, 30) * 256 + 410 874 c[3] = 0 875 c[4] = 0 - 532 // -0.13 rad: gaze slightly down at spawn 876 c[5] = 0 877 c[6] = 0 878 c[7] = 0 879 c[8] = 0 880 c[9] = 0 // invert-Y off (default: mouse-up looks up); client toggles with 'I' -- controls are DATA 881 c[10] = 0 // invert-X off; client toggles with 'O' 882 c[11] = MW_SENS // mouse sensitivity (client-owned data) 883 return 0 884} 885func tick_at(base: i64, keys: i64, mdx: i64, mdy: i64) -> i64 { 886 let c: *i64 = cam_ptr(base) 887 // mouse look -- sign is CONFIG (invert-X c[10], invert-Y c[9]) so the client owns feel; sens is c[11]. 888 // STANDARD default (invY=0): mouse-forward (movementY<0) looks UP, mouse-back looks DOWN => pitch -= mdy. 889 // (History: the original -mdy was CORRECT; the first "inverted" report was the YAW mirror [fixed in 890 // build_R] and pitch got wrongly flipped in overcorrection -- restored 2026-07-03. 'I' toggles feel.) 891 var sens: i64 = c[11] 892 if sens <= 0 { sens = MW_SENS } 893 var sx: i64 = 1 894 if c[10] == 1 { sx = 0 - 1 } 895 var sy: i64 = 1 896 if c[9] == 1 { sy = 0 - 1 } 897 c[3] = c[3] + sx * mdx * sens 898 c[4] = c[4] - sy * mdy * sens 899 if c[4] > PI2_MAGIC_5734 { c[4] = PI2_MAGIC_5734 } 900 if c[4] < 0 - PI2_MAGIC_5734 { c[4] = 0 - PI2_MAGIC_5734 } 901 // F edge-toggles fly; I edge-toggles invert-Y; O edge-toggles invert-X (edges vs prevkeys c[8]) 902 if (keys & 64) != 0 { if (c[8] & 64) == 0 { c[6] = 1 - c[6] } } 903 if (keys & 128) != 0 { if (c[8] & 128) == 0 { c[9] = 1 - c[9] } } 904 if (keys & 256) != 0 { if (c[8] & 256) == 0 { c[10] = 1 - c[10] } } 905 c[8] = keys 906 // walk vector from the integer-trig heading (parity with the old shim: diagonals unnormalized) 907 let sy: i64 = mw_sin4096(c[3]) 908 let cy: i64 = mw_cos4096(c[3]) 909 var dx: i64 = 0 910 var dz: i64 = 0 911 if (keys & 1) != 0 { dx = dx + sy; dz = dz + cy } 912 if (keys & 2) != 0 { dx = dx - sy; dz = dz - cy } 913 if (keys & 8) != 0 { dx = dx + cy; dz = dz - sy } 914 if (keys & 4) != 0 { dx = dx - cy; dz = dz + sy } 915 let tx: i64 = c[0] + dx * 67 / PI2_MAGIC_4096 916 let tz: i64 = c[2] + dz * 67 / PI2_MAGIC_4096 917 if c[6] == 1 { 918 c[0] = tx 919 c[2] = tz 920 if (keys & 16) != 0 { c[1] = c[1] + 67 } 921 if (keys & 32) != 0 { c[1] = c[1] - 67 } 922 c[5] = 0 923 return 0 924 } 925 // ---- VOXEL PHYSICS (rework 2026-07-03: the old column-top surface физics broke caves [the "floor" 926 // under a ceiling was the ceiling top], glided up 1.3-block steps, and WALKED ON water) ---- 927 // body = the two cells at feet and head height; water is render-solid but PHYS-permeable (swimmable) 928 let feet0: i64 = c[1] - 410 929 let fgy: i64 = mw_fd256(feet0) 930 // horizontal, axis-separated: blocked if either body cell at the target column is phys-solid (JUMP to climb) 931 let txg: i64 = mw_fd256(tx) 932 let czg: i64 = mw_fd256(c[2]) 933 if phys_solid(base, txg, fgy, czg) == 0 { if phys_solid(base, txg, fgy + 1, czg) == 0 { c[0] = tx } } 934 let cxg: i64 = mw_fd256(c[0]) 935 let tzg: i64 = mw_fd256(tz) 936 if phys_solid(base, cxg, fgy, tzg) == 0 { if phys_solid(base, cxg, fgy + 1, tzg) == 0 { c[2] = tz } } 937 // in water? (feet cell) -> buoyant sink + Space swims up; else gravity with terminal velocity 938 let pgx: i64 = mw_fd256(c[0]) 939 let pgz: i64 = mw_fd256(c[2]) 940 let fk2: i64 = kind_c(base, pgx, mw_fd256(c[1] - 410), pgz) 941 if fk2 == K_WATER { 942 c[5] = c[5] - 4 943 if c[5] < 0 - 40 { c[5] = 0 - 40 } 944 if (keys & 16) != 0 { c[5] = 55 } 945 c[7] = 0 946 } else { 947 c[5] = c[5] - 12 948 if c[5] < 0 - 200 { c[5] = 0 - 200 } 949 } 950 c[1] = c[1] + c[5] 951 // FLOOR: the highest phys-solid BELOW the feet in this column (caves/overhangs correct, not the column top) 952 let g: i64 = floor_y(base, pgx, pgz, mw_fd256(c[1] - 410)) * 256 + 410 953 if c[1] <= g { c[1] = g; c[5] = 0; c[7] = 1 } else { if fk2 != K_WATER { c[7] = 0 } } 954 // CEILING: rising into a solid cell stops the head 955 if c[5] > 0 { 956 let hgy: i64 = mw_fd256(c[1] + 60) 957 if phys_solid(base, pgx, hgy, pgz) == 1 { c[1] = hgy * 256 - 61; c[5] = 0 } 958 } 959 if (keys & 16) != 0 { if c[7] == 1 { c[5] = 179 } } 960 return 0 961} 962// aim direction in 1000-scale from the camera's yaw/pitch (for dig/put rays and future projectiles) 963func aim_at(base: i64, out: *i64) -> i64 { 964 let c: *i64 = cam_ptr(base) 965 let sy: i64 = mw_sin4096(c[3]) 966 let cy: i64 = mw_cos4096(c[3]) 967 let sp: i64 = mw_sin4096(c[4]) 968 let cp: i64 = mw_cos4096(c[4]) 969 out[0] = sy * cp * 1000 / PI2_MAGIC_16777216 970 out[1] = sp * 1000 / PI2_MAGIC_4096 971 out[2] = cy * cp * 1000 / PI2_MAGIC_16777216 972 return 0 973} 974func dig_at(base: i64) -> i64 { 975 let c: *i64 = cam_ptr(base) 976 let a: *i64 = (base + O_V) as *i64 // scratch (rebuilt every projection anyway) 977 aim_at(base, a) 978 let o: *i64 = (base + O_PJ) as *i64 979 raycast(base, c[0], c[1], c[2], a[0], a[1], a[2], o) 980 if o[0] == 1 { if o[2] >= 1 { if o[2] < YMAX { mw_eset(base, o[1], o[2], o[3], 2) } } } 981 return 0 982} 983func put_at(base: i64) -> i64 { 984 let c: *i64 = cam_ptr(base) 985 let a: *i64 = (base + O_V) as *i64 986 aim_at(base, a) 987 let o: *i64 = (base + O_PJ) as *i64 988 raycast(base, c[0], c[1], c[2], a[0], a[1], a[2], o) 989 if o[0] == 1 { if o[5] >= 0 { if o[5] < YMAX { mw_eset(base, o[4], o[5], o[6], 1) } } } 990 return 0 991} 992func render_cam_at(base: i64) -> i64 { 993 let c: *i64 = cam_ptr(base) 994 build_R(base, mw_cos4096(c[3]) * 1000 / PI2_MAGIC_4096, mw_sin4096(c[3]) * 1000 / PI2_MAGIC_4096, mw_cos4096(c[4]) * 1000 / PI2_MAGIC_4096, mw_sin4096(c[4]) * 1000 / PI2_MAGIC_4096) 995 let camx: i64 = f32_div(f32_of(c[0]), f32_of(256)) 996 let camy: i64 = f32_div(f32_of(c[1]), f32_of(256)) 997 let camz: i64 = f32_div(f32_of(c[2]), f32_of(256)) 998 render_at(base, camx, camy, camz, mw_fd256(c[0]), mw_fd256(c[2])) 999 return 0 1000} 1001func net_push_at(base: i64) -> i64 { 1002 let c: *i64 = cam_ptr(base) 1003 return net_pack_self_at(base, c[0], c[1], c[2], c[3] * 1000 / PI2_MAGIC_4096, c[4] * 1000 / PI2_MAGIC_4096) 1004} 1005// ---- multiplayer: peer table + fractional-position avatar boxes + in-wasm netstate ---- 1006func peer_ptr(base: i64, i: i64) -> *i64 { return (base + O_PEERS + i * 40) as *i64 } 1007func peers_clear_at(base: i64) -> i64 { 1008 var i: i64 = 0 1009 while i < MAXPEERS { let p: *i64 = peer_ptr(base, i); p[0] = 0; i = i + 1 } 1010 return 0 1011} 1012func peer_set_at(base: i64, i: i64, x256: i64, y256: i64, z256: i64, yaw1000: i64) -> i64 { 1013 if i < 0 { return 0 - 1 } 1014 if i >= MAXPEERS { return 0 - 1 } 1015 let p: *i64 = peer_ptr(base, i) 1016 p[0] = 1; p[1] = x256; p[2] = y256; p[3] = z256; p[4] = yaw1000 1017 return 0 1018} 1019// project a FIXED-POINT (x256) world position (peers move smoothly between cells) 1020func projectp(base: i64, camx: i64, camy: i64, camz: i64, wx256: i64, wy256: i64, wz256: i64) -> i64 { 1021 let v: *i64 = (base + O_V) as *i64 1022 let r: *i64 = (base + O_RV) as *i64 1023 let R: *i64 = (base + O_R) as *i64 1024 let pj: *i64 = (base + O_PJ) as *i64 1025 v[0] = f32_sub(f32_div(f32_of(wx256), f32_of(256)), camx) 1026 v[1] = f32_sub(f32_div(f32_of(wy256), f32_of(256)), camy) 1027 v[2] = f32_sub(f32_div(f32_of(wz256), f32_of(256)), camz) 1028 v[3] = f32_of(0) 1029 m4_vec4(R, v, r) 1030 let pz: i64 = r[2] 1031 if (pz & 0x80000000) != 0 { pj[3] = 0; return 0 } 1032 let zi: i64 = f32_int(f32_mul(pz, f32_of(64))) 1033 if zi <= 0 { pj[3] = 0; return 0 } 1034 pj[0] = HW + f32_int(f32_div(f32_mul(r[0], f32_of(FOCAL)), pz)) 1035 pj[1] = HH - f32_int(f32_div(f32_mul(r[1], f32_of(FOCAL)), pz)) 1036 pj[2] = zi 1037 pj[3] = 1 1038 return 0 1039} 1040func corners_p(base: i64, camx: i64, camy: i64, camz: i64, x256: i64, y256: i64, z256: i64, w256: i64, h256: i64, l256: i64) -> i64 { 1041 let SX: *i64 = (base + O_SX) as *i64 1042 let SY: *i64 = (base + O_SY) as *i64 1043 let SD: *i64 = (base + O_SD) as *i64 1044 let SOK: *i64 = (base + O_SOK) as *i64 1045 let pj: *i64 = (base + O_PJ) as *i64 1046 var k: i64 = 0 1047 while k < 8 { 1048 projectp(base, camx, camy, camz, x256 + (k & 1) * w256, y256 + ((k >> 1) & 1) * h256, z256 + ((k >> 2) & 1) * l256) 1049 SX[k] = pj[0]; SY[k] = pj[1]; SD[k] = pj[2]; SOK[k] = pj[3] 1050 k = k + 1 1051 } 1052 return 0 1053} 1054func draw_boxp(base: i64, camx: i64, camy: i64, camz: i64, x256: i64, y256: i64, z256: i64, w256: i64, h256: i64, l256: i64, col: i64) -> i64 { 1055 corners_p(base, camx, camy, camz, x256, y256, z256, w256, h256, l256) 1056 face(base, 2, 3, 7, 6, 0, 1, 0, col) 1057 face(base, 1, 5, 7, 3, 1, 0, 0, col) 1058 face(base, 0, 2, 6, 4, 0 - 1, 0, 0, col) 1059 face(base, 4, 5, 7, 6, 0, 0, 1, col) 1060 face(base, 0, 1, 3, 2, 0, 0, 0 - 1, col) 1061 return 0 1062} 1063func peer_body_col(idx: i64) -> i64 { 1064 let m: i64 = idx % 4 1065 if m == 0 { return 210 + 60 * 256 + 50 * PI2_MAGIC_65536 } // red 1066 if m == 1 { return 70 + 110 * 256 + 220 * PI2_MAGIC_65536 } // blue 1067 if m == 2 { return 230 + 150 * 256 + 40 * PI2_MAGIC_65536 } // orange 1068 return 170 + 80 * 256 + 200 * PI2_MAGIC_65536 // purple 1069} 1070// avatar: body box (0.6 x 1.2 x 0.6) from the feet + head cube; y256 = the peer's EYE height (shim cam.y) 1071func draw_peer(base: i64, camx: i64, camy: i64, camz: i64, x256: i64, y256: i64, z256: i64, idx: i64) -> i64 { 1072 let feet: i64 = y256 - 410 1073 draw_boxp(base, camx, camy, camz, x256 - 77, feet, z256 - 77, 154, 307, 154, peer_body_col(idx)) 1074 draw_boxp(base, camx, camy, camz, x256 - 64, feet + 307, z256 - 64, 128, 128, 128, 235 + 205 * 256 + 170 * PI2_MAGIC_65536) 1075 return 0 1076} 1077// pack own state into the 28B netstate frame at O_NETOUT (nx_pets_netstate layout; ALL protocol in-wasm) 1078func net_pack_self_at(base: i64, x256: i64, y256: i64, z256: i64, yaw1000: i64, pitch1000: i64) -> i64 { 1079 let f: *i64 = (base + O_NETF) as *i64 1080 f[0] = x256; f[1] = y256; f[2] = z256; f[3] = yaw1000; f[4] = pitch1000 1081 f[5] = 0; f[6] = 0; f[7] = 0; f[8] = 0; f[9] = 0 1082 return ps_pack((base + O_NETOUT) as *u8, f) 1083} 1084// ingest a /roster body ([len:1][frame] records) from O_NETIN -> peer table; returns peers set. 1085// bad-magic frames are REJECTED (ps_unpack 0) and do not occupy a slot. 1086func net_ingest_roster_at(base: i64, total0: i64) -> i64 { 1087 var total: i64 = total0 1088 if total > PI2_MAGIC_4096 { total = PI2_MAGIC_4096 } 1089 peers_clear_at(base) 1090 let inb: *u8 = (base + O_NETIN) as *u8 1091 let f: *i64 = (base + O_NETF) as *i64 1092 var o: i64 = 0 1093 var slot: i64 = 0 1094 var go: i64 = 1 1095 while go == 1 { 1096 if o >= total { go = 0 } else { if slot >= MAXPEERS { go = 0 } else { 1097 let fl: i64 = inb[o] as i64 1098 o = o + 1 1099 if fl <= 0 { go = 0 } else { if o + fl > total { go = 0 } else { 1100 if ps_unpack((inb as i64 + o) as *u8, fl, f) == 1 { 1101 peer_set_at(base, slot, f[0], f[1], f[2], f[3]) 1102 slot = slot + 1 1103 } 1104 o = o + fl 1105 } } 1106 } } 1107 } 1108 return slot 1109} 1110// surface height (highest solid voxel +1) at any global column -- includes trees, water surface, and edits 1111func surface_y(base: i64, gx: i64, gz: i64) -> i64 { 1112 var gy: i64 = YMAX - 1 1113 while gy >= 0 { 1114 if kind_c(base, gx, gy, gz) != 0 { return gy + 1 } 1115 gy = gy - 1 1116 } 1117 return 0 1118} 1119// 3D-DDA raycast (floor-division cell stepping so negative coords aim correctly) 1120func raycast(base: i64, camx256: i64, camy256: i64, camz256: i64, dx1000: i64, dy1000: i64, dz1000: i64, out: *i64) -> i64 { 1121 var px: i64 = camx256 1122 var py: i64 = camy256 1123 var pz: i64 = camz256 1124 var ax: i64 = mw_fd256(px) 1125 var ay: i64 = mw_fd256(py) 1126 var az: i64 = mw_fd256(pz) 1127 var i: i64 = 0 1128 while i < 140 { 1129 let gx: i64 = mw_fd256(px) 1130 let gy: i64 = mw_fd256(py) 1131 let gz: i64 = mw_fd256(pz) 1132 if solid(base, gx, gy, gz) == 1 { 1133 out[0] = 1; out[1] = gx; out[2] = gy; out[3] = gz; out[4] = ax; out[5] = ay; out[6] = az 1134 return 0 1135 } 1136 ax = gx; ay = gy; az = gz 1137 px = px + dx1000 * 38 / 1000 1138 py = py + dy1000 * 38 / 1000 1139 pz = pz + dz1000 * 38 / 1000 1140 i = i + 1 1141 } 1142 out[0] = 0 1143 return 0 1144} 1145// WASM exports (same surface as nx_wasmvox3d -> same shim contract) 1146func render(camx256: i64, camy256: i64, camz256: i64, ycos: i64, ysin: i64, pcos: i64, psin: i64) -> i64 { 1147 build_R(0, ycos, ysin, pcos, psin) 1148 let camx: i64 = f32_div(f32_of(camx256), f32_of(256)) 1149 let camy: i64 = f32_div(f32_of(camy256), f32_of(256)) 1150 let camz: i64 = f32_div(f32_of(camz256), f32_of(256)) 1151 render_at(0, camx, camy, camz, mw_fd256(camx256), mw_fd256(camz256)) 1152 return 0 1153} 1154func terrain_at(gx: i64, gz: i64) -> i64 { return surface_y(0, gx, gz) } 1155// break the aimed voxel (bedrock y=0 unbreakable) 1156func break_at(camx256: i64, camy256: i64, camz256: i64, dx1000: i64, dy1000: i64, dz1000: i64) -> i64 { 1157 let o: *i64 = (0 + O_PJ) as *i64 1158 raycast(0, camx256, camy256, camz256, dx1000, dy1000, dz1000, o) 1159 if o[0] == 1 { if o[2] >= 1 { if o[2] < YMAX { mw_eset(0, o[1], o[2], o[3], 2) } } } 1160 return 0 1161} 1162// place a solid voxel in the air cell just before the hit 1163func place_at(camx256: i64, camy256: i64, camz256: i64, dx1000: i64, dy1000: i64, dz1000: i64) -> i64 { 1164 let o: *i64 = (0 + O_PJ) as *i64 1165 raycast(0, camx256, camy256, camz256, dx1000, dy1000, dz1000, o) 1166 if o[0] == 1 { if o[5] >= 0 { if o[5] < YMAX { mw_eset(0, o[4], o[5], o[6], 1) } } } 1167 return 0 1168} 1169func edit_count_at(base: i64) -> i64 { let c: *i64 = (base + O_ECNT) as *i64; return c[0] } 1170func edit_count() -> i64 { return edit_count_at(0) } 1171// multiplayer exports (base=0 wrappers; the JS shim only memcpy's bytes + calls these) 1172func peers_clear() -> i64 { return peers_clear_at(0) } 1173func peer_set(i: i64, x256: i64, y256: i64, z256: i64, yaw1000: i64) -> i64 { return peer_set_at(0, i, x256, y256, z256, yaw1000) } 1174func net_pack_self(x256: i64, y256: i64, z256: i64, yaw1000: i64, pitch1000: i64) -> i64 { return net_pack_self_at(0, x256, y256, z256, yaw1000, pitch1000) } 1175func net_ingest_roster(total: i64) -> i64 { return net_ingest_roster_at(0, total) } 1176func net_out_off() -> i64 { return O_NETOUT } 1177func net_in_off() -> i64 { return O_NETIN } 1178// sovereign-tick exports: the WHOLE game loop body is in-wasm; JS calls these with raw input only 1179func start() -> i64 { return start_at(0) } 1180func tick(keys: i64, mdx: i64, mdy: i64) -> i64 { return tick_at(0, keys, mdx, mdy) } 1181func render_cam() -> i64 { return render_cam_at(0) } 1182func dig() -> i64 { return dig_at(0) } 1183func put() -> i64 { return put_at(0) } 1184func net_push() -> i64 { return net_push_at(0) } 1185// controls-as-data readouts for the HUD (client displays; logic stays in-wasm): invY*10 + invX 1186func invert_state() -> i64 { let c: *i64 = cam_ptr(0); return c[9] * 10 + c[10] } 1187// ---- MOD API (blocks-as-DATA): a mod is a sequence of pack_block records fed at RUNTIME (no recompile). 1188// pack_reset -> reload the built-in base pack; pack_block(id, top_rgb, side_rgb, style) -> override/extend. 1189func pack_reset() -> i64 { return pack_default_at(0) } 1190func pack_block(id: i64, top: i64, side: i64, style: i64) -> i64 { ensure_pack(0); return blk_set(0, id, top, side, style) } 1191func fb_off() -> i64 { return O_FB } 1192func ww() -> i64 { return W } 1193func hh() -> i64 { return H } 1194func main() -> i64 { return 0 }