From 87a72a4e93f87d71ff565b61650a1b1fb5072752 Mon Sep 17 00:00:00 2001 From: FloPinguin <25036848+FloPinguin@users.noreply.github.com> Date: Thu, 16 Apr 2026 06:03:01 +0200 Subject: [PATCH] =?UTF-8?q?Forward=20game=20tick=20errors=20from=20worker?= =?UTF-8?q?=20to=20client=20=F0=9F=90=9B=20(#3690)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description: Currently there is a "Game tick error: Invalid coordinates: NaN,NaN" error which crashes the game rarely. Maybe introduced by water nukes, I'm not sure. To properly debug it when it happens again, lets print the stacktrace: - Game tick errors (`ErrorUpdate`) were silently dropped in the web worker's `drain()` function, so the client's error modal never displayed - Added a `"game_error"` worker message type to forward `ErrorUpdate` from the worker to the main thread - The client now receives the full error message and stack trace via the existing `showErrorModal` dialog image ## Please complete the following: - [X] I have added screenshots for all UI updates - [X] I process any text displayed to the user through translateText() and I've added it to the en.json file - [X] I have added relevant tests to the test directory - [X] 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: FloPinguin --- src/core/worker/Worker.worker.ts | 3 +++ src/core/worker/WorkerClient.ts | 5 +++++ src/core/worker/WorkerMessages.ts | 9 ++++++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/core/worker/Worker.worker.ts b/src/core/worker/Worker.worker.ts index 65e33c6de..1a41bfb3c 100644 --- a/src/core/worker/Worker.worker.ts +++ b/src/core/worker/Worker.worker.ts @@ -60,6 +60,9 @@ async function drain(): Promise { const batch: GameUpdateViewData[] = []; const onTickUpdate = (gu: GameUpdateViewData | ErrorUpdate) => { if (!("updates" in gu)) { + if ("errMsg" in gu) { + sendMessage({ type: "game_error", error: gu } as WorkerMessage); + } return; } batch.push(gu); diff --git a/src/core/worker/WorkerClient.ts b/src/core/worker/WorkerClient.ts index 3ceadf32e..459ada824 100644 --- a/src/core/worker/WorkerClient.ts +++ b/src/core/worker/WorkerClient.ts @@ -53,6 +53,11 @@ export class WorkerClient { } } break; + case "game_error": + if (this.gameUpdateCallback && message.error) { + this.gameUpdateCallback(message.error); + } + break; case "initialized": default: diff --git a/src/core/worker/WorkerMessages.ts b/src/core/worker/WorkerMessages.ts index 861e31172..7f4158a46 100644 --- a/src/core/worker/WorkerMessages.ts +++ b/src/core/worker/WorkerMessages.ts @@ -7,7 +7,7 @@ import { PlayerProfile, } from "../game/Game"; import { TileRef } from "../game/GameMap"; -import { GameUpdateViewData } from "../game/GameUpdates"; +import { ErrorUpdate, GameUpdateViewData } from "../game/GameUpdates"; import { ClientID, GameStartInfo, Turn } from "../Schemas"; export type WorkerMessageType = @@ -16,6 +16,7 @@ export type WorkerMessageType = | "turn" | "game_update" | "game_update_batch" + | "game_error" | "player_actions" | "player_actions_result" | "player_buildables" @@ -62,6 +63,11 @@ export interface GameUpdateBatchMessage extends BaseWorkerMessage { gameUpdates: GameUpdateViewData[]; } +export interface GameErrorMessage extends BaseWorkerMessage { + type: "game_error"; + error: ErrorUpdate; +} + export interface PlayerActionsMessage extends BaseWorkerMessage { type: "player_actions"; playerID: PlayerID; @@ -147,6 +153,7 @@ export type WorkerMessage = | InitializedMessage | GameUpdateMessage | GameUpdateBatchMessage + | GameErrorMessage | PlayerActionsResultMessage | PlayerBuildablesResultMessage | PlayerProfileResultMessage