import { useEffect } from "react"; import { useShellStore } from "./app/shellStore"; import "./ui/uiLayout.css"; import { DualDisplayFrame } from "./components/DualDisplayFrame"; import { installInput, releasePointerLock } from "./game/inputManager"; import { CombatBridge } from "./game/CombatBridge"; import { connectDpsMeter } from "./game/dpsMeterStore"; import { useCombatStore } from "./game/combatStore"; import { releaseDungeonGltfCache } from "./game/dungeonAssetCache"; import { clearDungeonRuntimeCaches } from "./game/dungeonRuntimeReset"; import { bossTestingSourceDungeonId, clearBossTestingDungeons, requireDungeonDefinition } from "./game/dungeonRegistry"; import { BossTestingBridge } from "./game/BossTestingBridge"; import { PartyBridge } from "./game/PartyBridge"; import { usePartyStore } from "./game/partyStore"; import { useGameStore } from "./game/store"; import { GameScene } from "./scene/GameScene"; import { LocalCompanionPanel } from "./ui/CompanionPanel"; import { Hud } from "./ui/Hud"; import { GameplayPanels } from "./ui/GameplayPanels"; import { MapPanel } from "./ui/MapPanel"; import { PauseMenu } from "./ui/PauseMenu"; import { SceneErrorBoundary } from "./ui/SceneErrorBoundary"; import { OnlineSessionBridge } from "./game/OnlineSessionBridge"; import { DungeonRunCheckpointBridge } from "./game/DungeonRunCheckpointBridge"; import { DungeonRunBridge } from "./game/DungeonRunBridge"; import { DungeonRaceBridge } from "./game/DungeonRaceBridge"; import { DungeonRaceHud } from "./ui/DungeonRaceHud"; import { DungeonRunResults } from "./ui/DungeonRunResults"; import { DungeonEncounterEffectBridge } from "./game/DungeonEncounterEffectBridge"; import { interactWithActiveDungeonObject } from "./game/dungeonWorldInteraction"; import { UiLayoutEditor } from "./ui/UiLayoutEditor"; import { activeUiLayout, currentUiDevice } from "./game/uiLayoutStore"; import { useUiLayoutStore } from "./game/uiLayoutStore"; import { profileInputBindings } from "./game/keybindPreferences"; import { KeybindsPanel } from "./ui/KeybindsPanel"; import { lootShelvedBoss, releaseShelvedGameRuntime, ShelvedGameBridges } from "@shelvedGameRuntime"; import { useDungeonSimulationStore } from "./game/dungeonSimulationStore"; import { DungeonSimulationHud } from "./ui/DungeonSimulationHud"; import { DungeonBossIntro } from "./ui/DungeonBossIntro"; import { useDungeonRouteStore } from "./game/dungeonRouteStore"; import { installCombatClock } from "./game/combatClock"; import { dungeonSimulationNow } from "./game/dungeonSimulationStore"; import { useDungeonRaceStore } from "./app/dungeonRaceStore"; import { BiteSizedEditor } from "./ui/BiteSizedEditor"; import { useBiteSizedLayoutsStore } from "./game/biteSizedLayoutsStore"; function InputBridge() { const overlay = useGameStore((state) => state.overlay); const companionOpen = useGameStore((state) => state.companionOpen); useEffect(() => installInput({ desktopActionBarsActive: () => currentUiDevice() === "pc" && activeUiLayout().wowBars, inputSuspended: () => useDungeonSimulationStore.getState().sessionMode !== "play" || useBiteSizedLayoutsStore.getState().panelFocused || useGameStore.getState().dungeonIntroActive || useGameStore.getState().raceStartBlocked || ["ui-layout", "keybinds", "dungeon-results", "boss-test-review", "report-issue"].includes(useGameStore.getState().overlay ?? ""), getBindings: (device) => { const preferences = useUiLayoutStore.getState().preferences; const bindings = profileInputBindings(preferences, device); for (let b = activeUiLayout().barCount; b < 5; b++) for (let s = 0; s < 12; s++) bindings[`bar:${b}:${s}`] = null; return bindings; }, castDesktopSlot: (bar, slot) => { const game = useGameStore.getState(); const button = activeUiLayout().bars[bar]?.slots[slot]; if (button?.abilityId) useCombatStore.getState().castAbility(button.abilityId, game.playerPosition, Date.now()); }, togglePanel: (panel) => useGameStore.getState().toggleOverlay(panel), togglePause: () => useGameStore.getState().togglePause(), toggleMap: () => useGameStore.getState().toggleMap(), toggleInventory: () => useGameStore.getState().toggleOverlay("inventory"), toggleSpellbook: () => useGameStore.getState().toggleOverlay("spellbook"), toggleTalents: () => useGameStore.getState().toggleOverlay("talents"), lootActiveBoss: () => interactWithActiveDungeonObject() || lootShelvedBoss(), castActionBinding: (layer, control) => { const game = useGameStore.getState(); useCombatStore.getState().castActionBinding(layer, control, game.playerPosition, Date.now()); }, cycleTarget: (direction) => { const game = useGameStore.getState(); usePartyStore.getState().clearSelection(); useCombatStore.getState().cycleTarget(direction, game.playerPosition); }, cyclePartyTarget: (direction) => { useCombatStore.getState().clearTarget(); usePartyStore.getState().cycleMember(direction); }, setPartyCommand: (command) => usePartyStore.getState().setCommand(command), recallParty: () => usePartyStore.getState().recallParty(), clearTarget: () => { useCombatStore.getState().clearTarget(); usePartyStore.getState().clearSelection(); }, groundTargetActive: () => useCombatStore.getState().pendingGroundTarget !== null, confirmGroundTarget: () => { useCombatStore.getState().confirmGroundTarget(); }, cancelGroundTarget: () => useCombatStore.getState().cancelGroundTarget(), gameplayActionsBlocked: () => { const game = useGameStore.getState(); return game.overlay !== null || game.companionOpen || useBiteSizedLayoutsStore.getState().editorMode === "edit"; }, setCameraLookActive: (active) => useGameStore.getState().setCameraLookActive(active), setInputMode: (mode) => useGameStore.getState().setInputMode(mode), setActionLayer: (layer) => useGameStore.getState().setActionLayer(layer), }), []); useEffect(() => () => releasePointerLock(), []); useEffect(() => { if (overlay || companionOpen) releasePointerLock(); }, [companionOpen, overlay]); return null; } export default function GameRuntime() { useEffect(connectDpsMeter, []); useEffect(() => installCombatClock(dungeonSimulationNow), []); useEffect(() => { void useDungeonRouteStore.getState().refresh(); }, []); const editingControls = useGameStore((state) => state.overlay === "keybinds" || state.overlay === "ui-layout"); const dungeonSimulation = useDungeonSimulationStore((state) => state.sessionMode !== "play"); useEffect(() => () => { const race = useDungeonRaceStore.getState(); if (race.inGame && useShellStore.getState().phase !== "game") void race.leave(); const activeDungeon = requireDungeonDefinition(useGameStore.getState().activeDungeonId); clearDungeonRuntimeCaches(); releaseDungeonGltfCache(activeDungeon); releaseShelvedGameRuntime(); const sourceDungeonId = bossTestingSourceDungeonId(activeDungeon.id); if (sourceDungeonId) { useGameStore.setState({ activeDungeonId: sourceDungeonId, bossTest: null, gmTestMode: false }); useShellStore.setState({ activeDungeonId: sourceDungeonId }); } clearBossTestingDungeons(); if (useShellStore.getState().phase !== "game") useBiteSizedLayoutsStore.setState({ editorMode: null, panelFocused: false }); }, []); return ( useGameStore.getState().setCompanionOpen(surface === "bottom")} top={
{dungeonSimulation ? : } {!dungeonSimulation && } {!dungeonSimulation && } {!dungeonSimulation && } {!dungeonSimulation && } {!dungeonSimulation && } {!dungeonSimulation && } {!dungeonSimulation && } {!dungeonSimulation && }
} bottom={} /> ); }