Rebuild navmesh generation using shared client world geometry and KD-tree decoding
Intended outcome Rebuild navigation geometry loading and baking for static outdoor playfields, static indoor playfields, and dynamic ACG missions, including solo, team, RK, Shadowlands and Alien layouts. Use shared headless world geometry derived from PRK.Client's current loading and RDBLib2's real collision decoder. Preserve PRK.Navigation's safe native ownership and existing server navmesh serialization. This is a geometry/baking replacement and targeted navigation integration, not a replacement Recast/Detour engine. No deployment or commits without explicit authorization. Repository findings - Tools/NavGenerator/CalculateNavMeshes.cs reads pre-exported KD meshes from E:/18-4-conversion/kd-output, assembles terrain with separate RDBDrawing builders, uses hard-coded input/output paths, and silently skips existing output files. - PRK.Client/PRK.Client/WorldManager.cs separates simulation from presentation. CollisionSceneLoader uses SqliteCollisionSurfaceStore and CollisionSurfaceDecoder (v4 KDTreeFile and v5 range-coded bodies), with explicit zone refusal reporting. - Client outdoor physics/rendering share TerrainHeightField; retain its chunk orientation and alternating triangle splits. - Client indoor loading uses IndoorTilemapSource and ClientIndoorAutotiler. Current rendering uses IndoorRoomShellBuilder, IndoorCellSurface and IndoorRoomVertexPool. RDBLib2 IndoorVisualMeshBuilder is a separate implementation and must not be assumed identical to the current client shell assembly. - Tools/RDBExtractor/Extractors/NavmeshExtractor.cs consumes the existing .dat format. Keep compatibility unless an explicit migration is agreed. Additional ACG findings - AcgNavmeshBaker.BuildBakeGeometry currently loads custom PrkCollisionMesh records, builds collision-refined floor quads and wall skirts, selectively includes collision walls/ramps, and publishes mutable collision arrays on AcgData. It drops ceiling triangles from bake input and uses 0.2-unit clearance / 85-degree slope defaults; do not carry these over as correctness assumptions. - PathfindingPfSystem.OnFullyRegistered skips native baking for team ACG, SLACGDungeon and overlapping Alien boss floors. GeneratePathCore uses grid routing across room boundaries, native queries mainly within a room, and fallback on bake/query failure. AcgNavmeshBaker's off-mesh-link comment does not describe the actual current implementation. - RoomInstance.GetRoomPos preserves authored template Y relative to the floor band, plus quarter-turn placement and SL floor X offsets. Repeated template rooms must remain distinct by stable instance identity; Id is renumbered later by indoor cell setup. - AcgGridPathfinder.FindRoomByRect is XZ-only. Floor/room-aware membership and nearest-poly queries are required before enabling stacked-floor baking. Room/floor ownership must not use template/zone ids as unique instance ids. - TeamMissionSpawnManagementPfSystem builds floor-transition buttons as gameplay teleports. Baking floors must not introduce automatic NPC lift traversal or walkable links between floor bands. - ACG collision arrays also feed placement, LoS, smoothing and debug tools. Mask-only multi-floor loading intentionally avoids switching LoS onto a brute-force large combined triangle soup. - PRK.Client's current PlayfieldAnarchyFMessageHandler only passes playfield id and position to WorldManager. Reuse existing client assembly with an explicit generated-room adapter; do not assume it already assembles arbitrary dynamic mission layouts. Implementation sequence and behavior 1. Establish representative static and seeded ACG fixtures, existing compatibility/lifecycle regressions, and expected navigation outcomes before replacing geometry. Include repeated room templates, all rotations, cave ramps, pits/shafts, boss pivots, stacked RK and coplanar SL team floors. 2. Extract the client's CPU-only terrain/indoor assembly into the existing shared RDB layer where practical, or a narrowly scoped headless shared library if dependency boundaries require it. Client, offline tooling and server adapters consume the same positions/topology/transforms. No dependency on the Vulkan client executable, graphics device, lighting or render-distance culling. Preserve client rendering/physics behavior during extraction; reconcile competing indoor builders rather than retain a third assembler. 3. Add one validated geometry-loading boundary for tilemaps, room shells and collision zones using SqliteCollisionSurfaceStore / CollisionSurfaceDecoder. Resolve and test collision-zone-to-room mapping rather than assuming zone key equals room array index. Retain decoder version/refusal metadata. Establish ownership/coverage of KD surfaces versus terrain/shell/static statels so geometry is not duplicated or omitted; absent optional collision must be distinguishable from corrupt/missing required geometry. Production engine and CLI use an explicitly configured read-only asset source, not ad hoc Windows paths or a decoder fork. 4. Represent immutable world-space geometry with stable room-instance/floor identity and explicit navigable-surface versus blocking roles. Keep ceilings/overhangs for headroom rasterization; do not make every upward-facing prop/roof walkable. Use a validated, documented pedestrian profile shared across bake paths, with explicit indoor/outdoor/tileset overrides as needed. Calibrate radius, height, climb, slope, voxel resolution and border from fixtures, not old extreme values. If triangle roles require a PRK.Navigation extension, add only a narrow managed/native classification input; preserve SafeHandle ownership and serialized tile compatibility. 5. Replace the legacy offline generator with explicit CLI inputs for asset source, output, selected static playfields and bake profile, plus seeded/layout ACG validation/export using the same runtime builder. Bake tiles from spatially selected geometry including border overlap; bound concurrency/memory, sort output deterministically, and record source/profile/build provenance outside the existing tile format. Rebuild deliberately; reuse only when provenance matches, not merely when a filename exists. Reload/query completed meshes before atomically replacing output. Review tile-size units, grid origin, empty tiles and Detour tile/poly capacity with the existing NavmeshData / PathfindingPfSystem consumer; update both compatibly where needed. 6. Replace ACG custom collision/floor synthesis with a generated-room adapter: load/cache validated template-local geometry, then transform every placed instance using shared room placement and authored-height semantics. Runtime baking occurs after layout finalization and before navigation-ready publication. Bake all supported solo/team/template floors, retaining overlapping vertical layers and disconnected floor components without fake stair/lift links. Cache immutable templates by asset identity; keep mission transforms/navigation owners independent. Partition or tile large layouts and bound runtime cost; use existing registration/lifecycle with staged all-or-nothing publication and cancellation/disposal handling, not an unrelated scheduler rewrite. 7. Integrate floor-aware room resolution and hybrid routing. Reuse the existing door graph for room sequence/required portal waypoints, route approach/interior legs through baked geometry, and preserve door opening, locking and ZoneLink behavior. Do not let smoothing skip mandatory portals. Floor-button teleports remain explicit gameplay actions; ordinary NPC paths must not connect unrelated floors. Remove blanket mission bake exclusions only after the corresponding fixtures pass. Keep grid fallback for validated geometry/native failures, but audit direct-movement fallbacks so a failed query or missing geometry cannot become movement through a wall or onto another floor. 8. Consolidate the relevant ACG mask, placement, LoS, smoothing and visualization consumers around the same immutable geometry and indexed spatial queries. Retain AcgWalkableMask semantics where needed and adapt existing debug APIs rather than create separate geometry generators. Avoid unconditional brute-force rays across all mission triangles and stale probe/collision state on rebake/disposal. Do not rewrite unrelated static physics or gameplay; verify navmesh against the existing static collision world and report discrepancies as migration blockers. 9. Retire obsolete RDBDrawing/exported-KD generation paths and constants after parity passes. Preserve .dat importer/server compatibility; review affected NavmeshExtractor integration without changing or clearing a live database. Validate runtime native/asset delivery in the local production image. No rollout or automatic regeneration/import of production data during this task. Acceptance criteria and validation - Static indoor/outdoor and dynamic solo/team RK, SL and Alien missions use one shared headless geometry pipeline and real collision decoding. No generated-nav dependency on exported KD .dat files, legacy RDBDrawing builders or custom PrkCollisionMesh snapshots. This does not imply removal of that record type from unrelated consumers. - Client terrain/shell geometry parity holds for chunk orientation, alternating diagonals, quarter-turn room placement, height deformation and template pivots. Repeated templates, boss rooms, SL floor X offsets and stacked floors preserve per-instance ownership and correct Y. - Ground/ramps are navigable as intended; walls, pillars, furniture blockers, low ceilings and steep/unsupported surfaces prevent movement. No duplicate phantom floors or clearance obtained by dropping ceiling geometry. - Static files reload through NavmeshData and NavigationMesh, with valid nearest/path results across seams, negative/nonzero origins and vertical layers; units/capacity/empty tiles are verified. Deterministic output and provenance-aware reuse are tested. Malformed input, decode refusals, cancellation and failed validation cannot replace good output. - Runtime ACG bakes the formerly excluded layout families with correct room/floor selection; paths traverse actual door openings and collision-safe interior legs. Smoothing respects required portals. Locks/opening and player/pet floor-button teleport semantics remain unchanged; no accidental NPC lift routing or false floor connectivity. - Placement, mask, LoS and navigation share consistent geometry without introducing large brute-force per-query soup scans. Invalid/incomplete required assets cause an explicit refusal, not apparently successful partial navigation or unsafe direct movement. Any native failure fallback remains geometrically safe and observable. - Runtime initialization, create/bake/query/dispose, rebake failure and concurrent missions preserve native lifetime guarantees, avoid stale shared mutable state, and release allocations. Template caches and mission bakes have bounded memory/concurrency; benchmark representative large team missions and query latency against the existing baseline before setting acceptance budgets. - Reuse/extend RDBLib2 collision/KdTree and indoor tests; client TerrainPatchMesh, IndoorCellSurfacePosition, IndoorShellStampLog, IndoorSurface, WorldPlayfieldLoad and CollisionScene tests; engine AcgWalkableMask, AcgRay, AcgPlacementValidator, team/boss height, snap/shortcut/door regressions; and PRK.Navigation native lifecycle tests. Add behavior-level end-to-end offline generation/reload and seeded runtime mission routing cases. - Relevant generator, client, engine and test projects build; focused suites and local production-image smoke/runtime packaging checks pass. Real-asset cases must actually run before completion; fixture/native/platform absences and remaining release gates stay explicit. Planning has not run these validations. Scope decision User confirmed static indoor, static outdoor and dynamic ACG mission baking are all in scope. Preserve existing door/lift gameplay and land-based navigation; adding swimming/flying navigation or a full graphical-client ACG protocol/rendering feature is not part of this geometry/baking migration. Shared assembly must nevertheless accept generated room instances for server/runtime and offline verification. No unresolved product question currently blocks the plan; exact bake profile values and performance budgets will be set from fixture/baseline evidence. Implementation is in progress on feature/rebuild-world-navmesh-baking. User authorized committing the foundation, now b79f3f31f (feature: Share world geometry loading for navmesh baking), following the requested rebase onto origin/develop 98f9ecdd5. Working tree clean after rebase. No push, deployment or production asset regeneration performed. Verified foundation - Moved client TerrainHeightField, IndoorCellSurface, IndoorRoomShellBuilder and vertex pooling into RDBLib2; client consumes those shared types. Terrain triangle diagonals/winding now have one shared definition. Added finite/snapshot validation and dungeon mesh window/index validation. - Added WorldGeometryPart immutable validated snapshots with source, zone, stable instance and floor identity, and WorldGeometryLoader for static outdoor/indoor and generated room assembly. Uses the real SQLite collision decoder, refuses corrupt zones without publishing partial geometry, validates all decoded template zone ids against room ids, caches source shells within a load and independently places each repeated room. RDBController now supports SQLite read-only mode without writing a temp patch; mutations are explicitly refused. - Added optional immutable walkable-candidate masks to NavigationGeometry and an additive native classified-bake entry point. Existing bake ABI/serialized tile fields remain unchanged. Classified blockers remain in rasterization for headroom; standard Recast low-obstacle promotion semantics remain explicit. This is classification infrastructure, not a completed real-world surface classification policy. - Verified 66 selected client/world/physics tests with actual install assets, including Abandoned Mall's shell census, static 127/4001 and four rotations/repeated floors for all 11 TemplatePlayfields. Seven new loader tests cover snapshots, winding, placement, malformed input, decoder refusal and read-only mutation rejection. Native suite: 120 passed and one external-capture-only skip in Debug and Release; new tests cover blocked candidates, low ceiling and invalid flags. Selected existing engine/KD/mask/placement/codec regressions: 66 passed using isolated artifacts. PFE and legacy generator builds pass; shared library builds cleanly. Existing SQLite vulnerability advisory, generator unused-field and unit-test warnings remain unrelated. git diff --check passes. Verified static baking and generation - Added PRK.WorldNavigation as a narrow RDBLib2/PRK.Navigation bridge, without graphical client dependencies. Immutable triangle BVH selects tile geometry with border overlap; exact equally wound duplicates merge while near-coincident/opposite faces remain. World indexing is capped at two million triangles and tile selections at 250,000; profile/grid/parallelism budgets are explicit. Stable tile ordering yields byte-identical sequential/parallel output. Flat worlds, negative origins and stacked disconnected surfaces have native tests. - Replaced Tools/NavGenerator's constructor-driven Windows/exported-KD pipeline with explicit CLI asset/output/playfield/profile/jobs options, deliberate rebuilding, read-only source loading, source/build/profile/output provenance, verified reuse, reload/nearest queries and atomic mesh replacement. Data and manifest are separate renames; interrupted/mismatched sidecars cannot authorize reuse. Source changes/cancellation/failed bakes preserve previous valid artifacts. Removed tool-local RDBDrawing, backup and unused helper paths. Static generation only; seeded/layout ACG export remains pending. Usage and caveats are in Tools/NavGenerator/README.md. - Consolidated the unchanged server record format in PRK.Navigation.NavigationTileSet and delegated NavmeshData serialization/loading to it. Derived Detour capacities from actual populated tiles and polygon counts, replacing PathfindingPfSystem's voxel-size/log heuristic. Duplicate tile coordinates, record byte budgets and transactional insertion are checked; failed loads no longer publish partial tile sets. A 257-tile native regression and real 1,024-tile output exercise capacity. - Stacked-floor testing exposed Detour partial corridors being reported as successful complete routes. Native wrapper now rejects corridors that do not reach the end polygon, partial/truncated corridors and truncated straight paths. This is an intentional correctness change for unreachable targets, not merely an ownership refactor; grid fallback safety is still a separate remaining integration gate. - Provisional profiles use 45-degree slopes and 1.8/2-unit clearance. KD triangles default to blockers; terrain/authored shell triangles supply walkable candidates. WalkableSlopes is an explicit configurable policy, not the default. Neither default profile calibration nor complete outdoor bridge/platform coverage is claimed. Initial candidate classification still follows standard Recast low-obstacle promotion. - Real offline runs generated/reloaded playfield 127 (27 tiles, 303,391 indexed triangles) and 4001 (1,024 tiles, 681,114 triangles) under /tmp/prk-generated-navigation. Both verified reuse on a subsequent invocation and round-trip byte-identically through the engine codec. One local two-worker run across both playfields took 10.11 seconds and peaked at 355,736 KiB RSS; this is a static-tool baseline, not a runtime mission budget or universal performance guarantee. - Validation: six shared world-bake tests, four artifact tests, 124 native tests (one external capture case skipped), 89 selected engine/KD/pathfinding/placement tests including both real generated files, and 66 client geometry/physics tests passed. Native suite passed in Release; earlier Debug run passed before the added byte-budget case. Lean three-engine build passed with TreatWarningsAsErrors and zero warnings/errors; new tool/shared suites passed Release warning gates. Added explicit CI test steps and parsed workflow YAML locally; remote CI not run. Existing unit-test warnings and client SQLite advisory remain unrelated. git diff --check passes. User authorized committing the static milestone, now 61633b4d1 (feature: Rebuild static navmesh generation with shared world geometry), following foundation commit b79f3f31f. Branch rebased without conflicts onto origin/develop 98f9ecdd5, incorporating merged patrol/active-nano fix #2564. Rebase validation passed: 179 BehaviorTree/ActiveNano tests, 124 native navigation tests (one capture-dependent skip), and six shared world-bake tests. Working tree and diff checks clean. No push, server database import, deployment or production asset replacement. Verified dynamic ACG and final integration - Replaced AcgNavmeshBaker's custom PrkCollisionMesh/floor synthesis with the shared WorldGeometryLoader and tiled WorldTileBaker. Removed blanket SL/team/overlapping-boss exclusions; runtime now bakes solo/team RK, SL and Alien layouts. Preparation is transactional: cancellation and failed native bake do not replace prior managed state; malformed/missing required geometry marks the mission layout broken. Template geometry cache is bounded to 16 playfields and synchronized. Runtime profile uses 0.32 horizontal / 0.1 vertical voxels, 1.8 height, 0.2 radius, 0.8 climb and 64-unit tiles. - Added ReachableSlopes policy: collision ramps/decks initially bake, then a native Detour graph traversal seeded only by authored terrain/shell polygons disables disconnected roof/high-prop components. Synthetic connected bridge/isolated roof, collision-only island, two-sided collision and round-trip tests pass. Existing indoor policy remains BlockersOnly. Retained polygons serialize with zero flags for disabled components; debug extraction now omits disabled polygons. - Added native reachability API under the existing owning session/mutex/SafeHandle boundary plus repeated filtering, invalid seed/bounds and allocation-failure rollback tests. Fault injection found an upstream Detour BV-tree temporary null dereference; vendored Detour now propagates that allocation failure and frees the unfinished tile blob. Linux links with --no-undefined. Native Debug and Release suites each pass 127 tests with one external-capture-only skip. - Moved the client collision BVH/query implementation into RDBLib2 and exposed a narrow IWorldCollisionQuery. Runtime ACG LoS, floor probing, placement, wall orientation, smoothing validation and diagnostics now use indexed, two-sided managed queries rather than unconditional combined triangle soup scans. Client-facing winding-sensitive TrySegment semantics are unchanged; 42 focused client collision/world tests pass. Normal runtime no longer publishes large legacy arrays; NotumForge requests debug copies explicitly and builds (four existing unrelated warnings). - Added height-aware room ownership using per-instance decoded geometry bounds and nearest physical floor. Hybrid routing resolves a same-floor room graph, preserves both sides of every paired door, routes each room leg through Detour with grid fallback, validates every segment against indexed collision/floor/headroom, respects existing open/lock state and never creates floor-button/lift links. Mission shortcut smoothing is disabled outside these mandatory portal legs. Invalid/missing geometry cannot authorize direct movement. Synthetic locked-door, stacked-floor, wall fallback, missing-source and headroom cases pass. - Fixed two fixture-backed defects discovered during migration: doorless boss mask fallback could choose blocked ground under a raised prop; it now chooses a standable level nearest the authored floor. Alien team floor bands used Y=20 while decoded doorway floors were Y≈21.4; team generation now matches the solo/authored 21.4 baseline. - Real seeded validation now covers 20 layout cases: solo MidTech, HiTech, ClanStandard, Mine, OmniLab, Subway, Tarm, AlienMothership, Cave, SL and Alien; team MidTech, HiTech, ClanStandard, Mine, OmniLab, Subway, Alien and SL, plus a focused Alien door-band test. Each checks native floor coverage per floor, no invented lift connectivity, valid cell/door rebinding and at least one collision-safe cross-room route per connected floor. All pass. Runtime debug benchmark guard is 30 seconds; observed representative bakes ranged from ~0.17s to ~2.6s, with the largest 60-room SL team fixture ~12.8s in Debug. Release CLI export of that layout took 5.91s and 422,116 KiB peak RSS. - NavGenerator now supports reproducible dynamic validation exports with --acg-template/--acg-seed/--acg-team, using the same room adapter and runtime profile. Verified MidTech solo export (14 rooms, 4 tiles, 25,739 triangles) and SL team export (60 rooms, 66 tiles, 748,664 triangles), including verified reuse. These are validation/debug artifacts; runtime bakes the actual layout. - Validation: 228 selected engine tests including emergency patrol/active-nano regressions passed before final integration; final focused integration set passed 223 tests. Full AOEmu.UnitTests run passed 4,814, skipped 39 and had two unrelated launcher-markup failures caused by isolated output being unable to discover the repository root; those two are not behavior failures. Native suites pass Debug and Release (127 + one capture-only skip), shared world suite 9, generator suite 4, lean engine build zero warnings/errors, NotumForge build succeeds with four pre-existing warnings. Full client run passed 2,602, skipped 17 and failed 25 install-census/content expectations because this checkout has rdb.db rather than a complete AO client; the 42 affected client collision/world tests pass. Real static 127/4001 outputs regenerate/reload with reachable-slope policy; server codec tests pass. - Exact no-cache linux/amd64 production Dockerfile built as prk-world-navigation-validation:local. Image digest sha256:75fa545e2632d08a4d10f9642b24f26253773d9503299f4852e0d37ccdcfde42. Final-image smoke passed production bake, reachability, load, queries and 200 disposal cycles under Kamal preload/search-path settings; native dependencies resolve, shared navigation/RDB assemblies and license ship, test hooks and smoke harness do not. No registry push, database import, deployment or production asset replacement. Windows/macOS native runtime validation and a complete-client census remain unavailable release gates. git diff --check passes. User authorized committing the completed dynamic/runtime milestone, rebased as 25bc75e8f (feature: Migrate ACG navigation to shared world geometry), following ec0e569dc and 3890a43e1 on origin/develop 05d2bed25. Working tree clean. Branch pushed and draft pull request opened; no deployment, server database import or production navmesh replacement performed. Pull request - #2570: WIP: feature: Rebuild navmesh baking with shared world geometry - https://git.project-rk.com/prk/engines/pulls/2570 - Head: feature/rebuild-world-navmesh-baking; base: develop; draft. Current rebase follow-up User requested rebasing PR #2570 onto develop f555b8d6d. Local rebase complete and clean: 9990c64de, 77aa8fd90, 36b7c20fe. Conflicts resolved preserving newer indoor deformation/ACG placement, authored-only mission containers, read-only SQLite/type-factory changes, tick-lock monitoring and the #3498 mission-entry notification guarantee. Loader tests moved into the current client-test project; shared collision visualization access preserved. No deployment or production data changes. Verified on the rebased code: lean engine build zero warnings/errors; graphics-test project warning-gated build passes; 169 focused engine/navigation/ACG tests pass with no skips (including 80 OmniLab layouts, seeded missions and real generated codec checks); 142 focused client/world/geometry tests pass with real assets and no skips; native navigation 128 pass plus one unavailable external-capture skip; shared world baking 9 pass; generator 4 pass. Real static 127/4001 outputs regenerated/reloaded under .dev-data/navmesh-rebase. git diff --check and merge-tree pass. Disposable validation container needed native audio development headers and scoped Git safe-directory configuration for its root-owned font dependency access. Full suites, production-image smoke and Windows/macOS were not rerun for this rebase. Publication follow-up: user requested pushing; explicit old-SHA force-with-lease succeeded and PR #2570 now points to 36b7c20fec0d4f34ec2b4c2cb3823937ebce1aa2. Working tree was clean after push. Gitea still reported mergeable=false; ls-remote showed develop had advanced to 373823db4deeb206a9d3dea4a595bbfa3a0b8aec after the validated f555b8d6d base. Attempting to fetch the new develop failed with configured SSH agent refusing to sign; no authentication fallback or retry performed. Further rebasing to that newer base remains unverified and requires restored SSH access. User then requested a client navmesh visualizer, tracked separately as tsk_7zawn7vga7; its uncommitted implementation is now on the same local branch and must be preserved.
Checklist
7 of 7 complete- Establish real static-playfield and seeded solo/team ACG fixtures, geometry/path expectations and runtime performance baselines.
- Share headless client terrain/indoor assembly and validated KD collision loading; verify transform/topology parity and zone-to-room mapping.
- Verify shared surface/blocker classification, calibrated bake profiles, headroom and tile/layer capacity without unsafe or duplicate walkable surfaces.
- Replace legacy offline generation with configurable deterministic tiled builds, provenance-aware reuse and validated atomic compatible output.
- Bake dynamic solo/team RK, SL and Alien layouts from shared template geometry with stable instance/floor placement, bounded cost and safe lifecycle.
- Verify floor-aware hybrid door routing, safe fallback and shared indexed mask/placement/LoS/debug consumers while preserving door/lift gameplay.
- Pass affected builds, geometry/native regressions, real-asset generation/reload and seeded mission path tests plus local production-image delivery checks; retire obsolete generation paths.
- Area
- Project Rubi-Ka
- Project
- engines
- Kind
- Feature
- Task ID
tsk_sdukjehp7y- Updated