This commit is contained in:
2026-04-26 17:53:31 +08:00
46 changed files with 1027 additions and 626 deletions

View File

@@ -60,7 +60,7 @@ import {
createMiniGameDraftGenerationState,
type MiniGameDraftGenerationState,
} from '../../services/miniGameDraftGenerationProgress';
import { getPlatformProfileDashboard } from '../../services/platform-entry';
import { getPlatformProfileDashboard } from '../../services/platform-entry/platformProfileClient';
import {
createPuzzleAgentSession,
executePuzzleAgentAction,
@@ -81,15 +81,12 @@ import { deletePuzzleWork, listPuzzleWorks } from '../../services/puzzle-works';
import { isSamePuzzlePublicWorkCode } from '../../services/publicWorkCode';
import { deleteRpgCreationAgentSession } from '../../services/rpg-creation';
import { rpgCreationPreviewAdapter } from '../../services/rpg-creation/rpgCreationPreviewAdapter';
import { deleteRpgEntryWorldProfile } from '../../services/rpg-entry';
import { getRpgEntryWorldGalleryDetailByCode } from '../../services/rpg-entry/rpgEntryLibraryClient';
import {
deleteRpgEntryWorldProfile,
getRpgEntryWorldGalleryDetailByCode,
} from '../../services/rpg-entry/rpgEntryLibraryClient';
import type { CustomWorldProfile } from '../../types';
import { useAuthUi } from '../auth/AuthUiContext';
import { CustomWorldCreationHub } from '../custom-world-home/CustomWorldCreationHub';
import { PuzzleAgentWorkspace } from '../puzzle-agent/PuzzleAgentWorkspace';
import { PuzzleGalleryDetailView } from '../puzzle-gallery/PuzzleGalleryDetailView';
import { PuzzleResultView } from '../puzzle-result/PuzzleResultView';
import { PuzzleRuntimeShell } from '../puzzle-runtime/PuzzleRuntimeShell';
import { useRpgCreationAgentOperationPolling } from '../rpg-entry/useRpgCreationAgentOperationPolling';
import { useRpgCreationEnterWorld } from '../rpg-entry/useRpgCreationEnterWorld';
import { useRpgCreationResultAutosave } from '../rpg-entry/useRpgCreationResultAutosave';
@@ -334,6 +331,41 @@ const BigFishRuntimeShell = lazy(async () => {
};
});
const CustomWorldCreationHub = lazy(async () => {
const module = await import('../custom-world-home/CustomWorldCreationHub');
return {
default: module.CustomWorldCreationHub,
};
});
const PuzzleAgentWorkspace = lazy(async () => {
const module = await import('../puzzle-agent/PuzzleAgentWorkspace');
return {
default: module.PuzzleAgentWorkspace,
};
});
const PuzzleResultView = lazy(async () => {
const module = await import('../puzzle-result/PuzzleResultView');
return {
default: module.PuzzleResultView,
};
});
const PuzzleGalleryDetailView = lazy(async () => {
const module = await import('../puzzle-gallery/PuzzleGalleryDetailView');
return {
default: module.PuzzleGalleryDetailView,
};
});
const PuzzleRuntimeShell = lazy(async () => {
const module = await import('../puzzle-runtime/PuzzleRuntimeShell');
return {
default: module.PuzzleRuntimeShell,
};
});
function LazyPanelFallback({ label }: { label: string }) {
return (
<div className="flex h-full min-h-0 items-center justify-center">
@@ -1649,97 +1681,99 @@ export function PlatformEntryFlowShellImpl({
]);
const creationHubContent = (
<CustomWorldCreationHub
items={creationHubItems}
loading={
platformBootstrap.isLoadingPlatform ||
isBigFishLoadingLibrary ||
isPuzzleLoadingLibrary
}
error={
platformBootstrap.isLoadingPlatform ||
isBigFishLoadingLibrary ||
isPuzzleLoadingLibrary
? null
: (platformBootstrap.platformError ??
sessionController.agentWorkspaceRestoreError ??
bigFishError ??
puzzleError)
}
onRetry={() => {
platformBootstrap.setPlatformError(null);
setBigFishError(null);
setPuzzleError(null);
void platformBootstrap.refreshCustomWorldWorks().catch((error) => {
platformBootstrap.setPlatformError(
resolveRpgCreationErrorMessage(error, '读取创作作品列表失败。'),
);
});
void refreshBigFishShelf();
void refreshPuzzleShelf();
}}
createError={
sessionController.creationTypeError ?? bigFishError ?? puzzleError
}
createBusy={
sessionController.isCreatingAgentSession ||
isBigFishBusy ||
isPuzzleBusy
}
onCreateType={handleCreationHubCreateType}
onOpenDraft={(item) => {
runProtectedAction(() => {
void detailNavigation.handleOpenCreationWork(item);
});
}}
onEnterPublished={(profileId) => {
runProtectedAction(() => {
const matchedWork = creationHubItems.find(
(entry) => entry.profileId === profileId,
);
if (!matchedWork) {
return;
}
void detailNavigation.handleOpenCreationWork(matchedWork);
});
}}
onDeletePublished={(item) => {
handleDeletePublishedWork(item);
}}
deletingWorkId={deletingCreationWorkId}
onExperienceRpg={(item) => {
handleExperienceRpgWork(item);
}}
rpgLibraryEntries={platformBootstrap.savedCustomWorldEntries}
bigFishItems={bigFishWorks}
onOpenBigFishDetail={(item) => {
runProtectedAction(() => {
void openBigFishDraft(item);
});
}}
onExperienceBigFish={(item) => {
runProtectedAction(() => {
void startBigFishRunFromWork(item);
});
}}
onDeleteBigFish={(item) => {
handleDeleteBigFishWork(item);
}}
puzzleItems={puzzleWorks}
onOpenPuzzleDetail={(item) => {
runProtectedAction(() => {
void openPuzzleDraft(item);
});
}}
onExperiencePuzzle={(profileId) => {
runProtectedAction(() => {
void startPuzzleRunFromProfile(profileId);
});
}}
onDeletePuzzle={(item) => {
handleDeletePuzzleWork(item);
}}
/>
<Suspense fallback={<LazyPanelFallback label="正在加载创作中心..." />}>
<CustomWorldCreationHub
items={creationHubItems}
loading={
platformBootstrap.isLoadingPlatform ||
isBigFishLoadingLibrary ||
isPuzzleLoadingLibrary
}
error={
platformBootstrap.isLoadingPlatform ||
isBigFishLoadingLibrary ||
isPuzzleLoadingLibrary
? null
: (platformBootstrap.platformError ??
sessionController.agentWorkspaceRestoreError ??
bigFishError ??
puzzleError)
}
onRetry={() => {
platformBootstrap.setPlatformError(null);
setBigFishError(null);
setPuzzleError(null);
void platformBootstrap.refreshCustomWorldWorks().catch((error) => {
platformBootstrap.setPlatformError(
resolveRpgCreationErrorMessage(error, '读取创作作品列表失败。'),
);
});
void refreshBigFishShelf();
void refreshPuzzleShelf();
}}
createError={
sessionController.creationTypeError ?? bigFishError ?? puzzleError
}
createBusy={
sessionController.isCreatingAgentSession ||
isBigFishBusy ||
isPuzzleBusy
}
onCreateType={handleCreationHubCreateType}
onOpenDraft={(item) => {
runProtectedAction(() => {
void detailNavigation.handleOpenCreationWork(item);
});
}}
onEnterPublished={(profileId) => {
runProtectedAction(() => {
const matchedWork = creationHubItems.find(
(entry) => entry.profileId === profileId,
);
if (!matchedWork) {
return;
}
void detailNavigation.handleOpenCreationWork(matchedWork);
});
}}
onDeletePublished={(item) => {
handleDeletePublishedWork(item);
}}
deletingWorkId={deletingCreationWorkId}
onExperienceRpg={(item) => {
handleExperienceRpgWork(item);
}}
rpgLibraryEntries={platformBootstrap.savedCustomWorldEntries}
bigFishItems={bigFishWorks}
onOpenBigFishDetail={(item) => {
runProtectedAction(() => {
void openBigFishDraft(item);
});
}}
onExperienceBigFish={(item) => {
runProtectedAction(() => {
void startBigFishRunFromWork(item);
});
}}
onDeleteBigFish={(item) => {
handleDeleteBigFishWork(item);
}}
puzzleItems={puzzleWorks}
onOpenPuzzleDetail={(item) => {
runProtectedAction(() => {
void openPuzzleDraft(item);
});
}}
onExperiencePuzzle={(profileId) => {
runProtectedAction(() => {
void startPuzzleRunFromProfile(profileId);
});
}}
onDeletePuzzle={(item) => {
handleDeletePuzzleWork(item);
}}
/>
</Suspense>
);
return (
@@ -2076,21 +2110,23 @@ export function PlatformEntryFlowShellImpl({
exit={{ opacity: 0, y: -12 }}
className="flex h-full min-h-0 flex-col"
>
<PuzzleAgentWorkspace
session={puzzleSession}
activeOperation={puzzleOperation}
streamingReplyText={streamingPuzzleReplyText}
isStreamingReply={isStreamingPuzzleReply}
isBusy={isPuzzleBusy || isStreamingPuzzleReply}
error={puzzleError}
onBack={leavePuzzleFlow}
onSubmitMessage={(payload) => {
void submitPuzzleMessage(payload);
}}
onExecuteAction={(payload) => {
void executePuzzleAction(payload);
}}
/>
<Suspense fallback={<LazyPanelFallback label="正在加载拼图创作..." />}>
<PuzzleAgentWorkspace
session={puzzleSession}
activeOperation={puzzleOperation}
streamingReplyText={streamingPuzzleReplyText}
isStreamingReply={isStreamingPuzzleReply}
isBusy={isPuzzleBusy || isStreamingPuzzleReply}
error={puzzleError}
onBack={leavePuzzleFlow}
onSubmitMessage={(payload) => {
void submitPuzzleMessage(payload);
}}
onExecuteAction={(payload) => {
void executePuzzleAction(payload);
}}
/>
</Suspense>
</motion.div>
)}
@@ -2147,18 +2183,20 @@ export function PlatformEntryFlowShellImpl({
exit={{ opacity: 0, y: -12 }}
className="flex h-full min-h-0 flex-col"
>
<PuzzleResultView
session={puzzleSession}
author={authUi?.user ?? null}
isBusy={isPuzzleBusy}
error={puzzleError}
onBack={() => {
setSelectionStage('puzzle-agent-workspace');
}}
onExecuteAction={(payload) => {
void executePuzzleAction(payload);
}}
/>
<Suspense fallback={<LazyPanelFallback label="正在加载拼图结果..." />}>
<PuzzleResultView
session={puzzleSession}
author={authUi?.user ?? null}
isBusy={isPuzzleBusy}
error={puzzleError}
onBack={() => {
setSelectionStage('puzzle-agent-workspace');
}}
onExecuteAction={(payload) => {
void executePuzzleAction(payload);
}}
/>
</Suspense>
</motion.div>
)}
@@ -2170,31 +2208,33 @@ export function PlatformEntryFlowShellImpl({
exit={{ opacity: 0, y: -12 }}
className="flex h-full min-h-0 flex-col"
>
<PuzzleGalleryDetailView
item={selectedPuzzleDetail}
isBusy={isPuzzleBusy}
error={puzzleError}
onBack={() => {
platformBootstrap.setPlatformTab(
puzzleDetailReturnTarget?.tab ?? 'home',
);
setPuzzleDetailReturnTarget(null);
setSelectionStage('platform');
}}
onEdit={
selectedPuzzleDetail.ownerUserId === authUi?.user?.id &&
Boolean(selectedPuzzleDetail.sourceSessionId?.trim())
? () => {
runProtectedAction(() => {
void openPuzzleDraft(selectedPuzzleDetail);
});
}
: null
}
onStartGame={() => {
void startPuzzleRunFromProfile(selectedPuzzleDetail.profileId);
}}
/>
<Suspense fallback={<LazyPanelFallback label="正在加载拼图详情..." />}>
<PuzzleGalleryDetailView
item={selectedPuzzleDetail}
isBusy={isPuzzleBusy}
error={puzzleError}
onBack={() => {
platformBootstrap.setPlatformTab(
puzzleDetailReturnTarget?.tab ?? 'home',
);
setPuzzleDetailReturnTarget(null);
setSelectionStage('platform');
}}
onEdit={
selectedPuzzleDetail.ownerUserId === authUi?.user?.id &&
Boolean(selectedPuzzleDetail.sourceSessionId?.trim())
? () => {
runProtectedAction(() => {
void openPuzzleDraft(selectedPuzzleDetail);
});
}
: null
}
onStartGame={() => {
void startPuzzleRunFromProfile(selectedPuzzleDetail.profileId);
}}
/>
</Suspense>
</motion.div>
)}
@@ -2206,23 +2246,25 @@ export function PlatformEntryFlowShellImpl({
exit={{ opacity: 0 }}
className="fixed inset-0 z-[100]"
>
<PuzzleRuntimeShell
run={puzzleRun}
isBusy={isPuzzleBusy || isPuzzleNextLevelGenerating}
error={puzzleError}
onBack={() => {
setSelectionStage('puzzle-gallery-detail');
}}
onSwapPieces={(payload) => {
void swapPuzzlePiecesInRun(payload);
}}
onDragPiece={(payload) => {
void dragPuzzlePiece(payload);
}}
onAdvanceNextLevel={() => {
void advancePuzzleLevel();
}}
/>
<Suspense fallback={<LazyPanelFallback label="正在加载拼图玩法..." />}>
<PuzzleRuntimeShell
run={puzzleRun}
isBusy={isPuzzleBusy || isPuzzleNextLevelGenerating}
error={puzzleError}
onBack={() => {
setSelectionStage('puzzle-gallery-detail');
}}
onSwapPieces={(payload) => {
void swapPuzzlePiecesInRun(payload);
}}
onDragPiece={(payload) => {
void dragPuzzlePiece(payload);
}}
onAdvanceNextLevel={() => {
void advancePuzzleLevel();
}}
/>
</Suspense>
{isPuzzleNextLevelGenerating ? (
<div className="fixed inset-0 z-[120] flex items-center justify-center bg-slate-950/62 px-5 backdrop-blur-sm">
<div className="flex max-w-[18rem] flex-col items-center gap-3 rounded-[1.5rem] border border-white/12 bg-slate-950/92 px-6 py-5 text-center text-white shadow-[0_28px_80px_rgba(0,0,0,0.35)]">

View File

@@ -2,7 +2,7 @@ import type {
CustomWorldAgentSessionSnapshot,
} from '../../../packages/shared/src/contracts/customWorldAgent';
import type { HydratedSavedGameSnapshot } from '../../persistence/runtimeSnapshotTypes';
import type { CustomWorldProfile, GameState } from '../../types';
import type { CustomWorldProfile } from '../../types';
export type SelectionStage =
| 'platform'
@@ -34,7 +34,6 @@ export type SyncedAgentDraftResult = {
export type PlatformEntryFlowShellProps = {
selectionStage: SelectionStage;
setSelectionStage: (stage: SelectionStage) => void;
gameState: GameState;
hasSavedGame: boolean;
savedSnapshot: HydratedSavedGameSnapshot | null;
handleContinueGame: (snapshot?: HydratedSavedGameSnapshot | null) => void;

View File

@@ -28,8 +28,8 @@ import { EDITOR_ITEM_CATALOG_API_PATH } from '../../editor/shared/editorApiClien
import { fetchJson } from '../../editor/shared/jsonClient';
import { useCombatFlow } from '../../hooks/useCombatFlow';
import { useNpcInteractionFlow } from '../../hooks/useNpcInteractionFlow';
import { useRpgRuntimeStory } from '../../hooks/rpg-runtime-story';
import { useRpgSessionBootstrap } from '../../hooks/rpg-session';
import { useRpgRuntimeStory } from '../../hooks/rpg-runtime-story/useRpgRuntimeStory';
import { useRpgSessionBootstrap } from '../../hooks/rpg-session/useRpgSessionBootstrap';
import { buildSkillActionPrompt } from '../../prompts/customWorldEntityActionPrompts';
import type { CustomWorldSceneImageResult } from '../../services/aiTypes';
import { resolveCustomWorldCampScene } from '../../services/customWorldCamp';

View File

@@ -21,7 +21,6 @@ import type { AuthUser } from '../../services/authService';
import { ApiClientError } from '../../services/apiClient';
import {
clearRpgProfileBrowseHistory as clearProfileBrowseHistory,
deleteRpgEntryWorldProfile,
getRpgEntryWorldGalleryDetail,
getRpgProfileDashboard as getProfileDashboard,
listRpgEntryWorldGallery,
@@ -47,8 +46,10 @@ import {
listPuzzleGallery,
} from '../../services/puzzle-gallery';
import { listPuzzleWorks } from '../../services/puzzle-works';
import { getRpgEntryWorldGalleryDetailByCode } from '../../services/rpg-entry/rpgEntryLibraryClient';
import type { GameState } from '../../types';
import {
deleteRpgEntryWorldProfile,
getRpgEntryWorldGalleryDetailByCode,
} from '../../services/rpg-entry/rpgEntryLibraryClient';
import {
AuthUiContext,
type PlatformSettingsSection,
@@ -130,6 +131,7 @@ vi.mock('../../services/puzzle-gallery', () => ({
}));
vi.mock('../../services/rpg-entry/rpgEntryLibraryClient', () => ({
deleteRpgEntryWorldProfile: vi.fn(),
getRpgEntryWorldGalleryDetailByCode: vi.fn(),
}));
@@ -495,7 +497,6 @@ function TestWrapper({
<RpgEntryFlowShell
selectionStage={selectionStage}
setSelectionStage={setSelectionStage}
gameState={{} as GameState}
hasSavedGame={false}
savedSnapshot={null}
handleContinueGame={onContinueGame ?? (() => {})}
@@ -547,7 +548,7 @@ beforeEach(() => {
savedAt: '2026-04-19T12:00:00.000Z',
bottomTab: 'adventure',
currentStory: null,
gameState: {} as GameState,
gameState: {},
} as HydratedSavedGameSnapshot,
});
vi.mocked(upsertProfileBrowseHistory).mockResolvedValue([]);
@@ -1450,10 +1451,13 @@ test('published puzzle detail returns to the source platform tab', async () => {
await waitFor(() => {
expect(document.getElementById('platform-tab-panel-category')).toBeTruthy();
});
await waitFor(() => {
const categoryPanel = getPlatformTabPanel('category');
expect(
within(categoryPanel).getAllByText('星桥机关').length,
).toBeGreaterThan(0);
});
const categoryPanel = getPlatformTabPanel('category');
expect(
within(categoryPanel).getAllByText('星桥机关').length,
).toBeGreaterThan(0);
await user.click(
within(categoryPanel).getByRole('button', {
@@ -2087,7 +2091,6 @@ test('agent draft result publishes to gallery from publish panel', async () => {
<RpgEntryFlowShell
selectionStage={selectionStage}
setSelectionStage={setSelectionStage}
gameState={{} as GameState}
hasSavedGame={false}
savedSnapshot={null}
handleContinueGame={() => {}}
@@ -2162,7 +2165,6 @@ test('agent draft result test button enters current draft without publish gate',
<RpgEntryFlowShell
selectionStage={selectionStage}
setSelectionStage={setSelectionStage}
gameState={{} as GameState}
hasSavedGame={false}
savedSnapshot={null}
handleContinueGame={() => {}}
@@ -2778,7 +2780,7 @@ test('save tab can resume a selected archive directly into the game', async () =
currentStory: null,
gameState: {
worldType: 'CUSTOM',
} as GameState,
},
} as HydratedSavedGameSnapshot,
});

View File

@@ -1,4 +1,4 @@
import { PlatformEntryFlowShell } from '../platform-entry';
import { PlatformEntryFlowShell } from '../platform-entry/PlatformEntryFlowShell';
import type { RpgEntryFlowShellProps } from './rpgEntryTypes';
import type { SelectionStage } from './rpgEntryTypes';

View File

@@ -274,6 +274,7 @@ test('opens recharge modal and submits points product', async () => {
await user.click(screen.getByText('会员充值'));
expect(await screen.findByText('账户充值')).toBeTruthy();
expect(await screen.findByText('叙世币充值')).toBeTruthy();
expect(await screen.findByText('60叙世币')).toBeTruthy();
await user.click(screen.getByText('首充送60叙世币'));

View File

@@ -1306,6 +1306,9 @@ export function RpgEntryHomeView({
const [selectedCategoryTag, setSelectedCategoryTag] = useState<string | null>(
null,
);
const [visitedTabs, setVisitedTabs] = useState<Set<PlatformHomeTab>>(
() => new Set([activeTab]),
);
const isAuthenticated = Boolean(authUi?.user);
const isDesktopLayout = usePlatformDesktopLayout();
const featuredShelf = useMemo(
@@ -1355,6 +1358,18 @@ export function RpgEntryHomeView({
}
}, [activeTab, onTabChange, visibleTabs]);
useEffect(() => {
setVisitedTabs((currentTabs) => {
if (currentTabs.has(activeTab)) {
return currentTabs;
}
const nextTabs = new Set(currentTabs);
nextTabs.add(activeTab);
return nextTabs;
});
}, [activeTab]);
useEffect(() => {
if (categoryGroups.length === 0) {
setSelectedCategoryTag(null);
@@ -2213,11 +2228,15 @@ export function RpgEntryHomeView({
} satisfies Record<PlatformHomeTab, ReactNode>;
const tabPanels = PLATFORM_HOME_TABS.filter((tab) =>
visibleTabs.includes(tab),
).map((tab) => (
<PlatformTabPanel key={tab} tab={tab} activeTab={activeTab}>
{tabContentById[tab]}
</PlatformTabPanel>
));
).map((tab) => {
const shouldMountPanel = tab === activeTab || visitedTabs.has(tab);
return (
<PlatformTabPanel key={tab} tab={tab} activeTab={activeTab}>
{shouldMountPanel ? tabContentById[tab] : null}
</PlatformTabPanel>
);
});
if (!isDesktopLayout) {
return (

View File

@@ -15,7 +15,7 @@ import {
listRpgEntryWorldLibrary,
publishRpgEntryWorldProfile,
unpublishRpgEntryWorldProfile,
} from '../../services/rpg-entry';
} from '../../services/rpg-entry/rpgEntryLibraryClient';
import { ApiClientError } from '../../services/apiClient';
import type { CustomWorldProfile } from '../../types';
import {

View File

@@ -18,10 +18,8 @@ import type {
import { getNineSliceStyle, TAB_ICONS, UI_CHROME } from '../../uiAssets';
import type { GameCanvasEntitySelection } from '../GameCanvas';
import { PixelIcon } from '../PixelIcon';
import {
PanelLoadingFallback,
type RpgAdventureStatistics,
} from '../rpg-runtime-shell';
import { PanelLoadingFallback } from '../rpg-runtime-shell/rpgRuntimeLoaders';
import type { RpgAdventureStatistics } from '../rpg-runtime-shell/types';
const RpgAdventurePanel = lazy(async () => {
const module = await import('./RpgAdventurePanel');

View File

@@ -7,11 +7,17 @@ import {
} from '../../routing/appPageRoutes';
import { UI_CHROME } from '../../uiAssets';
import { useAuthUi } from '../auth/AuthUiContext';
import { RpgRuntimeCanvasStage } from './RpgRuntimeCanvasStage';
import { RpgRuntimeStageRouter } from './RpgRuntimeStageRouter';
import type { RpgRuntimeShellProps as RpgRuntimeShellComponentProps } from './types';
import { useRpgRuntimeShellViewModel } from './useRpgRuntimeShellViewModel';
const RpgRuntimeCanvasStage = lazy(async () => {
const module = await import('./RpgRuntimeCanvasStage');
return {
default: module.RpgRuntimeCanvasStage,
};
});
const RpgRuntimeOverlayHost = lazy(async () => {
const module = await import('./RpgRuntimeOverlayHost');
return {
@@ -154,20 +160,22 @@ export function RpgRuntimeShell({
backgroundRepeat: isPlatformShell ? undefined : 'repeat',
}}
>
<Suspense fallback={null}>
<RpgRuntimeCanvasStage
gameState={gameState}
visibleGameState={visibleGameState}
hideSelectionHero={hideSelectionHero}
canvasCompanionRenderStates={canvasCompanionRenderStates}
dialogueIndicator={dialogueIndicator}
sceneTransitionPhase={sceneTransitionPhase}
sceneTransitionToken={sceneTransitionToken}
setSelectedSceneEntity={setSelectedSceneEntity}
setIsMapOpen={setIsMapOpen}
setSceneTransitionDurations={setSceneTransitionDurations}
/>
</Suspense>
{gameState.worldType ? (
<Suspense fallback={null}>
<RpgRuntimeCanvasStage
gameState={gameState}
visibleGameState={visibleGameState}
hideSelectionHero={hideSelectionHero}
canvasCompanionRenderStates={canvasCompanionRenderStates}
dialogueIndicator={dialogueIndicator}
sceneTransitionPhase={sceneTransitionPhase}
sceneTransitionToken={sceneTransitionToken}
setSelectedSceneEntity={setSelectedSceneEntity}
setIsMapOpen={setIsMapOpen}
setSceneTransitionDurations={setSceneTransitionDurations}
/>
</Suspense>
) : null}
{visibleGameState.playerCharacter && !chrome?.hidePlayerLevelBadge && (
<div
@@ -243,35 +251,37 @@ export function RpgRuntimeShell({
handleSaveAndExit={handleSaveAndExit}
/>
<Suspense fallback={null}>
<RpgRuntimeOverlayHost
gameState={gameState}
isLoading={isLoading}
isMapOpen={isMapOpen}
setIsMapOpen={setIsMapOpen}
npcUi={npcUi}
characterChatUi={characterChatUi}
inventoryUi={inventoryUi}
companionRenderStates={companionRenderStates}
characterChatSummaries={characterChatSummaries}
overlayPanel={overlayPanel}
closeOverlayPanel={closeOverlayPanel}
openCampModal={openCampModal}
openPartyMemberDetails={openPartyMemberDetails}
shouldMountAdventureEntityModal={shouldMountAdventureEntityModal}
selectedSceneEntity={selectedSceneEntity}
closeAdventureEntityModal={closeAdventureEntityModal}
shouldMountCampModal={shouldMountCampModal}
showTeamModal={showTeamModal}
closeCampModal={closeCampModal}
onBenchCompanion={onBenchCompanion}
onActivateRosterCompanion={onActivateRosterCompanion}
shouldMountMapModal={shouldMountMapModal}
handleMapTravelToScene={handleMapTravelToScene}
shouldMountCharacterChatModal={shouldMountCharacterChatModal}
shouldMountNpcModals={shouldMountNpcModals}
/>
</Suspense>
{gameState.worldType ? (
<Suspense fallback={null}>
<RpgRuntimeOverlayHost
gameState={gameState}
isLoading={isLoading}
isMapOpen={isMapOpen}
setIsMapOpen={setIsMapOpen}
npcUi={npcUi}
characterChatUi={characterChatUi}
inventoryUi={inventoryUi}
companionRenderStates={companionRenderStates}
characterChatSummaries={characterChatSummaries}
overlayPanel={overlayPanel}
closeOverlayPanel={closeOverlayPanel}
openCampModal={openCampModal}
openPartyMemberDetails={openPartyMemberDetails}
shouldMountAdventureEntityModal={shouldMountAdventureEntityModal}
selectedSceneEntity={selectedSceneEntity}
closeAdventureEntityModal={closeAdventureEntityModal}
shouldMountCampModal={shouldMountCampModal}
showTeamModal={showTeamModal}
closeCampModal={closeCampModal}
onBenchCompanion={onBenchCompanion}
onActivateRosterCompanion={onActivateRosterCompanion}
shouldMountMapModal={shouldMountMapModal}
handleMapTravelToScene={handleMapTravelToScene}
shouldMountCharacterChatModal={shouldMountCharacterChatModal}
shouldMountNpcModals={shouldMountNpcModals}
/>
</Suspense>
) : null}
</div>
);
}

View File

@@ -20,25 +20,25 @@ import type {
} from '../../types';
import { UI_CHROME } from '../../uiAssets';
import type { GameCanvasEntitySelection } from '../GameCanvas';
import type { SelectionStage } from '../platform-entry';
import type { SelectionStage } from '../platform-entry/platformEntryTypes';
import type { RpgAdventureStatistics } from './types';
const RpgEntryCharacterSelectView = lazy(async () => {
const module = await import('../rpg-entry');
const module = await import('../rpg-entry/RpgEntryCharacterSelectView');
return {
default: module.RpgEntryCharacterSelectView,
};
});
const PlatformEntryFlowShell = lazy(async () => {
const module = await import('../platform-entry');
const module = await import('../platform-entry/PlatformEntryFlowShell');
return {
default: module.PlatformEntryFlowShell,
};
});
const RpgRuntimePanelRouter = lazy(async () => {
const module = await import('../rpg-runtime-panels');
const module = await import('../rpg-runtime-panels/RpgRuntimePanelRouter');
return {
default: module.RpgRuntimePanelRouter,
};
@@ -174,7 +174,6 @@ export function RpgRuntimeStageRouter({
<PlatformEntryFlowShell
selectionStage={selectionStage}
setSelectionStage={setSelectionStage}
gameState={gameState}
hasSavedGame={hasSavedGame}
savedSnapshot={savedSnapshot}
handleContinueGame={handleContinueGame}

View File

@@ -7,7 +7,7 @@ import {
} from '../../routing/appPageRoutes';
import type { GameState } from '../../types';
import type { GameCanvasEntitySelection } from '../GameCanvas';
import type { SelectionStage } from '../platform-entry';
import type { SelectionStage } from '../platform-entry/platformEntryTypes';
type OverlayPanel = 'character' | 'inventory' | null;