fix(debug): stabilize map debug controls

This commit is contained in:
Tom Boullay
2026-05-25 01:10:10 +02:00
parent f175ad6240
commit 4c42e11268
3 changed files with 76 additions and 30 deletions
+4 -1
View File
@@ -1,4 +1,5 @@
import { useDebugFolder } from "@/hooks/debug/useDebugFolder"; import { useDebugFolder } from "@/hooks/debug/useDebugFolder";
import { Debug } from "@/utils/debug/Debug";
import { import {
MAP_PERFORMANCE_GROUP_NAMES, MAP_PERFORMANCE_GROUP_NAMES,
MAP_PERFORMANCE_MODEL_NAMES, MAP_PERFORMANCE_MODEL_NAMES,
@@ -14,7 +15,9 @@ function toLabel(value: string): string {
} }
export function useMapPerformanceDebug(): void { export function useMapPerformanceDebug(): void {
useDebugFolder("Performance / Map", (folder) => { useDebugFolder("Map", (folder) => {
Debug.getInstance().addFogControl(folder);
const { const {
groups, groups,
models, models,
+48 -20
View File
@@ -17,12 +17,11 @@ interface DebugEvents {
} }
const DEBUG_FOLDER_ORDER = [ const DEBUG_FOLDER_ORDER = [
"La Fabrik",
"Lighting", "Lighting",
"Game", "Game",
"Interaction", "Interaction",
"Hand Tracking", "Hand Tracking",
"Performance / Map", "Map",
] as const; ] as const;
function isRecord(value: unknown): value is Record<string, unknown> { function isRecord(value: unknown): value is Record<string, unknown> {
@@ -100,14 +99,13 @@ export class Debug {
sceneMode: storedControls.sceneMode ?? "game", sceneMode: storedControls.sceneMode ?? "game",
}; };
this.gui = this.active ? new GUI({ title: "Debug" }) : null; this.gui = this.active ? new GUI({ title: "La Fabrik" }) : null;
if (this.gui) { if (this.gui) {
const folder = this.createFolder("La Fabrik", { open: true }); this.gui.open();
this.createOrderedFolders();
if (!folder) return; this.gui
folder
.add(this.controls, "cameraMode", { Player: "player", Debug: "debug" }) .add(this.controls, "cameraMode", { Player: "player", Debug: "debug" })
.name("Camera Mode") .name("Camera Mode")
.onChange((value: CameraMode) => { .onChange((value: CameraMode) => {
@@ -115,7 +113,7 @@ export class Debug {
this.saveAndEmit(); this.saveAndEmit();
}); });
folder this.gui
.add(this.controls, "sceneMode", { Game: "game", Physics: "physics" }) .add(this.controls, "sceneMode", { Game: "game", Physics: "physics" })
.name("Scene") .name("Scene")
.onChange((value: SceneMode) => { .onChange((value: SceneMode) => {
@@ -123,7 +121,7 @@ export class Debug {
this.saveAndEmit(); this.saveAndEmit();
}); });
folder this.gui
.add(this.controls, "showPerf") .add(this.controls, "showPerf")
.name("R3F Perf") .name("R3F Perf")
.onChange((value: boolean) => { .onChange((value: boolean) => {
@@ -131,7 +129,7 @@ export class Debug {
this.emit(); this.emit();
}); });
folder this.gui
.add(this.controls, "showDebugOverlay") .add(this.controls, "showDebugOverlay")
.name("Debug Overlay") .name("Debug Overlay")
.onChange((value: boolean) => { .onChange((value: boolean) => {
@@ -139,14 +137,6 @@ export class Debug {
this.emit(); this.emit();
}); });
folder
.add(this.controls, "fogEnabled")
.name("Fog")
.onChange((value: boolean) => {
this.controls.fogEnabled = value;
this.emit();
});
const handTrackingFolder = this.createFolder("Hand Tracking"); const handTrackingFolder = this.createFolder("Hand Tracking");
handTrackingFolder handTrackingFolder
@@ -180,8 +170,15 @@ export class Debug {
const existing = this.folders.get(name); const existing = this.folders.get(name);
if (existing) { if (existing) {
this.folderRefCounts.set(name, (this.folderRefCounts.get(name) ?? 0) + 1); const refCount = this.folderRefCounts.get(name) ?? 0;
return null;
if (refCount > 0) {
this.folderRefCounts.set(name, refCount + 1);
return null;
}
this.folderRefCounts.set(name, 1);
return existing;
} }
const folder = this.gui.addFolder(name); const folder = this.gui.addFolder(name);
@@ -198,6 +195,16 @@ export class Debug {
return folder; return folder;
} }
addFogControl(folder: GUI): void {
folder
.add(this.controls, "fogEnabled")
.name("Fog")
.onChange((value: boolean) => {
this.controls.fogEnabled = value;
this.emit();
});
}
destroyFolder(name: string): void { destroyFolder(name: string): void {
const folder = this.folders.get(name); const folder = this.folders.get(name);
const refCount = this.folderRefCounts.get(name); const refCount = this.folderRefCounts.get(name);
@@ -279,6 +286,27 @@ export class Debug {
this.emit(); this.emit();
} }
private createOrderedFolders(): void {
for (const folderName of DEBUG_FOLDER_ORDER) {
this.ensureFolder(folderName);
}
}
private ensureFolder(name: string): GUI | null {
if (!this.gui) return null;
const existing = this.folders.get(name);
if (existing) return existing;
const folder = this.gui.addFolder(name);
folder.close();
this.folders.set(name, folder);
this.folderRefCounts.set(name, 0);
this.sortFolders();
return folder;
}
private sortFolders(): void { private sortFolders(): void {
if (!this.gui) return; if (!this.gui) return;
+24 -9
View File
@@ -1,4 +1,4 @@
import { Suspense, useMemo, useRef, useState } from "react"; import { Suspense, useCallback, useMemo, useRef, useState } from "react";
import { useFrame, useThree } from "@react-three/fiber"; import { useFrame, useThree } from "@react-three/fiber";
import { CHUNK_CONFIG } from "@/data/world/fogConfig"; import { CHUNK_CONFIG } from "@/data/world/fogConfig";
import { useCameraMode } from "@/hooks/debug/useCameraMode"; import { useCameraMode } from "@/hooks/debug/useCameraMode";
@@ -106,16 +106,21 @@ export function VegetationSystem(): React.JSX.Element | null {
}, [data, groups, models]); }, [data, groups, models]);
const visibleChunks = streamingEnabled const visibleChunks = streamingEnabled
? chunks.filter((chunk) => activeChunkKeys.has(chunk.key)) ? chunks.filter((chunk) => {
if (activeChunkKeys.size > 0) {
return activeChunkKeys.has(chunk.key);
}
return (
Math.hypot(
chunk.centerX - camera.position.x,
chunk.centerZ - camera.position.z,
) <= CHUNK_CONFIG.loadRadius
);
})
: chunks; : chunks;
useFrame(({ clock }) => { const updateActiveChunks = useCallback(() => {
if (!streamingEnabled) return;
const now = clock.elapsedTime * 1000;
if (now - lastUpdateRef.current < CHUNK_CONFIG.updateInterval) return;
lastUpdateRef.current = now;
const nextKeys = new Set<string>(); const nextKeys = new Set<string>();
const cameraX = camera.position.x; const cameraX = camera.position.x;
const cameraZ = camera.position.z; const cameraZ = camera.position.z;
@@ -143,6 +148,16 @@ export function VegetationSystem(): React.JSX.Element | null {
} }
setActiveChunkKeys(nextKeys); setActiveChunkKeys(nextKeys);
}, [activeChunkKeys, camera, chunks]);
useFrame(({ clock }) => {
if (!streamingEnabled) return;
const now = clock.elapsedTime * 1000;
if (now - lastUpdateRef.current < CHUNK_CONFIG.updateInterval) return;
lastUpdateRef.current = now;
updateActiveChunks();
}); });
if (isLoading || !data) { if (isLoading || !data) {