feat: add baby object match edutainment flow
Some checks failed
CI / verify (push) Has been cancelled
Some checks failed
CI / verify (push) Has been cancelled
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
import type { BigFishSessionSnapshotResponse } from '../../packages/shared/src/contracts/bigFish';
|
||||
import type {
|
||||
BabyObjectMatchDraft,
|
||||
CreateBabyObjectMatchDraftRequest,
|
||||
} from '../../packages/shared/src/contracts/edutainmentBabyObject';
|
||||
import type {
|
||||
CreateMatch3DSessionRequest,
|
||||
Match3DAgentSessionSnapshot,
|
||||
@@ -18,7 +22,8 @@ export type MiniGameDraftGenerationKind =
|
||||
| 'puzzle'
|
||||
| 'big-fish'
|
||||
| 'square-hole'
|
||||
| 'match3d';
|
||||
| 'match3d'
|
||||
| 'baby-object-match';
|
||||
|
||||
export type MiniGameDraftGenerationPhase =
|
||||
| 'idle'
|
||||
@@ -37,6 +42,9 @@ export type MiniGameDraftGenerationPhase =
|
||||
| 'match3d-upload-images'
|
||||
| 'match3d-generate-models'
|
||||
| 'match3d-ready'
|
||||
| 'baby-object-draft'
|
||||
| 'baby-object-images'
|
||||
| 'baby-object-ready'
|
||||
| 'puzzle-images'
|
||||
| 'puzzle-select-image'
|
||||
| 'ready'
|
||||
@@ -191,6 +199,27 @@ const MATCH3D_PHASE_ORDER: Partial<
|
||||
'match3d-generate-models': 5,
|
||||
};
|
||||
|
||||
const BABY_OBJECT_MATCH_STEPS = [
|
||||
{
|
||||
id: 'baby-object-draft',
|
||||
label: '整理识物草稿',
|
||||
detail: '写入两个物品名称与寓教于乐标签。',
|
||||
weight: 22,
|
||||
},
|
||||
{
|
||||
id: 'baby-object-images',
|
||||
label: '生成物品图',
|
||||
detail: '为两个物品准备绘本风格图片资产。',
|
||||
weight: 68,
|
||||
},
|
||||
{
|
||||
id: 'baby-object-ready',
|
||||
label: '准备结果页',
|
||||
detail: '校验草稿字段并进入结果页。',
|
||||
weight: 10,
|
||||
},
|
||||
] as const satisfies ReadonlyArray<MiniGameStepDefinition>;
|
||||
|
||||
function clampProgress(value: number) {
|
||||
return Math.max(0, Math.min(100, Math.round(value)));
|
||||
}
|
||||
@@ -205,6 +234,9 @@ function getStepDefinitions(kind: MiniGameDraftGenerationKind) {
|
||||
if (kind === 'match3d') {
|
||||
return MATCH3D_STEPS;
|
||||
}
|
||||
if (kind === 'baby-object-match') {
|
||||
return BABY_OBJECT_MATCH_STEPS;
|
||||
}
|
||||
return BIG_FISH_STEPS;
|
||||
}
|
||||
|
||||
@@ -260,7 +292,9 @@ export function createMiniGameDraftGenerationState(
|
||||
? 'square-hole-draft'
|
||||
: kind === 'match3d'
|
||||
? 'match3d-work-title'
|
||||
: 'compile',
|
||||
: kind === 'baby-object-match'
|
||||
? 'baby-object-draft'
|
||||
: 'compile',
|
||||
startedAtMs: Date.now(),
|
||||
completedAssetCount: 0,
|
||||
totalAssetCount: 0,
|
||||
@@ -313,6 +347,18 @@ function resolveMatch3DPhaseByElapsedMs(
|
||||
return currentOrder > elapsedOrder ? currentPhase : elapsedPhase;
|
||||
}
|
||||
|
||||
function resolveBabyObjectMatchPhaseByElapsedMs(
|
||||
elapsedMs: number,
|
||||
): MiniGameDraftGenerationPhase {
|
||||
if (elapsedMs >= 52_000) {
|
||||
return 'baby-object-ready';
|
||||
}
|
||||
if (elapsedMs >= 8_000) {
|
||||
return 'baby-object-images';
|
||||
}
|
||||
return 'baby-object-draft';
|
||||
}
|
||||
|
||||
function resolvePuzzleTimelineByElapsedMs(elapsedMs: number) {
|
||||
let elapsedBeforePhase = 0;
|
||||
|
||||
@@ -360,27 +406,34 @@ export function buildMiniGameDraftGenerationProgress(
|
||||
phase: puzzleTimeline.phase,
|
||||
}
|
||||
: state.kind === 'big-fish' &&
|
||||
state.phase !== 'failed' &&
|
||||
state.phase !== 'ready'
|
||||
? {
|
||||
...state,
|
||||
phase: resolveBigFishPhaseByElapsedMs(elapsedMs),
|
||||
}
|
||||
: state.kind === 'square-hole' &&
|
||||
state.phase !== 'failed' &&
|
||||
state.phase !== 'ready'
|
||||
? {
|
||||
...state,
|
||||
phase: resolveSquareHolePhaseByElapsedMs(elapsedMs),
|
||||
phase: resolveBigFishPhaseByElapsedMs(elapsedMs),
|
||||
}
|
||||
: state.kind === 'match3d' &&
|
||||
: state.kind === 'square-hole' &&
|
||||
state.phase !== 'failed' &&
|
||||
state.phase !== 'ready'
|
||||
? {
|
||||
...state,
|
||||
phase: resolveMatch3DPhaseByElapsedMs(elapsedMs, state.phase),
|
||||
phase: resolveSquareHolePhaseByElapsedMs(elapsedMs),
|
||||
}
|
||||
: state;
|
||||
: state.kind === 'match3d' &&
|
||||
state.phase !== 'failed' &&
|
||||
state.phase !== 'ready'
|
||||
? {
|
||||
...state,
|
||||
phase: resolveMatch3DPhaseByElapsedMs(elapsedMs, state.phase),
|
||||
}
|
||||
: state.kind === 'baby-object-match' &&
|
||||
state.phase !== 'failed' &&
|
||||
state.phase !== 'ready'
|
||||
? {
|
||||
...state,
|
||||
phase: resolveBabyObjectMatchPhaseByElapsedMs(elapsedMs),
|
||||
}
|
||||
: state;
|
||||
|
||||
const steps = getStepDefinitions(normalizedState.kind);
|
||||
const activeStepIndex = getActiveStepIndex(steps, normalizedState.phase);
|
||||
@@ -401,13 +454,15 @@ export function buildMiniGameDraftGenerationProgress(
|
||||
? 1
|
||||
: normalizedState.kind === 'puzzle'
|
||||
? (puzzleTimeline?.activeStepProgressRatio ?? 0)
|
||||
: normalizedState.kind === 'big-fish'
|
||||
? 0.55
|
||||
: normalizedState.kind === 'square-hole'
|
||||
? 0.42
|
||||
: normalizedState.kind === 'match3d'
|
||||
? 0.5
|
||||
: 0;
|
||||
: normalizedState.kind === 'big-fish'
|
||||
? 0.55
|
||||
: normalizedState.kind === 'square-hole'
|
||||
? 0.42
|
||||
: normalizedState.kind === 'match3d'
|
||||
? 0.5
|
||||
: normalizedState.kind === 'baby-object-match'
|
||||
? 0.52
|
||||
: 0;
|
||||
const overallProgress =
|
||||
normalizedState.phase === 'failed'
|
||||
? Math.max(1, completedWeight)
|
||||
@@ -436,7 +491,9 @@ export function buildMiniGameDraftGenerationProgress(
|
||||
? '玩法草稿已准备完成,可进入结果页继续生成主图、动作和背景。'
|
||||
: normalizedState.kind === 'match3d'
|
||||
? '抓大鹅素材与草稿已准备完成,可进入结果页继续编辑。'
|
||||
: '首关草稿与正式图已准备完成,可进入结果页补作品信息。'
|
||||
: normalizedState.kind === 'baby-object-match'
|
||||
? '宝贝识物草稿已准备完成,可进入结果页继续发布。'
|
||||
: '首关草稿与正式图已准备完成,可进入结果页补作品信息。'
|
||||
: activeStep.detail),
|
||||
batchLabel: activeStep.label,
|
||||
overallProgress: clampProgress(cappedOverallProgress),
|
||||
@@ -448,13 +505,15 @@ export function buildMiniGameDraftGenerationProgress(
|
||||
? 0
|
||||
: normalizedState.kind === 'puzzle'
|
||||
? Math.max(0, PUZZLE_ESTIMATED_WAIT_MS - elapsedMs)
|
||||
: normalizedState.kind === 'big-fish'
|
||||
? Math.max(0, 7_000 - elapsedMs)
|
||||
: normalizedState.kind === 'square-hole'
|
||||
? Math.max(0, 12_000 - elapsedMs)
|
||||
: normalizedState.kind === 'match3d'
|
||||
? Math.max(0, 10 * 60_000 - elapsedMs)
|
||||
: null,
|
||||
: normalizedState.kind === 'big-fish'
|
||||
? Math.max(0, 7_000 - elapsedMs)
|
||||
: normalizedState.kind === 'square-hole'
|
||||
? Math.max(0, 12_000 - elapsedMs)
|
||||
: normalizedState.kind === 'match3d'
|
||||
? Math.max(0, 10 * 60_000 - elapsedMs)
|
||||
: normalizedState.kind === 'baby-object-match'
|
||||
? Math.max(0, 60_000 - elapsedMs)
|
||||
: null,
|
||||
activeStepIndex,
|
||||
steps: buildMiniGameProgressSteps(
|
||||
steps,
|
||||
@@ -580,6 +639,22 @@ export function buildMatch3DGenerationAnchorEntries(
|
||||
.filter((entry) => entry.value.trim());
|
||||
}
|
||||
|
||||
export function buildBabyObjectMatchGenerationAnchorEntries(
|
||||
formPayload: CreateBabyObjectMatchDraftRequest | null | undefined,
|
||||
draft: BabyObjectMatchDraft | null | undefined = null,
|
||||
): CustomWorldStructuredAnchorEntry[] {
|
||||
const itemNames =
|
||||
formPayload?.itemAName?.trim() || formPayload?.itemBName?.trim()
|
||||
? [formPayload.itemAName.trim(), formPayload.itemBName.trim()]
|
||||
: (draft?.itemNames ?? []);
|
||||
|
||||
return itemNames.filter(Boolean).map((value, index) => ({
|
||||
id: `baby-object-item-${index + 1}`,
|
||||
label: `物品 ${index + 1}`,
|
||||
value,
|
||||
}));
|
||||
}
|
||||
|
||||
export function buildSquareHoleGenerationAnchorEntries(
|
||||
session: SquareHoleSessionSnapshot | null | undefined,
|
||||
): CustomWorldStructuredAnchorEntry[] {
|
||||
|
||||
Reference in New Issue
Block a user