Merge remote-tracking branch 'origin/master' into codex/tiaoyitiao

# Conflicts:
#	server-rs/crates/api-server/src/jump_hop.rs
#	server-rs/crates/api-server/src/modules/jump_hop.rs
This commit is contained in:
2026-06-06 21:04:46 +08:00
451 changed files with 25780 additions and 2687 deletions

View File

@@ -11,6 +11,10 @@ import type {
CreatePuzzleAgentSessionRequest,
PuzzleAgentSessionSnapshot,
} from '../../packages/shared/src/contracts/puzzleAgentSession';
import type {
PuzzleClearSessionSnapshotResponse,
PuzzleClearWorkspaceCreateRequest,
} from '../../packages/shared/src/contracts/puzzleClear';
import type {
CustomWorldGenerationProgress,
CustomWorldGenerationStep,
@@ -33,6 +37,7 @@ export type MiniGameDraftGenerationKind =
| 'match3d'
| 'baby-object-match'
| 'jump-hop'
| 'puzzle-clear'
| 'wooden-fish';
export type MiniGameDraftGenerationPhase =
@@ -66,6 +71,11 @@ export type MiniGameDraftGenerationPhase =
| 'jump-hop-tile-atlas'
| 'jump-hop-slice-tiles'
| 'jump-hop-write-draft'
| 'puzzle-clear-draft'
| 'puzzle-clear-background'
| 'puzzle-clear-atlas'
| 'puzzle-clear-slices'
| 'puzzle-clear-write-draft'
| 'wooden-fish-draft'
| 'wooden-fish-hit-object'
| 'wooden-fish-background'
@@ -418,6 +428,41 @@ const JUMP_HOP_STEPS = [
const JUMP_HOP_ESTIMATED_WAIT_MS = 5 * 60_000;
const PUZZLE_CLEAR_STEPS = [
{
id: 'puzzle-clear-draft',
label: '整理玩法草稿',
detail: '保存作品信息、主题词与底图策略。',
weight: 8,
},
{
id: 'puzzle-clear-background',
label: '准备场地底图',
detail: '处理上传底图或生成中央场地底图。',
weight: 22,
},
{
id: 'puzzle-clear-atlas',
label: '生成复合图集',
detail: '生成 135 组复合图案 atlas。',
weight: 42,
},
{
id: 'puzzle-clear-slices',
label: '切分卡牌碎片',
detail: '按预排坐标切成 1x1 卡牌碎片并校验。',
weight: 20,
},
{
id: 'puzzle-clear-write-draft',
label: '写入正式草稿',
detail: '保存底图、图集、碎片和作品摘要。',
weight: 8,
},
] as const satisfies ReadonlyArray<MiniGameStepDefinition>;
const PUZZLE_CLEAR_ESTIMATED_WAIT_MS = 620_000;
const WOODEN_FISH_STEPS = [
{
id: 'wooden-fish-draft',
@@ -497,6 +542,9 @@ function getStepDefinitions(kind: MiniGameDraftGenerationKind) {
if (kind === 'jump-hop') {
return JUMP_HOP_STEPS;
}
if (kind === 'puzzle-clear') {
return PUZZLE_CLEAR_STEPS;
}
if (kind === 'wooden-fish') {
return WOODEN_FISH_STEPS;
}
@@ -571,9 +619,11 @@ export function createMiniGameDraftGenerationState(
? 'baby-object-draft'
: kind === 'jump-hop'
? 'jump-hop-draft'
: kind === 'wooden-fish'
? 'wooden-fish-draft'
: 'compile',
: kind === 'puzzle-clear'
? 'puzzle-clear-draft'
: kind === 'wooden-fish'
? 'wooden-fish-draft'
: 'compile',
startedAtMs,
completedAssetCount: 0,
totalAssetCount: 0,
@@ -657,6 +707,24 @@ function resolveJumpHopPhaseByElapsedMs(
return 'jump-hop-draft';
}
function resolvePuzzleClearPhaseByElapsedMs(
elapsedMs: number,
): MiniGameDraftGenerationPhase {
if (elapsedMs >= 590_000) {
return 'puzzle-clear-write-draft';
}
if (elapsedMs >= 470_000) {
return 'puzzle-clear-slices';
}
if (elapsedMs >= 120_000) {
return 'puzzle-clear-atlas';
}
if (elapsedMs >= 8_000) {
return 'puzzle-clear-background';
}
return 'puzzle-clear-draft';
}
function buildWoodenFishPhaseTimeline(): Array<{
phase: Extract<
MiniGameDraftGenerationPhase,
@@ -798,6 +866,8 @@ function resolveElapsedActiveStepProgressRatio(
? BABY_OBJECT_MATCH_ESTIMATED_WAIT_MS
: kind === 'jump-hop'
? JUMP_HOP_ESTIMATED_WAIT_MS
: kind === 'puzzle-clear'
? PUZZLE_CLEAR_ESTIMATED_WAIT_MS
: kind === 'wooden-fish'
? WOODEN_FISH_ESTIMATED_WAIT_MS
: 1;
@@ -924,7 +994,14 @@ export function buildMiniGameDraftGenerationProgress(
...state,
phase: resolveJumpHopPhaseByElapsedMs(elapsedMs),
}
: state;
: state.kind === 'puzzle-clear' &&
state.phase !== 'failed' &&
state.phase !== 'ready'
? {
...state,
phase: resolvePuzzleClearPhaseByElapsedMs(elapsedMs),
}
: state;
const puzzleTimedSteps =
normalizedState.kind === 'puzzle'
@@ -984,6 +1061,11 @@ export function buildMiniGameDraftGenerationProgress(
normalizedState.kind,
elapsedMs,
)
: normalizedState.kind === 'puzzle-clear'
? resolveElapsedActiveStepProgressRatio(
normalizedState.kind,
elapsedMs,
)
: normalizedState.kind === 'wooden-fish'
? (woodenFishTimeline?.activeStepProgressRatio ?? 0)
: 0;
@@ -1023,6 +1105,8 @@ export function buildMiniGameDraftGenerationProgress(
? '宝贝识物草稿已准备完成,可进入结果页继续发布。'
: normalizedState.kind === 'jump-hop'
? '跳一跳草稿已准备完成,可进入结果页试玩或发布。'
: normalizedState.kind === 'puzzle-clear'
? '拼消消草稿已准备完成,可进入结果页试玩或发布。'
: normalizedState.kind === 'wooden-fish'
? '敲木鱼草稿已准备完成,可进入结果页试玩或发布。'
: '首关草稿与正式图已准备完成,可进入结果页补作品信息。'
@@ -1050,6 +1134,11 @@ export function buildMiniGameDraftGenerationProgress(
? Math.max(0, BABY_OBJECT_MATCH_ESTIMATED_WAIT_MS - elapsedMs)
: normalizedState.kind === 'jump-hop'
? Math.max(0, JUMP_HOP_ESTIMATED_WAIT_MS - elapsedMs)
: normalizedState.kind === 'puzzle-clear'
? Math.max(
0,
PUZZLE_CLEAR_ESTIMATED_WAIT_MS - elapsedMs,
)
: normalizedState.kind === 'wooden-fish'
? Math.max(0, WOODEN_FISH_ESTIMATED_WAIT_MS - elapsedMs)
: null,
@@ -1163,6 +1252,49 @@ export function buildWoodenFishGenerationAnchorEntries(
.filter((entry) => entry.value.trim());
}
export function buildPuzzleClearGenerationAnchorEntries(
session: PuzzleClearSessionSnapshotResponse | null | undefined,
formPayload: PuzzleClearWorkspaceCreateRequest | null | undefined = null,
): CustomWorldStructuredAnchorEntry[] {
const draft = session?.draft;
const entries: Array<MiniGameAnchorSource | null> = [
{
key: 'puzzle-clear-title',
label: '作品',
value:
formPayload?.workTitle?.trim() || draft?.workTitle?.trim() || '拼消消',
},
{
key: 'puzzle-clear-theme',
label: '主题',
value:
formPayload?.themePrompt?.trim() || draft?.themePrompt?.trim() || '',
},
{
key: 'puzzle-clear-background',
label: '底图',
value:
formPayload?.boardBackgroundPrompt?.trim() ||
draft?.boardBackgroundPrompt?.trim() ||
(formPayload?.boardBackgroundAsset ?? draft?.boardBackgroundAsset)
?.prompt?.trim() ||
(formPayload?.generateBoardBackground ??
draft?.generateBoardBackground
? 'AI生成'
: '上传底图'),
},
];
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 buildPuzzleGenerationAnchorEntries(
session: PuzzleAgentSessionSnapshot | null | undefined,
formPayload: CreatePuzzleAgentSessionRequest | null | undefined = null,