Files
Genarrative/src/RpgRuntimeApp.tsx
2026-04-28 02:05:12 +08:00

63 lines
1.7 KiB
TypeScript

import { useEffect, useRef } from 'react';
import { RpgRuntimeShell } from './components/rpg-runtime-shell/RpgRuntimeShell';
import { useRpgRuntimeSession } from './hooks/rpg-session/useRpgRuntimeSession';
import type { HydratedSavedGameSnapshot } from './persistence/runtimeSnapshotTypes';
import type { CustomWorldProfile } from './types';
export type RpgRuntimeAppIntent =
| {
token: number;
kind: 'custom-world';
profile: CustomWorldProfile;
mode?: 'play';
disablePersistence?: boolean;
exitToResult?: boolean;
}
| {
token: number;
kind: 'snapshot';
snapshot: HydratedSavedGameSnapshot | null;
};
export function RpgRuntimeApp({
initialIntent,
onExitRuntime,
}: {
initialIntent: RpgRuntimeAppIntent | null;
onExitRuntime?: () => void;
}) {
const gameShellProps = useRpgRuntimeSession();
const handledIntentTokenRef = useRef<number | null>(null);
useEffect(() => {
if (!initialIntent || handledIntentTokenRef.current === initialIntent.token) {
return;
}
handledIntentTokenRef.current = initialIntent.token;
if (initialIntent.kind === 'custom-world') {
gameShellProps.entry.handleCustomWorldSelect(initialIntent.profile, {
mode: initialIntent.mode ?? 'play',
disablePersistence: initialIntent.disablePersistence,
});
return;
}
gameShellProps.entry.handleContinueGame(initialIntent.snapshot);
}, [gameShellProps.entry, initialIntent]);
return (
<RpgRuntimeShell
{...gameShellProps}
onExitRuntimePreview={onExitRuntime}
showRuntimePreviewExit={
initialIntent?.kind === 'custom-world' &&
initialIntent.exitToResult === true
}
/>
);
}
export default RpgRuntimeApp;