155 lines
4.2 KiB
TypeScript
155 lines
4.2 KiB
TypeScript
import type { PuzzleDraftLevel } from '../../../packages/shared/src/contracts/puzzleAgentDraft';
|
|
import type { PuzzleAgentSessionSnapshot } from '../../../packages/shared/src/contracts/puzzleAgentSession';
|
|
|
|
function normalizeRecoveryText(value: string | null | undefined) {
|
|
return value?.trim() || null;
|
|
}
|
|
|
|
function hasPuzzleAssetReference(
|
|
imageSrc: string | null | undefined,
|
|
objectKey: string | null | undefined,
|
|
) {
|
|
return Boolean(normalizeRecoveryText(imageSrc) || normalizeRecoveryText(objectKey));
|
|
}
|
|
|
|
function resolvePrimaryPuzzleLevel(session: PuzzleAgentSessionSnapshot) {
|
|
return session.draft?.levels?.[0] ?? null;
|
|
}
|
|
|
|
function resolvePuzzleRecoveryCandidate(
|
|
session: PuzzleAgentSessionSnapshot,
|
|
primaryLevel: PuzzleDraftLevel | null,
|
|
) {
|
|
const draft = session.draft;
|
|
if (!draft) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
primaryLevel?.candidates.find((candidate) => candidate.selected) ??
|
|
primaryLevel?.candidates[0] ??
|
|
draft.candidates.find((candidate) => candidate.selected) ??
|
|
draft.candidates[0] ??
|
|
null
|
|
);
|
|
}
|
|
|
|
function resolvePuzzleRecoveryCoverFields(
|
|
session: PuzzleAgentSessionSnapshot,
|
|
) {
|
|
const draft = session.draft;
|
|
const primaryLevel = resolvePrimaryPuzzleLevel(session);
|
|
const selectedCandidate = resolvePuzzleRecoveryCandidate(
|
|
session,
|
|
primaryLevel,
|
|
);
|
|
|
|
return {
|
|
coverImageSrc:
|
|
normalizeRecoveryText(draft?.coverImageSrc) ??
|
|
normalizeRecoveryText(primaryLevel?.coverImageSrc) ??
|
|
normalizeRecoveryText(selectedCandidate?.imageSrc),
|
|
coverAssetId:
|
|
normalizeRecoveryText(draft?.coverAssetId) ??
|
|
normalizeRecoveryText(primaryLevel?.coverAssetId) ??
|
|
normalizeRecoveryText(selectedCandidate?.assetId),
|
|
selectedCandidateId:
|
|
draft?.selectedCandidateId ??
|
|
primaryLevel?.selectedCandidateId ??
|
|
selectedCandidate?.candidateId ??
|
|
null,
|
|
};
|
|
}
|
|
|
|
function hasCompleteGeneratedPuzzleLevelAssets(
|
|
level: PuzzleDraftLevel | null,
|
|
coverImageSrc: string | null,
|
|
) {
|
|
return Boolean(
|
|
normalizeRecoveryText(coverImageSrc) &&
|
|
hasPuzzleAssetReference(
|
|
level?.levelSceneImageSrc,
|
|
level?.levelSceneImageObjectKey,
|
|
) &&
|
|
hasPuzzleAssetReference(
|
|
level?.uiSpritesheetImageSrc,
|
|
level?.uiSpritesheetImageObjectKey,
|
|
) &&
|
|
hasPuzzleAssetReference(
|
|
level?.levelBackgroundImageSrc,
|
|
level?.levelBackgroundImageObjectKey,
|
|
),
|
|
);
|
|
}
|
|
|
|
export function hasRecoverableGeneratedPuzzleDraft(
|
|
session: PuzzleAgentSessionSnapshot,
|
|
) {
|
|
const draft = session.draft;
|
|
if (!draft) {
|
|
return false;
|
|
}
|
|
|
|
const primaryLevel = resolvePrimaryPuzzleLevel(session);
|
|
const { coverImageSrc } = resolvePuzzleRecoveryCoverFields(session);
|
|
return hasCompleteGeneratedPuzzleLevelAssets(primaryLevel, coverImageSrc);
|
|
}
|
|
|
|
export function normalizeRecoveredPuzzleDraftSession(
|
|
session: PuzzleAgentSessionSnapshot,
|
|
): PuzzleAgentSessionSnapshot {
|
|
const draft = session.draft;
|
|
if (!draft) {
|
|
return session;
|
|
}
|
|
|
|
const { coverImageSrc, coverAssetId, selectedCandidateId } =
|
|
resolvePuzzleRecoveryCoverFields(session);
|
|
const nextLevels = draft.levels?.map((level, index) =>
|
|
index === 0
|
|
? {
|
|
...level,
|
|
coverImageSrc: normalizeRecoveryText(level.coverImageSrc)
|
|
? level.coverImageSrc
|
|
: coverImageSrc,
|
|
coverAssetId: normalizeRecoveryText(level.coverAssetId)
|
|
? level.coverAssetId
|
|
: coverAssetId,
|
|
selectedCandidateId:
|
|
level.selectedCandidateId ?? selectedCandidateId,
|
|
}
|
|
: level,
|
|
);
|
|
const nextSession = {
|
|
...session,
|
|
draft: {
|
|
...draft,
|
|
coverImageSrc,
|
|
coverAssetId,
|
|
selectedCandidateId,
|
|
levels: nextLevels,
|
|
},
|
|
} satisfies PuzzleAgentSessionSnapshot;
|
|
const isRecoverable = hasRecoverableGeneratedPuzzleDraft(nextSession);
|
|
|
|
if (!isRecoverable) {
|
|
return nextSession;
|
|
}
|
|
|
|
return {
|
|
...nextSession,
|
|
draft: {
|
|
...nextSession.draft,
|
|
generationStatus: 'ready',
|
|
levels: nextSession.draft.levels?.map((level, index) =>
|
|
index === 0
|
|
? {
|
|
...level,
|
|
generationStatus: 'ready',
|
|
}
|
|
: level,
|
|
),
|
|
},
|
|
};
|
|
}
|