From fcf45db67251730c45df5843d328ea8699eac313 Mon Sep 17 00:00:00 2001 From: scamiv <6170744+scamiv@users.noreply.github.com> Date: Thu, 19 Feb 2026 22:53:46 +0100 Subject: [PATCH] perf(core): reduce packed tile update churn (#3253) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description: - Build packedTileUpdates directly into a BigUint64Array (avoid intermediate JS array + copy). - Transfer packedTileUpdates.buffer in worker postMessage to avoid structured-clone. - Avoids large short-lived allocations during tile-update (lower peak heap and GC pressure). - Prevents duplicating buffers across thread boundaries when the main thread is behind. (one buffer per queued update, not two) **Notes** - after postMessage(..., [packedTileUpdates.buffer]) transfer the worker’s packedTileUpdates becomes unusable (its .buffer is detached). - [ ] I have added screenshots for all UI updates - [ ] I process any text displayed to the user through translateText() and I've added it to the en.json file - [ ] I have added relevant tests to the test directory - [ ] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: DISCORD_USERNAME --- src/core/GameRunner.ts | 8 ++++++-- src/core/worker/Worker.worker.ts | 6 ++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/core/GameRunner.ts b/src/core/GameRunner.ts index 2179d2df5..3e3affd39 100644 --- a/src/core/GameRunner.ts +++ b/src/core/GameRunner.ts @@ -173,12 +173,16 @@ export class GameRunner { } // Many tiles are updated to pack it into an array - const packedTileUpdates = updates[GameUpdateType.Tile].map((u) => u.update); + const tileUpdates = updates[GameUpdateType.Tile]; + const packedTileUpdates = new BigUint64Array(tileUpdates.length); + for (let i = 0; i < tileUpdates.length; i++) { + packedTileUpdates[i] = tileUpdates[i].update; + } updates[GameUpdateType.Tile] = []; this.callBack({ tick: this.game.ticks(), - packedTileUpdates: new BigUint64Array(packedTileUpdates), + packedTileUpdates, updates: updates, playerNameViewData: this.playerViewData, tickExecutionDuration: tickExecutionDuration, diff --git a/src/core/worker/Worker.worker.ts b/src/core/worker/Worker.worker.ts index aa61da3de..55c37dda1 100644 --- a/src/core/worker/Worker.worker.ts +++ b/src/core/worker/Worker.worker.ts @@ -30,6 +30,12 @@ function gameUpdate(gu: GameUpdateViewData | ErrorUpdate) { } function sendMessage(message: WorkerMessage) { + if (message.type === "game_update") { + // Transfer the packed tile updates buffer to avoid structured-clone copies and + // reduce worker-side memory churn during long runs / catch-up. + ctx.postMessage(message, [message.gameUpdate.packedTileUpdates.buffer]); + return; + } ctx.postMessage(message); }