Integrate unfinished server-rs refactor worklists
This commit is contained in:
@@ -18,6 +18,9 @@ import { useRpgSessionBootstrap } from './rpg-session';
|
||||
const aiServiceMocks = vi.hoisted(() => ({
|
||||
streamNpcChatTurn: vi.fn(),
|
||||
}));
|
||||
const rpgRuntimeStoryClientMocks = vi.hoisted(() => ({
|
||||
beginRpgRuntimeStorySession: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('../services/aiService', async () => {
|
||||
const actual =
|
||||
@@ -31,6 +34,18 @@ vi.mock('../services/aiService', async () => {
|
||||
};
|
||||
});
|
||||
|
||||
vi.mock('../services/rpg-runtime/rpgRuntimeStoryClient', async () => {
|
||||
const actual = await vi.importActual<
|
||||
typeof import('../services/rpg-runtime/rpgRuntimeStoryClient')
|
||||
>('../services/rpg-runtime/rpgRuntimeStoryClient');
|
||||
|
||||
return {
|
||||
...actual,
|
||||
beginRpgRuntimeStorySession:
|
||||
rpgRuntimeStoryClientMocks.beginRpgRuntimeStorySession,
|
||||
};
|
||||
});
|
||||
|
||||
function buildBackstoryReveal(label: string) {
|
||||
return {
|
||||
publicSummary: `${label}的公开背景`,
|
||||
@@ -401,6 +416,163 @@ function readSnapshot() {
|
||||
};
|
||||
}
|
||||
|
||||
function findRuntimeNpc(profile: ReturnType<typeof buildSavedProfile>) {
|
||||
const npc = profile.storyNpcs.find((candidate) => candidate.id === 'story-act-only');
|
||||
if (!npc) {
|
||||
throw new Error('test npc story-act-only not found');
|
||||
}
|
||||
|
||||
return npc;
|
||||
}
|
||||
|
||||
function buildRuntimeStoryBootstrapSnapshot(params: {
|
||||
profile: ReturnType<typeof buildSavedProfile>;
|
||||
character: NonNullable<ReturnType<typeof buildCustomWorldPlayableCharacters>[number]>;
|
||||
}) {
|
||||
const npc = findRuntimeNpc(params.profile);
|
||||
const playableSource = params.profile.playableNpcs.find(
|
||||
(candidate) => candidate.id === params.character.id,
|
||||
);
|
||||
const initialItems = playableSource?.initialItems ?? [];
|
||||
const currentScenePreset = {
|
||||
id: 'custom-scene-camp',
|
||||
name: '回潮暂栖所',
|
||||
description: '能暂时收拢队伍、整理灯册与潮路线索的落脚点。',
|
||||
imageSrc: '',
|
||||
connectedSceneIds: ['custom-scene-landmark-1', 'custom-scene-landmark-2'],
|
||||
};
|
||||
const weapon = initialItems.find(
|
||||
(item) => item.id === 'item-playable-1',
|
||||
);
|
||||
const relic = initialItems.find(
|
||||
(item) => item.id === 'item-playable-3',
|
||||
);
|
||||
|
||||
return {
|
||||
sessionId: 'runtime-main',
|
||||
serverVersion: 1,
|
||||
snapshot: {
|
||||
version: 2,
|
||||
savedAt: '2026-04-29T00:00:00.000Z',
|
||||
bottomTab: 'adventure',
|
||||
currentStory: null,
|
||||
gameState: {
|
||||
worldType: WorldType.CUSTOM,
|
||||
customWorldProfile: params.profile,
|
||||
playerCharacter: params.character,
|
||||
runtimeSessionId: 'runtime-main',
|
||||
storySessionId: 'storysess-main',
|
||||
runtimeActionVersion: 1,
|
||||
runtimeMode: 'play',
|
||||
runtimePersistenceDisabled: false,
|
||||
runtimeStats: {
|
||||
playTimeMs: 0,
|
||||
lastPlayTickAt: null,
|
||||
hostileNpcsDefeated: 0,
|
||||
questsAccepted: 0,
|
||||
itemsUsed: 0,
|
||||
scenesTraveled: 0,
|
||||
},
|
||||
playerProgression: {
|
||||
level: 1,
|
||||
currentLevelXp: 0,
|
||||
totalXp: 0,
|
||||
xpToNextLevel: 100,
|
||||
},
|
||||
currentScene: 'Story',
|
||||
storyHistory: [],
|
||||
storyEngineMemory: {
|
||||
discoveredFactIds: [],
|
||||
inferredFactIds: [],
|
||||
activeThreadIds: [],
|
||||
resolvedScarIds: [],
|
||||
recentCarrierIds: [],
|
||||
openedSceneChapterIds: ['chapter-1'],
|
||||
currentSceneActState: {
|
||||
sceneId: 'custom-scene-camp',
|
||||
chapterId: 'chapter-1',
|
||||
currentActId: 'act-1',
|
||||
currentActIndex: 0,
|
||||
completedActIds: [],
|
||||
visitedActIds: ['act-1'],
|
||||
},
|
||||
},
|
||||
chapterState: null,
|
||||
campaignState: null,
|
||||
activeScenarioPackId: 'scenario-pack:tide',
|
||||
activeCampaignPackId: 'campaign-pack:tide',
|
||||
characterChats: {},
|
||||
lastObserveSignsSceneId: null,
|
||||
lastObserveSignsReport: null,
|
||||
animationState: 'idle',
|
||||
currentEncounter: {
|
||||
id: 'story-act-only',
|
||||
kind: 'npc',
|
||||
npcName: npc.name,
|
||||
npcDescription: npc.description,
|
||||
npcAvatar: '',
|
||||
context: '陆衡拿着异常账本,在开盘前拦住玩家。',
|
||||
characterId: npc.id,
|
||||
initialAffinity: npc.initialAffinity,
|
||||
title: npc.title,
|
||||
backstory: npc.backstory,
|
||||
personality: npc.personality,
|
||||
motivation: npc.motivation,
|
||||
combatStyle: npc.combatStyle,
|
||||
relationshipHooks: npc.relationshipHooks,
|
||||
tags: npc.tags,
|
||||
backstoryReveal: npc.backstoryReveal,
|
||||
skills: npc.skills,
|
||||
initialItems: npc.initialItems,
|
||||
narrativeProfile: npc.narrativeProfile,
|
||||
},
|
||||
npcInteractionActive: false,
|
||||
currentScenePreset,
|
||||
sceneHostileNpcs: [],
|
||||
playerX: 0,
|
||||
playerOffsetY: 0,
|
||||
playerFacing: 'right',
|
||||
playerActionMode: 'idle',
|
||||
scrollWorld: false,
|
||||
inBattle: false,
|
||||
playerHp: 180,
|
||||
playerMaxHp: 180,
|
||||
playerMana: 0,
|
||||
playerMaxMana: 0,
|
||||
playerSkillCooldowns: {},
|
||||
activeBuildBuffs: [],
|
||||
activeCombatEffects: [],
|
||||
playerCurrency: 0,
|
||||
playerInventory: initialItems,
|
||||
playerEquipment: {
|
||||
weapon: weapon ?? null,
|
||||
armor: {
|
||||
id: 'test-armor',
|
||||
category: '防具',
|
||||
name: '潮雾外衣',
|
||||
quantity: 1,
|
||||
rarity: 'common',
|
||||
tags: ['防具'],
|
||||
equipmentSlotId: 'armor',
|
||||
},
|
||||
relic: relic ?? null,
|
||||
},
|
||||
npcStates: {},
|
||||
quests: [],
|
||||
roster: [],
|
||||
companions: [],
|
||||
currentBattleNpcId: null,
|
||||
currentNpcBattleMode: null,
|
||||
currentNpcBattleOutcome: null,
|
||||
sparReturnEncounter: null,
|
||||
sparPlayerHpBefore: null,
|
||||
sparPlayerMaxHpBefore: null,
|
||||
sparStoryHistoryBefore: null,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function GameFlowHarness({
|
||||
openingOppositeNpcId,
|
||||
}: {
|
||||
@@ -415,6 +587,14 @@ function GameFlowHarness({
|
||||
[profile],
|
||||
);
|
||||
const selectedCharacter = playableCharacters[0] ?? null;
|
||||
if (selectedCharacter) {
|
||||
rpgRuntimeStoryClientMocks.beginRpgRuntimeStorySession.mockResolvedValue(
|
||||
buildRuntimeStoryBootstrapSnapshot({
|
||||
profile,
|
||||
character: selectedCharacter,
|
||||
}),
|
||||
);
|
||||
}
|
||||
const {
|
||||
gameState,
|
||||
setGameState,
|
||||
|
||||
Reference in New Issue
Block a user