1
This commit is contained in:
@@ -1,16 +1,18 @@
|
||||
import { rehydrateSavedSnapshot } from '../../persistence/runtimeSnapshot';
|
||||
import { getForwardScenePreset } from '../../data/scenePresets';
|
||||
import { rehydrateSavedSnapshot } from '../../persistence/runtimeSnapshot';
|
||||
import type { HydratedSavedGameSnapshot } from '../../persistence/runtimeSnapshotTypes';
|
||||
import {
|
||||
getRpgRuntimeClientVersion,
|
||||
getRpgRuntimeSessionId,
|
||||
getRpgRuntimeStoryState,
|
||||
resolveRpgRuntimeStoryAction,
|
||||
type RuntimeStorySnapshotRequest,
|
||||
resolveRpgRuntimeStoryMoment,
|
||||
type RuntimeStoryChoicePayload,
|
||||
type RuntimeStoryResponse,
|
||||
type RuntimeStorySnapshotRequest,
|
||||
} from '../../services/rpg-runtime/rpgRuntimeStoryClient';
|
||||
import type { GameState, StoryMoment, StoryOption } from '../../types';
|
||||
import { buildMapTravelResolution } from './storyGenerationState';
|
||||
|
||||
function getRuntimeResponseOptions(response: RuntimeStoryResponse) {
|
||||
return response.viewModel.availableOptions.length > 0
|
||||
@@ -29,6 +31,95 @@ function buildRuntimeSnapshotRequest(
|
||||
};
|
||||
}
|
||||
|
||||
function resolveServerTravelTargetSceneId(params: {
|
||||
previousState: GameState;
|
||||
snapshotState: GameState;
|
||||
}) {
|
||||
const { previousState, snapshotState } = params;
|
||||
const snapshotSceneId = snapshotState.currentScenePreset?.id ?? null;
|
||||
if (
|
||||
snapshotSceneId &&
|
||||
snapshotSceneId !== previousState.currentScenePreset?.id
|
||||
) {
|
||||
return snapshotSceneId;
|
||||
}
|
||||
|
||||
if (!previousState.worldType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
getForwardScenePreset(
|
||||
previousState.worldType,
|
||||
previousState.currentScenePreset?.id,
|
||||
)?.id ??
|
||||
previousState.currentScenePreset?.forwardSceneId ??
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
function bridgeServerSceneTravelSnapshot(params: {
|
||||
previousState: GameState;
|
||||
hydratedSnapshot: HydratedSavedGameSnapshot;
|
||||
functionId: string;
|
||||
}) {
|
||||
const { previousState, hydratedSnapshot, functionId } = params;
|
||||
if (functionId !== 'idle_travel_next_scene' || !previousState.worldType) {
|
||||
return hydratedSnapshot;
|
||||
}
|
||||
|
||||
const targetSceneId = resolveServerTravelTargetSceneId({
|
||||
previousState,
|
||||
snapshotState: hydratedSnapshot.gameState,
|
||||
});
|
||||
if (!targetSceneId) {
|
||||
return hydratedSnapshot;
|
||||
}
|
||||
|
||||
const travelResolution = buildMapTravelResolution(previousState, targetSceneId);
|
||||
if (!travelResolution) {
|
||||
return hydratedSnapshot;
|
||||
}
|
||||
|
||||
return {
|
||||
...hydratedSnapshot,
|
||||
gameState: {
|
||||
...hydratedSnapshot.gameState,
|
||||
// 中文注释:服务端 compat 当前只保证“本轮旅行动作已经结算完成”,
|
||||
// 前端这里复用既有地图旅行真相,补齐下一幕场景 preset、遭遇预览和任务推进结果。
|
||||
currentScenePreset: travelResolution.nextState.currentScenePreset,
|
||||
currentEncounter: travelResolution.nextState.currentEncounter,
|
||||
npcInteractionActive: travelResolution.nextState.npcInteractionActive,
|
||||
sceneHostileNpcs: travelResolution.nextState.sceneHostileNpcs,
|
||||
playerX: travelResolution.nextState.playerX,
|
||||
playerFacing: travelResolution.nextState.playerFacing,
|
||||
animationState: travelResolution.nextState.animationState,
|
||||
playerActionMode: travelResolution.nextState.playerActionMode,
|
||||
activeCombatEffects: travelResolution.nextState.activeCombatEffects,
|
||||
scrollWorld: travelResolution.nextState.scrollWorld,
|
||||
inBattle: travelResolution.nextState.inBattle,
|
||||
lastObserveSignsSceneId: travelResolution.nextState.lastObserveSignsSceneId,
|
||||
lastObserveSignsReport: travelResolution.nextState.lastObserveSignsReport,
|
||||
currentBattleNpcId: travelResolution.nextState.currentBattleNpcId,
|
||||
currentNpcBattleMode: travelResolution.nextState.currentNpcBattleMode,
|
||||
currentNpcBattleOutcome: travelResolution.nextState.currentNpcBattleOutcome,
|
||||
sparReturnEncounter: travelResolution.nextState.sparReturnEncounter,
|
||||
sparPlayerHpBefore: travelResolution.nextState.sparPlayerHpBefore,
|
||||
sparPlayerMaxHpBefore: travelResolution.nextState.sparPlayerMaxHpBefore,
|
||||
sparStoryHistoryBefore: travelResolution.nextState.sparStoryHistoryBefore,
|
||||
runtimeStats: {
|
||||
...hydratedSnapshot.gameState.runtimeStats,
|
||||
scenesTraveled:
|
||||
travelResolution.nextState.runtimeStats.scenesTraveled,
|
||||
},
|
||||
quests:
|
||||
hydratedSnapshot.gameState.quests.length > 0
|
||||
? hydratedSnapshot.gameState.quests
|
||||
: travelResolution.nextState.quests,
|
||||
},
|
||||
} satisfies HydratedSavedGameSnapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* 前端访问服务端 runtime story 的统一网关。
|
||||
* 统一处理 option catalog 拉取、继续游戏恢复与正式动作结算。
|
||||
@@ -111,7 +202,11 @@ export async function resolveServerRuntimeChoice(params: {
|
||||
payload: params.payload,
|
||||
snapshot: buildRuntimeSnapshotRequest(params.gameState, params.currentStory),
|
||||
});
|
||||
const hydratedSnapshot = rehydrateSavedSnapshot(response.snapshot);
|
||||
const hydratedSnapshot = bridgeServerSceneTravelSnapshot({
|
||||
previousState: params.gameState,
|
||||
hydratedSnapshot: rehydrateSavedSnapshot(response.snapshot),
|
||||
functionId: params.option.functionId,
|
||||
});
|
||||
|
||||
return {
|
||||
response,
|
||||
|
||||
Reference in New Issue
Block a user