import { useRapier } from "@react-three/rapier"; import { useEffect, useMemo } from "react"; import { combatNavigationGraph } from "../game/combatSpatial"; import { createMobPursuit } from "../game/mobPursuit"; import { registerDungeonRuntimeReset } from "../game/dungeonRuntimeReset"; import { hasDungeonLineOfSight } from "./dungeonLineOfSight"; import { createPartyDirectSegmentValidator, createPartyRecoveryPointValidator, createPartyRouteSegmentValidator } from "./partyTraversal"; /** Uses terrain only; actors remain non-blocking and the graph is loaded only once. */ export function useMobNavigation() { const { rapier, world } = useRapier(); const navigator = useMemo(() => { let graph = combatNavigationGraph(); let landing = createPartyRecoveryPointValidator(rapier, world, graph); return createMobPursuit({ graph: combatNavigationGraph, hasLineOfSight: (from, to) => hasDungeonLineOfSight(rapier, world, from, to), directAllowed: createPartyDirectSegmentValidator(rapier, world), routeAllowed: createPartyRouteSegmentValidator(rapier, world), validateLanding: (point, anchor) => { const currentGraph = combatNavigationGraph(); if (graph !== currentGraph) { graph = currentGraph; landing = createPartyRecoveryPointValidator(rapier, world, graph); } return landing(point, anchor); }, }); }, [rapier, world]); useEffect(() => registerDungeonRuntimeReset(navigator.clear), [navigator]); return navigator; }