69 lines
2.2 KiB
TypeScript
69 lines
2.2 KiB
TypeScript
import type { ProjectManifest } from '../project/types';
|
||
import { resolveProjectMap } from './MapLoader';
|
||
import { composeProjectMap } from './MapComposer';
|
||
import { composePhysicalMap } from './physicalMap';
|
||
import { isSystemTerrainPreset, type PlacedMapAsset } from './types';
|
||
|
||
export interface MapStackComposition {
|
||
data: Uint8Array;
|
||
geomCount: number;
|
||
warnings: string[];
|
||
}
|
||
|
||
/** 将全部已放置地图实例依次合成到同一 MJCF;源地图条目本身不会自动进入场景。 */
|
||
export function composePlacedMapAssets(
|
||
source: Uint8Array,
|
||
generatedScenePath: string,
|
||
manifest: ProjectManifest,
|
||
assets: readonly PlacedMapAsset[],
|
||
): MapStackComposition {
|
||
let data = source;
|
||
let geomCount = 0;
|
||
const warnings: string[] = [];
|
||
const spawnOwnerId = assets.find(
|
||
(asset) => asset.selection.kind === 'project' && asset.selection.spawnPointId,
|
||
)?.id;
|
||
// 程序地形最后合成,确保工程地图或机器人自带的无限 plane 不会覆盖沟壑/深坑。
|
||
const orderedAssets = [
|
||
...assets.filter(
|
||
(asset) =>
|
||
asset.selection.kind !== 'builtin' || !isSystemTerrainPreset(asset.selection.config.preset),
|
||
),
|
||
...assets.filter(
|
||
(asset) =>
|
||
asset.selection.kind === 'builtin' && isSystemTerrainPreset(asset.selection.config.preset),
|
||
),
|
||
];
|
||
|
||
for (const asset of orderedAssets) {
|
||
if (asset.selection.kind === 'builtin') {
|
||
const composed = composePhysicalMap(data, asset.selection.config, {
|
||
instanceId: asset.id,
|
||
preserveExistingGround: true,
|
||
});
|
||
data = composed.data;
|
||
geomCount += composed.geomCount;
|
||
if (composed.summary) warnings.push(`${asset.name}:${composed.summary}`);
|
||
continue;
|
||
}
|
||
|
||
const resolvedMap = resolveProjectMap(manifest, asset.selection.descriptorPath);
|
||
const composed = composeProjectMap(
|
||
data,
|
||
generatedScenePath,
|
||
manifest,
|
||
resolvedMap,
|
||
asset.selection,
|
||
{
|
||
instanceId: asset.id,
|
||
applySpawnPoint: asset.id === spawnOwnerId,
|
||
},
|
||
);
|
||
data = composed.data;
|
||
geomCount += composed.geomCount;
|
||
warnings.push(...composed.warnings, `${asset.name}:${composed.summary}`);
|
||
}
|
||
|
||
return { data, geomCount, warnings };
|
||
}
|