136 lines
4.5 KiB
TypeScript
136 lines
4.5 KiB
TypeScript
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<unknown>;
|
||
syncAgentCreationResultView: (
|
||
sessionId: string,
|
||
) => Promise<RpgCreationResultView | null>;
|
||
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,
|
||
};
|
||
}
|