抓大鹅F3实现
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-30 21:01:36 +08:00
parent 22f6e6f4e7
commit 08815d98bc
39 changed files with 5891 additions and 18 deletions

View File

@@ -10,6 +10,7 @@ export interface PlatformEntryCreationTypeModalProps {
onClose: () => void;
onSelectRpg: () => void;
onSelectBigFish: () => void;
onSelectMatch3D: () => void;
onSelectPuzzle: () => void;
}
@@ -71,6 +72,7 @@ export function PlatformEntryCreationTypeModal({
onClose,
onSelectRpg,
onSelectBigFish,
onSelectMatch3D,
onSelectPuzzle,
}: PlatformEntryCreationTypeModalProps) {
if (!isOpen) {
@@ -103,6 +105,9 @@ export function PlatformEntryCreationTypeModal({
if (item.id === 'big-fish') {
onSelectBigFish();
}
if (item.id === 'match3d') {
onSelectMatch3D();
}
if (item.id === 'puzzle') {
onSelectPuzzle();
}

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,
@@ -72,6 +80,7 @@ import {
readCustomWorldAgentUiState,
shouldRestoreCustomWorldAgentUiState,
} from '../../services/customWorldAgentUiState';
import { match3dCreationClient } from '../../services/match3d-creation';
import {
buildBigFishGenerationAnchorEntries,
buildMiniGameDraftGenerationProgress,
@@ -510,6 +519,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 {
@@ -707,6 +730,11 @@ export function PlatformEntryFlowShellImpl({
resolveRpgCreationErrorMessage(error, fallback),
[],
);
const resolveMatch3DErrorMessage = useCallback(
(error: unknown, fallback: string) =>
resolveRpgCreationErrorMessage(error, fallback),
[],
);
const refreshBigFishShelf = useCallback(async () => {
setIsBigFishLoadingLibrary(true);
@@ -1086,6 +1114,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,
@@ -1196,6 +1262,12 @@ export function PlatformEntryFlowShellImpl({
const streamingBigFishReplyText = bigFishFlow.streamingReplyText;
const isStreamingBigFishReply = bigFishFlow.isStreamingReply;
const match3dSession = match3dFlow.session;
const match3dError = match3dFlow.error;
const isMatch3DBusy = match3dFlow.isBusy;
const streamingMatch3DReplyText = match3dFlow.streamingReplyText;
const isStreamingMatch3DReply = match3dFlow.isStreamingReply;
const puzzleSession = puzzleFlow.session;
const puzzleError = puzzleFlow.error;
const setPuzzleError = puzzleFlow.setError;
@@ -1219,6 +1291,14 @@ export function PlatformEntryFlowShellImpl({
await bigFishFlow.openWorkspace();
}, [bigFishFlow]);
const openMatch3DAgentWorkspace = useCallback(async () => {
match3dFlow.setSession(null);
match3dFlow.setError(null);
match3dFlow.setStreamingReplyText('');
match3dFlow.setIsStreamingReply(false);
await match3dFlow.openWorkspace();
}, [match3dFlow]);
const openPuzzleAgentWorkspace = useCallback(async () => {
setPuzzleRun(null);
setPuzzleOperation(null);
@@ -1276,6 +1356,10 @@ export function PlatformEntryFlowShellImpl({
setBigFishRuntimeReturnStage('platform');
setBigFishGenerationState(null);
setBigFishError(null);
match3dFlow.setSession(null);
match3dFlow.setError(null);
match3dFlow.setStreamingReplyText('');
match3dFlow.setIsStreamingReply(false);
setPuzzleOperation(null);
setPuzzleWorks([]);
setSelectedPuzzleDetail(null);
@@ -1304,6 +1388,7 @@ export function PlatformEntryFlowShellImpl({
}
}, [
authUi?.user,
match3dFlow,
platformBootstrap.canReadProtectedData,
persistRpgAgentUiState,
resetAutoSaveTrackingToIdle,
@@ -1340,6 +1425,13 @@ export function PlatformEntryFlowShellImpl({
return;
}
if (type === 'match3d') {
runProtectedAction(() => {
void openMatch3DAgentWorkspace();
});
return;
}
if (type === 'puzzle') {
runProtectedAction(() => {
void openPuzzleAgentWorkspace();
@@ -1348,6 +1440,7 @@ export function PlatformEntryFlowShellImpl({
},
[
openBigFishAgentWorkspace,
openMatch3DAgentWorkspace,
openPuzzleAgentWorkspace,
prepareCreationLaunch,
runProtectedAction,
@@ -1364,6 +1457,10 @@ export function PlatformEntryFlowShellImpl({
bigFishFlow.leaveFlow();
}, [bigFishFlow]);
const leaveMatch3DFlow = useCallback(() => {
match3dFlow.leaveFlow();
}, [match3dFlow]);
const leavePuzzleFlow = useCallback(() => {
setPuzzleOperation(null);
setPuzzleRun(null);
@@ -1374,10 +1471,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;
useEffect(() => {
@@ -3264,6 +3365,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"
@@ -3701,15 +3854,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;
@@ -3726,6 +3884,11 @@ export function PlatformEntryFlowShellImpl({
void openBigFishAgentWorkspace();
});
}}
onSelectMatch3D={() => {
runProtectedAction(() => {
void openMatch3DAgentWorkspace();
});
}}
onSelectPuzzle={() => {
runProtectedAction(() => {
void openPuzzleAgentWorkspace();

View File

@@ -1,6 +1,7 @@
export type PlatformCreationTypeId =
| 'rpg'
| 'big-fish'
| 'match3d'
| 'puzzle'
| 'airp'
| 'visual-novel';
@@ -56,6 +57,13 @@ export const PLATFORM_CREATION_TYPES: PlatformCreationTypeCard[] = [
badge: '可创建',
locked: false,
},
{
id: 'match3d',
title: '抓大鹅',
subtitle: '经典消除玩法',
badge: '可创建',
locked: false,
},
{
id: 'airp',
title: 'AIRP',

View File

@@ -22,6 +22,8 @@ export type SelectionStage =
| 'big-fish-generating'
| 'big-fish-result'
| 'big-fish-runtime'
| 'match3d-agent-workspace'
| 'match3d-result'
| 'puzzle-agent-workspace'
| 'puzzle-generating'
| 'puzzle-result'