Files
Genarrative/src/hooks/useTreasureFlow.ts
2026-04-21 18:27:46 +08:00

76 lines
1.9 KiB
TypeScript

import { useCallback } from 'react';
import { resolveRpgRuntimeChoice } from './rpg-runtime-story';
import { Character, GameState, StoryMoment, StoryOption } from '../types';
export function useTreasureFlow({
gameState,
runtime,
}: {
gameState: GameState;
runtime: {
currentStory: StoryMoment | null;
setGameState: (state: GameState) => void;
setCurrentStory: (story: StoryMoment) => void;
setAiError: (message: string | null) => void;
setIsLoading: (loading: boolean) => void;
buildFallbackStoryForState: (
state: GameState,
character: Character,
fallbackText?: string,
) => StoryMoment;
};
}) {
const handleTreasureInteraction = useCallback(
async (option: StoryOption) => {
if (
!gameState.playerCharacter ||
option.interaction?.kind !== 'treasure' ||
gameState.currentEncounter?.kind !== 'treasure'
) {
return false;
}
runtime.setAiError(null);
runtime.setIsLoading(true);
try {
const { hydratedSnapshot, nextStory } =
await resolveRpgRuntimeChoice({
gameState,
currentStory: runtime.currentStory,
option,
});
runtime.setGameState(hydratedSnapshot.gameState);
runtime.setCurrentStory(nextStory);
return true;
} catch (error) {
console.error(
'Failed to resolve treasure runtime action on the server:',
error,
);
runtime.setAiError(
error instanceof Error ? error.message : '宝藏动作执行失败',
);
if (!runtime.currentStory) {
runtime.setCurrentStory(
runtime.buildFallbackStoryForState(
gameState,
gameState.playerCharacter,
),
);
}
return false;
} finally {
runtime.setIsLoading(false);
}
},
[gameState, runtime],
);
return {
handleTreasureInteraction,
};
}