From f88035a58f3bfa7a8baafda02a6bd572a3693eee Mon Sep 17 00:00:00 2001 From: 44r0n7 <44r0n7+gitea@pm.me> Date: Thu, 29 Oct 2026 21:59:40 -0400 Subject: [PATCH] Remove conversions for old saves (t83) --- docs/PROJECT_MAP.md | 4 ++-- docs/agent-log.md | 10 ++++++++++ src/sim/save.js | 17 +---------------- test/t_conveyors.js | 4 ++-- test/t_load.js | 23 +++++++++++++++++++++++ test/t_weather.js | 4 ++-- 6 files changed, 40 insertions(+), 22 deletions(-) diff --git a/docs/PROJECT_MAP.md b/docs/PROJECT_MAP.md index e1005f3..381eec1 100644 --- a/docs/PROJECT_MAP.md +++ b/docs/PROJECT_MAP.md @@ -392,8 +392,8 @@ Dev commands are pure simulation operations; the browser owns the panel and conf - functions: resetDevConsole, enableDevConsole, devError, devName, devGiveable, devMaterialList, devDistance, devSuggestions, devHistory, devRemember, devRecall, devComplete, devMaterial, devCommand - variables: devWorld, devLog, devFree, devSpeed, devPaused, devSteps, DEV_COMMANDS, DEV_MATERIALS -### src/sim/save.js (216 lines) -Saving and loading a world (serializeWorld / deserializeWorld) and old-save migration. +### src/sim/save.js (201 lines) +Saving and loading a world (serializeWorld / deserializeWorld). - functions: serializeWorld, deserializeWorld, startLoadWake, wakeLoadArea, wakeLoadNearBot, loadWakeTick - variables: SAVE_VERSION, TOFF diff --git a/docs/agent-log.md b/docs/agent-log.md index 63c9051..f83a4ec 100644 --- a/docs/agent-log.md +++ b/docs/agent-log.md @@ -4,6 +4,16 @@ 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-29: t83 remove old-save conversions (Codex) + +- Removed only spring, solid-pipe, single-material-filter and foreground-tree conversions + from `src/sim/save.js`; world generation and its spring random draws are untouched. +- Files: save.js, test/t_{load,weather,conveyors}.js, docs/PROJECT_MAP.md, tasks/t83*. + Three expectations failed first; updated obsolete spring/filter migration tests deliberately. +- All 41 headless suites pass; pixel `test/play.py shots/t83-play` passes with no console + errors. Sandbox lacked WebGPU; host GPU rerun passed. Inspected saving-progress.png and + 10-after.png (saved/reloaded world). Map regenerated; nothing left open. + ## 2026-10-29: t81 shared piece direction variants (Codex) - `pieceV` accepts a direction and resolved code; `dragPlan` calls it for previews and diff --git a/src/sim/save.js b/src/sim/save.js index bcd1435..a1473c1 100644 --- a/src/sim/save.js +++ b/src/sim/save.js @@ -1,4 +1,4 @@ -// Saving and loading a world (serializeWorld / deserializeWorld) and old-save migration. +// Saving and loading a world (serializeWorld / deserializeWorld). // ---------- Save / load ---------- const SAVE_VERSION = 2; const TOFF = 64; // temperatures are saved with an offset so sub-zero snow and ice survive @@ -60,7 +60,6 @@ function deserializeWorld(meta, buffers) { mat.set(buffers.mat); life.set(buffers.life); flags.set(buffers.flags); for (let i = 0; i < N; i++) { if (mat[i] >= NMAT) mat[i] = EMPTY; - else if (mat[i] === SPRING) mat[i] = STONE; // springs are gone: older worlds keep plain rock there } blockP.set(buffers.blockP); blockV.set(buffers.blockV); filtersDirty = true; for (let b = 0; b < NB; b++) { @@ -81,22 +80,8 @@ function deserializeWorld(meta, buffers) { } s.open = open === true; rackState.set(b, s); } - // pipes used to be solid copper blocks; now they are thin and let things past - for (let b = 0; b < NB; b++) if (blockP[b] === BP_PIPE) for (const i of blockCellList(b % BW, (b / BW) | 0)) if (mat[i] === PIPE) { mat[i] = EMPTY; part[i] = P_PIPE; } for (const [b, m, inv] of meta.filters || []) if (isFilter(blockP[b])) filterCfg.set(b, filterRec({ m, inv })); - for (let b = 0; b < NB; b++) if (isFilter(blockP[b])) { - // the first filters kept one material in their block variant - if (!filterCfg.has(b)) filterCfg.set(b, filterRec({ m: [blockV[b] & 127], inv: 0 })); - blockV[b] &= 128; - } if (buffers.bgm) { bgm.set(buffers.bgm); } - else { - // older saves kept trees in the foreground: move them behind - for (let i = 0; i < N; i++) { - const m = mat[i], y = (i / W) | 0; - if (m === LEAVES || (m === WOOD && (flags[i] & F_NAT) && y < surfY[i % W])) { bgm[i] = m; mat[i] = EMPTY; flags[i] = 0; } - } - } const t16 = buffers.temp, off = meta.tOff || 0; for (let i = 0; i < N; i++) temp[i] = t16[i] / 16 - off; saplings = (meta.saplings || []).map(([x, y, age, th, seed]) => ({ x, y, age, th, seed })); findTreeBases(); diff --git a/test/t_conveyors.js b/test/t_conveyors.js index 7c74f0a..82c00ba 100644 --- a/test/t_conveyors.js +++ b/test/t_conveyors.js @@ -199,9 +199,9 @@ run('clearAllGhosts(); pasteGhost(flipBlueprint(copyRegion(120, 100, 123, 103)), check('pasting it builds a filter with the same materials and mode', run('blockP[25*BW+34]') === run('BP_FILTER') && run('JSON.stringify(filterInfo(25*BW+34))') === JSON.stringify({ m: [run('CUORE'), run('FEORE')].sort((a, b) => a - b), inv: 1 }), run('JSON.stringify(filterInfo(25*BW+34))')); run('globalThis.__s = serializeWorld(); deserializeWorld(__s.meta, __s.buffers);'); check('save and load keep filters, their materials, mode and direction', run('blockP[25*BW+30]') === run('BP_FILTER') && run('blockV[25*BW+30]') === 128 && run('filterInfo(25*BW+30).inv') === 1 && run('filterInfo(25*BW+30).m.length') === 2 && run('part[100*W+120]') === run('P_FILTER')); -// a save from before: one material kept in the block variant +// A retired single-material variant is no longer reconstructed on load. run('__s.meta.filters = []; __s.buffers.blockV[25*BW+30] = 128 | SAND; deserializeWorld(__s.meta, __s.buffers);'); -check('older filters keep the one material they had', run('JSON.stringify(filterInfo(25*BW+30))') === JSON.stringify({ m: [run('SAND')], inv: 0 }) && run('blockV[25*BW+30]') === 128); +check('loading does not reconstruct retired single-material filters', run('!filterCfg.has(25*BW+30) && blockV[25*BW+30] === (128 | SAND)')); // the run of matching filters in a row fresh(); run('for (let bx = 20; bx < 26; bx++) placeBlock(BP_FILTER, 128, bx, 25, true, { m: [SAND] }); placeBlock(BP_FILTER, 128, 26, 25, true, { m: [COAL] }); placeBlock(BP_FILTER, 0, 27, 25, true, { m: [COAL] });'); diff --git a/test/t_load.js b/test/t_load.js index 3cac6a4..fc061db 100644 --- a/test/t_load.js +++ b/test/t_load.js @@ -51,6 +51,29 @@ for (const [label, doctor, clean] of [ })()`)); } +// Retired save formats are no longer translated into current construction or trees. +flatWorld(run, 256, 256, 200); +run(` + placeBlock(BP_FILTER, 128, 5, 10, true, { m: [SAND, COAL], inv: 1 }); + placeBlock(BP_PIPE, 0, 8, 10, true); + bgm[100 * W + 40] = LEAVES; + globalThis.currentSave = serializeWorld(); + deserializeWorld(currentSave.meta, currentSave.buffers); +`); +check('current filter settings and direction survive loading', run('blockV[10 * BW + 5] === 128 && JSON.stringify(filterCfg.get(10 * BW + 5)) === JSON.stringify(filterRec({ m: [SAND, COAL], inv: 1 }))')); +check('current thin pipes and background trees survive loading', run('part[40 * W + 32] === P_PIPE && mat[40 * W + 32] === EMPTY && bgm[100 * W + 40] === LEAVES')); +run(` + currentSave.meta.filters = []; + currentSave.buffers.blockV[10 * BW + 5] = 128 | SAND; + delete currentSave.buffers.bgm; + currentSave.buffers.mat[100 * W + 40] = LEAVES; + currentSave.buffers.mat[110 * W + 40] = WOOD; + currentSave.buffers.flags[110 * W + 40] = F_NAT; + deserializeWorld(currentSave.meta, currentSave.buffers); +`); +check('loading does not invent a filter setting from its old block variant', run('!filterCfg.has(10 * BW + 5) && blockV[10 * BW + 5] === (128 | SAND)')); +check('loading does not move foreground trees into a missing background layer', run('mat[100 * W + 40] === LEAVES && mat[110 * W + 40] === WOOD && flags[110 * W + 40] === F_NAT && bgm[100 * W + 40] === EMPTY && bgm[110 * W + 40] === EMPTY')); + flatWorld(run, 1024, 256, 200); run(` bot.x = 510; bot.y = 170; diff --git a/test/t_weather.js b/test/t_weather.js index de2f23c..f7f899e 100644 --- a/test/t_weather.js +++ b/test/t_weather.js @@ -8,9 +8,9 @@ const rainInAir = (m) => run(`flyers.filter(f => f.rain && f.m === ${m}).length` run('generateWorld(777, 1024, 640, null)'); check('new worlds have no springs', count(run, run('SPRING')) === 0); check('and the same seed still makes the same land', run('surfY[512]') > 0 && run('!!dock()')); -// an older save with a spring in it: the spring becomes plain rock +// Loading no longer converts retired spring cells to rock. run('globalThis.__s = serializeWorld(); __s.buffers.mat[300 * W + 500] = SPRING; deserializeWorld(__s.meta, __s.buffers);'); -check('springs in older worlds turn into plain rock', run('mat[300 * W + 500]') === run('STONE') && count(run, run('SPRING')) === 0); +check('loading leaves retired spring cells unchanged', run('mat[300 * W + 500]') === run('SPRING') && count(run, run('SPRING')) === 1); // steam in the open sky rises into the clouds instead of condensing flatWorld(run, 320, 200, 120);