This commit is contained in:
2026-05-01 00:41:33 +08:00
49 changed files with 7540 additions and 157 deletions

View File

@@ -19,6 +19,14 @@ import type {
SubmitBigFishInputRequest,
} from '../../../packages/shared/src/contracts/bigFish';
import type { BigFishWorkSummary } from '../../../packages/shared/src/contracts/bigFishWorkSummary';
import type {
CreateMatch3DSessionRequest,
ExecuteMatch3DActionRequest,
Match3DActionResponse,
Match3DAgentSessionSnapshot,
Match3DSessionResponse,
SendMatch3DMessageRequest,
} from '../../../packages/shared/src/contracts/match3dAgent';
import type {
PuzzleAgentActionRequest,
PuzzleAgentOperationRecord,
@@ -75,6 +83,7 @@ import {
readCustomWorldAgentUiState,
shouldRestoreCustomWorldAgentUiState,
} from '../../services/customWorldAgentUiState';
import { match3dCreationClient } from '../../services/match3d-creation';
import {
buildBigFishGenerationAnchorEntries,
buildMiniGameDraftGenerationProgress,
@@ -652,6 +661,20 @@ const BigFishRuntimeShell = lazy(async () => {
};
});
const Match3DAgentWorkspace = lazy(async () => {
const module = await import('../match3d-creation/Match3DAgentWorkspace');
return {
default: module.Match3DAgentWorkspace,
};
});
const Match3DDraftReadyView = lazy(async () => {
const module = await import('../match3d-creation/Match3DDraftReadyView');
return {
default: module.Match3DDraftReadyView,
};
});
const CustomWorldCreationHub = lazy(async () => {
const module = await import('../custom-world-home/CustomWorldCreationHub');
return {
@@ -858,6 +881,11 @@ export function PlatformEntryFlowShellImpl({
resolveRpgCreationErrorMessage(error, fallback),
[],
);
const resolveMatch3DErrorMessage = useCallback(
(error: unknown, fallback: string) =>
resolveRpgCreationErrorMessage(error, fallback),
[],
);
const refreshBigFishShelf = useCallback(async () => {
setIsBigFishLoadingLibrary(true);
@@ -1237,6 +1265,44 @@ export function PlatformEntryFlowShellImpl({
},
});
const match3dFlow = usePlatformCreationAgentFlowController<
Match3DAgentSessionSnapshot,
CreateMatch3DSessionRequest,
Match3DSessionResponse,
SendMatch3DMessageRequest,
ExecuteMatch3DActionRequest,
Match3DActionResponse
>({
client: {
createSession: match3dCreationClient.createSession,
getSession: match3dCreationClient.getSession,
streamMessage: match3dCreationClient.streamMessage,
executeAction: match3dCreationClient.executeAction,
selectSession: (response) => response.session,
},
createPayload: {},
workspaceStage: 'match3d-agent-workspace',
resultStage: 'match3d-result',
platformStage: 'platform',
isCompileAction: (payload) => payload.action === 'match3d_compile_draft',
resolveErrorMessage: resolveMatch3DErrorMessage,
errorMessages: {
open: '开启抓大鹅共创工作台失败。',
restoreMissingSession: '这份抓大鹅草稿缺少会话信息,请重新开始创作。',
restore: '读取抓大鹅创作草稿失败。',
submit: '发送抓大鹅共创消息失败。',
execute: '执行抓大鹅操作失败。',
},
enterCreateTab,
setSelectionStage,
onSessionOpened: () => {
setShowCreationTypeModal(false);
},
onActionComplete: ({ response, setSession }) => {
setSession(response.session);
},
});
const puzzleFlow = usePlatformCreationAgentFlowController<
PuzzleAgentSessionSnapshot,
CreatePuzzleAgentSessionRequest,
@@ -1356,6 +1422,16 @@ export function PlatformEntryFlowShellImpl({
const streamingBigFishReplyText = bigFishFlow.streamingReplyText;
const isStreamingBigFishReply = bigFishFlow.isStreamingReply;
const match3dSession = match3dFlow.session;
const match3dError = match3dFlow.error;
const setMatch3DSession = match3dFlow.setSession;
const setMatch3DError = match3dFlow.setError;
const isMatch3DBusy = match3dFlow.isBusy;
const streamingMatch3DReplyText = match3dFlow.streamingReplyText;
const setStreamingMatch3DReplyText = match3dFlow.setStreamingReplyText;
const isStreamingMatch3DReply = match3dFlow.isStreamingReply;
const setIsStreamingMatch3DReply = match3dFlow.setIsStreamingReply;
const puzzleSession = puzzleFlow.session;
const puzzleError = puzzleFlow.error;
const setPuzzleError = puzzleFlow.setError;
@@ -1379,6 +1455,20 @@ export function PlatformEntryFlowShellImpl({
await bigFishFlow.openWorkspace();
}, [bigFishFlow]);
const openMatch3DAgentWorkspace = useCallback(async () => {
setMatch3DSession(null);
setMatch3DError(null);
setStreamingMatch3DReplyText('');
setIsStreamingMatch3DReply(false);
await match3dFlow.openWorkspace();
}, [
match3dFlow,
setIsStreamingMatch3DReply,
setMatch3DError,
setMatch3DSession,
setStreamingMatch3DReplyText,
]);
const openPuzzleAgentWorkspace = useCallback(async () => {
setPuzzleRun(null);
setPuzzleOperation(null);
@@ -1466,6 +1556,10 @@ export function PlatformEntryFlowShellImpl({
setBigFishRuntimeReturnStage('platform');
setBigFishGenerationState(null);
setBigFishError(null);
setMatch3DSession(null);
setMatch3DError(null);
setStreamingMatch3DReplyText('');
setIsStreamingMatch3DReply(false);
setPuzzleOperation(null);
setPuzzleWorks([]);
setSelectedPuzzleDetail(null);
@@ -1500,10 +1594,14 @@ export function PlatformEntryFlowShellImpl({
resetRpgSessionViewState,
selectionStage,
setBigFishError,
setIsStreamingMatch3DReply,
setMatch3DError,
setMatch3DSession,
setPuzzleError,
setRpgCustomWorldError,
setRpgGeneratedCustomWorldProfile,
setSelectionStage,
setStreamingMatch3DReplyText,
]);
const handleCreationHubCreateType = useCallback(
@@ -1523,6 +1621,13 @@ export function PlatformEntryFlowShellImpl({
return;
}
if (type === 'match3d') {
runProtectedAction(() => {
void openMatch3DAgentWorkspace();
});
return;
}
if (type === 'puzzle') {
runProtectedAction(() => {
void openPuzzleAgentWorkspace();
@@ -1531,6 +1636,7 @@ export function PlatformEntryFlowShellImpl({
},
[
openBigFishAgentWorkspace,
openMatch3DAgentWorkspace,
openPuzzleAgentWorkspace,
prepareCreationLaunch,
runProtectedAction,
@@ -1546,6 +1652,10 @@ export function PlatformEntryFlowShellImpl({
bigFishFlow.leaveFlow();
}, [bigFishFlow]);
const leaveMatch3DFlow = useCallback(() => {
match3dFlow.leaveFlow();
}, [match3dFlow]);
const leavePuzzleFlow = useCallback(() => {
setPuzzleOperation(null);
setPuzzleRun(null);
@@ -1556,10 +1666,14 @@ export function PlatformEntryFlowShellImpl({
const submitBigFishMessage = bigFishFlow.submitMessage;
const submitMatch3DMessage = match3dFlow.submitMessage;
const submitPuzzleMessage = puzzleFlow.submitMessage;
const executeBigFishAction = bigFishFlow.executeAction;
const executeMatch3DAction = match3dFlow.executeAction;
const executePuzzleAction = puzzleFlow.executeAction;
const retryPuzzleDraftGeneration = useCallback(() => {
@@ -1602,6 +1716,14 @@ export function PlatformEntryFlowShellImpl({
}
}, [bigFishRun, bigFishSession, selectionStage, setSelectionStage]);
useEffect(() => {
if (selectionStage === 'match3d-result' && !match3dSession?.draft) {
setSelectionStage(
match3dSession ? 'match3d-agent-workspace' : 'platform',
);
}
}, [match3dSession, selectionStage, setSelectionStage]);
const startBigFishRun = useCallback(() => {
if (!bigFishSession) {
return;
@@ -3280,11 +3402,13 @@ export function PlatformEntryFlowShellImpl({
: (platformBootstrap.platformError ??
sessionController.agentWorkspaceRestoreError ??
bigFishError ??
match3dError ??
puzzleError)
}
onRetry={() => {
platformBootstrap.setPlatformError(null);
setBigFishError(null);
setMatch3DError(null);
setPuzzleError(null);
void platformBootstrap.refreshCustomWorldWorks().catch((error) => {
platformBootstrap.setPlatformError(
@@ -3297,11 +3421,15 @@ export function PlatformEntryFlowShellImpl({
void refreshPuzzleShelf();
}}
createError={
sessionController.creationTypeError ?? bigFishError ?? puzzleError
sessionController.creationTypeError ??
bigFishError ??
match3dError ??
puzzleError
}
createBusy={
sessionController.isCreatingAgentSession ||
isBigFishBusy ||
isMatch3DBusy ||
isPuzzleBusy
}
onCreateType={handleCreationHubCreateType}
@@ -3469,7 +3597,12 @@ export function PlatformEntryFlowShellImpl({
entry={selectedPublicWorkDetail}
authorAvatarUrl={selectedPublicWorkAuthor?.avatarUrl ?? null}
authorDisplayName={selectedPublicWorkAuthor?.displayName ?? null}
isBusy={isPublicWorkDetailBusy || isPuzzleBusy || isBigFishBusy}
isBusy={
isPublicWorkDetailBusy ||
isPuzzleBusy ||
isBigFishBusy ||
isMatch3DBusy
}
error={publicWorkDetailError}
onBack={() => {
setPublicWorkDetailError(null);
@@ -3767,6 +3900,58 @@ export function PlatformEntryFlowShellImpl({
</motion.div>
)}
{selectionStage === 'match3d-agent-workspace' && (
<motion.div
key="match3d-agent-workspace"
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -12 }}
className="flex h-full min-h-0 flex-col"
>
<Suspense
fallback={<LazyPanelFallback label="正在加载抓大鹅共创工作区..." />}
>
<Match3DAgentWorkspace
session={match3dSession}
streamingReplyText={streamingMatch3DReplyText}
isStreamingReply={isStreamingMatch3DReply}
isBusy={isMatch3DBusy || isStreamingMatch3DReply}
error={match3dError}
onBack={leaveMatch3DFlow}
onSubmitMessage={(payload) => {
void submitMatch3DMessage(payload);
}}
onExecuteAction={(payload) => {
void executeMatch3DAction(payload);
}}
/>
</Suspense>
</motion.div>
)}
{selectionStage === 'match3d-result' && match3dSession?.draft && (
<motion.div
key="match3d-result"
initial={{ opacity: 0, y: 12 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -12 }}
className="flex h-full min-h-0 flex-col"
>
<Suspense
fallback={<LazyPanelFallback label="正在加载抓大鹅结果..." />}
>
<Match3DDraftReadyView
session={match3dSession}
isBusy={isMatch3DBusy}
error={match3dError}
onBack={() => {
setSelectionStage('match3d-agent-workspace');
}}
/>
</Suspense>
</motion.div>
)}
{selectionStage === 'puzzle-agent-workspace' && (
<motion.div
key="puzzle-agent-workspace"
@@ -4207,15 +4392,20 @@ export function PlatformEntryFlowShellImpl({
isBusy={
sessionController.isCreatingAgentSession ||
isBigFishBusy ||
isMatch3DBusy ||
isPuzzleBusy
}
error={
bigFishError ?? puzzleError ?? sessionController.creationTypeError
bigFishError ??
match3dError ??
puzzleError ??
sessionController.creationTypeError
}
onClose={() => {
if (
sessionController.isCreatingAgentSession ||
isBigFishBusy ||
isMatch3DBusy ||
isPuzzleBusy
) {
return;
@@ -4230,6 +4420,11 @@ export function PlatformEntryFlowShellImpl({
void openBigFishAgentWorkspace();
});
}}
onSelectMatch3D={() => {
runProtectedAction(() => {
void openMatch3DAgentWorkspace();
});
}}
onSelectPuzzle={() => {
runProtectedAction(() => {
void openPuzzleAgentWorkspace();