From aa211d16b7be6044068872b64782a85d0601b63c Mon Sep 17 00:00:00 2001 From: Tom Boullay Date: Tue, 28 Apr 2026 16:35:33 +0200 Subject: [PATCH] fix: persist debug modes and skip missing map models --- src/utils/debug/Debug.ts | 67 +++++++++++++++++++++++++++++++---- src/utils/loadMapSceneData.ts | 6 +++- 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/src/utils/debug/Debug.ts b/src/utils/debug/Debug.ts index 2c97d30..9f6e121 100644 --- a/src/utils/debug/Debug.ts +++ b/src/utils/debug/Debug.ts @@ -2,6 +2,41 @@ import GUI from "lil-gui"; import type { CameraMode, SceneMode } from "@/types/debug"; import { isDebugEnabled } from "@/utils/debug/isDebugEnabled"; +const DEBUG_CONTROLS_STORAGE_KEY = "la-fabrik-debug-controls"; + +interface StoredDebugControls { + cameraMode: CameraMode; + sceneMode: SceneMode; +} + +function isCameraMode(value: unknown): value is CameraMode { + return value === "player" || value === "debug"; +} + +function isSceneMode(value: unknown): value is SceneMode { + return value === "game" || value === "physics"; +} + +function getStoredDebugControls(): Partial { + try { + const rawValue = window.localStorage.getItem(DEBUG_CONTROLS_STORAGE_KEY); + if (!rawValue) return {}; + + const parsedValue = JSON.parse(rawValue) as Partial; + + return { + ...(isCameraMode(parsedValue.cameraMode) + ? { cameraMode: parsedValue.cameraMode } + : {}), + ...(isSceneMode(parsedValue.sceneMode) + ? { sceneMode: parsedValue.sceneMode } + : {}), + }; + } catch { + return {}; + } +} + export class Debug { private static instance: Debug | null = null; @@ -14,10 +49,6 @@ export class Debug { cameraMode: CameraMode; showInteractionSpheres: boolean; sceneMode: SceneMode; - } = { - cameraMode: "player", - showInteractionSpheres: false, - sceneMode: "game", }; static getInstance(): Debug { @@ -30,6 +61,14 @@ export class Debug { private constructor() { this.active = isDebugEnabled(); + const storedControls = getStoredDebugControls(); + + this.controls = { + cameraMode: storedControls.cameraMode ?? "player", + showInteractionSpheres: false, + sceneMode: storedControls.sceneMode ?? "game", + }; + this.gui = this.active ? new GUI({ title: "La-Fabrik Debug" }) : null; if (this.gui) { @@ -42,7 +81,7 @@ export class Debug { .name("Camera Mode") .onChange((value: CameraMode) => { this.controls.cameraMode = value; - this.emit(); + this.saveAndEmit(); }); folder @@ -50,7 +89,7 @@ export class Debug { .name("Scene") .onChange((value: SceneMode) => { this.controls.sceneMode = value; - this.emit(); + this.saveAndEmit(); }); folder @@ -122,4 +161,20 @@ export class Debug { private emit(): void { this.listeners.forEach((listener) => listener()); } + + private saveAndEmit(): void { + try { + window.localStorage.setItem( + DEBUG_CONTROLS_STORAGE_KEY, + JSON.stringify({ + cameraMode: this.controls.cameraMode, + sceneMode: this.controls.sceneMode, + }), + ); + } catch { + // Debug persistence is optional; controls still work if storage is blocked. + } + + this.emit(); + } } diff --git a/src/utils/loadMapSceneData.ts b/src/utils/loadMapSceneData.ts index 4735f07..27ef6f8 100644 --- a/src/utils/loadMapSceneData.ts +++ b/src/utils/loadMapSceneData.ts @@ -3,6 +3,7 @@ import { parseMapNodes } from "@/utils/mapNodeValidation"; const MAP_JSON_PATH = "/map.json"; const MODEL_FILE_NAME = "model.gltf"; +const HTML_CONTENT_TYPE = "text/html"; type ModelEntry = [modelName: string, modelUrl: string]; export async function loadMapSceneData(): Promise { @@ -31,8 +32,11 @@ async function loadMapModelUrls( try { const response = await fetch(modelUrl, { method: "HEAD" }); + const contentType = response.headers.get("content-type") ?? ""; const modelEntry: ModelEntry = [modelName, modelUrl]; - return response.ok ? modelEntry : null; + return response.ok && !contentType.includes(HTML_CONTENT_TYPE) + ? modelEntry + : null; } catch { return null; }