import { useEffect, useRef } from "react"; import { useShellStore } from "../app/shellStore"; import { exportDungeonEncounterCheckpointSnapshots, subscribeDungeonEncounterSnapshots, } from "./dungeonEncounterRuntime"; import { DUNGEON_RUN_CHECKPOINT_VERSION } from "./dungeonRunCheckpoint"; import { useGameStore } from "./store"; import { useDungeonRunStore } from "./dungeonRunStore"; function checkpointSignature(dungeonId: string): string { const game = useGameStore.getState(); const encounters = exportDungeonEncounterCheckpointSnapshots(dungeonId, 0); return JSON.stringify({ dungeonId, difficultyId: game.activeDifficultyId, spawn: game.activeSpawn, encounters, run: useDungeonRunStore.getState().progress, }); } /** Persists only reset-projected state when encounter progress reaches a new stable revision. */ export function DungeonRunCheckpointBridge() { const phase = useShellStore((state) => state.phase); const activeCharacterId = useShellStore((state) => state.activeCharacter?.id ?? null); const lastSignature = useRef(""); useEffect(() => { if (phase !== "game" || !activeCharacterId) return undefined; const save = () => { const game = useGameStore.getState(); if (game.gameMode !== "dungeon" || game.gmTestMode) return; const signature = checkpointSignature(game.activeDungeonId); if (signature === lastSignature.current) return; lastSignature.current = signature; const encounters = exportDungeonEncounterCheckpointSnapshots(game.activeDungeonId, 0); useShellStore.getState().saveActiveDungeonRunCheckpoint({ version: DUNGEON_RUN_CHECKPOINT_VERSION, dungeonId: game.activeDungeonId, difficultyId: game.activeDifficultyId, checkpointId: encounters.find((entry) => entry.checkpointId)?.checkpointId ?? "entrance", spawn: game.activeSpawn, encounters, savedAt: Date.now(), run: useDungeonRunStore.getState().progress ?? undefined, }); }; save(); const unsubscribeEncounters = subscribeDungeonEncounterSnapshots(save); const unsubscribeRun = useDungeonRunStore.subscribe(save); return () => { unsubscribeEncounters(); unsubscribeRun(); }; }, [activeCharacterId, phase]); return null; }