57 lines
2.2 KiB
TypeScript
57 lines
2.2 KiB
TypeScript
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;
|
|
}
|