refactor: 收口 Match3D 生成资产进度
This commit is contained in:
@@ -49,7 +49,6 @@ import type {
|
||||
} from '../../../packages/shared/src/contracts/match3dAgent';
|
||||
import type { Match3DRunSnapshot } from '../../../packages/shared/src/contracts/match3dRuntime';
|
||||
import type {
|
||||
Match3DGeneratedItemAsset,
|
||||
Match3DWorkProfile,
|
||||
Match3DWorkSummary,
|
||||
} from '../../../packages/shared/src/contracts/match3dWorks';
|
||||
@@ -516,6 +515,7 @@ import {
|
||||
createPuzzleDraftGenerationStateFromPayload,
|
||||
isMiniGameDraftGenerating,
|
||||
isMiniGameDraftReady,
|
||||
mergeMatch3DGeneratedAssetsIntoGenerationState,
|
||||
mergePuzzleSessionProgressIntoGenerationState,
|
||||
rebaseMiniGameDraftBackgroundCompileTaskForDisplay,
|
||||
rebaseMiniGameDraftGenerationStateForDisplay,
|
||||
@@ -751,35 +751,6 @@ function mapVisualNovelWorkDetailToSession(
|
||||
};
|
||||
}
|
||||
|
||||
function resolveMatch3DGenerationStateFromAssets(
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
function buildSquareHoleProfileFromSession(
|
||||
session: SquareHoleSessionSnapshot | null,
|
||||
): SquareHoleWorkProfile | null {
|
||||
@@ -4807,7 +4778,7 @@ export function PlatformEntryFlowShellImpl({
|
||||
const normalizedItem = normalizeMatch3DWorkForRuntimeUi(item);
|
||||
setMatch3DProfile(normalizedItem);
|
||||
setMatch3DGenerationState((current) =>
|
||||
resolveMatch3DGenerationStateFromAssets(
|
||||
mergeMatch3DGeneratedAssetsIntoGenerationState(
|
||||
current,
|
||||
normalizedItem.generatedItemAssets,
|
||||
),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
|
||||
|
||||
import type { Match3DGeneratedItemAsset } from '../../../packages/shared/src/contracts/match3dWorks';
|
||||
import type { PuzzleAnchorPack } from '../../../packages/shared/src/contracts/puzzleAgentDraft';
|
||||
import type {
|
||||
CreatePuzzleAgentSessionRequest,
|
||||
@@ -12,6 +13,7 @@ import {
|
||||
createPuzzleDraftGenerationStateFromPayload,
|
||||
isMiniGameDraftGenerating,
|
||||
isMiniGameDraftReady,
|
||||
mergeMatch3DGeneratedAssetsIntoGenerationState,
|
||||
mergePuzzleSessionProgressIntoGenerationState,
|
||||
rebaseMiniGameDraftBackgroundCompileTaskForDisplay,
|
||||
rebaseMiniGameDraftGenerationStateForDisplay,
|
||||
@@ -96,6 +98,17 @@ function buildState(
|
||||
};
|
||||
}
|
||||
|
||||
function buildMatch3DAsset(
|
||||
overrides: Partial<Match3DGeneratedItemAsset> = {},
|
||||
): Match3DGeneratedItemAsset {
|
||||
return {
|
||||
itemId: 'item-1',
|
||||
itemName: '红宝石',
|
||||
status: 'pending',
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
vi.setSystemTime(NOW);
|
||||
@@ -277,6 +290,74 @@ describe('platformMiniGameDraftGenerationStateModel', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('merges match3d generated assets into active generation state', () => {
|
||||
const state = buildState({
|
||||
kind: 'match3d',
|
||||
phase: 'match3d-material-sheet',
|
||||
completedAssetCount: 0,
|
||||
totalAssetCount: 0,
|
||||
error: '旧错误',
|
||||
});
|
||||
|
||||
expect(
|
||||
mergeMatch3DGeneratedAssetsIntoGenerationState(state, [
|
||||
buildMatch3DAsset({
|
||||
itemId: 'item-with-view',
|
||||
imageViews: [
|
||||
{
|
||||
viewId: 'front',
|
||||
viewIndex: 0,
|
||||
imageObjectKey: 'objects/front.png',
|
||||
},
|
||||
],
|
||||
}),
|
||||
buildMatch3DAsset({
|
||||
itemId: 'item-with-src',
|
||||
imageSrc: '/generated/item.png',
|
||||
}),
|
||||
buildMatch3DAsset({
|
||||
itemId: 'item-with-error',
|
||||
error: '切图失败',
|
||||
}),
|
||||
]),
|
||||
).toMatchObject({
|
||||
phase: 'match3d-generate-views',
|
||||
completedAssetCount: 2,
|
||||
totalAssetCount: 5,
|
||||
error: '切图失败',
|
||||
});
|
||||
});
|
||||
|
||||
test('keeps match3d generated asset merge away from finished states', () => {
|
||||
const readyState = buildState({
|
||||
kind: 'match3d',
|
||||
phase: 'ready',
|
||||
completedAssetCount: 5,
|
||||
totalAssetCount: 5,
|
||||
});
|
||||
const failedState = buildState({
|
||||
kind: 'match3d',
|
||||
phase: 'failed',
|
||||
error: '已失败',
|
||||
});
|
||||
|
||||
expect(
|
||||
mergeMatch3DGeneratedAssetsIntoGenerationState(readyState, [
|
||||
buildMatch3DAsset({ imageSrc: '/generated/new.png' }),
|
||||
]),
|
||||
).toBe(readyState);
|
||||
expect(
|
||||
mergeMatch3DGeneratedAssetsIntoGenerationState(failedState, [
|
||||
buildMatch3DAsset({ imageSrc: '/generated/new.png' }),
|
||||
]),
|
||||
).toBe(failedState);
|
||||
expect(
|
||||
mergeMatch3DGeneratedAssetsIntoGenerationState(null, [
|
||||
buildMatch3DAsset({ imageSrc: '/generated/new.png' }),
|
||||
]),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
test('finishes generation state and resolves ready/generating flags', () => {
|
||||
const failedState = resolveFinishedMiniGameDraftGenerationState(
|
||||
buildState({ error: '旧错误' }),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { Match3DGeneratedItemAsset } from '../../../packages/shared/src/contracts/match3dWorks';
|
||||
import type {
|
||||
CreatePuzzleAgentSessionRequest,
|
||||
PuzzleAgentSessionSnapshot,
|
||||
@@ -134,6 +135,35 @@ export function mergePuzzleSessionProgressIntoGenerationState(
|
||||
};
|
||||
}
|
||||
|
||||
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',
|
||||
|
||||
Reference in New Issue
Block a user