Check imported world size, buffers, materials and block codes (t80)

This commit is contained in:
2026-10-29 17:55:18 -04:00
parent cf762268ce
commit 0483fb8da4
4 changed files with 95 additions and 5 deletions
+28 -4
View File
@@ -32,7 +32,24 @@ function serializeWorld() {
}
function deserializeWorld(meta, buffers) {
if (meta.v !== SAVE_VERSION) throw new Error('This world was saved by an older version of the game and cannot be loaded.');
alloc(meta.W, meta.H);
// worldgen accepts smaller test worlds; the largest nw-size option is 6144 x 2048.
const w = meta.W, h = meta.H;
if (!Number.isInteger(w) || !Number.isInteger(h) || w <= 0 || h <= 0 || w > 6144 || h > 2048)
throw new Error('Invalid world size: expected positive whole dimensions up to 6144 x 2048.');
const n = w * h, nb = Math.ceil(w / BS) * Math.ceil(h / BS);
for (const key of ['mat', 'temp', 'life', 'flags', 'part', 'blockP', 'blockV', 'bgm', 'fog']) {
if ((key === 'bgm' || key === 'fog') && !Object.hasOwn(buffers, key)) continue;
const expected = key === 'blockP' || key === 'blockV' ? nb : key === 'fog' ? Math.ceil(w / FOG) * Math.ceil(h / FOG) : n;
if (!buffers[key] || buffers[key].length !== expected)
throw new Error('Invalid saved buffer: ' + key + ' must contain ' + expected + ' values.');
}
for (const key of ['surfY', 'dirtY', 'graniteY', 'basaltY', 'magmaY']) {
if (!meta.cols?.[key] || meta.cols[key].length !== w)
throw new Error('Invalid saved column: ' + key + ' must contain ' + w + ' values.');
}
if (meta.slopePhases && meta.slopePhases.length !== nb)
throw new Error('Invalid saved buffer: slopePhases must contain ' + nb + ' values.');
alloc(w, h);
devWorld = meta.dev === true;
devLog = devWorld && Array.isArray(meta.devLog) ? meta.devLog.filter(e => Array.isArray(e) && Number.isSafeInteger(e[0]) && e[0] >= 0 && typeof e[1] === 'string').slice(-200).map(e => [e[0], e[1]]) : [];
worldSeed = meta.seed;
@@ -41,9 +58,16 @@ function deserializeWorld(meta, buffers) {
surfY.set(meta.cols.surfY); dirtY.set(meta.cols.dirtY); graniteY.set(meta.cols.graniteY); basaltY.set(meta.cols.basaltY); magmaY.set(meta.cols.magmaY);
computeAmbient(); fillNoise();
mat.set(buffers.mat); life.set(buffers.life); flags.set(buffers.flags);
for (let i = 0; i < N; i++) 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; rebuildProcessors();
for (let b = 0; b < NB; b++) if (blockP[b] === BP_RACK) rackState.set(b, newRack());
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++) {
if (!Object.hasOwn(PIECE_BY_CODE, blockP[b])) blockP[b] = 0;
if (blockP[b] === BP_RACK) rackState.set(b, newRack());
}
rebuildProcessors();
for (const entry of Array.isArray(meta.racks) ? meta.racks : []) {
if (!Array.isArray(entry)) continue;
const [b, q, open] = entry;