This commit is contained in:
2026-05-10 22:20:54 +08:00
parent d6219f1a0c
commit 192accd796
92 changed files with 7045 additions and 1559 deletions

View File

@@ -3,6 +3,10 @@ import type {
CreatePuzzleAgentSessionRequest,
PuzzleAgentSessionSnapshot,
} from '../../packages/shared/src/contracts/puzzleAgentSession';
import type {
CreateMatch3DSessionRequest,
Match3DAgentSessionSnapshot,
} from '../../packages/shared/src/contracts/match3dAgent';
import type {
CustomWorldGenerationProgress,
CustomWorldGenerationStep,
@@ -10,7 +14,11 @@ import type {
import type { SquareHoleSessionSnapshot } from '../../packages/shared/src/contracts/squareHoleAgent';
import type { CustomWorldStructuredAnchorEntry } from './customWorldAgentGenerationProgress';
export type MiniGameDraftGenerationKind = 'puzzle' | 'big-fish' | 'square-hole';
export type MiniGameDraftGenerationKind =
| 'puzzle'
| 'big-fish'
| 'square-hole'
| 'match3d';
export type MiniGameDraftGenerationPhase =
| 'idle'
@@ -22,6 +30,11 @@ export type MiniGameDraftGenerationPhase =
| 'square-hole-cover'
| 'square-hole-shapes'
| 'square-hole-ready'
| 'match3d-item-names'
| 'match3d-material-sheet'
| 'match3d-slice-images'
| 'match3d-upload-images'
| 'match3d-ready'
| 'puzzle-images'
| 'puzzle-select-image'
| 'ready'
@@ -126,6 +139,33 @@ const SQUARE_HOLE_STEPS = [
},
] as const satisfies ReadonlyArray<MiniGameStepDefinition>;
const MATCH3D_STEPS = [
{
id: 'match3d-item-names',
label: '生成物品名称',
detail: '根据题材生成本局的 3 个物品名称。',
weight: 16,
},
{
id: 'match3d-material-sheet',
label: '生成素材图',
detail: '生成一张 1:1 的网格素材图。',
weight: 30,
},
{
id: 'match3d-slice-images',
label: '切割独立图片',
detail: '把素材图切成独立物品参考图。',
weight: 14,
},
{
id: 'match3d-upload-images',
label: '上传图片资产',
detail: '写入切割图片并准备进入草稿页。',
weight: 40,
},
] as const satisfies ReadonlyArray<MiniGameStepDefinition>;
function clampProgress(value: number) {
return Math.max(0, Math.min(100, Math.round(value)));
}
@@ -137,6 +177,9 @@ function getStepDefinitions(kind: MiniGameDraftGenerationKind) {
if (kind === 'square-hole') {
return SQUARE_HOLE_STEPS;
}
if (kind === 'match3d') {
return MATCH3D_STEPS;
}
return BIG_FISH_STEPS;
}
@@ -190,7 +233,9 @@ export function createMiniGameDraftGenerationState(
? 'big-fish-draft'
: kind === 'square-hole'
? 'square-hole-draft'
: 'compile',
: kind === 'match3d'
? 'match3d-item-names'
: 'compile',
startedAtMs: Date.now(),
completedAssetCount: 0,
totalAssetCount: 0,
@@ -222,6 +267,21 @@ function resolveSquareHolePhaseByElapsedMs(
return 'square-hole-draft';
}
function resolveMatch3DPhaseByElapsedMs(
elapsedMs: number,
): MiniGameDraftGenerationPhase {
if (elapsedMs >= 72_000) {
return 'match3d-upload-images';
}
if (elapsedMs >= 58_000) {
return 'match3d-slice-images';
}
if (elapsedMs >= 16_000) {
return 'match3d-material-sheet';
}
return 'match3d-item-names';
}
function resolvePuzzleTimelineByElapsedMs(elapsedMs: number) {
let elapsedBeforePhase = 0;
@@ -282,6 +342,13 @@ export function buildMiniGameDraftGenerationProgress(
...state,
phase: resolveSquareHolePhaseByElapsedMs(elapsedMs),
}
: state.kind === 'match3d' &&
state.phase !== 'failed' &&
state.phase !== 'ready'
? {
...state,
phase: resolveMatch3DPhaseByElapsedMs(elapsedMs),
}
: state;
const steps = getStepDefinitions(normalizedState.kind);
@@ -307,6 +374,8 @@ export function buildMiniGameDraftGenerationProgress(
? 0.55
: normalizedState.kind === 'square-hole'
? 0.42
: normalizedState.kind === 'match3d'
? 0.5
: 0;
const overallProgress =
normalizedState.phase === 'failed'
@@ -334,7 +403,9 @@ export function buildMiniGameDraftGenerationProgress(
(normalizedState.phase === 'ready'
? normalizedState.kind === 'big-fish'
? '玩法草稿已准备完成,可进入结果页继续生成主图、动作和背景。'
: '首关草稿与正式图已准备完成,可进入结果页补作品信息。'
: normalizedState.kind === 'match3d'
? '抓大鹅素材与草稿已准备完成,可进入结果页继续编辑。'
: '首关草稿与正式图已准备完成,可进入结果页补作品信息。'
: activeStep.detail),
batchLabel: activeStep.label,
overallProgress: clampProgress(cappedOverallProgress),
@@ -350,7 +421,9 @@ export function buildMiniGameDraftGenerationProgress(
? Math.max(0, 7_000 - elapsedMs)
: normalizedState.kind === 'square-hole'
? Math.max(0, 12_000 - elapsedMs)
: null,
: normalizedState.kind === 'match3d'
? Math.max(0, 120_000 - elapsedMs)
: null,
activeStepIndex,
steps: buildMiniGameProgressSteps(
steps,
@@ -439,6 +512,43 @@ export function buildBigFishGenerationAnchorEntries(
.filter((entry) => entry.value.trim());
}
export function buildMatch3DGenerationAnchorEntries(
session: Match3DAgentSessionSnapshot | null | undefined,
formPayload: CreateMatch3DSessionRequest | null | undefined = null,
): CustomWorldStructuredAnchorEntry[] {
if (!session && !formPayload) {
return [];
}
const config = session?.config;
const itemCount = 3;
const entries: Array<MiniGameAnchorSource | null> = [
{
key: 'match3d-theme',
label: '题材',
value:
formPayload?.themeText?.trim() ||
config?.themeText?.trim() ||
session?.anchorPack.theme.value ||
'',
},
{
key: 'match3d-items',
label: '物品数量',
value: `${itemCount}`,
},
];
return entries
.filter((entry): entry is MiniGameAnchorSource => Boolean(entry))
.map((entry) => ({
id: entry.key,
label: entry.label,
value: entry.value,
}))
.filter((entry) => entry.value.trim());
}
export function buildSquareHoleGenerationAnchorEntries(
session: SquareHoleSessionSnapshot | null | undefined,
): CustomWorldStructuredAnchorEntry[] {