Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/architecture/OVERVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -786,6 +786,10 @@ Browsers throttle `requestAnimationFrame` and `setInterval` to ~1fps when tabs a

When tab is visible, Phaser uses its normal RAF-based loop. When hidden, the worker takes over to keep overlay state synchronized with game state.

### Debug Logging (Worker Mode)

Debug categories are toggled in the Options menu and forwarded to the game worker via `WorkerBridge` (`setDebugSettings`). Worker-side systems use `debugLogger` with worker-local settings so AI/pathfinding logs respect the same category filters as the main thread.

### Performance Workers

Vision and AI workers offload computation from the main thread:
Expand Down
13 changes: 13 additions & 0 deletions src/components/game/WebGPUGameCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,9 @@ export function WebGPUGameCanvas() {
// Initialize the worker
await bridge.initialize();

// Sync debug settings to worker for category filtering
bridge.setDebugSettings(useUIStore.getState().debugSettings);

// Set terrain data on worker
bridge.setTerrainGrid(CURRENT_MAP.terrain);

Expand Down Expand Up @@ -602,6 +605,16 @@ export function WebGPUGameCanvas() {
}
}, [isLandingMode, landingBuildingId, isBuilding, refs.placementPreview]);

// Sync debug settings to worker
useEffect(() => {
const unsubscribe = useUIStore.subscribe((state: UIState, prevState: UIState) => {
if (state.debugSettings === prevState.debugSettings) return;
workerBridgeRef.current?.setDebugSettings(state.debugSettings);
});

return () => unsubscribe();
}, []);

// Subscribe to overlay settings changes
useEffect(() => {
const unsubscribe = useUIStore.subscribe((state: UIState, prevState: UIState) => {
Expand Down
6 changes: 6 additions & 0 deletions src/engine/workers/GameWorker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import type {
} from './types';
import type { GameConfig, GameState, TerrainCell } from '../core/Game';
import { dispatchCommand, type GameCommand } from '../core/GameCommand';
import { setWorkerDebugSettings } from '@/utils/debugLogger';

// ============================================================================
// WORKER GAME CLASS
Expand Down Expand Up @@ -1180,6 +1181,11 @@ self.onmessage = async (event: MessageEvent<MainToWorkerMessage>) => {
break;
}

case 'setDebugSettings': {
setWorkerDebugSettings(message.settings);
break;
}

case 'command': {
if (!game) return;
game.issueCommand(message.command);
Expand Down
9 changes: 9 additions & 0 deletions src/engine/workers/WorkerBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { RenderStateWorldAdapter } from './RenderStateAdapter';
import type { MapData } from '@/data/maps';
import type { GameConfig, GameState, TerrainCell } from '../core/Game';
import type { AIDifficulty } from '../systems/EnhancedAISystem';
import type { DebugSettings } from '@/store/uiStore';
import { EventBus } from '../core/EventBus';
import {
isMultiplayerMode,
Expand Down Expand Up @@ -383,6 +384,14 @@ export class WorkerBridge {
this.worker?.postMessage({ type: 'registerAI', playerId, difficulty } satisfies MainToWorkerMessage);
}

// ============================================================================
// DEBUG SETTINGS
// ============================================================================

public setDebugSettings(settings: DebugSettings): void {
this.worker?.postMessage({ type: 'setDebugSettings', settings } satisfies MainToWorkerMessage);
}

// ============================================================================
// ENTITY SPAWNING
// ============================================================================
Expand Down
2 changes: 2 additions & 0 deletions src/engine/workers/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type { ArmorType } from '../components/Health';
import type { GameState, TerrainCell, GameConfig } from '../core/Game';
import type { AIDifficulty } from '../systems/EnhancedAISystem';
import type { GameCommand } from '../core/GameCommand';
import type { DebugSettings } from '@/store/uiStore';

// ============================================================================
// RENDER STATE - Data transferred from worker to main thread for rendering
Expand Down Expand Up @@ -361,6 +362,7 @@ export type MainToWorkerMessage =
| { type: 'stop' }
| { type: 'pause' }
| { type: 'resume' }
| { type: 'setDebugSettings'; settings: DebugSettings }
| { type: 'command'; command: GameCommand }
| { type: 'setTerrain'; terrain: TerrainCell[][] }
| { type: 'setNavMesh'; positions: Float32Array; indices: Uint32Array }
Expand Down
19 changes: 16 additions & 3 deletions src/utils/debugLogger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,28 @@ const categoryToSettingKey: Record<DebugCategory, keyof DebugSettings> = {
performance: 'debugPerformance',
};

let workerDebugSettings: DebugSettings | null = null;

export function setWorkerDebugSettings(settings: DebugSettings): void {
workerDebugSettings = settings;
}

function getDebugSettings(): DebugSettings | null {
if (typeof window === 'undefined') {
return workerDebugSettings;
}

return useUIStore.getState().debugSettings;
}

/**
* Check if debugging is enabled for a specific category
*/
function isEnabled(category: DebugCategory): boolean {
const state = useUIStore.getState();
const { debugSettings } = state;
const debugSettings = getDebugSettings();

// Check master toggle first
if (!debugSettings.debugEnabled) {
if (!debugSettings || !debugSettings.debugEnabled) {
return false;
}

Expand Down
46 changes: 46 additions & 0 deletions tests/utils/debugLogger.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { describe, it, expect, beforeEach } from 'vitest';
import type { DebugSettings } from '@/store/uiStore';
import { debugLog, setWorkerDebugSettings } from '@/utils/debugLogger';

const baseSettings: DebugSettings = {
debugEnabled: false,
debugAnimation: false,
debugMesh: false,
debugTerrain: false,
debugShaders: false,
debugPostProcessing: false,
debugBuildingPlacement: false,
debugCombat: false,
debugResources: false,
debugProduction: false,
debugSpawning: false,
debugAI: false,
debugPathfinding: false,
debugAssets: false,
debugInitialization: false,
debugAudio: false,
debugNetworking: false,
debugPerformance: false,
};

const createSettings = (overrides: Partial<DebugSettings>): DebugSettings => ({
...baseSettings,
...overrides,
});

describe('debugLogger worker settings', () => {
beforeEach(() => {
setWorkerDebugSettings(baseSettings);
});

it('disables categories when master toggle is off', () => {
setWorkerDebugSettings(createSettings({ debugEnabled: false, debugAI: true }));
expect(debugLog.isEnabled('ai')).toBe(false);
});

it('respects category toggles when master is on', () => {
setWorkerDebugSettings(createSettings({ debugEnabled: true, debugAI: true, debugResources: false }));
expect(debugLog.isEnabled('ai')).toBe(true);
expect(debugLog.isEnabled('resources')).toBe(false);
});
});