A loaded world starts around the player first, the rest a few areas a tick (t21)
- Areas within 150 grains of the bot start at once; the others 12 a tick, nearest first, and any the bot flies toward start straight away. A Huge world is fully started after 17 s. - Huge world, first 600 ticks: average 15.2 -> 5.5 ms/tick, worst 79.7 -> 16.2. - New test/t_load.js. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -358,6 +358,12 @@ above, including:
|
|||||||
still sleep. Through burning fuel sinking stays at the old slow pace: furnace beds are tuned to
|
still sleep. Through burning fuel sinking stays at the old slow pace: furnace beds are tuned to
|
||||||
it, and dirt heaped on a burning pile must smother it into charcoal rather than sink through.
|
it, and dirt heaped on a burning pile must smother it into charcoal rather than sink through.
|
||||||
|
|
||||||
|
- **A loaded world starts around the player first (t21, 2026-10-25).** Loading used to start every
|
||||||
|
area of the world at once, and a Huge world then took 15 ms a tick for its first 10 seconds,
|
||||||
|
with ticks up to 80 ms. Now the areas within 150 grains of the bot start at once, the rest 12 a
|
||||||
|
tick, nearest first (a Huge world is fully started after 17 s), and flying toward areas still
|
||||||
|
waiting starts them. Nothing is skipped: the same settling happens, spread out.
|
||||||
|
|
||||||
## Ideas not built yet
|
## Ideas not built yet
|
||||||
|
|
||||||
- **Concrete**, as a stronger wall material from rubble.
|
- **Concrete**, as a stronger wall material from rubble.
|
||||||
|
|||||||
+6
-5
@@ -220,10 +220,10 @@ Starter furnace designs and the milestone list shown in the notebook.
|
|||||||
- functions: smelterBlueprint
|
- functions: smelterBlueprint
|
||||||
- variables: STARTER_DESIGNS, MILESTONES
|
- variables: STARTER_DESIGNS, MILESTONES
|
||||||
|
|
||||||
### src/sim/world.js (102 lines)
|
### src/sim/world.js (104 lines)
|
||||||
World state: the per-cell typed arrays, alloc(), ambient temperature by depth, waking.
|
World state: the per-cell typed arrays, alloc(), ambient temperature by depth, waking.
|
||||||
- functions: emit, bagCap, discover, alloc, depthU, depthY, meanSurface, computeAmbient, fillNoise, wakeXY, wakeHeatXY, wakeIdx, wakeHeatIdx
|
- functions: emit, bagCap, discover, alloc, depthU, depthY, meanSurface, computeAmbient, fillNoise, 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, awake, hot, hotLvl, powderArea, roofDirty, tick, tickStamp, machines, molds, nets, pcells, powerDirty, beltL, beltR, tubeLists, brokenMachines, ghostMachines, ghostBlocked, EV, bot, bag, bagTotal, player, seen, ledger, stats
|
- 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, awake, hot, hotLvl, powderArea, roofDirty, loadWakeOrder, loadWakePending, loadWakeIndex, tick, tickStamp, machines, molds, nets, pcells, powerDirty, beltL, beltR, tubeLists, brokenMachines, ghostMachines, ghostBlocked, EV, bot, bag, bagTotal, player, seen, ledger, stats
|
||||||
|
|
||||||
### src/sim/fog.js (52 lines)
|
### src/sim/fog.js (52 lines)
|
||||||
Exploration only: never changes grains or the random stream.
|
Exploration only: never changes grains or the random stream.
|
||||||
@@ -329,7 +329,7 @@ Weather: clouds from steam, rain and snow, and the world water count.
|
|||||||
- functions: wrnd, resetWeather, rainGap, worldWater, absorbSteam, spawnRain, rainAt, weatherTick
|
- functions: wrnd, resetWeather, rainGap, worldWater, absorbSteam, spawnRain, rainAt, weatherTick
|
||||||
- variables: WBAND, WS, weather
|
- variables: WBAND, WS, weather
|
||||||
|
|
||||||
### src/sim/tick.js (27 lines)
|
### src/sim/tick.js (28 lines)
|
||||||
simTick: one simulation step, in order.
|
simTick: one simulation step, in order.
|
||||||
- functions: simTick
|
- functions: simTick
|
||||||
|
|
||||||
@@ -342,9 +342,9 @@ World generation helpers: noise and removal of tiny hard rock specks.
|
|||||||
World generation: staged terrain, ore, caves and placement, with synchronous and async entry points.
|
World generation: staged terrain, ore, caves and placement, with synchronous and async entry points.
|
||||||
- functions: generateWorld, generateWorldAsync
|
- functions: generateWorld, generateWorldAsync
|
||||||
|
|
||||||
### src/sim/save.js (141 lines)
|
### src/sim/save.js (177 lines)
|
||||||
Saving and loading a world (serializeWorld / deserializeWorld) and old-save migration.
|
Saving and loading a world (serializeWorld / deserializeWorld) and old-save migration.
|
||||||
- functions: serializeWorld, deserializeWorld
|
- functions: serializeWorld, deserializeWorld, startLoadWake, wakeLoadArea, wakeLoadNearBot, loadWakeTick
|
||||||
- variables: SAVE_VERSION, TOFF
|
- variables: SAVE_VERSION, TOFF
|
||||||
|
|
||||||
### src/render/setup.js (200 lines)
|
### src/render/setup.js (200 lines)
|
||||||
@@ -509,6 +509,7 @@ The frame loop and boot.
|
|||||||
- `test/t_econ.js`: Economy: the dock (instant sale), orders, prices, the market dip, money for machines, alloys.
|
- `test/t_econ.js`: Economy: the dock (instant sale), orders, prices, the market dip, money for machines, alloys.
|
||||||
- `test/t_fog.js`: Fog: surface, sight, range, saves and simulation independence.
|
- `test/t_fog.js`: Fog: surface, sight, range, saves and simulation independence.
|
||||||
- `test/t_furnace_repeat.js`: The starter furnaces keep working when fired again and again without cleaning, however the charge goes in: mixed, ore first with coal on top, or blown in through the vent. Each case plays furnace_play.js, which builds the design and fires it like a player.
|
- `test/t_furnace_repeat.js`: The starter furnaces keep working when fired again and again without cleaning, however the charge goes in: mixed, ore first with coal on top, or blown in through the vent. Each case plays furnace_play.js, which builds the design and fires it like a player.
|
||||||
|
- `test/t_load.js`: Reload wakes nearby areas first, without losing distant water, fire or saved state.
|
||||||
- `test/t_molds.js`: Molds and furnaces stay usable: ingots drop below and keep their stubs, plugs over molds are cleared, spoiled castings can be knocked out, grains never drop through a grate by teleporting, and slag lets the fire breathe.
|
- `test/t_molds.js`: Molds and furnaces stay usable: ingots drop below and keep their stubs, plugs over molds are cleared, spoiled castings can be knocked out, grains never drop through a grate by teleporting, and slag lets the fire breathe.
|
||||||
- `test/t_physics.js`: Sand and other powders, molten metal and gases: heaps, sorting, sinking, setting, rising and fading. Water has its own suite (t_water.js). Tall worlds keep geothermal heat out of the way.
|
- `test/t_physics.js`: Sand and other powders, molten metal and gases: heaps, sorting, sinking, setting, rising and fading. Water has its own suite (t_water.js). Tall worlds keep geothermal heat out of the way.
|
||||||
- `test/t_pipes.js`: Pipes, pumps and outlets move liquids; the Grinder grinds waste rock for trace ore.
|
- `test/t_pipes.js`: Pipes, pumps and outlets move liquids; the Grinder grinds waste rock for trace ore.
|
||||||
|
|||||||
@@ -4,6 +4,18 @@ 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
|
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.
|
open or not verified. Keep each entry short; the git history has the details.
|
||||||
|
|
||||||
|
## 2026-10-25: t21: a loaded world starts around the player first (Claude Code, Codex)
|
||||||
|
|
||||||
|
- Owner: "lets speed up the first load speed. load in areas around the player first".
|
||||||
|
- `src/sim/save.js`: `deserializeWorld` no longer wakes every area; `startLoadWake()` keeps the
|
||||||
|
load-time heat scan's result per area, wakes those within 150 grains of the bot, and queues the
|
||||||
|
rest by distance; `loadWakeTick()` (from `simTick`) wakes 12 a tick and, every 8 ticks, any still
|
||||||
|
waiting within 150 grains of the bot. The queue is not saved.
|
||||||
|
- Huge world, ms/tick before -> after: ticks 0-600 average 15.2 -> 5.5, max 79.7 -> 16.2, 95th
|
||||||
|
percentile 21.0 -> 11.0; ticks 600-1800 average 7.3 -> 10.0 (the same work, later). Every area
|
||||||
|
has started by tick 1024 (17 s).
|
||||||
|
- `test/t_load.js` (19 checks). `run_all.py --browser` ALL PASSED.
|
||||||
|
|
||||||
## 2026-10-24: t21 phase 4: duplicates merged, largest files split (Claude Code, Codex)
|
## 2026-10-24: t21 phase 4: duplicates merged, largest files split (Claude Code, Codex)
|
||||||
|
|
||||||
- Merged seven real duplicates: wall refunds (`removeWallCell`, walls and molds), tube edges and
|
- Merged seven real duplicates: wall refunds (`removeWallCell`, walls and molds), tube edges and
|
||||||
|
|||||||
+43
-7
@@ -117,13 +117,6 @@ function deserializeWorld(meta, buffers) {
|
|||||||
seen = new Uint8Array(NMAT); meta.seen.forEach((v, k) => { if (k < NMAT) seen[k] = v; });
|
seen = new Uint8Array(NMAT); meta.seen.forEach((v, k) => { if (k < NMAT) seen[k] = v; });
|
||||||
ledger = meta.ledger || {};
|
ledger = meta.ledger || {};
|
||||||
Object.assign(stats, meta.stats || {});
|
Object.assign(stats, meta.stats || {});
|
||||||
awake.fill(3);
|
|
||||||
for (let c = 0; c < NCH; c++) {
|
|
||||||
const cx = c % CW, cy = (c / CW) | 0, x0 = cx << 5, y0 = cy << 5, x1 = Math.min(W, x0 + 32), y1 = Math.min(H, y0 + 32);
|
|
||||||
let dev = 0;
|
|
||||||
for (let y = y0; y < y1 && dev < 2; y++) for (let x = x0; x < x1; x++) { const d = Math.abs(temp[y * W + x] - AMB[y]); if (d > dev) dev = d; if (flags[y * W + x] & F_BURN) dev = 99; }
|
|
||||||
if (dev >= 2) { hot[c] = 6; hotLvl[c] = 2; }
|
|
||||||
}
|
|
||||||
powerDirty = true; rebuildPower(); updateRoof();
|
powerDirty = true; rebuildPower(); updateRoof();
|
||||||
if (!weather.base) weather.base = worldWater(); // older saves: take the water it has now as its starting amount
|
if (!weather.base) weather.base = worldWater(); // older saves: take the water it has now as its starting amount
|
||||||
if (!meta.specks) clearHardSpecks(true); // older saves: tidy away tiny specks of too-hard rock once
|
if (!meta.specks) clearHardSpecks(true); // older saves: tidy away tiny specks of too-hard rock once
|
||||||
@@ -137,5 +130,48 @@ function deserializeWorld(meta, buffers) {
|
|||||||
for (const mo of molds) for (const i of moldCellsAt(mo.kind, mo.x, mo.y).walls) fogRevealAround(i % W, (i / W) | 0, 12);
|
for (const mo of molds) for (const i of moldCellsAt(mo.kind, mo.x, mo.y).walls) fogRevealAround(i % W, (i / W) | 0, 12);
|
||||||
}
|
}
|
||||||
fogLook(bot.x + bot.w / 2, bot.y + bot.h / 2);
|
fogLook(bot.x + bot.w / 2, bot.y + bot.h / 2);
|
||||||
|
startLoadWake();
|
||||||
EV.length = 0;
|
EV.length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Keep the load-time heat scan, but start distant areas in order instead of all at once.
|
||||||
|
function startLoadWake() {
|
||||||
|
awake.fill(0); hot.fill(0); hotLvl.fill(0);
|
||||||
|
loadWakePending = new Uint8Array(NCH).fill(1);
|
||||||
|
for (let c = 0; c < NCH; c++) {
|
||||||
|
const cx = c % CW, cy = (c / CW) | 0, x0 = cx << 5, y0 = cy << 5, x1 = Math.min(W, x0 + 32), y1 = Math.min(H, y0 + 32);
|
||||||
|
let dev = 0;
|
||||||
|
for (let y = y0; y < y1 && dev < 2; y++) for (let x = x0; x < x1; x++) { const d = Math.abs(temp[y * W + x] - AMB[y]); if (d > dev) dev = d; if (flags[y * W + x] & F_BURN) dev = 99; }
|
||||||
|
if (dev >= 2) loadWakePending[c] = 2;
|
||||||
|
}
|
||||||
|
const x = bot.x + bot.w / 2, y = bot.y + bot.h / 2;
|
||||||
|
const distance = c => (c % CW * 32 + 16 - x) ** 2 + (((c / CW) | 0) * 32 + 16 - y) ** 2;
|
||||||
|
loadWakeOrder = Uint32Array.from({ length: NCH }, (_, c) => c);
|
||||||
|
loadWakeOrder.sort((a, b) => distance(a) - distance(b));
|
||||||
|
loadWakeIndex = 0;
|
||||||
|
wakeLoadNearBot();
|
||||||
|
}
|
||||||
|
function wakeLoadArea(c) {
|
||||||
|
const pending = loadWakePending[c];
|
||||||
|
if (!pending) return;
|
||||||
|
loadWakePending[c] = 0;
|
||||||
|
awake[c] = 3;
|
||||||
|
if (pending === 2) { hot[c] = 6; hotLvl[c] = 2; }
|
||||||
|
}
|
||||||
|
function wakeLoadNearBot() {
|
||||||
|
const x = bot.x + bot.w / 2, y = bot.y + bot.h / 2;
|
||||||
|
const x0 = Math.max(0, Math.floor((x - 150) / 32)), x1 = Math.min(CW - 1, Math.floor((x + 150) / 32));
|
||||||
|
const y0 = Math.max(0, Math.floor((y - 150) / 32)), y1 = Math.min(CH - 1, Math.floor((y + 150) / 32));
|
||||||
|
for (let cy = y0; cy <= y1; cy++) for (let cx = x0; cx <= x1; cx++) {
|
||||||
|
const dx = Math.max(cx * 32 - x, 0, x - (cx * 32 + 31));
|
||||||
|
const dy = Math.max(cy * 32 - y, 0, y - (cy * 32 + 31));
|
||||||
|
if (dx * dx + dy * dy <= 150 * 150) wakeLoadArea(cy * CW + cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function loadWakeTick() {
|
||||||
|
if (tick % 8 === 0) wakeLoadNearBot();
|
||||||
|
// Twelve per tick finishes a Huge world in 1024 ticks, and a Small one in 171.
|
||||||
|
const end = Math.min(loadWakeIndex + 12, loadWakeOrder.length);
|
||||||
|
while (loadWakeIndex < end) wakeLoadArea(loadWakeOrder[loadWakeIndex++]);
|
||||||
|
if (loadWakeIndex === loadWakeOrder.length) loadWakeOrder = loadWakePending = null;
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
function simTick() {
|
function simTick() {
|
||||||
tick++;
|
tick++;
|
||||||
tickStamp = (tickStamp % 255) + 1;
|
tickStamp = (tickStamp % 255) + 1;
|
||||||
|
if (loadWakeOrder) loadWakeTick();
|
||||||
if (tick % 20 === 1) updateDirtyRoof();
|
if (tick % 20 === 1) updateDirtyRoof();
|
||||||
weatherTick();
|
weatherTick();
|
||||||
machinesTick();
|
machinesTick();
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ let bgm; // background layer: trees. Liquids, powders and gases pass in front of
|
|||||||
let flyers = []; // grains in flight, blown out of the bot
|
let flyers = []; // grains in flight, blown out of the bot
|
||||||
let ghostBlocks = new Map(), ghostMolds = [];
|
let ghostBlocks = new Map(), ghostMolds = [];
|
||||||
let awake, hot, hotLvl, powderArea, roofDirty;
|
let awake, hot, hotLvl, powderArea, roofDirty;
|
||||||
|
let loadWakeOrder = null, loadWakePending = null, loadWakeIndex = 0;
|
||||||
let tick = 0, tickStamp = 1;
|
let tick = 0, tickStamp = 1;
|
||||||
let machines = [null], molds = [], nets = [null], pcells = new Set(), powerDirty = true;
|
let machines = [null], molds = [], nets = [null], pcells = new Set(), powerDirty = true;
|
||||||
let beltL = [], beltR = [], tubeLists = [[], [], [], [], []];
|
let beltL = [], beltR = [], tubeLists = [[], [], [], [], []];
|
||||||
@@ -49,6 +50,7 @@ function alloc(w, h) {
|
|||||||
surfBase = Math.round(Math.min(h * 0.27, 175)); underD = h - surfBase; shallowD = 0; lapse = 0.36;
|
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);
|
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);
|
AMB = new Float32Array(h);
|
||||||
|
loadWakeOrder = loadWakePending = null; loadWakeIndex = 0;
|
||||||
awake = new Uint8Array(NCH); hot = new Uint8Array(NCH); hotLvl = new Uint8Array(NCH);
|
awake = new Uint8Array(NCH); hot = new Uint8Array(NCH); hotLvl = new Uint8Array(NCH);
|
||||||
roofDirty = new Uint8Array(CW).fill(1);
|
roofDirty = new Uint8Array(CW).fill(1);
|
||||||
powderArea = new Uint8Array(NCH).fill(1); // unknown areas get one visit before being ruled out
|
powderArea = new Uint8Array(NCH).fill(1); // unknown areas get one visit before being ruled out
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
// Reload wakes nearby areas first, without losing distant water, fire or saved state.
|
||||||
|
const { load, suite, flatWorld, rect, count, ticks } = require('./harness');
|
||||||
|
const { run } = load();
|
||||||
|
const { check, done } = suite();
|
||||||
|
|
||||||
|
flatWorld(run, 1024, 256, 200);
|
||||||
|
run(`
|
||||||
|
bot.x = 510; bot.y = 170;
|
||||||
|
setCell(192 * W + 16, WOOD, AMB[192], F_BURN); life[192 * W + 16] = FUEL[WOOD];
|
||||||
|
temp[210 * W + 16] = AMB[210] + 200;
|
||||||
|
temp[210 * W + 512] = AMB[210] + 200;
|
||||||
|
`);
|
||||||
|
rect(run, 48, 160, 49, 199, run('STONE'));
|
||||||
|
rect(run, 78, 160, 79, 199, run('STONE'));
|
||||||
|
rect(run, 50, 170, 60, 179, run('WATER'));
|
||||||
|
run('globalThis.loadSave = serializeWorld(); deserializeWorld(loadSave.meta, loadSave.buffers);');
|
||||||
|
check('nearby areas wake immediately, with heat', run('awake[6 * CW + 16] > 0 && hot[6 * CW + 16] > 0'));
|
||||||
|
check('distant areas wait, including their heat', run('awake[6 * CW] === 0 && hot[6 * CW] === 0'));
|
||||||
|
ticks(run, 1);
|
||||||
|
check('nearby areas are awake on the first tick while far areas wait', run('awake[6 * CW + 16] > 0 && awake[6 * CW] === 0'));
|
||||||
|
|
||||||
|
check('the order contains every area once and goes outward from the saved bot', run(`(() => {
|
||||||
|
const visited = new Uint8Array(NCH);
|
||||||
|
let previous = -1;
|
||||||
|
for (const c of loadWakeOrder) {
|
||||||
|
const d = (c % CW * 32 + 16 - (bot.x + bot.w / 2)) ** 2 + (((c / CW) | 0) * 32 + 16 - (bot.y + bot.h / 2)) ** 2;
|
||||||
|
if (visited[c] || d < previous) return false;
|
||||||
|
visited[c] = 1; previous = d;
|
||||||
|
}
|
||||||
|
return visited.every(v => v === 1);
|
||||||
|
})()`));
|
||||||
|
check('waiting leaves distant fire and water unchanged', run('life[192 * W + 16] === FUEL[WOOD] && mat[170 * W + 50] === WATER'));
|
||||||
|
ticks(run, 120);
|
||||||
|
check('all areas of a small world have had their turn', run('loadWakeOrder === null && loadWakePending === null'));
|
||||||
|
check('distant burning wood resumes burning after its turn', run('life[192 * W + 16] < FUEL[WOOD] || mat[192 * W + 16] !== WOOD'));
|
||||||
|
check('distant stored heat resumes flowing', run('temp[210 * W + 16] < AMB[210] + 190'));
|
||||||
|
ticks(run, 600);
|
||||||
|
check('distant water settles without losing grains', count(run, run('WATER')) === 110 && count(run, run('WATER'), 50, 196, 77, 199) === 110);
|
||||||
|
check('the settled water area goes back to sleep', run('awake[6 * CW + 1] === 0 && awake[6 * CW + 2] === 0'));
|
||||||
|
|
||||||
|
// Moving to a waiting area must apply its saved heat hint, even at ambient with F_BURN.
|
||||||
|
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]'));
|
||||||
|
|
||||||
|
// 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);');
|
||||||
|
check('saving midway preserves all cell buffers', run(`(() => {
|
||||||
|
const saved = serializeWorld();
|
||||||
|
return ['mat', 'temp', 'life', 'flags'].every(key => saved.buffers[key].every((v, i) => v === midLoadSave.buffers[key][i]));
|
||||||
|
})()`));
|
||||||
|
check('loading midway starts a new queue around the current bot', run('loadWakeIndex === 0 && loadWakePending[6 * CW] === 0 && loadWakePending[6 * CW + 16] > 0'));
|
||||||
|
run('alloc(64, 64);');
|
||||||
|
check('alloc clears a previous load queue', run('loadWakeOrder === null && loadWakePending === null && loadWakeIndex === 0'));
|
||||||
|
run('deserializeWorld(loadSave.meta, loadSave.buffers); generateWorld(77, 256, 256, null);');
|
||||||
|
check('generating a new world clears the load queue', run('loadWakeOrder === null && loadWakePending === null && loadWakeIndex === 0'));
|
||||||
|
|
||||||
|
// The Huge-world budget is checked with real ticks on quiet terrain.
|
||||||
|
flatWorld(run, 6144, 2048, 1900);
|
||||||
|
run('startLoadWake();');
|
||||||
|
check('a Huge world has 12288 scheduled areas', run('loadWakeOrder.length === 12288'));
|
||||||
|
ticks(run, 1023);
|
||||||
|
check('the final areas are still queued at tick 1023', run('loadWakeOrder !== null && loadWakePending.some(v => v > 0)'));
|
||||||
|
ticks(run, 1);
|
||||||
|
check('every Huge-world area has had its turn by tick 1024 (17.07 seconds)', run('loadWakeOrder === null && loadWakePending === null && loadWakeIndex === 12288'));
|
||||||
|
done();
|
||||||
Reference in New Issue
Block a user