From 7468d00efb13e86a26d010728ca8cec18cbb3aa3 Mon Sep 17 00:00:00 2001 From: 44r0n7 <44r0n7+gitea@pm.me> Date: Wed, 28 Oct 2026 03:23:43 -0400 Subject: [PATCH] Multi-core simulation: grain movement and heat across a worker pool (t88 phase 3) Co-Authored-By: Claude Opus 5.5 --- README.md | 4 + build.py | 6 +- docs/PROJECT_MAP.md | 27 ++-- docs/TESTING.md | 18 ++- docs/agent-log.md | 82 +++++++++++ src/manifest.json | 2 + src/render/gpu/device.js | 1 + src/sim/cells.js | 72 +++++----- src/sim/fog.js | 2 +- src/sim/heat.js | 23 ++-- src/sim/machines.js | 2 +- src/sim/weather.js | 2 +- src/sim/workers.js | 153 +++++++++++++++++++++ src/sim/world.js | 48 ++++--- src/ui/loop.js | 8 +- src/ui/settings.js | 1 + src/ui/state.js | 2 +- src/ui/threads.js | 39 ++++++ src/ui/title.js | 2 +- test/fixtures/golden-world-640x384.json.gz | Bin 0 -> 73736 bytes test/fixtures/golden-world-640x512.json.gz | Bin 0 -> 81974 bytes test/fixtures/heat-chunk.js | 8 +- test/harness.js | 31 +++++ test/t_caps.py | 13 +- test/t_conveyors.js | 3 +- test/t_corner_seal.js | 12 +- test/t_gpu.py | 6 +- test/t_gpu_golden.py | 14 +- test/t_load.js | 6 +- test/t_render_dirty.js | 4 +- test/t_sim_optimizations.js | 6 + test/t_slope_belts.js | 3 +- test/t_threads.js | 75 ++++++++++ tools/perf-measure.js | 11 +- tools/perf.py | 5 +- 35 files changed, 578 insertions(+), 113 deletions(-) create mode 100644 src/sim/workers.js create mode 100644 src/ui/threads.js create mode 100644 test/fixtures/golden-world-640x384.json.gz create mode 100644 test/fixtures/golden-world-640x512.json.gz create mode 100644 test/t_threads.js diff --git a/README.md b/README.md index 4226bc7..a3b652a 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,10 @@ python3 build.py python3 tools/serve.py # builds, serves at http://localhost:8000 and rebuilds when src/ changes ``` +The game requires WebGPU and cross-origin isolation for shared-memory CPU workers. +Grains and heat run across up to 16 helpers (two CPU cores are reserved); Settings → +Simulation → CPU workers caps the pool on the next world load. Small jobs run inline. + The game must be served: use `python3 tools/serve.py` locally, or serve `dist/` with any web server that sends these headers. Opening `dist/index.html` from disk is no longer supported. Use HTTPS when hosting remotely (localhost works over HTTP). diff --git a/build.py b/build.py index 8159aa1..d1c03b0 100644 --- a/build.py +++ b/build.py @@ -35,9 +35,13 @@ def main(): shell = (src / man['shell']).read_text() css, _ = join(man['css']) js, starts = join(man['sim'] + man['client']) + sim, _ = join(man['sim']) + # Keep worker code outside the indexed script so source line mappings stay exact. + worker = '' head, tail = shell.split('//__JS__') body = head.replace('/*__CSS__*/', css) page = body + js + tail + page = worker + page pre = ('' '' '') @@ -46,7 +50,7 @@ def main(): (dist / 'deepgrain-foundry.html').write_text(page) (dist / 'index.html').write_text(full) # the script starts on this line of index.html (the doctype prefix has no newlines) - js_line = body.count('\n') + 1 + js_line = worker.count('\n') + body.count('\n') + 1 (dist / 'bundle-lines.json').write_text(json.dumps( {'page': 'dist/index.html', 'files': [[js_line + s - 1, f] for s, f in starts]}, indent=1) + '\n') print(f'built dist/index.html ({len(full):,} bytes, {len(starts)} source files)') diff --git a/docs/PROJECT_MAP.md b/docs/PROJECT_MAP.md index 7f2e5a6..1fcc78b 100644 --- a/docs/PROJECT_MAP.md +++ b/docs/PROJECT_MAP.md @@ -244,9 +244,9 @@ Starter furnace designs and the milestone list shown in the notebook. - functions: smelterBlueprint - variables: STARTER_DESIGNS, MILESTONES -### src/sim/world.js (113 lines) +### src/sim/world.js (123 lines) World state: the per-cell typed arrays, alloc(), ambient temperature by depth, waking. -- functions: emit, bagCap, discover, alloc, depthU, depthY, meanSurface, computeAmbient, fillNoise, renderDirtyXY, renderDirtyIdx, wakeXY, wakeHeatXY, wakeIdx, wakeHeatIdx +- functions: emit, bagCap, discover, sharedArray, alloc, depthU, depthY, meanSurface, computeAmbient, fillNoise, renderDirtyXY, renderDirtyChunk, renderDirtyIdx, wakeXY, wakeHeatXY, wakeIdx, wakeHeatIdx - variables: W, H, N, CW, CH, NCH, mat, temp, life, flags, stamp, part, mach, digp, noiseB, airS, netId, isPow, occ, surfY, dirtY, graniteY, basaltY, magmaY, roofY, AMB, worldSeed, surfBase, underD, shallowD, lapse, BW, BH, NB, blockP, blockV, ents, bgm, flyers, ghostBlocks, ghostMolds, renderDirty, awake, hot, hotLvl, powderArea, roofDirty, loadWakeOrder, loadWakePending, loadWakeIndex, tick, tickStamp, machines, molds, nets, pcells, powerDirty, beltL, beltR, screwLists, brokenMachines, ghostMachines, ghostBlocked, EV, bot, bag, bagTotal, player, seen, ledger, stats ### src/sim/fog.js (52 lines) @@ -254,12 +254,12 @@ Exploration only: never changes grains or the random stream. - functions: fogAlloc, fogMark, fogSeen, fogInit, fogLook, fogRevealAround, fogRevealAll - variables: FOG, FOG_SENSE, FOG_SENSE_FADE, fog, FW, FH -### src/sim/cells.js (227 lines) +### src/sim/cells.js (223 lines) Cell helpers (setCell, move, enter) and the falling-sand movement of powders, liquids and gases (simMove). -- functions: setCell, swapCells, move, enter, enterFree, powder, passable, liquid, gas, wakeBotPowder, simMove +- functions: setCell, swapCells, swapCellData, move, enter, enterFree, powder, passable, liquid, liquidSearch, gas, wakeBotPowder, simMove, moveChunk - variables: SORTP, SORTP_FUEL, LSTEP, LFILM, CORNER_SEAL -### src/sim/heat.js (271 lines) +### src/sim/heat.js (266 lines) Heat: conduction, melting and freezing, reactions, fire and air, steel. - functions: curAir, airflowAt, alloyMix, airy, hasO2, condPair, heatPass, heatChunk, neighborDir, react, char, quench, burningNear, burn, steelCheck - variables: POROUS, SOIL, HOTLIQ, REACT_MIN, ALLOY @@ -369,6 +369,11 @@ Weather: clouds from steam, rain and snow, and the world water count. - functions: wrnd, resetWeather, rainGap, worldWater, absorbSteam, spawnRain, rainAt, weatherTick - variables: WBAND, WS, weather +### src/sim/workers.js (153 lines) +The same chunk schedule runs inline or in workers. Workers only own a pass at a time. +- functions: threadWorld, threadBind, threadContext, resetChunkWork, inlineChunkWork, chunkEvent, chunkWake, chunkHeat, chunkSeed, runChunks, mergeChunkWork, chunkPasses, threadParams, threadSetParams, threadSlot, threadExecute, threadPass, threadWait, threadFailure, threadMessage +- variables: simPool, chunkWork, inlineWork + ### src/sim/tick.js (29 lines) simTick: one simulation step, in order. - functions: simTick @@ -451,7 +456,7 @@ Field mip levels preserve the legacy trilinear AO sample at level 2.2. - functions: gpuSmoothInit, gpuSmoothTextures, gpuSmoothBindings, gpuSmoothUpload, gpuSmoothMips - variables: GPU_FIELD_MIP -### src/render/gpu/device.js (89 lines) +### src/render/gpu/device.js (90 lines) All pipelines compile during startup; rendering never falls back. - functions: gpuLimitsOK, gpuInit, gpuFail, gpuRecover, gpuWarmWorld, worldPixelContext - variables: GPU_LIMITS, GPU @@ -492,6 +497,11 @@ Game shell (src/ui/): browser only. This file: settings, the GAME state object, - functions: loadSettings, saveSettings, el, esc, rgbOf, fmtT, toast, setStatus - variables: SET_DEFAULT, SET, TOOLS, ICONS, BAG_ORDER, GAME, keys, hudDirty, $ +### src/ui/threads.js (39 lines) +Browser transport only; the simulation owns the schedule and shared state. +- functions: startThreads +- variables: threadStarting + ### src/ui/title.js (77 lines) Startup capabilities and title art. - functions: checkCapabilities, renderCapabilityNotice, canStartGame, buildTitleCells, drawTitle @@ -511,7 +521,7 @@ Shared player state; the world save remains a complete standalone fallback. Starting, loading and quitting a game; modal dialogs; the pause menu. - functions: showLoading, enterGame, setupNewWorld, startNewWorld, startFromSave, loadSavedWorld, quitToTitle, refreshContinue, anyModal, openModal, closeModal, closeAllModals, topModal, dialog, openPause, renderWorlds -### src/ui/settings.js (123 lines) +### src/ui/settings.js (124 lines) The settings screen. - functions: openSettings, renderSettings, applySettings, toggleFullscreen, confirmWipe - variables: SET_TABS, setTab @@ -607,7 +617,7 @@ Shared world colours, minimap and full map. Browser-only clocks; simulation code stays usable without a browser or a clock. - variables: PERF_MARKS, PERF_FRAME, perfMarks, perfTimes, perfLast -### src/ui/loop.js (143 lines) +### src/ui/loop.js (149 lines) The frame loop and boot. - functions: scanVisible, frame, boot - variables: lastT, acc, lastRender, frameMs, simMs, fpsSm, ambientT @@ -656,6 +666,7 @@ The frame loop and boot. - `test/t_slopes.js`: Sloped walls: flow, sealed joints, building, refunds and persistence. - `test/t_smooth.py`: The smooth look: the WebGPU pass compiles and draws, and the thermal lens still works. - `test/t_stone.js`: Uses for waste rock and sand: glass bricks from a fan furnace, the Saw, the silo and builders' orders. +- `test/t_threads.js`: Shared allocation, checkerboard independence, and real worker-count determinism. - `test/t_water.js`: Water conservation, settling, ledge pouring, boundaries, pipes and phase changes. Tall worlds keep geothermal heat out of the ponds. - `test/t_weather.js`: Weather: no more springs; steam rises into clouds and rains back; showers; snow when it is freezing. - `test/t_world.js`: Trees from acorns, charcoal, brick, density, water/lava/snow/ice, full-bag refunds, drill reach, ballistic blowing, snowy mountains. diff --git a/docs/TESTING.md b/docs/TESTING.md index 430b1ef..a730030 100644 --- a/docs/TESTING.md +++ b/docs/TESTING.md @@ -49,7 +49,7 @@ done(); // prints ALL PASS or N FAILED, sets the - A new suite named `test/t_.js` is picked up by `run_all.py` automatically. **Determinism.** The simulation's randomness comes from seeded generators. The same code and the -same test give the same output every run, apart from lines with timings in ms. To prove a +same test give outputs identical across thread counts and between runs, apart from lines with timings in ms. To prove a refactor changed nothing, save every suite's output before and after, and diff them: ```sh @@ -58,6 +58,17 @@ for t in test/t_*.js; do node $t > /tmp/after/$(basename $t).txt; done # afte diff -r /tmp/before /tmp/after ``` +`test/t_threads.js` runs the real shared-memory scheduler inline and with 1, 2 and 8 +Node workers, including repeats, comparing all mutable cell/chunk bytes and JS side effects. +The browser creates up to `min(16, hardwareConcurrency - 2, CPU workers setting)` helpers. +Small passes run inline; larger passes use batches to amortize dispatch. Wakes and heat flags +merge after each pass; long liquid searches are deferred until that merge. Global machine and +weather randomness remains separate from the chunk streams. World generation uses the same +inline schedule while settling. The t88 re-baseline changes worldgen material hashes and the +seeded sand pile bounds in `t_corner_seal.js`; the heat oracle now supports pass outputs. +The conveyor fixture uses a wider feed pile, the screen fixture warms longer, and `t_load.js` +checks waking within eight ticks separately from the probabilistic consumption of fuel. + ## Browser tests - They need the `.venv` from README.md → Develop; plain `python3` switches to it on its own. @@ -73,7 +84,8 @@ diff -r /tmp/before /tmp/after both looks at zoom 12 and 2. ImageMagick decodes RGB; the per-channel tolerance is 8, mean RGB error must stay below 0.5/255 and fewer than 0.3% of pixels may exceed 8 (smooth AO/edge rounding). These are frozen pre-removal legacy images, not generated - from the new renderer. Inspect the matching `shots/golden-*.png` after visible changes. + from the new renderer. The compressed `golden-world-640x*.json.gz` fixtures retain the + Phase 2 world bytes that produced them, isolating renderer checks from worldgen RNG changes. Inspect the matching `shots/golden-*.png` after visible changes. - `test/t_gpu.py` checks default limits (four storage textures per stage), dirty-upload readback after 240 busy ticks with scrolling and both looks, exact dirty/full image equality with a frozen clock, world replacement, transparent overlays, drill contours, shader compilation timing, successful device recreation and failed recovery with @@ -98,7 +110,7 @@ diff -r /tmp/before /tmp/after - `python3 tools/caps.py` prints isolation, actual WebGPU adapter info and the GL renderer for Chromium and installed Firefox. Real mode requires a hardware Chromium adapter. - `test/t_caps.py` checks absent, null, rejected and insufficient-limit adapters, notices and - the mandatory WebGPU startup gate. Threads remain optional until Phase 3. Firefox smoke + the mandatory WebGPU startup gate. Cross-origin isolation is required for threads. Firefox smoke checks that a browser without WebGPU shows the notice and cannot start a world. - Install Firefox with `.venv/bin/python -m playwright install firefox`. `python3 test/firefox_smoke.py` checks isolation and the WebGPU notice, starts a pixel world diff --git a/docs/agent-log.md b/docs/agent-log.md index b018ccf..69ab956 100644 --- a/docs/agent-log.md +++ b/docs/agent-log.md @@ -4,6 +4,88 @@ What agents have done, newest first. Add an entry for every piece of work: the d note or request it was for, what changed, the files touched, the tests run, and anything left open or not verified. Keep each entry short; the git history has the details. +## 2026-10-28: t88 phase 3 resume, final review and verification (Codex) + +- Preserved the interrupted uncommitted implementation and reviewed the schedule, shared + writes, deferred effects, startup gate, test changes and profiler against the Phase 3 brief. +- Reproduced a deferred-liquid bug before fixing it: replaying liquid() rolled the movement + chance twice. Extracted liquidSearch() so the deferred search resumes at its exact direction + and distance without another random draw; removed the now-unneeded RNG replay records. + Added a failing-then-passing regression and a long water shelf to the repeated 320-tick + inline/1/2/8-worker and reversed-order fixture. +- Chunk passes now skip per-cell renderDirty stores in wakeXY/wakeHeatXY; the scanned chunk + and write halo provide their invalidation. Outside passes, explicit invalidation remains. +- All headless suites passed. Initial sandboxed browser gate failed (no GPU device); an + elevated capability check confirms RTX 5070 WebGPU, isolation and 24 cores. Firefox still + has no adapter and correctly requires WebGPU. Final host-GPU browser gate in progress. +- Files additionally changed on resume: sim/{cells,workers,world}, test/t_threads.js, + PROJECT_MAP and tracking. Full fresh profile, two-minute live run and screenshot inspection + pending. No commit; DESIGN and owner's Context untouched. + +## 2026-10-27: t88 phase 3, multi-core simulation (Codex; verification in progress) + +- SharedArrayBuffer allocation for world arrays (ArrayBuffer only when unavailable in Node). + Four (chunkX&1, chunkY&1) movement passes then four heat passes. Each chunk scopes RS to + hash(world seed,tick,chunk,pass), restoring the global machine/worldgen RNG afterwards. + Long liquid reads outside a 24-cell horizontal halo are deferred and replayed in chunk order; + movement writes reach at most 8 cells, so parallel read/write regions cannot overlap. +- Pass-local wake/heat flags merge by maximum; per-chunk heat outputs merge first. Discoveries, + events, fuel ignition counts, wheel flow, cloud moisture, broken machines and partLost merge + in chunk order. Flyers/launchGrain remain reachable only from main-thread transport, not these + cell passes; their existing state is included in the determinism hash. Direct shared writes + are disjoint cell/powder outputs or idempotent render/roof bits. +- Browser Blob pool uses min(16,hardwareConcurrency-2,setting), at least one. Main thread owns + machines, transport and game logic, processes a batch in each pass, then polls Atomics.load. + No Atomics.wait on the document: it is prohibited by + https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics/wait + and https://tc39.es/ecma262/2024/multipage/structured-data.html. Polling is synchronous and + occupies the main core; it preserves atomic ticks so input/save/render cannot race workers. + No whole-simulation worker or asynchronous rendering overlap. Worker timeouts/errors stop + frame simulation. Small jobs run inline and larger batches use only enough helpers to + amortize dispatch (32 movement or 8 heat chunks per helper). Pool setting applies on load. +- Invalidation: remove swap's duplicate hot marks, gas marks and repeated coordinate-to-chunk + function calls. Each scanned movement chunk marks its halo once; heat marks conduction edges. + wake functions reuse their already computed chunk index for one direct render bit store; + rare swaps/building/fog/dig/background writes retain explicit marks. Paused clean draws upload + zero world cells. GPU equality passes without changing any tolerance. +- Measurements so far: fresh Phase 2 settled/factory/heat 3.537/4.077/5.824 ms/tick vs frozen + baseline 3.715/3.657/4.938. Isolated removal of hot dirty calls in a temporary Phase 2 copy + gave 3.530/3.921/5.936: it did NOT recover the full 15% on its own. Do not claim it did. + Initial unbatched pool factory 4.21; batched trial 3.04 ms/tick. Full final matrix pending. +- Final full matrix (`/tmp/t88-phase3-final.json`, `/tmp/t88-phase3-final-perf.txt`, 218.0 s), + RTX 5070, 24 logical cores, 1920x1080, 2048x1024 world. Pool 16 helpers, peak active 4 + (settled) / 5 (factory, heat), plus main-thread batch. All values below are ms. + settled: baseline 3.715 -> wall/main occupied 1.897 (1.96x); main compute excluding polling 1.624, polling 0.272. + factory: baseline 3.657 -> wall/main occupied 2.495 (1.47x); main compute excluding polling 2.037, polling 0.458. + heat: baseline 4.938 -> wall/main occupied 2.649 (1.86x); main compute excluding polling 2.236, polling 0.412. + Real-loop CPU work p50/p95, zoom 2 / zoom 6; pixel then smooth: + settled: pixel 7.08/8.58 / 2.77/3.83; smooth 8.46/9.98 / 2.98/4.13. + factory: pixel 8.48/10.05 / 4.96/5.95; smooth 9.59/10.80 / 5.13/6.12. + heat: pixel 8.53/10.56 / 4.88/6.03; smooth 10.05/11.51 / 5.17/6.21. + Frame intervals p50/p95 are 16.67/16.67 for all these runs (60 fps). Tick wall time and + occupied main-thread time are equal: polling blocks this core; rendering does not overlap. + The final threaded sim meets the baseline target in every scene; standalone dirty-only + recovery remains unproven/unmet (numbers above). Recommend a future whole-simulation worker + to remove the remaining 1.90-2.65 ms from the main thread; it would require an explicit + ownership/input/save boundary and is outside this phase. +- Re-baseline: three worldgen material hashes and seeded pile bounds (57x17 -> 46x19 grains). + The heat oracle retains its unoptimized per-cell computation, updated for buffered pass + outputs, and is compared against all four new passes. Same throughput assertions retained: + conveyor feed heap widened, downhill-screen warm-up lengthened; load-wake deadline kept at + eight ticks, fuel consumption checked later instead of demanding a random burn on that tick. + Frozen renderer PNGs and tolerances unchanged: original Phase 2 world bytes captured from the + Phase 2 simulation (only invalidation edits) in the temporary copy, compressed as golden-world fixtures, so changed + terrain doesn't get counted as changed renderer pixels. +- Headless suites pass; repeated inline/1/2/8 real-worker hashes pass (world arrays + JS effects). + Extended test passes 320 busy ticks including stamp wrap, reversed chunk order, Node fallback. + First full browser gate: gameplay 361, smooth 28, console 18, capabilities 7, GPU equality 12, + light 71 and Firefox 2 pass; golden sky failed due changed worldgen terrain. Frozen-input + golden rerun, final browser gate, full profile and 2-minute play-through pending. +- Files: sim/{world,cells,heat,workers,fog,machines,weather}, ui/{threads,title,state,settings,loop}, + render/gpu/device, build.py/manifest; harness, threads/heat/load/corner/conveyor/screen/capability/ + golden tests and fixtures; profiler, README, TESTING, PROJECT_MAP and t88 tracking. + No commit; DESIGN and owner's task context untouched. Phase 3 remains in progress. + ## 2026-10-27: t88 phase 2d, required WebGPU and dirty uploads (Codex) - Per-32x32-chunk `renderDirty` marks cell writes, heat with its conduction halo, stationary diff --git a/src/manifest.json b/src/manifest.json index 39393da..c2d95c1 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -37,6 +37,7 @@ "sim/bot.js", "sim/ledger.js", "sim/weather.js", + "sim/workers.js", "sim/tick.js", "sim/worldgen-helpers.js", "sim/worldgen.js", @@ -66,6 +67,7 @@ "render/overlays.js", "ui/audio.js", "ui/state.js", + "ui/threads.js", "ui/title.js", "ui/saves.js", "ui/claims.js", diff --git a/src/render/gpu/device.js b/src/render/gpu/device.js index 687c05d..91af20b 100644 --- a/src/render/gpu/device.js +++ b/src/render/gpu/device.js @@ -68,6 +68,7 @@ async function gpuRecover(message) { } // Submit both looks behind the loading screen, including their first real bindings. async function gpuWarmWorld() { + await startThreads(); buildSky(); resizeRender(); snapCamera(); const look = SET.look, started = performance.now(); try { diff --git a/src/sim/cells.js b/src/sim/cells.js index d6f6b23..b2be7a8 100644 --- a/src/sim/cells.js +++ b/src/sim/cells.js @@ -12,7 +12,9 @@ function setCell(i, m, t, fl) { if (t - AMB[y] > 20 || AMB[y] - t > 20 || (MELT[m] !== 0 && AMB[y] >= MELT[m]) || (m === WATER && AMB[y] < -0.5)) wakeHeatXY(x, y); } function swapCells(i, j) { - renderDirtyIdx(i); renderDirtyIdx(j); + renderDirtyIdx(i); renderDirtyIdx(j); swapCellData(i, j); +} +function swapCellData(i, j) { let a = mat[i]; mat[i] = mat[j]; mat[j] = a; const f = temp[i]; temp[i] = temp[j]; temp[j] = f; a = life[i]; life[i] = life[j]; life[j] = a; @@ -20,16 +22,16 @@ function swapCells(i, j) { stamp[i] = tickStamp; stamp[j] = tickStamp; } function move(i, j, x, y, nx, ny) { - swapCells(i, j); + swapCellData(i, j); wakeXY(x, y); wakeXY(nx, ny); if (ny === y && LFILM > 1 && PH[mat[j]] === PH_LIQUID && (y === 0 || PH[mat[i - W]] !== PH_LIQUID)) { // a top-layer grain stepping sideways may clear the path to a drop for surface grains far // along the row, so wake them; moves inside a body of water do not (settled lakes must sleep) const reach = SPREAD[mat[j]] * LFILM, row = (y >> 5) * CW; const first = Math.max(0, x - reach) >> 5, last = Math.min(W - 1, x + reach) >> 5; - for (let cx = first; cx <= last; cx++) awake[row + cx] = 3; + for (let cx = first; cx <= last; cx++) chunkWake(row + cx); } - if (part[j] === P_WHEEL) { const mm = machines[mach[j]]; if (mm) mm.flow += PH[mat[j]] === PH_LIQUID ? 1 : 0.5; } + if (part[j] === P_WHEEL) { if (chunkWork) chunkEvent('flow', mach[j], PH[mat[j]] === PH_LIQUID ? 1 : 0.5); else { const mm = machines[mach[j]]; if (mm) mm.flow += PH[mat[j]] === PH_LIQUID ? 1 : 0.5; } } const d = temp[j] - AMB[ny]; if (d > 25 || d < -25) wakeHeatXY(nx, ny); } @@ -83,7 +85,7 @@ function powder(i, x, y, m, barriers = cleatChunks[(y >> 5) * CW + (x >> 5)]) { // a grain at least twice as dense works its way down through a loose pile. Unlit fuel // packs too tight for that, so a mixed furnace charge stays mixed until the fire gets in. const t = mat[b]; - if (PH[t] === PH_POWDER && (!barriers || (!cleatMask[i] && !cleatMask[b])) && DENS[m] >= DENS[t] * 2 && (!FUEL[t] || (flags[b] & F_BURN)) && stamp[b] !== tickStamp && !occ[b] && part[b] !== P_GRATE && part[b] !== P_FILTER && rnd() < (FUEL[t] ? SORTP_FUEL : SORTP)) { move(i, b, x, y, x, y + 1); awake[(y >> 5) * CW + (x >> 5)] = 40; return; } + if (PH[t] === PH_POWDER && (!barriers || (!cleatMask[i] && !cleatMask[b])) && DENS[m] >= DENS[t] * 2 && (!FUEL[t] || (flags[b] & F_BURN)) && stamp[b] !== tickStamp && !occ[b] && part[b] !== P_GRATE && part[b] !== P_FILTER && rnd() < (FUEL[t] ? SORTP_FUEL : SORTP)) { move(i, b, x, y, x, y + 1); chunkWake((y >> 5) * CW + (x >> 5), 40); return; } // a grain lying right on a belt or filter is held by it: the surface carries it, it does not slide off the edge if ((t === BELTL || t === BELTR || part[b] === P_FILTER) && !isSlopeBelt(blockP[((y + 1) >> 2) * BW + (x >> 2)])) return; @@ -132,11 +134,18 @@ function liquid(i, x, y, m) { if (rnd() > FLUID[m]) return; const sp = SPREAD[m] * (y === 0 || PH[mat[i - W]] !== PH_LIQUID ? LFILM : 1); const d0 = (RS & 4) ? 1 : -1; - for (let pass = 0; pass < 2; pass++) { + liquidSearch(i, x, y, m, sp, d0); +} +function liquidSearch(i, x, y, m, sp, d0, firstPass = 0, firstStep = 1) { + for (let pass = firstPass; pass < 2; pass++) { const d = pass ? -d0 : d0; - for (let s = 1; s <= sp; s++) { + for (let s = pass === firstPass ? firstStep : 1; s <= sp; s++) { const nx = x + d * s; if (nx < 0 || nx >= W) break; + // Same-colour chunks are separated by 32 cells; their maximum write halo is 8. + if (chunkWork && (nx < chunkWork.x0 - 24 || nx >= chunkWork.x1 + 24)) { + chunkEvent('liquid', i, m, sp, d0, pass, s); return; + } const j = i + d * s; if (!passable(m, PH_LIQUID, j, d, 0)) break; if (y < H - 1 && passable(m, PH_LIQUID, j + W, 0, 1)) { @@ -149,8 +158,7 @@ function liquid(i, x, y, m) { } function gas(i, x, y, m) { // Even blocked gas must keep aging or condensing until it is gone. - awake[(y >> 5) * CW + (x >> 5)] = 3; - renderDirtyXY(x, y); // Gas can age without moving. + chunkWake((y >> 5) * CW + (x >> 5)); if (m === FIRE) { const l = life[i]; if (l <= 1) { mat[i] = EMPTY; life[i] = 0; wakeXY(x, y); return; } @@ -193,35 +201,23 @@ function wakeBotPowder() { if (dx * dx + dy * dy <= 10000) awake[c] = 1; } } -function simMove() { - for (let cy = CH - 1; cy >= 0; cy--) { - const rowBase = cy * CW; - let any = false; - for (let cx = 0; cx < CW; cx++) if (awake[rowBase + cx]) { any = true; powderArea[rowBase + cx] = 0; } - if (!any) continue; - const y0 = cy << 5, y1 = Math.min(H, y0 + 32); - for (let y = y1 - 1; y >= y0; y--) { - const ltr = ((y + tick) & 1) === 0; - const yw = y * W; - for (let k = 0; k < CW; k++) { - const cx = ltr ? k : CW - 1 - k; - if (!awake[rowBase + cx]) continue; - roofDirty[cx] = 1; - const x0 = cx << 5, x1 = Math.min(W, x0 + 32), barriers = cleatChunks[rowBase + cx]; - // alternate rows scan left to right and right to left, so nothing drifts one way - const dx = ltr ? 1 : -1, xEnd = ltr ? x1 : x0 - 1; - for (let x = ltr ? x0 : x1 - 1; x !== xEnd; x += dx) { - const i = yw + x, m = mat[i]; - if (m === EMPTY) continue; - const ph = PH[m]; - if (ph === PH_POWDER) powderArea[rowBase + cx] = 1; - if (stamp[i] === tickStamp) continue; - if (ph === PH_SOLID) continue; - const p = part[i]; - if (IS_SCREW[p] && ph === PH_POWDER) continue; // a screw conveyor moves its own grains - if (ph === PH_POWDER) powder(i, x, y, m, barriers); else if (ph === PH_LIQUID) liquid(i, x, y, m); else gas(i, x, y, m); - } - } +function simMove() { chunkPasses(false); } +function moveChunk(c) { + const cx = c % CW, cy = (c / CW) | 0; + const x0 = cx << 5, x1 = Math.min(W, x0 + 32), y0 = cy << 5, y1 = Math.min(H, y0 + 32); + const barriers = cleatChunks[c]; + powderArea[c] = 0; roofDirty[cx] = 1; renderDirtyChunk(c); + for (let y = y1 - 1; y >= y0; y--) { + const ltr = ((y + tick) & 1) === 0, dx = ltr ? 1 : -1, end = ltr ? x1 : x0 - 1, yw = y * W; + for (let x = ltr ? x0 : x1 - 1; x !== end; x += dx) { + const i = yw + x, m = mat[i]; + if (m === EMPTY) continue; + const ph = PH[m]; + if (ph === PH_POWDER) powderArea[c] = 1; + if (stamp[i] === tickStamp || ph === PH_SOLID) continue; + if (IS_SCREW[part[i]] && ph === PH_POWDER) continue; + if (ph === PH_POWDER) powder(i, x, y, m, barriers); + else if (ph === PH_LIQUID) liquid(i, x, y, m); else gas(i, x, y, m); } } } diff --git a/src/sim/fog.js b/src/sim/fog.js index dd3c093..059b0dc 100644 --- a/src/sim/fog.js +++ b/src/sim/fog.js @@ -3,7 +3,7 @@ const FOG = 2; const FOG_SENSE = 24; // Reveal nearby ground through rock, in grains. const FOG_SENSE_FADE = 12; let fog, FW, FH; -function fogAlloc() { FW = Math.ceil(W / FOG); FH = Math.ceil(H / FOG); fog = new Uint8Array(FW * FH); } +function fogAlloc() { FW = Math.ceil(W / FOG); FH = Math.ceil(H / FOG); fog = sharedArray(Uint8Array, FW * FH); } function fogMark(x, y, v) { if (x < 0 || y < 0 || x >= W || y >= H) return; const i = Math.floor(y / FOG) * FW + Math.floor(x / FOG); diff --git a/src/sim/heat.js b/src/sim/heat.js index e3d4402..d72b07a 100644 --- a/src/sim/heat.js +++ b/src/sim/heat.js @@ -52,16 +52,9 @@ function condPair(a, b, sc, nc, da) { const q = d * k * sc; temp[a] -= q * ICAP[ma]; temp[b] += q * ICAP[mb]; - if (nc >= 0 && (q > 0.15 || q < -0.15)) { if (!hot[nc]) hotLvl[nc] = 2; hot[nc] = 6; } -} -function heatPass() { - for (let c = 0; c < NCH; c++) { - if (!hot[c]) continue; - let sc = 1; - if (hotLvl[c] === 1) { if (((tick + c) & 3) !== 0) continue; sc = 4; } - heatChunk(c, sc); - } + if (nc >= 0 && (q > 0.15 || q < -0.15)) { chunkHeat(nc, !hot[nc] ? 2 : 0); } } +function heatPass() { chunkPasses(true); } function heatChunk(c, sc) { const cx = c % CW, cy = (c / CW) | 0; const x0 = cx << 5, y0 = cy << 5, x1 = Math.min(W, x0 + 32), y1 = Math.min(H, y0 + 32); @@ -93,7 +86,7 @@ function heatChunk(c, sc) { if ((pu === PH_EMPTY || pu === PH_GAS) && ex > 2) { const a = ex * (sc > 1 ? 0.45 : 0.25); t -= a; temp[u] += a; - if (y === y0 && upCold && a > 0.5) { hot[c - CW] = 6; hotLvl[c - CW] = 2; } + if (y === y0 && upCold && a > 0.5) { chunkHeat(c - CW); } } } rel = y < roofY[x] ? 0.02 : 0.002; @@ -110,8 +103,10 @@ function heatChunk(c, sc) { if (flags[i] & F_BURN) burning = true; } } - if (burning || maxDev > 1.5) { hot[c] = 6; hotLvl[c] = (burning || maxDev > 60) ? 2 : 1; } - else hot[c]--; + const h = burning || maxDev > 1.5 ? 6 : hot[c] - 1; + const level = burning || maxDev > 1.5 ? ((burning || maxDev > 60) ? 2 : 1) : hotLvl[c]; + if (chunkWork) { chunkWork.ownHot[c] = h; chunkWork.ownLevel[c] = level; } + else { hot[c] = h; hotLvl[c] = level; } } function neighborDir(i, x, y, d) { if (d === 0) return y > 0 ? i - W : -1; @@ -125,7 +120,7 @@ function react(i, x, y, m) { if (fl & F_BURN) { burn(i, x, y, m, t); return; } if (IGN[m] !== 0 && t >= IGN[m] && (hasO2(i, x, y) || burningNear(i, x, y))) { flags[i] = fl | F_BURN; life[i] = FUEL[m]; - stats.ignitions++; discover(FIRE, x, y, m, 'ignite', t); + if (chunkWork) chunkEvent('ignite'); else stats.ignitions++; discover(FIRE, x, y, m, 'ignite', t); return; } const ph = PH[m]; @@ -183,7 +178,7 @@ function react(i, x, y, m) { if (rnd() < 0.03 + (t - mp) * 0.002) { let to = MELTTO[m]; if (SMELTP[m] !== 0 && rnd() >= SMELTP[m]) to = t >= FRZ[MSLAG] ? MSLAG : SLAG; // the waste runs off molten when it is hot enough - if (PARTMAT[m]) { partLost(i); if (m === HULL && mach[i]) brokenMachines.push(mach[i]); } + if (PARTMAT[m]) { partLost(i); if (m === HULL && mach[i]) { if (chunkWork) chunkEvent('broken', mach[i]); else brokenMachines.push(mach[i]); } } mat[i] = to; flags[i] = 0; life[i] = PH[to] === PH_LIQUID ? 255 : 0; digp[i] = 0; wakeXY(x, y); discover(to, x, y, m, SMELTP[m] !== 0 ? 'smelt' : 'melt', mp); } diff --git a/src/sim/machines.js b/src/sim/machines.js index 1070442..7828714 100644 --- a/src/sim/machines.js +++ b/src/sim/machines.js @@ -5,7 +5,7 @@ function markPow(i, on) { else if (isPow[i]) { isPow[i] = 0; pcells.delete(i); netId[i] = 0; } powerDirty = true; } -function partLost(i) { markPow(i, false); } +function partLost(i) { if (chunkWork) chunkEvent('lost', i); else markPow(i, false); } let nextPowerBuild = 0; function rebuildPower() { powerDirty = false; diff --git a/src/sim/weather.js b/src/sim/weather.js index d10ee84..9f7475d 100644 --- a/src/sim/weather.js +++ b/src/sim/weather.js @@ -25,7 +25,7 @@ function worldWater() { for (const mm of machines) if (mm && mm.type === 'silo' && mm.sm === SNOW) n += mm.sn; // and snow in silos return Math.round(n + bag[WATER] + bag[SNOW]); } -function absorbSteam(x) { const b = Math.min(weather.moist.length - 1, Math.max(0, (x / WBAND) | 0)); weather.moist[b] += 1; } +function absorbSteam(x) { if (chunkWork) { chunkEvent('moist', x); return; } const b = Math.min(weather.moist.length - 1, Math.max(0, (x / WBAND) | 0)); weather.moist[b] += 1; } // Send about k drops (snowflakes where it is freezing) down from the clouds over x0..x1; returns how many fell function spawnRain(x0, x1, k) { if (flyers.length > 2500) return 0; diff --git a/src/sim/workers.js b/src/sim/workers.js new file mode 100644 index 0000000..78439bd --- /dev/null +++ b/src/sim/workers.js @@ -0,0 +1,153 @@ +// The same chunk schedule runs inline or in workers. Workers only own a pass at a time. +let simPool = null, chunkWork = null, inlineWork = null; +function threadWorld() { + return { W,H,N,CW,CH,NCH,BW,BH,NB,mat,temp,life,flags,stamp,part,mach,digp,noiseB,bgm, + airS,netId,isPow,occ,cleatMask,cleatChunks,blockP,blockV,slopePhase,awake,hot,hotLvl, + powderArea,roofDirty,renderDirty,AMB,roofY }; +} +function threadBind(s) { + ({ W,H,N,CW,CH,NCH,BW,BH,NB,mat,temp,life,flags,stamp,part,mach,digp,noiseB,bgm, + airS,netId,isPow,occ,cleatMask,cleatChunks,blockP,blockV,slopePhase,awake,hot,hotLvl, + powderArea,roofDirty,renderDirty,AMB,roofY } = s); +} +function threadContext() { + return { wake: new Uint8Array(NCH), heat: new Uint8Array(NCH), level: new Uint8Array(NCH), + ownHot: new Uint8Array(NCH).fill(255), ownLevel: new Uint8Array(NCH), events: [], c: -1, + x0: 0, x1: 0 }; +} +function resetChunkWork(work) { + work.wake.fill(0); work.heat.fill(0); work.level.fill(0); work.ownHot.fill(255); work.events.length = 0; + return work; +} +function inlineChunkWork() { + if (!inlineWork || inlineWork.wake.length !== NCH) inlineWork = threadContext(); + return resetChunkWork(inlineWork); +} +function chunkEvent(kind, ...args) { chunkWork.events.push([chunkWork.c, kind, ...args]); } +function chunkWake(c, n = 3) { + if (chunkWork) { if (chunkWork.wake[c] < n) chunkWork.wake[c] = n; } + else awake[c] = n; +} +function chunkHeat(c, level = 2) { + if (chunkWork) { chunkWork.heat[c] = 6; if (chunkWork.level[c] < level) chunkWork.level[c] = level; } + else { hot[c] = 6; if (level) hotLvl[c] = level; } +} +function chunkSeed(c, pass) { return hash2(c, tick, worldSeed ^ Math.imul(pass + 1, 0x9e3779b9)) | 1; } +function runChunks(chunks, pass, work) { + const savedRS = RS; + chunkWork = work; + try { + for (const c of chunks) { + work.c = c; work.x0 = (c % CW) * 32; work.x1 = Math.min(W, work.x0 + 32); + RS = chunkSeed(c, pass); + if (pass < 4) moveChunk(c); else { + const sc = hotLvl[c] === 1 ? 4 : 1; + heatChunk(c, sc); + } + } + } finally { chunkWork = null; RS = savedRS; } +} +function mergeChunkWork(works) { + for (const work of works) for (let c = 0; c < NCH; c++) if (work.ownHot[c] !== 255) { + hot[c] = work.ownHot[c]; hotLvl[c] = work.ownLevel[c]; + } + for (const work of works) for (let c = 0; c < NCH; c++) { + if (awake[c] < work.wake[c]) awake[c] = work.wake[c]; + if (hot[c] < work.heat[c]) hot[c] = work.heat[c]; + if (hotLvl[c] < work.level[c]) hotLvl[c] = work.level[c]; + } + const events = works.flatMap(w => w.events).sort((a,b) => a[0] - b[0]); + for (const [,kind,...a] of events) { + if (kind === 'discover') discover(...a); + else if (kind === 'emit') emit(a[0]); + else if (kind === 'flow') { const mm = machines[a[0]]; if (mm) mm.flow += a[1]; } + else if (kind === 'moist') absorbSteam(a[0]); + else if (kind === 'lost') partLost(a[0]); + else if (kind === 'broken') brokenMachines.push(a[0]); + else if (kind === 'ignite') stats.ignitions++; + else if (kind === 'liquid') { + const i = a[0]; + if (stamp[i] !== tickStamp && mat[i] === a[1]) liquidSearch(i, i % W, (i / W) | 0, ...a.slice(1)); + } + } +} +function chunkPasses(heat) { + for (let color = 0; color < 4; color++) { + const chunks = []; + for (let c = 0; c < NCH; c++) { + if (((c % CW & 1) | (((c / CW) & 1) << 1)) !== color) continue; + if (heat ? (!hot[c] || (hotLvl[c] === 1 && ((tick + c) & 3) !== 0)) : !awake[c]) continue; + chunks.push(c); + } + if (!chunks.length) continue; + const pass = color + (heat ? 4 : 0); + if (simPool && simPool.world === mat && chunks.length >= (simPool.force ? 1 : (heat ? 16 : 64))) threadPass(simPool, chunks, pass); + else { const work = inlineChunkWork(); runChunks(chunks, pass, work); mergeChunkWork([work]); } + } +} +function threadParams() { + return { tick,tickStamp,worldSeed,LSTEP,LFILM,SORTP,CORNER_SEAL, + seen, bot: {...bot}, skyY: weather.skyY, barriers: !!cleatCells.length, filterCfg }; +} +function threadSetParams(s) { + ({tick,tickStamp,worldSeed,LSTEP,LFILM,SORTP,CORNER_SEAL,filterCfg} = s); + seen.set(s.seen); Object.assign(bot, s.bot); + weather.skyY = s.skyY; cleatCells = s.barriers ? [1] : []; +} +// Transport is injected by the browser or Node harness; no browser globals in the simulation. +function threadSlot() { + // shortcut: 1 MiB of events per helper per pass; grow or stream it if dense reactions fill it. + return { control: sharedArray(Int32Array, 2), bytes: sharedArray(Uint8Array, 1024 * 1024), + wake: sharedArray(Uint8Array, NCH), heat: sharedArray(Uint8Array, NCH), + level: sharedArray(Uint8Array, NCH), ownHot: sharedArray(Uint8Array, NCH), + ownLevel: sharedArray(Uint8Array, NCH) }; +} +function threadExecute(slot, chunks, pass) { + slot.wake.fill(0); slot.heat.fill(0); slot.level.fill(0); slot.ownHot.fill(255); + const work = { ...slot, events: [], c: -1 }; + runChunks(chunks, pass, work); + const encoded = new TextEncoder().encode(JSON.stringify(work.events)); + if (encoded.length > slot.bytes.length) throw Error('Simulation event buffer full'); + slot.bytes.set(encoded); Atomics.store(slot.control, 1, encoded.length); +} +function threadPass(pool, chunks, pass) { + const params = threadParams(), n = Math.min(pool.slots.length, (pool.force ? chunks.length : Math.max(1, Math.floor(chunks.length / (pass < 4 ? 32 : 8))))); + pool.activeMax = Math.max(pool.activeMax || 0, n); + const batches = Array.from({length:n + 1}, () => []); + for (let k = 0; k < chunks.length; k++) batches[k % batches.length].push(chunks[k]); + for (let k = 0; k < n; k++) { + const slot = pool.slots[k]; Atomics.store(slot.control, 0, 0); + pool.workers[k].postMessage({ chunks: batches[k], pass, params }); + } + const local = inlineChunkWork(); runChunks(batches[n], pass, local); + const works = [local], deadline = Date.now() + 10000; + for (let k = 0; k < n; k++) { + const slot = pool.slots[k]; + threadWait(slot, deadline); + const events = JSON.parse(new TextDecoder().decode(slot.bytes.slice(0, Atomics.load(slot.control, 1)))); + if (Atomics.load(slot.control, 0) < 0) throw Error('Simulation worker: ' + events); + works.push({ ...slot, events }); + } + mergeChunkWork(works); +} +function threadWait(slot, deadline) { + let spins = 0; + // Atomics.wait is forbidden on the browser main thread. Bound polling to fail closed. + while (Atomics.load(slot.control, 0) === 0) { + if (++spins === 16384) { spins = 0; if (Date.now() > deadline) throw Error('Simulation worker timed out'); } + } +} +function threadFailure(slot, error) { + const bytes = new TextEncoder().encode(JSON.stringify(String(error.stack || error))); + slot.bytes.set(bytes.subarray(0, slot.bytes.length)); + Atomics.store(slot.control, 1, Math.min(bytes.length, slot.bytes.length)); + Atomics.store(slot.control, 0, -1); Atomics.notify(slot.control, 0); +} +function threadMessage(data) { + if (data.world) { threadBind(data.world); globalThis.threadWorkerSlot = data.slot; Atomics.store(data.slot.control, 0, 1); return; } + const slot = globalThis.threadWorkerSlot; + try { + threadSetParams(data.params); threadExecute(slot, data.chunks, data.pass); + Atomics.store(slot.control, 0, 1); Atomics.notify(slot.control, 0); + } catch (e) { threadFailure(slot, e); } +} diff --git a/src/sim/world.js b/src/sim/world.js index a43e042..33ee4d6 100644 --- a/src/sim/world.js +++ b/src/sim/world.js @@ -29,36 +29,41 @@ let seen = new Uint8Array(NMAT); let ledger = {}; const stats = { dug: 0, moved: 0, placed: 0, ignitions: 0, cast: 0, bars: 0 }; -function emit(e) { if (EV.length < 400) EV.push(e); } +function emit(e) { if (chunkWork) { chunkEvent('emit', e); return; } if (EV.length < 400) EV.push(e); } function bagCap() { return TANK_TIERS[player.tankTier].cap; } // Things count as discovered only when they happen near the player (or in the bag). // how: 'dig', 'pickup', 'melt', 'smelt', 'freeze', 'boil', 'ignite', 'burn', 'fire', 'blow', 'condense' function discover(m, x, y, from, how, T) { if (seen[m]) return; if (x !== undefined) { const dx = x - bot.x, dy = y - bot.y; if (dx * dx + dy * dy > 110 * 110) return; } + if (chunkWork) { chunkEvent('discover', m, x, y, from, how, T); return; } seen[m] = 1; emit({ t: 'discover', m, from: from || 0, how: how || '', T: T || 0 }); } +function sharedArray(Type, length) { + const Buffer = typeof SharedArrayBuffer === 'function' ? SharedArrayBuffer : ArrayBuffer; + return new Type(new Buffer(length * Type.BYTES_PER_ELEMENT)); +} function alloc(w, h) { resetDevConsole(); W = w; H = h; N = w * h; fogAlloc(); CW = Math.ceil(w / 32); CH = Math.ceil(h / 32); NCH = CW * CH; - cleatMask = new Uint8Array(N); cleatCells = []; - mat = new Uint8Array(N); temp = new Float32Array(N); life = new Uint8Array(N); flags = new Uint8Array(N); - stamp = new Uint8Array(N); part = new Uint8Array(N); mach = new Uint16Array(N); digp = new Uint8Array(N); - noiseB = new Uint8Array(N); bgm = new Uint8Array(N); airS = new Uint16Array(N); netId = new Uint16Array(N); isPow = new Uint8Array(N); occ = new Uint8Array(N); - BW = Math.ceil(w / BS); BH = Math.ceil(h / BS); NB = BW * BH; blockP = new Uint8Array(NB); blockV = new Uint8Array(NB); slopePhase = new Uint8Array(NB); filtersDirty = true; filterCfg = new Map(); procDirty = true; procState.clear(); rackState.clear(); + cleatMask = sharedArray(Uint8Array, N); cleatCells = []; + mat = sharedArray(Uint8Array, N); temp = sharedArray(Float32Array, N); life = sharedArray(Uint8Array, N); flags = sharedArray(Uint8Array, N); + stamp = sharedArray(Uint8Array, N); part = sharedArray(Uint8Array, N); mach = sharedArray(Uint16Array, N); digp = sharedArray(Uint8Array, N); + noiseB = sharedArray(Uint8Array, N); bgm = sharedArray(Uint8Array, N); airS = sharedArray(Uint16Array, N); netId = sharedArray(Uint16Array, N); isPow = sharedArray(Uint8Array, N); occ = sharedArray(Uint8Array, N); + BW = Math.ceil(w / BS); BH = Math.ceil(h / BS); NB = BW * BH; blockP = sharedArray(Uint8Array, NB); blockV = sharedArray(Uint8Array, NB); slopePhase = sharedArray(Uint8Array, NB); filtersDirty = true; filterCfg = new Map(); procDirty = true; procState.clear(); rackState.clear(); ents = []; flyers = []; ghostBlocks = new Map(); ghostMolds = []; treeBases = []; saplings = []; surfBase = Math.round(Math.min(h * 0.27, 175)); underD = h - surfBase; shallowD = 0; lapse = 0.36; - surfY = new Int16Array(w); roofY = new Int16Array(w); dirtY = new Int16Array(w); graniteY = new Int16Array(w); basaltY = new Int16Array(w); magmaY = new Int16Array(w); - AMB = new Float32Array(h); + surfY = sharedArray(Int16Array, w); roofY = sharedArray(Int16Array, w); dirtY = sharedArray(Int16Array, w); graniteY = sharedArray(Int16Array, w); basaltY = sharedArray(Int16Array, w); magmaY = sharedArray(Int16Array, w); + AMB = sharedArray(Float32Array, h); loadWakeOrder = loadWakePending = null; loadWakeIndex = 0; - renderDirty = new Uint8Array(NCH).fill(1); - cleatChunks = new Uint8Array(NCH); - awake = new Uint8Array(NCH); hot = new Uint8Array(NCH); hotLvl = new Uint8Array(NCH); - roofDirty = new Uint8Array(CW).fill(1); - powderArea = new Uint8Array(NCH).fill(1); // unknown areas get one visit before being ruled out + renderDirty = sharedArray(Uint8Array, NCH).fill(1); + cleatChunks = sharedArray(Uint8Array, NCH); + awake = sharedArray(Uint8Array, NCH); hot = sharedArray(Uint8Array, NCH); hotLvl = sharedArray(Uint8Array, NCH); + roofDirty = sharedArray(Uint8Array, CW).fill(1); + powderArea = sharedArray(Uint8Array, NCH).fill(1); // unknown areas get one visit before being ruled out machines = [null]; molds = []; nets = [null]; pcells = new Set(); powerDirty = true; beltL = []; beltR = []; screwLists = Array.from({ length: IS_SCREW.length }, () => []); brokenMachines = []; ghostMachines = []; ghostBlocked = new Set(); @@ -93,21 +98,26 @@ function fillNoise() { // ---------- Waking ---------- function renderDirtyXY(x, y) { renderDirty[(y >> 5) * CW + (x >> 5)] = 1; } +function renderDirtyChunk(c) { + const cx = c % CW, cy = (c / CW) | 0; + for (let yy = Math.max(0, cy - 1); yy <= Math.min(CH - 1, cy + 1); yy++) + for (let xx = Math.max(0, cx - 1); xx <= Math.min(CW - 1, cx + 1); xx++) renderDirty[yy * CW + xx] = 1; +} function renderDirtyIdx(i) { renderDirtyXY(i % W, (i / W) | 0); } function wakeXY(x, y) { - renderDirtyXY(x, y); const cx = x >> 5, cy = y >> 5, c = cy * CW + cx; + if (!chunkWork) renderDirty[c] = 1; roofDirty[cx] = 1; - awake[c] = 3; + chunkWake(c); const lx = x & 31, ly = y & 31; - if (lx === 0) { if (cx > 0) awake[c - 1] = 3; } else if (lx === 31 && cx < CW - 1) awake[c + 1] = 3; - if (ly === 0) { if (cy > 0) awake[c - CW] = 3; } else if (ly === 31 && cy < CH - 1) awake[c + CW] = 3; + if (lx === 0) { if (cx > 0) chunkWake(c - 1); } else if (lx === 31 && cx < CW - 1) chunkWake(c + 1); + if (ly === 0) { if (cy > 0) chunkWake(c - CW); } else if (ly === 31 && cy < CH - 1) chunkWake(c + CW); } function wakeHeatXY(x, y) { - renderDirtyXY(x, y); const c = (y >> 5) * CW + (x >> 5); + if (!chunkWork) renderDirty[c] = 1; roofDirty[x >> 5] = 1; - hot[c] = 6; hotLvl[c] = 2; + chunkHeat(c); } function wakeIdx(i) { wakeXY(i % W, (i / W) | 0); } function wakeHeatIdx(i) { wakeHeatXY(i % W, (i / W) | 0); } diff --git a/src/ui/loop.js b/src/ui/loop.js index 9c0455d..739c182 100644 --- a/src/ui/loop.js +++ b/src/ui/loop.js @@ -40,7 +40,13 @@ function frame(now) { GAME.padRun = pm > 0.92 ? GAME.padRun + 1 : 0; botStep(ix, iy, keys.has('Shift') || GAME.padRun > 24); toolTick(); - const s0 = performance.now(); simTick(); const elapsed = performance.now() - s0; + const s0 = performance.now(); + try { simTick(); } + catch (e) { + GAME.paused = true; acc = 0; console.error(e); + toast('The world stopped updating. Reload this world to try again.', {big:true}); break; + } + const elapsed = performance.now() - s0; simMs = simMs * 0.9 + elapsed * 0.1; frameSim += elapsed; frameSteps++; if (devPaused) devSteps--; else acc -= step; steps++; diff --git a/src/ui/settings.js b/src/ui/settings.js index e04f68c..d1389c9 100644 --- a/src/ui/settings.js +++ b/src/ui/settings.js @@ -29,6 +29,7 @@ const SET_TABS = { { note: 'Upscaling (DLSS, FSR), frame generation and hardware ray tracing need native graphics APIs that browsers do not expose. They are planned for the compiled build.' }, ], Simulation: [ + { k: 'workerCap', label: 'CPU workers', d: 'Maximum helpers for grains and heat. Applies when you next load a world.', type: 'range', min: 1, max: 16, step: 1, fmt: v => v }, { k: 'simSpeed', label: 'Simulation speed', type: 'select', opts: [[0.5, '0.5×'], [1, '1×'], [2, '2×']] }, { k: 'maxSteps', label: 'Catch-up steps per frame', d: 'How hard the game tries to keep real time when frames are slow.', type: 'range', min: 1, max: 4, step: 1, fmt: v => v }, { note: 'The whole world keeps simulating, wherever you are. Your factories keep running when you fly away. Areas where nothing moves or changes temperature go to sleep and cost almost nothing; busy areas cost the same near you or far away.' }, diff --git a/src/ui/state.js b/src/ui/state.js index d12a0f2..ca7ebdb 100644 --- a/src/ui/state.js +++ b/src/ui/state.js @@ -5,7 +5,7 @@ const SET_DEFAULT = { zoom: 12, integerScale: true, renderScale: 1, uiScale: 1, fpsCap: 0, showPerf: false, shake: true, cameraSmooth: 0.7, cameraLead: true, look: 'smooth', lighting: 'full', lightEvery: 1, ambient: 0.12, daylight: 1, glow: 'low', grain: 1, incandescence: true, particles: true, - minimap: true, minimapZoom: 4, fog: true, thermalPalette: 'inferno', simSpeed: 1, maxSteps: 3, + minimap: true, minimapZoom: 4, fog: true, thermalPalette: 'inferno', simSpeed: 1, maxSteps: 3, workerCap: 16, volMaster: 0.8, volMusic: 0.5, volSfx: 0.8, muted: false, muteUnfocused: true, deadzone: 0.18, aimSpeed: 1, autosave: 3, cardSeconds: 9, cursorLabel: 'ores', sv: 2, }; diff --git a/src/ui/threads.js b/src/ui/threads.js new file mode 100644 index 0000000..2448a38 --- /dev/null +++ b/src/ui/threads.js @@ -0,0 +1,39 @@ +// Browser transport only; the simulation owns the schedule and shared state. +let threadStarting = null; +async function startThreads() { + const count = Math.max(1, Math.min(16, Math.floor(SET.workerCap) || 16, (navigator.hardwareConcurrency || 3) - 2)); + if (simPool && simPool.world === mat && simPool.workers.length === count) return; + if (threadStarting) await threadStarting; + if (simPool && simPool.world === mat && simPool.workers.length === count) return; + threadStarting = (async () => { + if (simPool) for (const worker of simPool.workers) worker.terminate(); + simPool = null; + if (!(mat.buffer instanceof SharedArrayBuffer)) throw Error('Shared memory is unavailable'); + const url = URL.createObjectURL(new Blob([SIM_WORKER_SOURCE, '\nonmessage=e=>threadMessage(e.data);'], {type:'text/javascript'})); + const pool = { world: mat, workers: [], slots: [] }; + try { + const ready = []; + for (let k = 0; k < count; k++) { + const worker = new Worker(url), slot = threadSlot(); + pool.workers.push(worker); pool.slots.push(slot); + ready.push(new Promise((resolve,reject) => { + const deadline = performance.now() + 10000; + worker.onerror = e => { + const error = Error(e.message || 'Simulation worker failed'); + threadFailure(slot, error); reject(error); + }; + const poll = () => { + if (Atomics.load(slot.control,0)) resolve(); + else if (performance.now() > deadline) reject(Error('Simulation worker startup timed out')); + else setTimeout(poll, 1); + }; + poll(); + })); + worker.postMessage({world:threadWorld(),slot}); + } + await Promise.all(ready); simPool = pool; + } catch (e) { for (const worker of pool.workers) worker.terminate(); throw e; } + finally { URL.revokeObjectURL(url); } + })(); + try { await threadStarting; } finally { threadStarting = null; } +} diff --git a/src/ui/title.js b/src/ui/title.js index d2a06e0..b99f8a8 100644 --- a/src/ui/title.js +++ b/src/ui/title.js @@ -1,6 +1,6 @@ // Startup capabilities and title art. const REQUIRE_WEBGPU = true; -const REQUIRE_THREADS = false; +const REQUIRE_THREADS = true; const CAPS = { isolated: self.crossOriginIsolated === true, webgpu: false, adapterInfo: null, ready: false }; async function checkCapabilities() { try { diff --git a/test/fixtures/golden-world-640x384.json.gz b/test/fixtures/golden-world-640x384.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..5023b19d29251513e38e7b4e5d7b1c1bdde2bf34 GIT binary patch literal 73736 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 z +8Xsw{cP-M1DYAUjI)gB2_ZCzx!`tHRAuhZK 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%0APnWeuKr*u%!@3YCNd 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%0A1PHN<>`xB7X)J=t~tEw>|_ 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

yMqLRX^_v%3TF|KNWUZ7ycUq#?KAb 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 literal 0 HcmV?d00001 diff --git a/test/fixtures/heat-chunk.js b/test/fixtures/heat-chunk.js index 8857653..e08695c 100644 --- a/test/fixtures/heat-chunk.js +++ b/test/fixtures/heat-chunk.js @@ -1,4 +1,4 @@ -// Reference heat loop before t21 phase 3; preserves conduction and Float32 store order. +// Unoptimized heat oracle, re-baselined for t88 chunk-pass heat outputs. function referenceHeatChunk(c, sc) { const cx = c % CW, cy = (c / CW) | 0; const x0 = cx << 5, y0 = cy << 5, x1 = Math.min(W, x0 + 32), y1 = Math.min(H, y0 + 32); @@ -37,6 +37,8 @@ function referenceHeatChunk(c, sc) { if (flags[i] & F_BURN) burning = true; } } - if (burning || maxDev > 1.5) { hot[c] = 6; hotLvl[c] = (burning || maxDev > 60) ? 2 : 1; } - else hot[c]--; + const h = burning || maxDev > 1.5 ? 6 : hot[c] - 1; + const level = burning || maxDev > 1.5 ? ((burning || maxDev > 60) ? 2 : 1) : hotLvl[c]; + if (chunkWork) { chunkWork.ownHot[c] = h; chunkWork.ownLevel[c] = level; } + else { hot[c] = h; hotLvl[c] = level; } } diff --git a/test/harness.js b/test/harness.js index 6292197..39e65aa 100644 --- a/test/harness.js +++ b/test/harness.js @@ -81,3 +81,34 @@ function dump(run, x0, y0, x1, y1, withTemp) { } } module.exports.dump = dump; + +// Node uses exactly the browser worker entry point and scheduler. +async function enableThreads(run, count) { + const { Worker } = require('worker_threads'); + const entry = `const {parentPort}=require('worker_threads'); + require(${JSON.stringify(__filename)}).load(); + parentPort.on('message', data=>threadMessage(data));`; + const pool = { world: run('mat'), workers: [], slots: [], force: true }; + try { + const ready = []; + for (let k = 0; k < count; k++) { + const worker = new Worker(entry, {eval:true}), slot = run('threadSlot()'); + pool.workers.push(worker); pool.slots.push(slot); + ready.push(new Promise((resolve,reject) => { + const deadline = Date.now()+10000; + worker.once('error',reject); + const poll = () => { + if (Atomics.load(slot.control,0)) resolve(); + else if (Date.now()>deadline) reject(Error('Worker startup timed out')); + else setTimeout(poll,1); + }; + poll(); + })); + worker.postMessage({world:run('threadWorld()'),slot}); + } + await Promise.all(ready); + globalThis.__testPool = pool; run('simPool = globalThis.__testPool;'); delete globalThis.__testPool; + return async () => { run('simPool=null;'); await Promise.all(pool.workers.map(w=>w.terminate())); }; + } catch (e) { await Promise.all(pool.workers.map(w=>w.terminate())); throw e; } +} +module.exports.enableThreads = enableThreads; diff --git a/test/t_caps.py b/test/t_caps.py index f3c80b8..d08cc79 100644 --- a/test/t_caps.py +++ b/test/t_caps.py @@ -8,16 +8,18 @@ ensure_playwright() from browser import capabilities, consume_gpu_option, launch consume_gpu_option() -for case in ['native', 'absent', 'null', 'reject', 'firefox', 'limits']: +for case in ['native', 'absent', 'null', 'reject', 'firefox', 'limits', 'threads']: with launch() as (_, page, url): errors = [] page.on('pageerror', lambda e: errors.append(str(e))) - if case != 'native': + if case not in ('native', 'threads'): gpu = 'undefined' if case == 'absent' else "{requestAdapter: async () => null}" if case == 'reject': gpu = "{requestAdapter: async () => {throw new Error('adapter denied')}}" if case == 'limits': gpu="{requestAdapter:async()=>({limits:{maxStorageTexturesPerShaderStage:3}})}" page.add_init_script(f"Object.defineProperty(navigator, 'gpu', {{value: {gpu}}});") page.add_init_script("Object.defineProperty(self, 'crossOriginIsolated', {value: false});") + if case == 'threads': + page.add_init_script("Object.defineProperty(self, 'crossOriginIsolated', {value: false});") if case == 'firefox': page.add_init_script("Object.defineProperty(navigator, 'userAgent', {value: 'Firefox/157.0'});") page.goto(url) @@ -26,6 +28,13 @@ for case in ['native', 'absent', 'null', 'reject', 'firefox', 'limits']: if case == 'native': assert caps['isolated'] assert page.locator('#cap-notice').is_hidden() == caps['webgpu'] + elif case == 'threads': + assert caps['webgpu'] and not caps['isolated'] + assert not page.evaluate('canStartGame()') + page.evaluate('startNewWorld(424242, 512, 384)') + assert not page.evaluate('GAME.running || GAME.loading') + assert not page.evaluate('startFromSave({})') + assert 'python3 tools/serve.py' in page.inner_text('#cap-notice') else: assert not caps['webgpu'] and caps['adapterInfo'] is None notice = page.inner_text('#cap-notice') diff --git a/test/t_conveyors.js b/test/t_conveyors.js index 4ccaafb..7c74f0a 100644 --- a/test/t_conveyors.js +++ b/test/t_conveyors.js @@ -123,7 +123,8 @@ const liftLanes = run('(() => { const s = new Set(); for (let y = 76; y < 80; y+ check('a lift turns its corner without squeezing down to one lane', liftLanes === 4 && lr > 30, `${lr.toFixed(0)}/s, ${liftLanes} lanes at the top`); fresh(); run('for (let bx = 20; bx < 32; bx++) placeBlock(BP_BELT, 1, bx, 25, true);'); -rect(run, 80, 20, 95, 99, run('SAND')); +// A wide heap keeps the belt fed across the new chunk-local random streams. +rect(run, 80, 20, 111, 99, run('SAND')); const br = rate(128, 319, 104, 119, 90, 300); ticks(run, 0); check('a belt carries a pile off at several dozen grains a second', br > 50, `${br.toFixed(0)}/s`); diff --git a/test/t_corner_seal.js b/test/t_corner_seal.js index 9fbb981..10b0479 100644 --- a/test/t_corner_seal.js +++ b/test/t_corner_seal.js @@ -5,13 +5,13 @@ const { run } = load(); const { check, done } = suite(); for (const [seed, expected] of [ - [777, '040644fb50c891911383ef0206ea988677d7ec447a3e6637cefa99364e765861'], - [77, '2e6af816af54c8de4fe9c7188607f7af503ef844b2087245779bcf39e8330bdb'], - [4242, 'f09270f4ac5da9347bc277c9959e31ee797313b4a994598b4647dcf852532782'], + [777, 'b6f7b493e93a59e38ee57d33f24690daa87e7be0f4b356b32225a3a6f1a9d001'], + [77, '5e08c24603686c8617dd1156b10612b91a05fd9ee8b3648dfc4ee32fc008383a'], + [4242, 'f7ca75d19eba9eae4894b21b95fe1b683bd54e1f65a415dcc296f3c23b5d7e05'], ]) { run(`generateWorld(${seed}, 512, 384)`); check(`seed ${seed} restores corner sealing`,run('CORNER_SEAL')===true); - check(`seed ${seed} keeps its pre-seal material hash`, createHash('sha256').update(run('mat')).digest('hex') === expected); + check(`seed ${seed} matches its thread-independent material hash`, createHash('sha256').update(run('mat')).digest('hex') === expected); } for (const material of ['SAND', 'WATER', 'STEAM']) for (const mirror of [false, true]) { @@ -64,8 +64,8 @@ ticks(run, 600); const pile = run(`(()=>{let x0=W,x1=0,y0=H,y1=0; for(let y=0;y=55 && pile[0]<=59 && pile[1]>=16 && pile[1]<=18 && count(run,run('SAND'))===400, pile); +// t88 chunk streams re-baseline this seeded pile to 46 wide and 19 high. +check('the seeded sand pile keeps its re-baselined shape and all grains', pile[0]>=44 && pile[0]<=48 && pile[1]>=18 && pile[1]<=20 && count(run,run('SAND'))===400, pile); const sealedPile = createHash('sha256').update(run('mat')).digest('hex'), sealedRS=run('RS'); flatWorld(run,240,160,120); run('RS=12345; CORNER_SEAL=false;'); diff --git a/test/t_gpu.py b/test/t_gpu.py index 9a5003c..74bc1b2 100644 --- a/test/t_gpu.py +++ b/test/t_gpu.py @@ -23,7 +23,7 @@ with launch(viewport={'width':960,'height':600}) as (_,pg,url): assert startup['warm']>=0 print('PASS both looks submit behind loading screen; first visible frame ms',startup) pg.add_script_tag(path=str(root/'tools/perf-scenes.js')) - pg.evaluate("perfScene('factory',1024,640); SET.look='pixel'; SET.zoom=2;resizeRender();snapCamera();drawWorld();") + pg.evaluate("async()=>{perfScene('factory',1024,640);await startThreads();simPool.force=true;SET.look='pixel';SET.zoom=2;resizeRender();snapCamera();drawWorld();}") result=pg.evaluate('''async () => { const results=[]; for(let n=0;n<240;n++) { @@ -35,9 +35,9 @@ with launch(viewport={'width':960,'height':600}) as (_,pg,url): } } drawWorld();await gpuCheckUploads(); - drawWorld();return {checked:results,cleanCells:GPU.uploadCells}; + drawWorld();return {checked:results,cleanCells:GPU.uploadCells,workers:simPool.workers.length,active:simPool.activeMax}; }''') - assert min(result['checked'])>1000 and result['cleanCells']==0,result + assert min(result['checked'])>1000 and result['cleanCells']==0 and result['workers']>0 and result['active']>0,result print('PASS busy ticks, heat, fog, scrolling, both looks: GPU bytes equal full CPU data; clean frame uploads no world cells',result) parity=pg.evaluate("""async()=>{ const results=[]; diff --git a/test/t_gpu_golden.py b/test/t_gpu_golden.py index 6566279..54375fe 100644 --- a/test/t_gpu_golden.py +++ b/test/t_gpu_golden.py @@ -1,5 +1,5 @@ """Frozen legacy references, captured before retirement; compare the WebGPU world only.""" -import base64, pathlib, sys, subprocess +import base64, gzip, json, pathlib, sys, subprocess sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent.parent / 'tools')) from use_venv import ensure_playwright; ensure_playwright() from browser import launch, consume_gpu_option @@ -16,7 +16,17 @@ with launch(viewport={'width': 640, 'height': 480}) as (_, pg, url): for scene in ['renderer','joins','sky','lamp','opening','magma','fire']: for look in ['pixel','smooth']: for zoom in [12,2]: - pg.evaluate('(h)=>{generateWorld(424242,640,h,null);enterGame();GAME.paused=true;}',512 if scene=='joins' else 384) + height = 512 if scene=='joins' else 384 + frozen = json.loads(gzip.decompress((ROOT/f'test/fixtures/golden-world-640x{height}.json.gz').read_bytes())) + # Keep the inputs that produced the legacy PNGs when simulation RNG changes. + pg.evaluate("""([h, frozen])=>{ + generateWorld(424242,640,h,null); + for(const [name,encoded]of Object.entries(frozen)) { + const target=eval(name),raw=Uint8Array.from(atob(encoded),c=>c.charCodeAt(0)); + new Uint8Array(target.buffer).set(raw); + } + enterGame();GAME.paused=true; + }""",[height,frozen]) name = 'joins' if scene=='joins' else 't88-renderer' if scene in ['renderer','sky'] else 't88-light' pg.evaluate('() => {'+(ROOT / f'tools/scenes/{name}.js').read_text()+'}') if scene not in ['renderer','joins','sky']: diff --git a/test/t_load.js b/test/t_load.js index 6308373..fb69008 100644 --- a/test/t_load.js +++ b/test/t_load.js @@ -42,7 +42,11 @@ check('the settled water area goes back to sleep', run('awake[6 * CW + 1] === 0 run('deserializeWorld(loadSave.meta, loadSave.buffers); bot.x = 14; bot.y = 190;'); check('the destination is still waiting before moving wakes it', run('loadWakePending[6 * CW] === 2 && hot[6 * CW] === 0')); ticks(run, 8); -check('moving near a waiting area wakes it within eight ticks, including heat', run('loadWakePending[6 * CW] === 0 && hot[6 * CW] > 0 && life[192 * W + 16] < FUEL[WOOD]')); +check('moving near a waiting area wakes it within eight ticks, including heat', run('loadWakePending[6 * CW] === 0 && hot[6 * CW] > 0')); + +// Burning is probabilistic: waking does not promise a fuel draw on that exact tick. +ticks(run, 32); +check('newly woken fuel resumes burning', run('life[192 * W + 16] < FUEL[WOOD]')); // Saving midway keeps the actual cells, and loading starts a fresh queue at the new bot. run('globalThis.midLoadSave = serializeWorld(); deserializeWorld(midLoadSave.meta, midLoadSave.buffers);'); diff --git a/test/t_render_dirty.js b/test/t_render_dirty.js index 56b64fd..d270425 100644 --- a/test/t_render_dirty.js +++ b/test/t_render_dirty.js @@ -12,7 +12,9 @@ check('revealing the whole map invalidates every chunk',marked('fogRevealAll();' check('heat invalidates the chunk and conduction across its edges',marked('heatChunk(5,1);',64,40)&&run('!!renderDirty[1] && !!renderDirty[4] && !!renderDirty[9]')); check('tree growth invalidates the background',marked('setTreeCell(70,70,WOOD);',70,70)); run('setCell(60*W+60,FIRE,900,0);life[60*W+60]=10;for(const j of [60*W+59,60*W+61,59*W+60,61*W+60])setCell(j,STONE,20,F_NAT);'); -check('blocked fire aging invalidates without movement',marked('gas(60*W+60,60,60,FIRE);',60,60) && run('life[60*W+60]===9')); +check('blocked fire aging invalidates without movement',marked('tick++;tickStamp++;simMove();',60,60) && run('life[60*W+60]===9')); run('setCell(32*W+64,SAND,20,0);part[32*W+64]=P_GOPEN;setCell(31*W+64,EMPTY,20,0);'); check('closing a gate invalidates the displaced grain across a chunk edge',marked('toggleGateAt(64,32);',64,31) && run('mat[31*W+64]===SAND')); +run('awake.fill(0);setCell(63*W+63,SAND,20,0);renderDirty.fill(0);tick++;tickStamp++;simMove();'); +check('movement invalidates its scanned chunk and diagonal destination',run('renderDirty[5] && renderDirty[9]')); done(); diff --git a/test/t_sim_optimizations.js b/test/t_sim_optimizations.js index f27d1f2..b068910 100644 --- a/test/t_sim_optimizations.js +++ b/test/t_sim_optimizations.js @@ -52,4 +52,10 @@ for (const scale of [1, 4]) { run(`for (let c = 1; c < NCH; c++) heatChunk(c, ${scale});`); check('heat matches original bytes and random state at scale ' + scale, snapshot() === expected); } +setup(); +run('const optimizedHeatChunk=heatChunk;heatChunk=referenceHeatChunk;heatPass();'); +const passExpected=snapshot(); +run('heatChunk=optimizedHeatChunk;'); +setup();run('heatPass();'); +check('four-pass heat matches the unoptimized oracle byte for byte',snapshot()===passExpected); done(); diff --git a/test/t_slope_belts.js b/test/t_slope_belts.js index b8e1974..7d837f8 100644 --- a/test/t_slope_belts.js +++ b/test/t_slope_belts.js @@ -88,7 +88,8 @@ for(const grade of [-1,1]) { for(const grade of [-1,1]) { const s=line(grade,true); run('for(const b of filterCfg.keys())setFilter(b,{m:[SAND],inv:1});'); - collect(s,220,true); + // Let the changed seeded pile reach the full screen before timing its throughput. + collect(s,440,true); const r=collect(s,600,true); console.log(`Filter throughput grade ${grade}, grains/s: ${r.out/10}`); check(`downhill screen grade ${grade} discharges its generous feed`,r.out/10>=45 && r.out/10<=90,JSON.stringify(r)); diff --git a/test/t_threads.js b/test/t_threads.js new file mode 100644 index 0000000..5e1e4a4 --- /dev/null +++ b/test/t_threads.js @@ -0,0 +1,75 @@ +// Shared allocation, checkerboard independence, and real worker-count determinism. +const assert = require('assert'); +const { load, flatWorld } = require('./harness'); +const { run } = load(); +flatWorld(run, 131, 129, 110); +assert(run('[mat,temp,life,flags,stamp,part,mach,digp,noiseB,bgm,airS,netId,isPow,occ,awake,hot,hotLvl,renderDirty,powderArea,cleatMask,cleatChunks,roofDirty,blockP,blockV,slopePhase,fog,AMB,roofY].every(a=>a.buffer instanceof SharedArrayBuffer)')); +console.log('PASS world arrays use shared memory'); +const crypto = require('crypto'); +const { enableThreads } = require('./harness'); +flatWorld(run, 192, 96, 31); +run(`setCell(30*W+32,WATER,20,0);setCell(31*W+130,EMPTY,20,0); + tick++;tickStamp++;var draws=0,savedRnd=rnd;rnd=()=>{draws++;return .99}; + var searchWork=inlineChunkWork();runChunks([1],0,searchWork);`); +assert(run('searchWork.events.some(e=>e[1]==="liquid")'), 'fixture must defer a long search'); +run('mergeChunkWork([searchWork]);rnd=savedRnd;'); +assert.strictEqual(run('draws'),1,'resuming a liquid search must not reroll its movement chance'); +assert.strictEqual(run('mat[30*W+40]'),run('WATER'),'the resumed search finds the distant drop'); +console.log('PASS long liquid search resumes without rerolling movement'); +function setup() { + flatWorld(run, 387, 257, 214); + run(`{RS=123;WS=456;resetWeather();weather.next=1e15;seen.fill(0);ledger={};EV.length=0;for(const k of Object.keys(stats))stats[k]=0; + resetEconomy();nextPowerBuild=0;bot.x=185;bot.y=120; + const random=mulberry32(99), materials=[SAND,COAL,WATER,MAGMA,MCU,SNOW,LWOOD,STEAM,SMOKE]; + for(let y=40;y<210;y++)for(let x=8;x { + let expected; + for (const n of [0,1,2,8,8,2,1,0]) { + setup(); const stop = n ? await enableThreads(run,n) : null; + try { + run('for(let k=0;k<320;k++)simTick();'); + const actual=hash(); + if(!expected)expected=actual; + assert.strictEqual(actual,expected,`world and effects differ with ${n} workers`); + console.log(`PASS identical world and side effects with ${n} workers (${actual.slice(0,16)})`); + } finally { if(stop)await stop(); } + } + setup(); + run('const forwardChunks=runChunks;runChunks=(chunks,pass,work)=>forwardChunks(chunks.slice().reverse(),pass,work);for(let k=0;k<320;k++)simTick();runChunks=forwardChunks;'); + assert.strictEqual(hash(),expected,'chunk order within a colour must not matter'); + console.log('PASS reversing chunks within every pass preserves all bytes and effects'); + const {execFileSync}=require('child_process'); + const fallback=execFileSync(process.execPath,['-e',` + global.SharedArrayBuffer=undefined; + const {load,flatWorld}=require(${JSON.stringify(require.resolve('./harness'))}); + const {run}=load();flatWorld(run,64,64,50); + if(!run('mat.buffer instanceof ArrayBuffer'))throw Error('fallback allocation'); + run('setCell(20*W+20,SAND,20,0);for(let k=0;k<60;k++)simTick();'); + process.stdout.write(JSON.stringify(run('Array.from(mat)'))); + `],{encoding:'utf8'}); + flatWorld(run,64,64,50); + run('setCell(20*W+20,SAND,20,0);for(let k=0;k<60;k++)simTick();'); + assert.strictEqual(JSON.stringify(run('Array.from(mat)')),fallback); + console.log('PASS Node ArrayBuffer fallback matches shared inline movement'); + console.log('ALL PASS'); +})().catch(e=>{console.error(e);process.exitCode=1;}); diff --git a/tools/perf-measure.js b/tools/perf-measure.js index b027c83..6928584 100644 --- a/tools/perf-measure.js +++ b/tools/perf-measure.js @@ -13,20 +13,25 @@ function perfWrap(names, data) { } return () => { for (const name of names) window[name] = originals[name]; }; } -function perfSim(names, scene, w, h) { +async function perfSim(names, scene, w, h) { // Five full periods warm even the 120-tick cold pass without forcing conditional calls. for (let k = 0; k < 600; k++) simTick(); perfScene(scene, w, h); + await startThreads(); const start = perfState(), data = {}, restore = perfWrap(names, data), n = 240; + const threadData = {}, restoreThread = perfWrap(['threadWait'], threadData); + if (simPool) simPool.activeMax = 0; const t = performance.now(); try { for (let k = 0; k < n; k++) simTick(); } - finally { restore(); } + finally { restore(); restoreThread(); } const total = (performance.now() - t) / n; const steps = {}; for (const [name, d] of Object.entries(data)) steps[name] = { ms_per_tick: d.ms / n, ms_per_call: d.calls ? d.ms / d.calls : null, calls: d.calls }; - return { total_ms: total, ticks: n, start, end: perfState(), steps, + return { total_ms: total, main_thread_ms: total, polling_ms: threadData.threadWait.ms / n, + main_compute_ms: total - threadData.threadWait.ms / n, + workers: simPool ? simPool.workers.length : 0, active_workers: simPool ? simPool.activeMax : 0, ticks: n, start, end: perfState(), steps, rest_ms: total - Object.values(data).reduce((s, d) => s + d.ms / n, 0) }; } async function perfRender(lighting, overlays) { diff --git a/tools/perf.py b/tools/perf.py index a5a927b..5f7e780 100644 --- a/tools/perf.py +++ b/tools/perf.py @@ -74,6 +74,9 @@ def report(result, baseline=None): print(f'{name:24}' + ''.join(f'{v:12.4f}' for v in values)) for scene, d in result['scenes'].items(): s = d['sim'] + print(f" {scene}: wall {s['total_ms']:.3f}, main occupied {s.get('main_thread_ms',s['total_ms']):.3f}, " + f"main compute {s.get('main_compute_ms',s['total_ms']):.3f}, polling {s.get('polling_ms',0):.3f} ms/tick; " + f"workers {s.get('workers',0)} (active peak {s.get('active_workers',0)})") print(f" {scene}: awake {s['start']['awake']} -> {s['end']['awake']}, hot {s['start']['hot']} -> {s['end']['hot']} / {s['end']['chunks']}") print('\nReal loop: frame interval / CPU frame work / sim per frame, p50/p95/p99 ms') for scene, d in result['scenes'].items(): @@ -174,7 +177,7 @@ def main(): raise RuntimeError('Refusing a software-rendered baseline') result['machine']['browser_version'] = browser.version def setup(scene): - return pg.evaluate('([s,w,h]) => perfScene(s,w,h)', [scene, *args.world]) + return pg.evaluate('async ([s,w,h]) => { const state=perfScene(s,w,h); await startThreads(); return state; }', [scene, *args.world]) for scene in scenes: print(f'Measuring {scene}...', file=sys.stderr, flush=True) setup(scene)