import { useCallback, useEffect, useState } from 'react'; import { pushAppHistoryPath, resolvePathForSelectionStage, resolveSelectionStageFromPath, } from '../../routing/appPageRoutes'; import type { GameState } from '../../types'; import type { GameCanvasEntitySelection } from '../GameCanvas'; import type { SelectionStage } from '../platform-entry/platformEntryTypes'; type OverlayPanel = 'character' | 'inventory' | null; function useLazyModalMount(active: boolean) { const [shouldMount, setShouldMount] = useState(active); useEffect(() => { if (active) { setShouldMount(true); } }, [active]); return shouldMount; } /** * RPG 运行态 overlay 与独立面板状态。 * 负责保留现有弹窗装配顺序,同时把壳层 UI 状态从旧 GameShell 命名迁出。 */ export function useRpgRuntimeOverlayState(params: { gameState: GameState; isMapOpen: boolean; characterChatModalOpen: boolean; hasNpcModalOpen: boolean; }) { const { gameState, isMapOpen, characterChatModalOpen, hasNpcModalOpen, } = params; const [selectionStage, setRawSelectionStage] = useState(() => resolveSelectionStageFromPath(window.location.pathname), ); const [overlayPanel, setOverlayPanel] = useState(null); const [selectedSceneEntity, setSelectedSceneEntity] = useState(null); const [showTeamModal, setShowTeamModal] = useState(false); const setSelectionStage = useCallback((stage: SelectionStage) => { setRawSelectionStage(stage); pushAppHistoryPath(resolvePathForSelectionStage(stage)); }, []); useEffect(() => { const syncStageFromHistory = () => { setRawSelectionStage( resolveSelectionStageFromPath(window.location.pathname), ); }; window.addEventListener('popstate', syncStageFromHistory); return () => window.removeEventListener('popstate', syncStageFromHistory); }, []); useEffect(() => { setSelectedSceneEntity(null); }, [gameState.currentScenePreset?.id, gameState.playerCharacter?.id]); const shouldMountAdventureEntityModal = useLazyModalMount( Boolean(selectedSceneEntity), ); const shouldMountCampModal = useLazyModalMount(showTeamModal); const shouldMountMapModal = useLazyModalMount(isMapOpen); const shouldMountCharacterChatModal = useLazyModalMount( characterChatModalOpen, ); const shouldMountNpcModals = useLazyModalMount(hasNpcModalOpen); const openOverlayPanel = (panel: Exclude) => { setSelectedSceneEntity(null); setOverlayPanel(panel); }; const closeOverlayPanel = () => setOverlayPanel(null); const openPartyMemberDetails = (selection: GameCanvasEntitySelection) => setSelectedSceneEntity(selection); const closeAdventureEntityModal = () => setSelectedSceneEntity(null); const openCampModal = () => setShowTeamModal(true); const closeCampModal = () => setShowTeamModal(false); const resetSelectionFlow = () => setSelectionStage('platform'); const resetForSaveAndExit = () => { setSelectedSceneEntity(null); setOverlayPanel(null); setShowTeamModal(false); setSelectionStage('platform'); }; return { selectionStage, setSelectionStage, resetSelectionFlow, overlayPanel, openOverlayPanel, closeOverlayPanel, selectedSceneEntity, setSelectedSceneEntity, openPartyMemberDetails, closeAdventureEntityModal, showTeamModal, openCampModal, closeCampModal, resetForSaveAndExit, shouldMountAdventureEntityModal, shouldMountCampModal, shouldMountMapModal, shouldMountCharacterChatModal, shouldMountNpcModals, }; }