Files
OpenFrontIO/src/core/worker/WorkerMessages.ts
T
scamiv 45a8e33562 Implement worker metrics and debugging events
- Introduced WorkerMetricsEvent and SetWorkerDebugEvent to facilitate communication between the main thread and worker for performance monitoring.
- Enhanced ClientGameRunner to emit worker metrics and handle debug configuration updates.
- Updated PerformanceOverlay to display worker metrics and allow toggling of debug settings.
- Refactored Canvas2DRendererProxy and TerritoryRendererProxy to improve rendering performance and manage render cooldowns.
- Added profiling capabilities in Worker.worker.ts to track event loop lag, simulation delays, and message handling metrics.
2026-02-05 21:46:50 +01:00

376 lines
9.2 KiB
TypeScript

import {
PlayerActions,
PlayerBorderTiles,
PlayerID,
PlayerProfile,
} from "../game/Game";
import { TileRef } from "../game/GameMap";
import { GameUpdateViewData } from "../game/GameUpdates";
import { ClientID, GameStartInfo, Turn } from "../Schemas";
export type WorkerMessageType =
| "heartbeat"
| "init"
| "initialized"
| "turn"
| "game_update"
| "tile_context"
| "tile_context_result"
| "player_actions"
| "player_actions_result"
| "player_profile"
| "player_profile_result"
| "player_border_tiles"
| "player_border_tiles_result"
| "attack_average_position"
| "attack_average_position_result"
| "transport_ship_spawn"
| "transport_ship_spawn_result"
| "init_renderer"
| "renderer_ready"
| "set_patterns_enabled"
| "set_palette"
| "set_view_size"
| "set_view_transform"
| "set_alternative_view"
| "set_highlighted_owner"
| "set_shader_settings"
| "mark_tile"
| "mark_all_dirty"
| "refresh_palette"
| "refresh_terrain"
| "tick_renderer"
| "render_frame"
| "render_done"
| "set_worker_debug"
| "worker_metrics"
| "renderer_metrics";
// Base interface for all messages
interface BaseWorkerMessage {
type: WorkerMessageType;
id?: string;
/**
* Cross-thread timestamp (Date.now()) set by the sender when enqueuing the
* message. Used for queue latency debugging.
*/
sentAtWallMs?: number;
}
export interface HeartbeatMessage extends BaseWorkerMessage {
type: "heartbeat";
}
// Messages from main thread to worker
export interface InitMessage extends BaseWorkerMessage {
type: "init";
gameStartInfo: GameStartInfo;
clientID: ClientID;
}
export interface TurnMessage extends BaseWorkerMessage {
type: "turn";
turn: Turn;
}
// Messages from worker to main thread
export interface InitializedMessage extends BaseWorkerMessage {
type: "initialized";
}
export interface GameUpdateMessage extends BaseWorkerMessage {
type: "game_update";
gameUpdate: GameUpdateViewData;
}
export interface TileContext {
hasOwner: boolean;
ownerSmallId: number | null;
ownerId: PlayerID | null;
hasFallout: boolean;
isDefended: boolean;
}
export interface TileContextMessage extends BaseWorkerMessage {
type: "tile_context";
tile: TileRef;
}
export interface TileContextResultMessage extends BaseWorkerMessage {
type: "tile_context_result";
result: TileContext;
}
export interface PlayerActionsMessage extends BaseWorkerMessage {
type: "player_actions";
playerID: PlayerID;
x?: number;
y?: number;
}
export interface PlayerActionsResultMessage extends BaseWorkerMessage {
type: "player_actions_result";
result: PlayerActions;
}
export interface PlayerProfileMessage extends BaseWorkerMessage {
type: "player_profile";
playerID: number;
}
export interface PlayerProfileResultMessage extends BaseWorkerMessage {
type: "player_profile_result";
result: PlayerProfile;
}
export interface PlayerBorderTilesMessage extends BaseWorkerMessage {
type: "player_border_tiles";
playerID: PlayerID;
}
export interface PlayerBorderTilesResultMessage extends BaseWorkerMessage {
type: "player_border_tiles_result";
result: PlayerBorderTiles;
}
export interface AttackAveragePositionMessage extends BaseWorkerMessage {
type: "attack_average_position";
playerID: number;
attackID: string;
}
export interface AttackAveragePositionResultMessage extends BaseWorkerMessage {
type: "attack_average_position_result";
x: number | null;
y: number | null;
}
export interface TransportShipSpawnMessage extends BaseWorkerMessage {
type: "transport_ship_spawn";
playerID: PlayerID;
targetTile: TileRef;
}
export interface TransportShipSpawnResultMessage extends BaseWorkerMessage {
type: "transport_ship_spawn_result";
result: TileRef | false;
}
// Renderer messages from main thread to worker
export interface InitRendererMessage extends BaseWorkerMessage {
type: "init_renderer";
offscreenCanvas: OffscreenCanvas;
darkMode: boolean; // Whether to use dark theme
backend?: "webgpu" | "canvas2d";
}
export interface SetPatternsEnabledMessage extends BaseWorkerMessage {
type: "set_patterns_enabled";
enabled: boolean;
}
export interface SetPaletteMessage extends BaseWorkerMessage {
type: "set_palette";
paletteWidth: number;
maxSmallId: number;
row0: Uint8Array;
row1: Uint8Array;
}
export interface SetViewSizeMessage extends BaseWorkerMessage {
type: "set_view_size";
width: number;
height: number;
}
export interface SetViewTransformMessage extends BaseWorkerMessage {
type: "set_view_transform";
scale: number;
offsetX: number;
offsetY: number;
}
export interface SetAlternativeViewMessage extends BaseWorkerMessage {
type: "set_alternative_view";
enabled: boolean;
}
export interface SetHighlightedOwnerMessage extends BaseWorkerMessage {
type: "set_highlighted_owner";
ownerSmallId: number | null;
}
export interface SetShaderSettingsMessage extends BaseWorkerMessage {
type: "set_shader_settings";
territoryShader?: string;
territoryShaderParams0?: number[];
territoryShaderParams1?: number[];
terrainShader?: string;
terrainShaderParams0?: number[];
terrainShaderParams1?: number[];
preSmoothing?: {
enabled: boolean;
shaderPath: string;
params0: number[];
};
postSmoothing?: {
enabled: boolean;
shaderPath: string;
params0: number[];
};
}
export interface MarkTileMessage extends BaseWorkerMessage {
type: "mark_tile";
tile: TileRef;
}
export interface MarkAllDirtyMessage extends BaseWorkerMessage {
type: "mark_all_dirty";
}
export interface RefreshPaletteMessage extends BaseWorkerMessage {
type: "refresh_palette";
}
export interface RefreshTerrainMessage extends BaseWorkerMessage {
type: "refresh_terrain";
}
export interface TickRendererMessage extends BaseWorkerMessage {
type: "tick_renderer";
}
export interface ViewSize {
width: number;
height: number;
}
export interface ViewTransform {
scale: number;
offsetX: number;
offsetY: number;
}
export interface RenderFrameMessage extends BaseWorkerMessage {
type: "render_frame";
/**
* Optional per-frame view state. This allows the main thread to coalesce
* high-frequency camera updates into the existing render message.
*/
viewSize?: ViewSize;
viewTransform?: ViewTransform;
}
// Renderer messages from worker to main thread
export interface RenderDoneMessage extends BaseWorkerMessage {
type: "render_done";
/**
* Timestamp (performance.now()) in the worker right before starting work.
*/
startedAt?: number;
/**
* Timestamp (performance.now()) in the worker right after finishing work.
*/
endedAt?: number;
/**
* Echo of RenderFrameMessage.sentAtWallMs (if provided) so callers can
* compute queue/processing latency without storing state.
*/
sentAtWallMs?: number;
/**
* Timestamps (Date.now()) in the worker. Use these for cross-thread latency
* (Firefox may use a different time origin for performance.now()).
*/
startedAtWallMs?: number;
endedAtWallMs?: number;
/**
* Optional breakdown from the worker's renderAsync implementation.
* All values are milliseconds.
*/
renderWaitPrevGpuMs?: number;
renderCpuMs?: number;
renderGetTextureMs?: number;
renderGpuWaitMs?: number;
renderWaitPrevGpuTimedOut?: boolean;
renderGpuWaitTimedOut?: boolean;
}
export interface RendererReadyMessage extends BaseWorkerMessage {
type: "renderer_ready";
ok: boolean;
error?: string;
}
export interface RendererMetricsMessage extends BaseWorkerMessage {
type: "renderer_metrics";
computeMs: number;
}
export interface SetWorkerDebugMessage extends BaseWorkerMessage {
type: "set_worker_debug";
enabled: boolean;
intervalMs?: number;
includeTrace?: boolean;
}
export interface WorkerMetricsMessage extends BaseWorkerMessage {
type: "worker_metrics";
intervalMs: number;
eventLoopLagMsAvg: number;
eventLoopLagMsMax: number;
simPumpDelayMsAvg: number;
simPumpDelayMsMax: number;
simPumpExecMsAvg: number;
simPumpExecMsMax: number;
msgCounts: Record<string, number>;
msgHandlerMsAvg: Record<string, number>;
msgHandlerMsMax: Record<string, number>;
msgQueueMsAvg: Record<string, number>;
msgQueueMsMax: Record<string, number>;
trace?: string[];
}
// Union types for type safety
export type MainThreadMessage =
| HeartbeatMessage
| InitMessage
| TurnMessage
| TileContextMessage
| PlayerActionsMessage
| PlayerProfileMessage
| PlayerBorderTilesMessage
| AttackAveragePositionMessage
| TransportShipSpawnMessage
| InitRendererMessage
| SetPatternsEnabledMessage
| SetPaletteMessage
| SetViewSizeMessage
| SetViewTransformMessage
| SetAlternativeViewMessage
| SetHighlightedOwnerMessage
| SetShaderSettingsMessage
| MarkTileMessage
| MarkAllDirtyMessage
| RefreshPaletteMessage
| RefreshTerrainMessage
| TickRendererMessage
| SetWorkerDebugMessage
| RenderFrameMessage;
// Message send from worker
export type WorkerMessage =
| InitializedMessage
| GameUpdateMessage
| TileContextResultMessage
| PlayerActionsResultMessage
| PlayerProfileResultMessage
| PlayerBorderTilesResultMessage
| AttackAveragePositionResultMessage
| TransportShipSpawnResultMessage
| RenderDoneMessage
| RendererReadyMessage
| RendererMetricsMessage
| WorkerMetricsMessage;