Release Healer Man 0.1.11
This commit is contained in:
1 parent
5f1a14d8de
commit
13970d03c8
18 files changed
+514
-19
No files matched your search
@@ -91,6 +91,11 @@ export interface StaticMobSpawnCluster {
|
||||
readonly spawns: readonly StaticMobSpawnDefinition[];
|
||||
}
|
||||
|
||||
export interface NormalizedMobPopulationPaths {
|
||||
readonly roamingPacks: readonly MobPackDefinition[];
|
||||
readonly staticSpawns: readonly StaticMobSpawnDefinition[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Partitions large imported populations into bounded activation cells. Actors
|
||||
* in distant cells are not mounted or registered with combat until approached.
|
||||
@@ -141,6 +146,51 @@ export interface LoopedPath {
|
||||
|
||||
const EPSILON = 1e-6;
|
||||
|
||||
export function hasUsableLoopedMobPath(waypoints: readonly MobVector3[]): boolean {
|
||||
if (waypoints.length < 2 || !waypoints.every((point) => point.every(Number.isFinite))) {
|
||||
return false;
|
||||
}
|
||||
const origin = waypoints[0];
|
||||
return waypoints.some((point) => Math.hypot(
|
||||
point[0] - origin[0],
|
||||
point[1] - origin[1],
|
||||
point[2] - origin[2],
|
||||
) > EPSILON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Imported databases occasionally label a stationary spawn as a patrol by
|
||||
* repeating one waypoint. Keep those actors, but mount them through the static
|
||||
* path so malformed content can never take down the scene.
|
||||
*/
|
||||
export function normalizeMobPopulationPaths(
|
||||
roamingPacks: readonly MobPackDefinition[],
|
||||
staticSpawns: readonly StaticMobSpawnDefinition[],
|
||||
): NormalizedMobPopulationPaths {
|
||||
const invalidPacks = roamingPacks.filter((pack) => !hasUsableLoopedMobPath(pack.waypoints));
|
||||
if (!invalidPacks.length) return { roamingPacks, staticSpawns };
|
||||
|
||||
const invalidIds = new Set(invalidPacks.map((pack) => pack.id));
|
||||
const stationarySpawns = invalidPacks.flatMap((pack) => {
|
||||
const anchor = pack.waypoints.find((point) => point.every(Number.isFinite));
|
||||
if (!anchor) return [];
|
||||
return pack.members.map((member): StaticMobSpawnDefinition => ({
|
||||
id: `${pack.id}:${member.id}`,
|
||||
entityId: member.entityId,
|
||||
position: [
|
||||
anchor[0] + member.formationOffset[0],
|
||||
anchor[1] + member.formationOffset[1],
|
||||
anchor[2] - member.formationOffset[2],
|
||||
],
|
||||
spawnMask: pack.spawnMask,
|
||||
}));
|
||||
});
|
||||
return {
|
||||
roamingPacks: roamingPacks.filter((pack) => !invalidIds.has(pack.id)),
|
||||
staticSpawns: [...staticSpawns, ...stationarySpawns],
|
||||
};
|
||||
}
|
||||
|
||||
function assertFiniteWaypoint(point: MobVector3, index: number): void {
|
||||
if (!point.every(Number.isFinite)) {
|
||||
throw new Error(`Waypoint ${index} contains a non-finite coordinate.`);
|
||||
|
||||
Reference in new issue
Block a user