forked from phenom/healer-man
Release Healer Man 0.1.22
This commit is contained in:
1 parent
f6f2375145
commit
7f6001723a
144 files changed
+54107
-690
No files matched your search
@@ -0,0 +1,69 @@
|
||||
import { BufferGeometry, type Group, type Mesh } from "three";
|
||||
import type { DungeonNavigationLink } from "./dungeonTypes";
|
||||
import {
|
||||
buildPartyNavigationGraph,
|
||||
type PartyNavigationGraph,
|
||||
} from "./partyNavigation";
|
||||
import { MAX_SYNCHRONOUS_PARTY_NAVIGATION_TRIANGLES } from "./partyNavigationPolicy";
|
||||
|
||||
const MAX_CACHED_NAVIGATION_GRAPHS = 8;
|
||||
const graphCache = new Map<string, PartyNavigationGraph>();
|
||||
|
||||
function graphCacheKey(url: string, offMeshLinks: readonly DungeonNavigationLink[]): string {
|
||||
const links = offMeshLinks.map((link) => [
|
||||
link.id,
|
||||
link.start,
|
||||
link.end,
|
||||
link.bidirectional,
|
||||
]);
|
||||
return `${url}:${JSON.stringify(links)}`;
|
||||
}
|
||||
|
||||
function navigationGeometry(scene: Group): BufferGeometry {
|
||||
scene.updateMatrixWorld(true);
|
||||
let sourceMesh: Mesh | null = null;
|
||||
let largestVertexCount = 0;
|
||||
scene.traverse((node) => {
|
||||
const mesh = node as Mesh;
|
||||
const count = mesh.isMesh ? mesh.geometry.getAttribute("position")?.count ?? 0 : 0;
|
||||
if (count > largestVertexCount) {
|
||||
sourceMesh = mesh;
|
||||
largestVertexCount = count;
|
||||
}
|
||||
});
|
||||
if (!sourceMesh) throw new Error("The party navigation GLB has no triangle geometry.");
|
||||
const geometry = (sourceMesh as Mesh).geometry.clone();
|
||||
geometry.applyMatrix4((sourceMesh as Mesh).matrixWorld);
|
||||
return geometry;
|
||||
}
|
||||
|
||||
export function preparePartyNavigationGraph(
|
||||
url: string,
|
||||
scene: Group,
|
||||
offMeshLinks: readonly DungeonNavigationLink[],
|
||||
): PartyNavigationGraph {
|
||||
const cacheKey = graphCacheKey(url, offMeshLinks);
|
||||
const cached = graphCache.get(cacheKey);
|
||||
if (cached) {
|
||||
graphCache.delete(cacheKey);
|
||||
graphCache.set(cacheKey, cached);
|
||||
return cached;
|
||||
}
|
||||
|
||||
const geometry = navigationGeometry(scene);
|
||||
let graph: PartyNavigationGraph;
|
||||
try {
|
||||
graph = buildPartyNavigationGraph(geometry, {
|
||||
maxSourceTriangles: MAX_SYNCHRONOUS_PARTY_NAVIGATION_TRIANGLES,
|
||||
offMeshLinks,
|
||||
});
|
||||
} finally {
|
||||
geometry.dispose();
|
||||
}
|
||||
graphCache.set(cacheKey, graph);
|
||||
if (graphCache.size > MAX_CACHED_NAVIGATION_GRAPHS) {
|
||||
const oldest = graphCache.keys().next().value as string | undefined;
|
||||
if (oldest) graphCache.delete(oldest);
|
||||
}
|
||||
return graph;
|
||||
}
|
||||
Reference in new issue
Block a user