86 lines
2.6 KiB
TypeScript
86 lines
2.6 KiB
TypeScript
import { loadScenarioDefinitionById } from '@sammo-ts/game-engine/scenario/scenarioLoader.js';
|
|
import type { ScenarioDefinition } from '@sammo-ts/logic';
|
|
|
|
import { loadMapDefinitionByName } from './mapDefinition.js';
|
|
|
|
export interface MapLayoutCity {
|
|
id: number;
|
|
name: string;
|
|
level: number;
|
|
region: number;
|
|
x: number;
|
|
y: number;
|
|
path: number[];
|
|
}
|
|
|
|
export interface MapLayout {
|
|
mapName: string;
|
|
cityList: MapLayoutCity[];
|
|
regionMap: Record<number, string>;
|
|
levelMap: Record<number, string>;
|
|
}
|
|
|
|
export interface MapLayoutLoaderOptions {
|
|
loadScenario?: (scenarioId: number) => Promise<ScenarioDefinition>;
|
|
loadMap?: typeof loadMapDefinitionByName;
|
|
}
|
|
|
|
const layoutCache = new Map<string, MapLayout>();
|
|
|
|
const parseScenarioId = (scenario: string): number | null => {
|
|
const normalized = scenario.replace(/^scenario_/i, '').replace(/\.json$/i, '');
|
|
if (!/^\d+$/.test(normalized)) {
|
|
return null;
|
|
}
|
|
const scenarioId = Number(normalized);
|
|
return Number.isSafeInteger(scenarioId) ? scenarioId : null;
|
|
};
|
|
|
|
const resolveMapName = async (
|
|
scenario: string,
|
|
loadScenario: (scenarioId: number) => Promise<ScenarioDefinition>
|
|
): Promise<string> => {
|
|
const scenarioId = parseScenarioId(scenario);
|
|
if (scenarioId === null) {
|
|
return 'che';
|
|
}
|
|
try {
|
|
const definition = await loadScenario(scenarioId);
|
|
return definition.config.environment.mapName;
|
|
} catch {
|
|
// 운영 DB가 보존된 상태에서 해당 commit에 scenario resource가 없을 수
|
|
// 있으므로 기존 기본 map인 che로 안전하게 돌아갑니다.
|
|
return 'che';
|
|
}
|
|
};
|
|
|
|
export const loadMapLayout = async (scenario: string, options: MapLayoutLoaderOptions = {}): Promise<MapLayout> => {
|
|
const mapName = await resolveMapName(scenario, options.loadScenario ?? loadScenarioDefinitionById);
|
|
const useCache = !options.loadScenario && !options.loadMap;
|
|
const cached = useCache ? layoutCache.get(mapName) : undefined;
|
|
if (cached) {
|
|
return cached;
|
|
}
|
|
|
|
const map = await (options.loadMap ?? loadMapDefinitionByName)(mapName);
|
|
const layout: MapLayout = {
|
|
mapName,
|
|
cityList: map.cities.map((city) => ({
|
|
id: city.id,
|
|
name: city.name,
|
|
level: city.level,
|
|
region: city.region,
|
|
x: city.position.x,
|
|
y: city.position.y,
|
|
path: [...city.connections],
|
|
})),
|
|
regionMap: {},
|
|
levelMap: {},
|
|
};
|
|
|
|
if (useCache) {
|
|
layoutCache.set(mapName, layout);
|
|
}
|
|
return layout;
|
|
};
|