Integrate unfinished server-rs refactor worklists

This commit is contained in:
2026-04-30 13:39:06 +08:00
parent 62934b0809
commit 7ab0933f6d
676 changed files with 24487 additions and 21531 deletions

View File

@@ -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,