fix: persist debug modes and skip missing map models
This commit is contained in:
@@ -2,6 +2,41 @@ import GUI from "lil-gui";
|
|||||||
import type { CameraMode, SceneMode } from "@/types/debug";
|
import type { CameraMode, SceneMode } from "@/types/debug";
|
||||||
import { isDebugEnabled } from "@/utils/debug/isDebugEnabled";
|
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<StoredDebugControls> {
|
||||||
|
try {
|
||||||
|
const rawValue = window.localStorage.getItem(DEBUG_CONTROLS_STORAGE_KEY);
|
||||||
|
if (!rawValue) return {};
|
||||||
|
|
||||||
|
const parsedValue = JSON.parse(rawValue) as Partial<StoredDebugControls>;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...(isCameraMode(parsedValue.cameraMode)
|
||||||
|
? { cameraMode: parsedValue.cameraMode }
|
||||||
|
: {}),
|
||||||
|
...(isSceneMode(parsedValue.sceneMode)
|
||||||
|
? { sceneMode: parsedValue.sceneMode }
|
||||||
|
: {}),
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class Debug {
|
export class Debug {
|
||||||
private static instance: Debug | null = null;
|
private static instance: Debug | null = null;
|
||||||
|
|
||||||
@@ -14,10 +49,6 @@ export class Debug {
|
|||||||
cameraMode: CameraMode;
|
cameraMode: CameraMode;
|
||||||
showInteractionSpheres: boolean;
|
showInteractionSpheres: boolean;
|
||||||
sceneMode: SceneMode;
|
sceneMode: SceneMode;
|
||||||
} = {
|
|
||||||
cameraMode: "player",
|
|
||||||
showInteractionSpheres: false,
|
|
||||||
sceneMode: "game",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static getInstance(): Debug {
|
static getInstance(): Debug {
|
||||||
@@ -30,6 +61,14 @@ export class Debug {
|
|||||||
|
|
||||||
private constructor() {
|
private constructor() {
|
||||||
this.active = isDebugEnabled();
|
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;
|
this.gui = this.active ? new GUI({ title: "La-Fabrik Debug" }) : null;
|
||||||
|
|
||||||
if (this.gui) {
|
if (this.gui) {
|
||||||
@@ -42,7 +81,7 @@ export class Debug {
|
|||||||
.name("Camera Mode")
|
.name("Camera Mode")
|
||||||
.onChange((value: CameraMode) => {
|
.onChange((value: CameraMode) => {
|
||||||
this.controls.cameraMode = value;
|
this.controls.cameraMode = value;
|
||||||
this.emit();
|
this.saveAndEmit();
|
||||||
});
|
});
|
||||||
|
|
||||||
folder
|
folder
|
||||||
@@ -50,7 +89,7 @@ export class Debug {
|
|||||||
.name("Scene")
|
.name("Scene")
|
||||||
.onChange((value: SceneMode) => {
|
.onChange((value: SceneMode) => {
|
||||||
this.controls.sceneMode = value;
|
this.controls.sceneMode = value;
|
||||||
this.emit();
|
this.saveAndEmit();
|
||||||
});
|
});
|
||||||
|
|
||||||
folder
|
folder
|
||||||
@@ -122,4 +161,20 @@ export class Debug {
|
|||||||
private emit(): void {
|
private emit(): void {
|
||||||
this.listeners.forEach((listener) => listener());
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { parseMapNodes } from "@/utils/mapNodeValidation";
|
|||||||
|
|
||||||
const MAP_JSON_PATH = "/map.json";
|
const MAP_JSON_PATH = "/map.json";
|
||||||
const MODEL_FILE_NAME = "model.gltf";
|
const MODEL_FILE_NAME = "model.gltf";
|
||||||
|
const HTML_CONTENT_TYPE = "text/html";
|
||||||
type ModelEntry = [modelName: string, modelUrl: string];
|
type ModelEntry = [modelName: string, modelUrl: string];
|
||||||
|
|
||||||
export async function loadMapSceneData(): Promise<SceneData | null> {
|
export async function loadMapSceneData(): Promise<SceneData | null> {
|
||||||
@@ -31,8 +32,11 @@ async function loadMapModelUrls(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(modelUrl, { method: "HEAD" });
|
const response = await fetch(modelUrl, { method: "HEAD" });
|
||||||
|
const contentType = response.headers.get("content-type") ?? "";
|
||||||
const modelEntry: ModelEntry = [modelName, modelUrl];
|
const modelEntry: ModelEntry = [modelName, modelUrl];
|
||||||
return response.ok ? modelEntry : null;
|
return response.ok && !contentType.includes(HTML_CONTENT_TYPE)
|
||||||
|
? modelEntry
|
||||||
|
: null;
|
||||||
} catch {
|
} catch {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user