allow selecting different game types

This commit is contained in:
Brian Beck 2025-12-14 11:06:57 -08:00
parent 7f75ed84da
commit 049566cdbb
56 changed files with 436 additions and 207 deletions

View file

@ -1,5 +1,5 @@
"use client";
import { useState, useEffect, useCallback, Suspense } from "react";
import { useState, useEffect, useCallback, Suspense, useMemo } from "react";
import { useSearchParams, useRouter } from "next/navigation";
import { Canvas, GLProps } from "@react-three/fiber";
import { NoToneMapping, SRGBColorSpace, PCFShadowMap } from "three";
@ -30,10 +30,19 @@ function MapInspector() {
const searchParams = useSearchParams();
const router = useRouter();
// Initialize state from query params
const [missionName, setMissionName] = useState(
searchParams.get("mission") || "TWL2_WoodyMyrk",
const [initialMissionName, initialMissionType] = useMemo(
() => (searchParams.get("mission") || "RiverDance:CTF").split("~"),
[],
);
const [missionName, setMissionName] = useState(initialMissionName);
const availableMissionTypes = getMissionInfo(missionName).missionTypes;
const [missionType, setMissionType] = useState(() =>
initialMissionType && availableMissionTypes.includes(initialMissionType)
? initialMissionType
: availableMissionTypes[0],
);
const isOnlyMissionType = availableMissionTypes.length === 1;
const [loadingProgress, setLoadingProgress] = useState(0);
const [showLoadingIndicator, setShowLoadingIndicator] = useState(true);
const isLoading = loadingProgress < 1;
@ -64,9 +73,12 @@ function MapInspector() {
// Update query params when state changes
useEffect(() => {
const params = new URLSearchParams();
params.set("mission", missionName);
const value = isOnlyMissionType
? missionName
: `${missionName}~${missionType}`;
params.set("mission", value);
router.replace(`?${params.toString()}`, { scroll: false });
}, [missionName, router]);
}, [missionName, missionType, isOnlyMissionType, router]);
const handleLoadingChange = useCallback(
(_loading: boolean, progress: number = 0) => {
@ -94,13 +106,19 @@ function MapInspector() {
</div>
</div>
)}
<Canvas frameloop="always" gl={glSettings} shadows={{ type: PCFShadowMap }}>
<Canvas
frameloop="always"
gl={glSettings}
shadows={{ type: PCFShadowMap }}
>
<CamerasProvider>
<AudioProvider>
<Mission
key={missionName}
key={`${missionName}~${missionType}`}
name={missionName}
missionType={missionType}
onLoadingChange={handleLoadingChange}
setMissionType={setMissionType}
/>
<ObserverCamera />
<DebugElements />
@ -111,7 +129,11 @@ function MapInspector() {
</div>
<InspectorControls
missionName={missionName}
onChangeMission={setMissionName}
missionType={missionType}
onChangeMission={({ missionName, missionType }) => {
setMissionName(missionName);
setMissionType(missionType);
}}
/>
</SettingsProvider>
</main>

View file

@ -61,6 +61,10 @@ main {
z-index: 1;
}
input[type="range"] {
max-width: 80px;
}
.CheckboxField {
display: flex;
align-items: center;
@ -73,11 +77,6 @@ main {
gap: 6px;
}
#fovInput,
#speedInput {
max-width: 80px;
}
.StaticShapeLabel {
background: rgba(0, 0, 0, 0.5);
color: #fff;
@ -85,6 +84,7 @@ main {
white-space: nowrap;
padding: 1px 3px;
border-radius: 1px;
text-align: center;
}
.StatsPanel {
@ -133,7 +133,7 @@ main {
}
.MissionSelect-input {
width: 240px;
width: 280px;
padding: 6px 36px 6px 8px;
font-size: 14px;
border: 1px solid rgba(255, 255, 255, 0.3);
@ -152,8 +152,37 @@ main {
}
.MissionSelect-input::placeholder {
color: transparent;
}
.MissionSelect-selectedValue {
position: absolute;
left: 8px;
right: 36px;
display: flex;
align-items: center;
gap: 6px;
pointer-events: none;
overflow: hidden;
}
.MissionSelect-input[aria-expanded="true"] ~ .MissionSelect-selectedValue {
display: none;
}
.MissionSelect-selectedName {
color: #fff;
font-weight: 600;
font-size: 14px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
flex-shrink: 1;
min-width: 0;
}
.MissionSelect-selectedValue > .MissionSelect-itemType {
flex-shrink: 0;
}
.MissionSelect-popover {
@ -246,6 +275,10 @@ main {
color: #fff;
}
.MissionSelect-itemType:hover {
background: rgba(255, 157, 0, 0.7);
}
.MissionSelect-itemMissionName {
font-size: 12px;
color: rgba(255, 255, 255, 0.5);