Merge branch 'master' into codex/puzzle-clear-template-runtime-fixes

This commit is contained in:
kdletters
2026-06-06 20:01:52 +08:00
425 changed files with 16451 additions and 6022 deletions

View File

@@ -38,7 +38,10 @@ import type {
BabyObjectMatchDraft,
CreateBabyObjectMatchDraftRequest,
} from '../../../packages/shared/src/contracts/edutainmentBabyObject';
import type { JumpHopWorkSummaryResponse } from '../../../packages/shared/src/contracts/jumpHop';
import type {
JumpHopJumpRequest,
JumpHopWorkSummaryResponse,
} from '../../../packages/shared/src/contracts/jumpHop';
import type {
CreateMatch3DSessionRequest,
ExecuteMatch3DActionRequest,
@@ -67,6 +70,7 @@ import type {
PuzzleAgentSessionSnapshot,
SendPuzzleAgentMessageRequest,
} from '../../../packages/shared/src/contracts/puzzleAgentSession';
import { isPuzzleCompileActionReady } from './puzzleDraftGenerationState';
import type { PuzzleCreativeTemplateSelection } from '../../../packages/shared/src/contracts/puzzleCreativeTemplate';
import type {
PuzzleRunSnapshot,
@@ -127,6 +131,7 @@ import {
} from '../../services/authService';
import {
createBarkBattleDraft,
deleteBarkBattleWork,
listBarkBattleGallery,
listBarkBattleWorks,
publishBarkBattleWork,
@@ -188,6 +193,7 @@ import {
jumpHopClient,
type JumpHopGalleryCardResponse,
type JumpHopRunResponse,
type JumpHopRuntimeRequestOptions,
type JumpHopSessionResponse,
type JumpHopSessionSnapshotResponse,
JumpHopWorkProfileResponse,
@@ -386,6 +392,7 @@ import {
resolvePuzzleWorkCoverImageSrc,
} from '../custom-world-home/creationWorkShelf';
import {
buildPlatformPublicGalleryCardKey,
isBarkBattleGalleryEntry,
isBigFishGalleryEntry,
isEdutainmentGalleryEntry,
@@ -462,7 +469,6 @@ import {
type PlatformErrorDialogPayload,
} from './PlatformErrorDialog';
import { PlatformFeedbackView } from './PlatformFeedbackView';
import { shouldTickPlatformGenerationProgressClock } from './platformGenerationProgressClock';
import {
PlatformTaskCompletionDialog,
type PlatformTaskCompletionDialogPayload,
@@ -513,6 +519,31 @@ type PuzzleBackgroundCompileTask = {
error: string | null;
};
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;
}
type PuzzleDetailReturnTarget = {
tab: PlatformHomeTab;
};
@@ -574,6 +605,7 @@ type BabyObjectMatchGenerationPhase = 'generating' | 'ready' | 'failed';
type RecommendRuntimeState = {
activeKind: RecommendRuntimeKind | null;
barkBattlePublishedConfig: BarkBattlePublishedConfig | null;
babyObjectMatchDraft: BabyObjectMatchDraft | null;
bigFishRun: BigFishRuntimeSnapshotResponse | null;
jumpHopRun: JumpHopRunResponse['run'] | null;
@@ -621,11 +653,11 @@ const AGENT_RESULT_STRUCTURAL_BLOCKER_CODES = new Set([
'publish_missing_main_chapter',
'publish_missing_first_act',
]);
const RECOMMEND_RUNTIME_BACKGROUND_AUTH_OPTIONS =
const RECOMMEND_RUNTIME_BACKGROUND_AUTH_OPTIONS: JumpHopRuntimeRequestOptions =
BACKGROUND_AUTH_REQUEST_OPTIONS;
const RECOMMEND_PUZZLE_BACKGROUND_AUTH_OPTIONS =
const RECOMMEND_PUZZLE_BACKGROUND_AUTH_OPTIONS: JumpHopRuntimeRequestOptions =
RECOMMEND_RUNTIME_BACKGROUND_AUTH_OPTIONS;
async function buildRecommendRuntimeGuestOptions() {
async function buildRecommendRuntimeGuestOptions(): Promise<JumpHopRuntimeRequestOptions> {
const { token } = await ensureRuntimeGuestToken();
return {
...RECOMMEND_RUNTIME_BACKGROUND_AUTH_OPTIONS,
@@ -640,9 +672,9 @@ function shouldUseRecommendRuntimeGuestAuth(
async function buildRecommendRuntimeAuthOptions(
authUi: { user?: { id?: string } | null } | null | undefined,
embedded?: boolean,
) {
): Promise<JumpHopRuntimeRequestOptions> {
if (!embedded) {
return {};
return RECOMMEND_RUNTIME_BACKGROUND_AUTH_OPTIONS;
}
if (shouldUseRecommendRuntimeGuestAuth(authUi)) {
@@ -662,28 +694,7 @@ function getPlatformPublicGalleryEntryTime(entry: PlatformPublicGalleryCard) {
}
function getPlatformPublicGalleryEntryKey(entry: PlatformPublicGalleryCard) {
const kind = isBigFishGalleryEntry(entry)
? 'big-fish'
: isPuzzleGalleryEntry(entry)
? 'puzzle'
: isPuzzleClearGalleryEntry(entry)
? 'puzzle-clear'
: isJumpHopGalleryEntry(entry)
? 'jump-hop'
: isWoodenFishGalleryEntry(entry)
? 'wooden-fish'
: isMatch3DGalleryEntry(entry)
? 'match3d'
: isSquareHoleGalleryEntry(entry)
? 'square-hole'
: isVisualNovelGalleryEntry(entry)
? 'visual-novel'
: isBarkBattleGalleryEntry(entry)
? 'bark-battle'
: isEdutainmentGalleryEntry(entry)
? `edutainment:${entry.templateId}`
: 'rpg';
return `${kind}:${entry.ownerUserId}:${entry.profileId}`;
return buildPlatformPublicGalleryCardKey(entry);
}
function getPlatformRecommendRuntimeKind(
@@ -769,7 +780,7 @@ function isRecommendRuntimeReadyForEntry(
return Boolean(state.visualNovelRun);
}
if (expectedKind === 'bark-battle') {
return true;
return Boolean(state.barkBattlePublishedConfig);
}
if (expectedKind === 'edutainment') {
return Boolean(state.babyObjectMatchDraft);
@@ -2084,6 +2095,7 @@ function buildJumpHopPendingSession(
templateId: 'jump-hop',
templateName: '跳一跳',
profileId: item.profileId,
themeText: item.themeText || item.workTitle,
workTitle: item.workTitle,
workDescription: item.workDescription,
themeTags: item.themeTags,
@@ -2899,6 +2911,7 @@ function buildPendingJumpHopWorks(
profileId: `jump-hop-profile-${sessionId}`,
ownerUserId: '',
sourceSessionId: sessionId,
themeText: '跳一跳',
workTitle: '跳一跳草稿',
workDescription:
state.status === 'failed'
@@ -3785,6 +3798,8 @@ export function PlatformEntryFlowShellImpl({
const [jumpHopRun, setJumpHopRun] = useState<
JumpHopRunResponse['run'] | null
>(null);
const [jumpHopRuntimeRequestOptions, setJumpHopRuntimeRequestOptions] =
useState<JumpHopRuntimeRequestOptions | null>(null);
const [jumpHopWork, setJumpHopWork] =
useState<JumpHopWorkProfileResponse | null>(null);
const [jumpHopGalleryEntries, setJumpHopGalleryEntries] = useState<
@@ -5644,30 +5659,27 @@ export function PlatformEntryFlowShellImpl({
]);
useEffect(() => {
const activeGenerationState =
selectionStage === 'puzzle-generating'
? puzzleGenerationState
: selectionStage === 'match3d-generating'
? match3dGenerationState
: selectionStage === 'big-fish-generating'
? bigFishGenerationState
: selectionStage === 'square-hole-generating'
? squareHoleGenerationState
: selectionStage === 'jump-hop-generating'
? jumpHopGenerationState
: selectionStage === 'puzzle-clear-generating'
? puzzleClearGenerationState
: selectionStage === 'wooden-fish-generating'
? woodenFishGenerationState
: selectionStage === 'baby-object-match-generating'
? babyObjectMatchGenerationState
: null;
const shouldTickProgress = shouldTickPlatformGenerationProgressClock({
const activeGenerationState = resolveMiniGameGenerationProgressTickState(
selectionStage,
generationState: activeGenerationState,
visualNovelGenerationStartedAtMs,
visualNovelGenerationPhase,
});
{
puzzle: puzzleGenerationState,
'big-fish': bigFishGenerationState,
'square-hole': squareHoleGenerationState,
match3d: match3dGenerationState,
'baby-object-match': babyObjectMatchGenerationState,
'jump-hop': jumpHopGenerationState,
'puzzle-clear': puzzleClearGenerationState,
'wooden-fish': woodenFishGenerationState,
},
);
const shouldTickProgress =
selectionStage === 'visual-novel-generating'
? visualNovelGenerationStartedAtMs != null &&
visualNovelGenerationPhase !== 'ready' &&
visualNovelGenerationPhase !== 'failed'
: activeGenerationState != null &&
activeGenerationState.phase !== 'ready' &&
activeGenerationState.phase !== 'failed';
if (!shouldTickProgress) {
return undefined;
@@ -6505,7 +6517,7 @@ export function PlatformEntryFlowShellImpl({
sessionController.setCreationTypeError(errorMessage);
setPuzzleCreationError(errorMessage);
},
onActionComplete: async ({ payload, response, setSession }) => {
onActionComplete: async ({ payload, response, session, setSession }) => {
setPuzzleOperation(response.operation);
setSession(response.session);
const formPayload = buildPuzzleFormPayloadFromAction(payload);
@@ -6529,6 +6541,47 @@ export function PlatformEntryFlowShellImpl({
if (payload.action === 'compile_puzzle_draft') {
const openResult = selectionStageRef.current === 'puzzle-generating';
if (!isPuzzleCompileActionReady(response.session)) {
const nextPayload =
formPayload ?? buildPuzzleFormPayloadFromSession(response.session);
const fallbackGenerationState = createPuzzleDraftGenerationStateFromPayload(
nextPayload,
response.session,
);
const nextGenerationState = mergePuzzleSessionProgressIntoGenerationState(
puzzleGenerationState ?? fallbackGenerationState,
response.session,
);
activePuzzleGenerationSessionIdRef.current = response.session.sessionId;
setSelectionStage('puzzle-generating');
markDraftGenerating('puzzle', [
response.session.sessionId,
buildPuzzleResultWorkId(response.session.sessionId),
response.session.publishedProfileId,
buildPuzzleResultProfileId(response.session.sessionId),
]);
markPendingDraftGenerating(
'puzzle',
response.session.sessionId,
buildPendingPuzzleDraftMetadata(nextPayload),
);
setPuzzleGenerationState(nextGenerationState);
setPuzzleBackgroundCompileTasks((current) => {
const next = { ...current };
if (session.sessionId !== response.session.sessionId) {
delete next[session.sessionId];
}
next[response.session.sessionId] = {
session: response.session,
payload: nextPayload,
generationState: nextGenerationState,
error: null,
};
return next;
});
void refreshPuzzleShelf();
return { openResult: false };
}
setPuzzleGenerationState((current) =>
current
? resolveFinishedMiniGameDraftGenerationState(current, 'ready', {
@@ -7445,6 +7498,22 @@ export function PlatformEntryFlowShellImpl({
return;
}
if (hasRecoverableGeneratedPuzzleDraft(latestSession)) {
const payload =
puzzleGenerationViewPayload ??
buildPuzzleFormPayloadFromSession(latestSession);
const generationState =
puzzleGenerationViewState ??
createPuzzleDraftGenerationStateFromPayload(payload, latestSession);
await recoverCompletedPuzzleDraftGeneration({
sessionId: latestSession.sessionId,
payload,
generationState,
setSession: setPuzzleSession,
});
return;
}
setPuzzleSession(latestSession);
setPuzzleBackgroundCompileTasks((current) => {
const task = current[activePuzzleGenerationSessionId];
@@ -7488,6 +7557,9 @@ export function PlatformEntryFlowShellImpl({
};
}, [
activePuzzleGenerationSessionId,
puzzleGenerationViewPayload,
puzzleGenerationViewState,
recoverCompletedPuzzleDraftGeneration,
shouldPollPuzzleGenerationSession,
setPuzzleSession,
]);
@@ -7616,6 +7688,7 @@ export function PlatformEntryFlowShellImpl({
setJumpHopSession(null);
setJumpHopWork(null);
setJumpHopRun(null);
setJumpHopRuntimeRequestOptions(null);
setJumpHopGenerationState(null);
enterCreateTab();
setShowCreationTypeModal(false);
@@ -8778,6 +8851,7 @@ export function PlatformEntryFlowShellImpl({
setJumpHopRuntimeReturnStage('jump-hop-result');
setJumpHopGenerationState(null);
setJumpHopSession(null);
setJumpHopRuntimeRequestOptions(null);
setJumpHopError(null);
returnToCreationFlowSource();
}, [returnToCreationFlowSource]);
@@ -9774,20 +9848,26 @@ export function PlatformEntryFlowShellImpl({
const executeSquareHoleAction = squareHoleFlow.executeAction;
const retryMatch3DDraftGeneration = useCallback(() => {
if (match3dFormDraftPayload && !match3dSession?.draft?.profileId) {
void createMatch3DDraftFromForm(match3dFormDraftPayload);
if (match3dSession?.sessionId) {
const retryPayload =
match3dFormDraftPayload ??
buildMatch3DFormPayloadFromSession(match3dSession);
void executeMatch3DAction({
action: 'match3d_compile_draft',
generateClickSound: retryPayload.generateClickSound,
});
return;
}
void executeMatch3DAction({
action: 'match3d_compile_draft',
generateClickSound: match3dFormDraftPayload?.generateClickSound,
});
if (match3dFormDraftPayload) {
void createMatch3DDraftFromForm(match3dFormDraftPayload);
return;
}
}, [
createMatch3DDraftFromForm,
executeMatch3DAction,
match3dFormDraftPayload,
match3dSession?.draft?.profileId,
match3dSession,
]);
const retrySquareHoleAssetGeneration = useCallback(() => {
@@ -9820,6 +9900,7 @@ export function PlatformEntryFlowShellImpl({
);
setJumpHopWork(null);
setJumpHopRun(null);
setJumpHopRuntimeRequestOptions(null);
setJumpHopGenerationState(generationState);
setIsJumpHopBusy(true);
setSelectionStage('jump-hop-generating');
@@ -9834,6 +9915,8 @@ export function PlatformEntryFlowShellImpl({
created.session.sessionId,
{
actionType: 'compile-draft',
themeText:
payload?.themeText ?? created.session.draft?.themeText,
workTitle: payload?.workTitle ?? created.session.draft?.workTitle,
workDescription:
payload?.workDescription ??
@@ -9948,7 +10031,7 @@ export function PlatformEntryFlowShellImpl({
}, [compileJumpHopSession, jumpHopSession, setSelectionStage]);
const regenerateJumpHopAsset = useCallback(
async (actionType: 'regenerate-character' | 'regenerate-tiles') => {
async (actionType: 'regenerate-tiles') => {
if (!jumpHopSession?.sessionId) {
setSelectionStage('jump-hop-workspace');
return;
@@ -9964,6 +10047,9 @@ export function PlatformEntryFlowShellImpl({
jumpHopSession.sessionId,
{
actionType,
profileId:
jumpHopWork?.summary.profileId ?? jumpHopSession.draft?.profileId,
themeText: jumpHopSession.draft?.themeText,
workTitle: jumpHopSession.draft?.workTitle,
workDescription: jumpHopSession.draft?.workDescription,
themeTags: jumpHopSession.draft?.themeTags,
@@ -9989,9 +10075,7 @@ export function PlatformEntryFlowShellImpl({
} catch (error) {
const errorMessage = resolveRpgCreationErrorMessage(
error,
actionType === 'regenerate-character'
? '重新生成跳一跳角色失败。'
: '重新生成跳一跳地块失败。',
'重新生成跳一跳地块失败。',
);
setJumpHopError(errorMessage);
setJumpHopGenerationState(
@@ -10067,7 +10151,9 @@ export function PlatformEntryFlowShellImpl({
setJumpHopError(null);
setJumpHopRuntimeReturnStage('jump-hop-result');
try {
const response = await jumpHopClient.startRun(profileId);
const response = await jumpHopClient.startRun(profileId, {
runtimeMode: 'draft',
});
setJumpHopRun(response.run);
setSelectionStage('jump-hop-runtime');
} catch (error) {
@@ -10098,13 +10184,30 @@ export function PlatformEntryFlowShellImpl({
setJumpHopError(null);
setJumpHopRuntimeReturnStage(options.returnStage ?? 'work-detail');
try {
const runtimeGuestOptions = await buildRecommendRuntimeAuthOptions(
authUi,
options.embedded,
const runtimeGuestOptions =
options.embedded || shouldUseRecommendRuntimeGuestAuth(authUi)
? await buildRecommendRuntimeAuthOptions(authUi, true)
: RECOMMEND_RUNTIME_BACKGROUND_AUTH_OPTIONS;
setJumpHopRuntimeRequestOptions(
runtimeGuestOptions.runtimeGuestToken?.trim()
? {
runtimeGuestToken: runtimeGuestOptions.runtimeGuestToken,
authImpact: runtimeGuestOptions.authImpact,
skipAuth: runtimeGuestOptions.skipAuth,
skipRefresh: runtimeGuestOptions.skipRefresh,
notifyAuthStateChange:
runtimeGuestOptions.notifyAuthStateChange,
clearAuthOnUnauthorized:
runtimeGuestOptions.clearAuthOnUnauthorized,
}
: null,
);
const [detail, runResponse] = await Promise.all([
jumpHopClient.getWorkDetail(normalizedProfileId).catch(() => null),
jumpHopClient.startRun(normalizedProfileId, runtimeGuestOptions),
jumpHopClient.startRun(normalizedProfileId, {
...runtimeGuestOptions,
runtimeMode: 'published',
}),
]);
if (detail?.item) {
setJumpHopWork(detail.item);
@@ -10142,7 +10245,10 @@ export function PlatformEntryFlowShellImpl({
setIsJumpHopBusy(true);
setJumpHopError(null);
try {
const response = await jumpHopClient.restartRun(runId);
const response = await jumpHopClient.restartRun(
runId,
jumpHopRuntimeRequestOptions ?? undefined,
);
setJumpHopRun(response.run);
} catch (error) {
setJumpHopError(
@@ -10151,16 +10257,29 @@ export function PlatformEntryFlowShellImpl({
} finally {
setIsJumpHopBusy(false);
}
}, [jumpHopRun?.runId, startJumpHopTestRunFromProfile]);
}, [
jumpHopRun?.runId,
jumpHopRuntimeRequestOptions,
startJumpHopTestRunFromProfile,
]);
const submitJumpHopJumpAction = useCallback(
async (payload: { chargeMs: number }) => {
async (
payload: Pick<
JumpHopJumpRequest,
'dragDistance' | 'dragVectorX' | 'dragVectorY'
>,
) => {
const runId = jumpHopRun?.runId;
if (!runId) {
return;
}
try {
const response = await jumpHopClient.submitJump(runId, payload);
const response = await jumpHopClient.submitJump(
runId,
payload,
jumpHopRuntimeRequestOptions ?? undefined,
);
setJumpHopRun(response.run);
} catch (error) {
setJumpHopError(
@@ -10168,7 +10287,7 @@ export function PlatformEntryFlowShellImpl({
);
}
},
[jumpHopRun?.runId],
[jumpHopRun?.runId, jumpHopRuntimeRequestOptions],
);
const compilePuzzleClearSession = useCallback(
@@ -11123,15 +11242,25 @@ export function PlatformEntryFlowShellImpl({
);
const retryPuzzleDraftGeneration = useCallback(() => {
if (puzzleFormDraftPayload) {
void createPuzzleDraftFromForm(puzzleFormDraftPayload);
if (puzzleSession?.sessionId) {
const retryPayload =
puzzleFormDraftPayload ??
buildPuzzleFormPayloadFromSession(puzzleSession);
void executePuzzleAction(
buildPuzzleCompileActionFromFormPayload(retryPayload),
);
return;
}
void executePuzzleAction(
buildPuzzleCompileActionFromFormPayload(puzzleFormDraftPayload),
);
}, [createPuzzleDraftFromForm, executePuzzleAction, puzzleFormDraftPayload]);
if (puzzleFormDraftPayload) {
void createPuzzleDraftFromForm(puzzleFormDraftPayload);
}
}, [
createPuzzleDraftFromForm,
executePuzzleAction,
puzzleFormDraftPayload,
puzzleSession,
]);
const retryVisualNovelDraftGeneration = useCallback(() => {
if (!visualNovelFormDraftPayload) {
@@ -12929,6 +13058,154 @@ export function PlatformEntryFlowShellImpl({
],
);
const handleDeleteJumpHopWork = useCallback(
(work: JumpHopWorkSummaryResponse) => {
if (deletingCreationWorkId) {
return;
}
const noticeKeys = collectDraftNoticeKeys('jump-hop', [
work.workId,
work.profileId,
work.sourceSessionId,
]);
requestDeleteCreationWork({
id: work.workId,
title: work.workTitle || '未命名跳一跳',
detail:
work.publicationStatus === 'published'
? '删除后会从你的作品列表和公开广场中移除。'
: '删除后会从你的作品列表中移除。',
run: () => {
setDeletingCreationWorkId(work.workId);
setJumpHopError(null);
void jumpHopClient
.deleteWork(work.profileId)
.then((response) => {
markDraftNoticeSeen(noticeKeys);
setJumpHopWorks(response.items);
void refreshJumpHopGallery();
})
.catch((error) => {
setJumpHopError(
resolvePuzzleErrorMessage(error, '删除跳一跳作品失败。'),
);
})
.finally(() => {
setDeletingCreationWorkId(null);
});
},
});
},
[
deletingCreationWorkId,
markDraftNoticeSeen,
refreshJumpHopGallery,
requestDeleteCreationWork,
resolvePuzzleErrorMessage,
setJumpHopError,
],
);
const handleDeleteWoodenFishWork = useCallback(
(work: WoodenFishWorkSummaryResponse) => {
if (deletingCreationWorkId) {
return;
}
const noticeKeys = collectDraftNoticeKeys('wooden-fish', [
work.workId,
work.profileId,
work.sourceSessionId,
]);
requestDeleteCreationWork({
id: work.workId,
title: work.workTitle || '未命名敲木鱼',
detail:
work.publicationStatus === 'published'
? '删除后会从你的作品列表和公开广场中移除。'
: '删除后会从你的作品列表中移除。',
run: () => {
setDeletingCreationWorkId(work.workId);
setWoodenFishError(null);
void woodenFishClient
.deleteWork(work.profileId)
.then((response) => {
markDraftNoticeSeen(noticeKeys);
setWoodenFishWorks(response.items);
void refreshWoodenFishGallery();
})
.catch((error) => {
setWoodenFishError(
resolvePuzzleErrorMessage(error, '删除敲木鱼作品失败。'),
);
})
.finally(() => {
setDeletingCreationWorkId(null);
});
},
});
},
[
deletingCreationWorkId,
markDraftNoticeSeen,
refreshWoodenFishGallery,
requestDeleteCreationWork,
resolvePuzzleErrorMessage,
setWoodenFishError,
],
);
const handleDeleteBarkBattleWork = useCallback(
(work: BarkBattleWorkSummary) => {
if (deletingCreationWorkId) {
return;
}
const noticeKeys = collectDraftNoticeKeys('bark-battle', [
work.workId,
work.draftId,
]);
requestDeleteCreationWork({
id: work.workId,
title: work.title || '未命名汪汪声浪',
detail:
work.status === 'published'
? '删除后会从你的作品列表和公开广场中移除。'
: '删除后会从你的作品列表中移除。',
run: () => {
setDeletingCreationWorkId(work.workId);
setBarkBattleError(null);
void deleteBarkBattleWork(work.workId)
.then((response) => {
markDraftNoticeSeen(noticeKeys);
setBarkBattleWorks(mergeBarkBattleWorksByWorkId(response.items));
void refreshBarkBattleGallery();
})
.catch((error) => {
setBarkBattleError(
resolveBarkBattleErrorMessage(error, '删除汪汪声浪作品失败。'),
);
})
.finally(() => {
setDeletingCreationWorkId(null);
});
},
});
},
[
deletingCreationWorkId,
markDraftNoticeSeen,
refreshBarkBattleGallery,
requestDeleteCreationWork,
resolveBarkBattleErrorMessage,
setBarkBattleError,
],
);
const handleDeleteVisualNovelWork = useCallback(
(work: VisualNovelWorkSummary) => {
if (deletingCreationWorkId) {
@@ -15139,6 +15416,14 @@ export function PlatformEntryFlowShellImpl({
return;
}
if (isJumpHopGalleryEntry(selectedPublicWorkDetail)) {
setPublicWorkDetailError(null);
void startJumpHopRunFromProfile(selectedPublicWorkDetail.profileId, {
returnStage: 'work-detail',
});
return;
}
runProtectedAction(() => {
if (isBigFishGalleryEntry(selectedPublicWorkDetail)) {
const work = mapPublicWorkDetailToBigFishWork(selectedPublicWorkDetail);
@@ -15699,37 +15984,15 @@ export function PlatformEntryFlowShellImpl({
run={jumpHopRun}
isBusy={isJumpHopBusy}
error={jumpHopError}
runtimeRequestOptions={jumpHopRuntimeRequestOptions ?? undefined}
onBack={() => {
setActiveRecommendRuntimeKind(null);
}}
onRestart={() => {
if (!jumpHopRun?.runId || isJumpHopBusy) {
return;
}
setIsJumpHopBusy(true);
setJumpHopError(null);
void jumpHopClient
.restartRun(jumpHopRun.runId)
.then((response) => {
setJumpHopRun(response.run);
})
.catch((error) => {
setJumpHopError(
resolveRpgCreationErrorMessage(error, '重新开始跳一跳失败。'),
);
})
.finally(() => {
setIsJumpHopBusy(false);
});
void restartJumpHopRuntimeRun();
}}
onJump={async (payload) => {
const runId = jumpHopRun?.runId;
if (!runId) {
throw new Error('跳一跳运行态缺少 runId。');
}
const response = await jumpHopClient.submitJump(runId, payload);
setJumpHopRun(response.run);
await submitJumpHopJumpAction(payload);
}}
/>
);
@@ -15975,6 +16238,30 @@ export function PlatformEntryFlowShellImpl({
swapPuzzleClearCardsInRun,
]);
const activeRecommendEntry =
activeRecommendEntryKey && !isDesktopLayout
? (recommendRuntimeEntries.find(
(entry) =>
getPlatformPublicGalleryEntryKey(entry) ===
activeRecommendEntryKey,
) ?? null)
: null;
const isActiveRecommendRuntimeReady =
activeRecommendEntry !== null &&
isRecommendRuntimeReadyForEntry(activeRecommendEntry, {
activeKind: activeRecommendRuntimeKind,
barkBattlePublishedConfig,
babyObjectMatchDraft,
bigFishRun,
jumpHopRun,
match3dRun,
puzzleRun,
puzzleClearRun,
squareHoleRun,
visualNovelRun,
woodenFishRun,
});
useEffect(() => {
if (
isDesktopLayout ||
@@ -15992,26 +16279,6 @@ export function PlatformEntryFlowShellImpl({
return;
}
const activeRecommendEntry = activeRecommendEntryKey
? (recommendRuntimeEntries.find(
(entry) =>
getPlatformPublicGalleryEntryKey(entry) === activeRecommendEntryKey,
) ?? null)
: null;
const isActiveRecommendRuntimeReady =
activeRecommendEntry !== null &&
isRecommendRuntimeReadyForEntry(activeRecommendEntry, {
activeKind: activeRecommendRuntimeKind,
babyObjectMatchDraft,
bigFishRun,
jumpHopRun,
match3dRun,
puzzleRun,
puzzleClearRun,
squareHoleRun,
visualNovelRun,
woodenFishRun,
});
if (
(activeRecommendEntry !== null && isActiveRecommendRuntimeReady) ||
isStartingRecommendEntry
@@ -16027,9 +16294,12 @@ export function PlatformEntryFlowShellImpl({
}, [
activeRecommendEntryKey,
activeRecommendRuntimeKind,
activeRecommendEntry,
barkBattlePublishedConfig,
babyObjectMatchDraft,
bigFishRun,
jumpHopRun,
isActiveRecommendRuntimeReady,
isStartingRecommendEntry,
match3dRun,
platformBootstrap.isLoadingPlatform,
@@ -17316,7 +17586,13 @@ export function PlatformEntryFlowShellImpl({
}
: null
}
onDeleteJumpHop={null}
onDeleteJumpHop={
isJumpHopCreationVisible
? (item) => {
handleDeleteJumpHopWork(item);
}
: null
}
onOpenPuzzleClearDetail={
isPuzzleClearCreationVisible
? (item) => {
@@ -17334,7 +17610,9 @@ export function PlatformEntryFlowShellImpl({
void openWoodenFishDraft(item);
});
}}
onDeleteWoodenFish={null}
onDeleteWoodenFish={(item) => {
handleDeleteWoodenFishWork(item);
}}
match3dItems={match3dShelfItems}
onOpenMatch3DDetail={(item) => {
runProtectedAction(() => {
@@ -17398,6 +17676,9 @@ export function PlatformEntryFlowShellImpl({
openBarkBattleDraft(item);
});
}}
onDeleteBarkBattle={(item) => {
handleDeleteBarkBattleWork(item);
}}
visualNovelItems={visualNovelShelfItems}
onOpenVisualNovelDetail={(item) => {
runProtectedAction(() => {
@@ -17482,6 +17763,7 @@ export function PlatformEntryFlowShellImpl({
onOpenRecommendGalleryDetail={openRecommendGalleryDetail}
recommendRuntimeContent={recommendRuntimeContent}
activeRecommendEntryKey={activeRecommendEntryKey}
isRecommendRuntimeReady={isActiveRecommendRuntimeReady}
isStartingRecommendEntry={
isStartingRecommendEntry ||
isBigFishBusy ||
@@ -17847,7 +18129,6 @@ export function PlatformEntryFlowShellImpl({
backLabel="返回创作中心"
settingActionLabel={null}
retryLabel="重新生成草稿"
settingTitle="当前玩法信息"
settingDescription={null}
progressTitle="大鱼吃小鱼草稿生成进度"
activeBadgeLabel="草稿生成中"
@@ -18253,7 +18534,6 @@ export function PlatformEntryFlowShellImpl({
backLabel="返回创作中心"
settingActionLabel={null}
retryLabel="重新生成草稿"
settingTitle="当前宝贝识物信息"
settingDescription={null}
progressTitle="宝贝识物草稿生成进度"
activeBadgeLabel="草稿生成中"
@@ -18454,7 +18734,6 @@ export function PlatformEntryFlowShellImpl({
backLabel="返回创作中心"
settingActionLabel={null}
retryLabel="重新生成图片"
settingTitle="当前方洞挑战"
settingDescription={null}
progressTitle="方洞挑战图片生成进度"
activeBadgeLabel="图片生成中"
@@ -18697,9 +18976,6 @@ export function PlatformEntryFlowShellImpl({
}}
onStartTestRun={startJumpHopTestRunFromProfile}
onPublish={publishJumpHopDraft}
onRegenerateCharacter={() => {
void regenerateJumpHopAsset('regenerate-character');
}}
onRegenerateTiles={() => {
void regenerateJumpHopAsset('regenerate-tiles');
}}
@@ -18735,6 +19011,7 @@ export function PlatformEntryFlowShellImpl({
profile={jumpHopWork}
isBusy={isJumpHopBusy}
error={jumpHopError}
runtimeRequestOptions={jumpHopRuntimeRequestOptions ?? undefined}
onBack={() => {
setSelectionStage(jumpHopRuntimeReturnStage);
}}
@@ -19250,7 +19527,6 @@ export function PlatformEntryFlowShellImpl({
backLabel="返回创作中心"
settingActionLabel={null}
retryLabel="重新生成草稿"
settingTitle="当前视觉小说信息"
settingDescription={null}
progressTitle="视觉小说草稿生成进度"
activeBadgeLabel="草稿生成中"
@@ -19501,7 +19777,6 @@ export function PlatformEntryFlowShellImpl({
backLabel="返回创作中心"
settingActionLabel={null}
retryLabel="继续生成草稿"
settingTitle="当前世界信息"
settingDescription={null}
progressTitle="世界草稿生成进度"
activeBadgeLabel="草稿编译中"