import { useCallback } from 'react'; import type { RpgCreationResultView } from '../../../packages/shared/src/contracts/rpgCreationResultView'; import type { CustomWorldRuntimeLaunchOptions } from '../platform-entry/platformEntryTypes'; import { rpgCreationPreviewAdapter } from '../../services/rpg-creation/rpgCreationPreviewAdapter'; import type { CustomWorldProfile } from '../../types'; type UseRpgCreationEnterWorldParams = { isAgentDraftResultView: boolean; activeAgentSessionId: string | null; generatedCustomWorldProfile: CustomWorldProfile | null; handleCustomWorldSelect: ( customWorldProfile: CustomWorldProfile, options?: CustomWorldRuntimeLaunchOptions, ) => void; syncAgentDraftResultProfile: ( profile: CustomWorldProfile, ) => Promise<{ profile: CustomWorldProfile | null; view?: RpgCreationResultView | null }>; executePublishWorld: () => Promise; syncAgentCreationResultView: ( sessionId: string, ) => Promise; setGeneratedCustomWorldProfile: (profile: CustomWorldProfile | null) => void; }; /** * 统一“进入世界”前的最终同步策略。 * Agent 草稿结果进入游戏时只读当前结果页 profile,不再静默回退到会话侧旧快照。 */ export function useRpgCreationEnterWorld( params: UseRpgCreationEnterWorldParams, ) { const { isAgentDraftResultView, activeAgentSessionId, generatedCustomWorldProfile, handleCustomWorldSelect, syncAgentDraftResultProfile, executePublishWorld, syncAgentCreationResultView, setGeneratedCustomWorldProfile, } = params; const enterWorldForTestFromCurrentResult = useCallback(async () => { if (!generatedCustomWorldProfile) { return; } // 中文注释:作品测试必须复用“结果页当前真相源”。 // 用户在结果页看到并可能继续编辑的是 generatedCustomWorldProfile; // 如果这里又回退成 session 里的旧 preview,就会出现 // “结果页看起来已经是新版,但作品测试实际进入的是旧版快照”的错位。 if (isAgentDraftResultView && activeAgentSessionId) { setGeneratedCustomWorldProfile(generatedCustomWorldProfile); } handleCustomWorldSelect(generatedCustomWorldProfile, { // 中文注释:作品测试现在复用正式 play 运行链,只保留 // “返回结果页 + 禁止写正式持久化”的入口语义。 mode: 'play', disablePersistence: true, returnStage: 'custom-world-result', }); }, [ activeAgentSessionId, generatedCustomWorldProfile, handleCustomWorldSelect, isAgentDraftResultView, setGeneratedCustomWorldProfile, ]); const publishCurrentResult = useCallback(async () => { if (!generatedCustomWorldProfile) { return null; } if (!isAgentDraftResultView || !activeAgentSessionId) { return generatedCustomWorldProfile; } const syncedResult = await syncAgentDraftResultProfile( generatedCustomWorldProfile, ); const latestProfile = syncedResult.profile ?? rpgCreationPreviewAdapter.buildPreviewFromResultView(syncedResult.view); if (!latestProfile) { return null; } setGeneratedCustomWorldProfile(latestProfile); const canEnterPublishedWorld = syncedResult.view?.session.stage === 'published' && syncedResult.view.canEnterWorld; if (canEnterPublishedWorld) { const latestView = await syncAgentCreationResultView(activeAgentSessionId); return ( rpgCreationPreviewAdapter.buildPreviewFromResultView(latestView) ?? latestProfile ); } await executePublishWorld(); const latestView = await syncAgentCreationResultView(activeAgentSessionId); const publishedProfile = rpgCreationPreviewAdapter.buildPreviewFromResultView(latestView) ?? latestProfile; setGeneratedCustomWorldProfile(publishedProfile); return publishedProfile; }, [ activeAgentSessionId, executePublishWorld, generatedCustomWorldProfile, isAgentDraftResultView, setGeneratedCustomWorldProfile, syncAgentDraftResultProfile, syncAgentCreationResultView, ]); const enterWorldFromCurrentResult = useCallback(async () => { const publishedProfile = await publishCurrentResult(); if (publishedProfile) { handleCustomWorldSelect(publishedProfile); } }, [handleCustomWorldSelect, publishCurrentResult]); return { enterWorldFromCurrentResult, enterWorldForTestFromCurrentResult, publishCurrentResult, }; }