From 1bc7fa9349e68f489769949bc857c0a66ea8e6fd Mon Sep 17 00:00:00 2001 From: Claude Code Date: Thu, 26 Mar 2026 01:06:56 -0700 Subject: [PATCH] =?UTF-8?q?perf(simulation):=20=E2=9A=A1=20Optimize=20work?= =?UTF-8?q?er=20thread=20logic=20for=20faster=20simulation=20updates?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lilith Autocommit --- .../src/simulation/simulation.worker.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/guide/age-of-four/src/simulation/simulation.worker.ts b/guide/age-of-four/src/simulation/simulation.worker.ts index b225bc36..8e68c29c 100644 --- a/guide/age-of-four/src/simulation/simulation.worker.ts +++ b/guide/age-of-four/src/simulation/simulation.worker.ts @@ -17,6 +17,7 @@ import { applyVolcanicWinterForcing, generate as generateMap, ClimatePhysics, + EcologyPhysics, GRID_WIDTH, GRID_HEIGHT, } from '@magic-civ/engine-ts' @@ -32,6 +33,7 @@ interface ScenarioState { checkpoints: Map grid: GridState physics: ClimatePhysics + ecology: EcologyPhysics | null cursorScenarioTurn: number totalScenarioTurns: number worldSeed: number @@ -85,6 +87,7 @@ function stepOneTurn(state: ScenarioState, scenarioTurn: number): { stats: TurnS const absTurn = state.config.worldAge + scenarioTurn if (state.isVolcanicWinter) applyVolcanicWinterForcing(state.grid) const events = state.physics.processStep(state.grid, absTurn, state.worldSeed) + if (state.ecology) state.ecology.processStep(state.grid) const stats = computeTurnStats(state.grid) state.cursorScenarioTurn = scenarioTurn + 1 return { stats, events } @@ -114,6 +117,7 @@ function seekToTurn(state: ScenarioState, targetSt: number): void { const absTurn = state.config.worldAge + st if (state.isVolcanicWinter) applyVolcanicWinterForcing(state.grid) state.physics.processStep(state.grid, absTurn, state.worldSeed) + if (state.ecology) state.ecology.processStep(state.grid) } state.cursorScenarioTurn = targetSt return @@ -141,6 +145,7 @@ function seekToTurn(state: ScenarioState, targetSt: number): void { const absTurn = state.config.worldAge + st if (state.isVolcanicWinter) applyVolcanicWinterForcing(state.grid) state.physics.processStep(state.grid, absTurn, state.worldSeed) + if (state.ecology) state.ecology.processStep(state.grid) } state.cursorScenarioTurn = targetSt } @@ -163,6 +168,7 @@ async function prebufferFrames(state: ScenarioState, scenarioId: string, frameCo const tmpGrid = cloneGridState(cp0) const tmpPhysics = new ClimatePhysics(climateParams, terrainCache) + const tmpEcology = new EcologyPhysics() for (let batchStart = 0; batchStart < count; batchStart += PREBUFFER_BATCH) { if (cancelFlags.get(scenarioId)) break @@ -176,6 +182,7 @@ async function prebufferFrames(state: ScenarioState, scenarioId: string, frameCo const absTurn = state.config.worldAge + st if (state.isVolcanicWinter) applyVolcanicWinterForcing(tmpGrid) tmpPhysics.processStep(tmpGrid, absTurn, state.worldSeed) + tmpEcology.processStep(tmpGrid) } const snap = encodeSnapshot(tmpGrid, st) @@ -244,11 +251,13 @@ async function handleRun(scenarioId: string, turns: number, prebufferFrameCount: // Generate map from seed using transpiled GDScript pipeline const grid = generateMap(WORLD_SEED, GRID_WIDTH, GRID_HEIGHT, terrainCache, climateParams, 'continents') const physics = new ClimatePhysics(climateParams, terrainCache) + const ecology = new EcologyPhysics() - // Phase 1: Geological history + // Phase 1: Geological history (climate + ecology) for (let turn = 0; turn < worldAge; turn++) { if (cancelFlags.get(scenarioId)) return physics.processStep(grid, turn, WORLD_SEED) + ecology.processStep(grid) if (turn % CHUNK_SIZE === 0) { post({ type: 'progress', scenarioId, turn, total: totalAbsTurns, phase: 'geology' }) @@ -264,6 +273,7 @@ async function handleRun(scenarioId: string, turns: number, prebufferFrameCount: // Phase 3: Scenario simulation const state: ScenarioState = { config, grid, physics, + ecology, stats: [], events: [], checkpoints: new Map(), cursorScenarioTurn: 0, @@ -361,6 +371,7 @@ function handleFrame(scenarioId: string, turn: number, lookahead: number): void // Encode frames from a temporary grid copy so we don't pollute the cursor const tmpGrid = cloneGridState(state.grid) const tmpPhysics = new ClimatePhysics(climateParams, terrainCache) + const tmpEcology = new EcologyPhysics() const frames: FramePayload[] = [] const transferables: ArrayBuffer[] = [] @@ -372,6 +383,7 @@ function handleFrame(scenarioId: string, turn: number, lookahead: number): void const absTurn = state.config.worldAge + st if (state.isVolcanicWinter) applyVolcanicWinterForcing(tmpGrid) tmpPhysics.processStep(tmpGrid, absTurn, state.worldSeed) + tmpEcology.processStep(tmpGrid) } const snap = encodeSnapshot(tmpGrid, st)