cdcbaf4cee
平台壳生成完成和失败收口消费 notification.showLocal 新增 HostBridge 草稿通知 payload 与去重模型测试 迁移生成状态纯函数以通过组件 Fast Refresh 约束 更新原生壳方案、HostBridge 协议和共享决策记录
231 lines
7.0 KiB
TypeScript
231 lines
7.0 KiB
TypeScript
import type { Match3DGeneratedItemAsset } from '../../../packages/shared/src/contracts/match3dWorks';
|
|
import type {
|
|
CreatePuzzleAgentSessionRequest,
|
|
PuzzleAgentSessionSnapshot,
|
|
} from '../../../packages/shared/src/contracts/puzzleAgentSession';
|
|
import {
|
|
createMiniGameDraftGenerationState,
|
|
type MiniGameDraftGenerationKind,
|
|
type MiniGameDraftGenerationPhase,
|
|
type MiniGameDraftGenerationState,
|
|
resolveMiniGameDraftGenerationStartedAtMs,
|
|
} from '../../services/miniGameDraftGenerationProgress';
|
|
import type { SelectionStage } from './platformEntryTypes';
|
|
|
|
export type MiniGameGenerationProgressTickStateMap = Partial<
|
|
Record<MiniGameDraftGenerationKind, MiniGameDraftGenerationState | null>
|
|
>;
|
|
|
|
export function resolveMiniGameGenerationProgressTickState(
|
|
selectionStage: SelectionStage,
|
|
states: MiniGameGenerationProgressTickStateMap,
|
|
) {
|
|
const stageKindMap: Partial<
|
|
Record<SelectionStage, MiniGameDraftGenerationKind>
|
|
> = {
|
|
'puzzle-generating': 'puzzle',
|
|
'big-fish-generating': 'big-fish',
|
|
'square-hole-generating': 'square-hole',
|
|
'match3d-generating': 'match3d',
|
|
'baby-object-match-generating': 'baby-object-match',
|
|
'jump-hop-generating': 'jump-hop',
|
|
'puzzle-clear-generating': 'puzzle-clear',
|
|
'wooden-fish-generating': 'wooden-fish',
|
|
};
|
|
const kind = stageKindMap[selectionStage];
|
|
|
|
return kind ? (states[kind] ?? null) : null;
|
|
}
|
|
|
|
export function resolveMiniGameGenerationViewBusy(
|
|
isBusy: boolean,
|
|
state: MiniGameDraftGenerationState | null | undefined,
|
|
) {
|
|
return isBusy || isMiniGameDraftGenerating(state ?? null);
|
|
}
|
|
|
|
export function createMiniGameDraftGenerationStateForRestoredDraft(
|
|
kind: MiniGameDraftGenerationKind,
|
|
metadata?: MiniGameDraftGenerationState['metadata'],
|
|
startedAtMs = Date.now(),
|
|
): MiniGameDraftGenerationState {
|
|
return {
|
|
...createMiniGameDraftGenerationState(kind, startedAtMs),
|
|
...(metadata ? { metadata } : {}),
|
|
};
|
|
}
|
|
|
|
export function createFailedMiniGameDraftGenerationStateForRestoredDraft(
|
|
kind: MiniGameDraftGenerationKind,
|
|
updatedAt: string | null | undefined,
|
|
error: string,
|
|
metadata?: MiniGameDraftGenerationState['metadata'],
|
|
): MiniGameDraftGenerationState {
|
|
return resolveFinishedMiniGameDraftGenerationState(
|
|
createMiniGameDraftGenerationStateForRestoredDraft(
|
|
kind,
|
|
metadata,
|
|
resolveMiniGameDraftGenerationStartedAtMs(updatedAt),
|
|
),
|
|
'failed',
|
|
{ error },
|
|
);
|
|
}
|
|
|
|
/** 清理生成态完成时间,避免返回生成页后继续沿用结束态计时。 */
|
|
export function rebaseMiniGameDraftGenerationStateForDisplay(
|
|
state: MiniGameDraftGenerationState,
|
|
): MiniGameDraftGenerationState {
|
|
return {
|
|
...state,
|
|
finishedAtMs: undefined,
|
|
};
|
|
}
|
|
|
|
export function rebaseMiniGameDraftBackgroundCompileTaskForDisplay<
|
|
T extends { generationState: MiniGameDraftGenerationState },
|
|
>(task: T): T {
|
|
return {
|
|
...task,
|
|
generationState: rebaseMiniGameDraftGenerationStateForDisplay(
|
|
task.generationState,
|
|
),
|
|
};
|
|
}
|
|
|
|
export function createPuzzleDraftGenerationStateFromPayload(
|
|
payload: CreatePuzzleAgentSessionRequest | null | undefined,
|
|
session: PuzzleAgentSessionSnapshot | null | undefined = null,
|
|
): MiniGameDraftGenerationState {
|
|
const puzzleProgressPercent =
|
|
session?.draft && !session.draft.formDraft
|
|
? session.progressPercent
|
|
: undefined;
|
|
|
|
return {
|
|
...createMiniGameDraftGenerationState(
|
|
'puzzle',
|
|
resolveMiniGameDraftGenerationStartedAtMs(session?.updatedAt),
|
|
),
|
|
metadata: {
|
|
puzzleAiRedraw: payload?.aiRedraw ?? true,
|
|
puzzleActivePhaseId:
|
|
typeof puzzleProgressPercent === 'number' ? 'compile' : undefined,
|
|
puzzleActiveStepStartedAtMs:
|
|
typeof puzzleProgressPercent === 'number' ? Date.now() : undefined,
|
|
puzzleProgressPercent,
|
|
},
|
|
};
|
|
}
|
|
|
|
export function resolvePuzzlePhaseFromSessionProgress(
|
|
state: MiniGameDraftGenerationState,
|
|
session: PuzzleAgentSessionSnapshot,
|
|
): MiniGameDraftGenerationPhase {
|
|
if (session.progressPercent >= 96) {
|
|
return 'puzzle-select-image';
|
|
}
|
|
if (session.progressPercent >= 94) {
|
|
return 'puzzle-ui-assets';
|
|
}
|
|
if (session.progressPercent >= 88) {
|
|
return state.metadata?.puzzleAiRedraw === false
|
|
? 'puzzle-level-scene'
|
|
: 'puzzle-cover-image';
|
|
}
|
|
|
|
return 'compile';
|
|
}
|
|
|
|
export function mergePuzzleSessionProgressIntoGenerationState(
|
|
state: MiniGameDraftGenerationState,
|
|
session: PuzzleAgentSessionSnapshot,
|
|
): MiniGameDraftGenerationState {
|
|
const isCompiledGenerationSession = Boolean(
|
|
session.draft && !session.draft.formDraft,
|
|
);
|
|
|
|
const nextPhaseId = isCompiledGenerationSession
|
|
? resolvePuzzlePhaseFromSessionProgress(state, session)
|
|
: state.metadata?.puzzleActivePhaseId;
|
|
const shouldResetActiveStepStart =
|
|
isCompiledGenerationSession &&
|
|
nextPhaseId != null &&
|
|
nextPhaseId !== state.metadata?.puzzleActivePhaseId;
|
|
|
|
return {
|
|
...state,
|
|
metadata: {
|
|
...state.metadata,
|
|
puzzleActivePhaseId: nextPhaseId,
|
|
puzzleActiveStepStartedAtMs: shouldResetActiveStepStart
|
|
? resolveMiniGameDraftGenerationStartedAtMs(session.updatedAt)
|
|
: state.metadata?.puzzleActiveStepStartedAtMs,
|
|
puzzleProgressPercent: isCompiledGenerationSession
|
|
? session.progressPercent
|
|
: state.metadata?.puzzleProgressPercent,
|
|
},
|
|
};
|
|
}
|
|
|
|
export function mergeMatch3DGeneratedAssetsIntoGenerationState(
|
|
current: MiniGameDraftGenerationState | null,
|
|
assets: readonly Match3DGeneratedItemAsset[] | null | undefined,
|
|
): MiniGameDraftGenerationState | null {
|
|
if (!current || current.phase === 'ready' || current.phase === 'failed') {
|
|
return current;
|
|
}
|
|
|
|
const assetList = assets ?? [];
|
|
const imageReadyCount = assetList.filter(
|
|
(asset) =>
|
|
asset.imageViews?.some(
|
|
(view) => view.imageObjectKey?.trim() || view.imageSrc?.trim(),
|
|
) ||
|
|
asset.imageObjectKey?.trim() ||
|
|
asset.imageSrc?.trim(),
|
|
).length;
|
|
const totalAssetCount = Math.max(5, assetList.length);
|
|
const failedAsset = assetList.find((asset) => asset.error?.trim());
|
|
|
|
return {
|
|
...current,
|
|
phase: imageReadyCount > 0 ? 'match3d-generate-views' : current.phase,
|
|
completedAssetCount: imageReadyCount,
|
|
totalAssetCount,
|
|
error: failedAsset?.error?.trim() || current.error,
|
|
};
|
|
}
|
|
|
|
export function resolveFinishedMiniGameDraftGenerationState(
|
|
state: MiniGameDraftGenerationState,
|
|
phase: 'ready' | 'failed',
|
|
options: {
|
|
error?: string | null;
|
|
completedAssetCount?: number;
|
|
totalAssetCount?: number;
|
|
} = {},
|
|
): MiniGameDraftGenerationState {
|
|
return {
|
|
...state,
|
|
phase,
|
|
finishedAtMs: Date.now(),
|
|
error: options.error ?? state.error,
|
|
completedAssetCount:
|
|
options.completedAssetCount ?? state.completedAssetCount,
|
|
totalAssetCount: options.totalAssetCount ?? state.totalAssetCount,
|
|
};
|
|
}
|
|
|
|
export function isMiniGameDraftReady(
|
|
state: MiniGameDraftGenerationState | null,
|
|
) {
|
|
return state?.phase === 'ready';
|
|
}
|
|
|
|
export function isMiniGameDraftGenerating(
|
|
state: MiniGameDraftGenerationState | null,
|
|
) {
|
|
return Boolean(state && state.phase !== 'ready' && state.phase !== 'failed');
|
|
}
|