--- id: TASK-0028 title: Перевести runtime NavMesh на interest-cluster-based coverage summary: Заменить основной runtime pathing mode с множества region-based NavMeshData на небольшой набор крупных cluster-based coverage windows, чтобы убрать seam-разрывы и сделать покрытие совместимым с multiplayer interest set. priority: Highest area: ai owner: unassigned created: 2026-04-08 updated: 2026-04-08 execution_time: 2d depends_on: - TASK-0023 canonical_docs: - docs/tasks/Index.md - docs/architecture/mvp-world-authority-navmesh.md - docs/plans/TASK-0023-runtime-navmesh-implementation-plan.md related_files: - Assets/Features/VoxelWorldNavMesh/Runtime/VoxelWorldNavMeshService.cs - Assets/Features/VoxelWorldNavMesh/Runtime/VoxelWorldNavMeshConfig.cs - Assets/Features/VoxelWorld/Contracts/NavMeshWorldContracts.cs - Assets/Features/VoxelWorld/Runtime/VoxelWorldGenerator.cs --- # TASK-0028 - Перевести runtime NavMesh на interest-cluster-based coverage ## Status Статус задачи ведется в `docs/tasks/Index.md` и является каноническим там. ## Why Текущая region-based runtime NavMesh схема подтверждает локальную работоспособность build pipeline, но уже показала архитектурно важную проблему: pathfinding между соседними зонами покрытия дает `PathPartial`, даже когда destination сам лежит на NavMesh. Это означает, что текущий основной runtime pathing mode опирается на набор разрозненных nav islands и не гарантирует непрерывный navigation graph между активными зонами симуляции. Для multiplayer host-authoritative pathing этого недостаточно. Хосту нужен не просто локально построенный NavMesh, а непрерывное coverage в активной области симуляции без систематических seam-разрывов на границах мелких регионов. ## Expected Outcome - Основной runtime pathing mode больше не строится как множество мелких независимых `NavMeshData` по nav regions. - Вместо этого используется небольшой набор крупных `coverage windows`, каждый из которых покрывает `interest cluster`. - Внутри активной области симуляции pathfinding не ломается на границах бывших nav regions. - Coverage учитывает не только одного игрока, а multiplayer interest set: `spawn anchors + players + active NPC`. - Модуль остается sidecar-решением поверх `VoxelWorld`, без hardwiring внутрь `VoxelWorldGenerator`. ## Current Context Сейчас runtime NavMesh уже вынесен в sidecar-модуль и строится локально на каждом peer: - `VoxelWorldGenerator` отдает nav sources через contracts; - `VoxelWorldNavMeshService` собирает sources из chunk snapshots; - build идет локально и не реплицируется по сети; - authority gameplay сохраняется у хоста. Однако unit of build и unit of scheduling пока выбраны неудачно как основной pathing mode: - много мелких `NavMeshData` по region-based сетке; - pathfinding между region surfaces может распадаться на отдельные islands; - visual continuity overlay не гарантирует graph connectivity для `NavMesh.CalculatePath` / `NavMeshAgent`. ## Source Of Truth - `docs/architecture/mvp-world-authority-navmesh.md` - `docs/plans/TASK-0023-runtime-navmesh-implementation-plan.md` - фактическая реализация `VoxelWorldNavMeshService` - подтвержденные smoke-test результаты с `PathPartial` на границах region coverage ## Read First - `Assets/Features/VoxelWorldNavMesh/Runtime/VoxelWorldNavMeshService.cs` - `Assets/Features/VoxelWorldNavMesh/Runtime/VoxelWorldNavMeshConfig.cs` - `Assets/Features/VoxelWorld/Contracts/NavMeshWorldContracts.cs` - `Assets/Features/VoxelWorld/Runtime/VoxelWorldGenerator.cs` - `docs/architecture/mvp-world-authority-navmesh.md` ## Fixed Decisions ### 1. NavMesh remains local-build sidecar state NavMesh по-прежнему: - строится локально на каждом peer; - не реплицируется как data blob; - остается derived cache от world state; - не является authoritative network state. ### 2. Chunk stays source/invalidation unit, not build unit `Chunk` остается: - источником nav build sources; - unit of invalidation для world lifecycle; - источником dirty notifications. `Chunk` не должен оставаться каноническим unit of nav coverage build. ### 3. Coverage window is built from interest clusters, not from one player and not from camera Нельзя строить канонический runtime pathing вокруг: - `Camera.main`; - только одного tracked player; - presentation-level сущности. Coverage должен строиться вокруг `interest clusters`, формируемых из: - spawn anchors; - players; - active NPC. ### 4. One player does not imply one dedicated volume Нельзя закреплять правило `один игрок = один volume`. Правильная модель: - один spatially coherent interest cluster = один coverage window; - близкие игроки и NPC должны merge'иться в один cluster; - число active windows должно быть bounded. ### 5. Scene scan through `NavMeshSurface` sample is not the canonical integration model Подход из sample `NavMeshSurfaceVolumeUpdater` полезен как диагностическая подсказка, но не должен становиться буквальной production integration model. Канонический путь для проекта: - bounds уровня sliding coverage window; - build sources из `IChunkNavSourceReader` / world contracts; - DI + typed MessagePipe + reader contracts. ### 6. Spawn readiness must become first-class Покрытие должно учитывать spawn anchors до player movement activation. Нельзя полагаться на то, что NavMesh magically появится только после того, как actor уже стал единственной точкой интереса. ## Scope In - замена основного runtime pathing mode с region-based surfaces на cluster-based coverage windows; - новый scheduler по coverage windows; - cluster builder для `players + active NPC + spawn anchors`; - build source collection по bounds окна, а не по одному nav region; - read-model для current nav coverage state; - explicit coverage readiness для spawn / first path command / AI activation; - bounded merge policy для близких interest points; - debug visibility coverage windows. ## Scope Out - изменение authority model NPC/AI; - репликация NavMesh; - полноценная crowd avoidance система; - multi-agent taxonomy beyond current single-agent MVP; - player host-authoritative navigation system как отдельная feature-задача; - большой рефактор world feature вне необходимого nav contracts surface. ## Required Architecture ### New canonical unit: interest cluster Нужна новая внутренняя модель coverage: - `WorldInterestPoint` остается atomic input; - `NavInterestCluster` становится unit of grouping; - `NavCoverageWindow` становится unit of build and readiness. Минимальная ответственность cluster builder: - собрать текущий interest set; - spatially merge близкие точки интереса; - стабилизировать cluster ids между обновлениями; - строить quantized window bounds с margin. ### Coverage window replaces region as primary build unit `Coverage window` должен хранить: - cluster id; - current bounds; - `NavMeshData` / `NavMeshDataInstance`; - dirty/building/ready state; - список covered chunks или equivalent cached source membership. ### Source collection remains contract-driven Build sources должны собираться: - не через scene scan; - не через direct references на private world internals; - а через `IChunkNavSourceReader` и chunk nav source snapshots. `Chunk` используется как source/invalidation unit, но не как primary coverage unit. ### Coverage state must be queryable Нужен reader contract уровня: - `INavCoverageReader` Минимальная ответственность: - `IsPositionCovered(Vector3 worldPosition)`; - возможность получить current active coverage windows; - возможность проверить readiness для spawn/path activation. ### Scheduler must be bounded and quantized Нельзя rebuild'ить coverage window на каждый микрошаг игрока. Нужны: - quantized movement threshold; - bounded number of active windows; - bounded builds per frame; - rebuild только при существенном смещении cluster bounds, изменении cluster composition или chunk invalidation внутри covered bounds. ## Suggested Runtime Structure ### New or refactored runtime types - `NavInterestClusterBuilder` - `NavCoverageWindowRuntime` - `NavCoverageWindowSnapshot` - `NavBuildSourceCollector` - `INavCoverageReader` - `VoxelWorldClusteredNavMeshService` или equivalent refactor текущего `VoxelWorldNavMeshService` ### Config changes Текущий config должен сместиться от region-centric параметров к cluster/window-centric: - `clusterMergeDistance` - `clusterBoundsPadding` - `clusterRebuildQuantization` - `maxActiveCoverageWindows` - `chunkCollectionMarginInChunks` - `maxBuildsPerFrame` Если старые region-centric поля остаются временно ради миграции, они не должны продолжать определять основной runtime pathing mode. ## Main Highlights Of Changes 1. **Смена unit of build** - было: `nav region` - станет: `interest cluster coverage window` 2. **Смена unit of scheduling** - было: очередь dirty regions - станет: очередь dirty coverage windows 3. **Смена unit of readiness** - было: неявная region-local готовность - станет: явная coverage readiness по world position 4. **Смена логики multiplayer coverage** - было: первая practical привязка к локальному player interest - станет: `spawn anchors + players + active NPC` 5. **Уход от seam-first topology** - было: pathing через сеть мелких surfaces с риском disconnected islands - станет: меньшее число более цельных coverage windows ## Acceptance Criteria - Основной runtime pathing mode больше не опирается на множество мелких region-based `NavMeshData` как на primary navigation graph. - Destination на NavMesh в соседней активной области больше не приводит систематически к `PathPartial` только из-за seam между бывшими nav regions. - Coverage формируется по interest clusters, а не по одному tracked player и не по `Camera.main`. - Spawn anchors участвуют в initial nav coverage. - Нужное coverage state можно query'ить через reader contract. - Sidecar-модуль остается отключаемым без переписывания `VoxelWorld` core. - Build pipeline остается bounded и пригодным для WebGL-host бюджета. ## Verification - ручной тест: pathfinding между соседними активными областями больше не обрывается на границе бывших region surfaces; - ручной тест: при удалении игроков друг от друга coverage windows корректно split/merge'ятся по кластерам; - ручной тест: spawn area получает nav coverage до first path command; - ручной тест: pathfinding внутри cluster window и между близкими covered areas дает `PathComplete`, где раньше получался `PathPartial` из-за seam; - debug visualization coverage windows подтверждает ожидаемую cluster topology. ## Risks / Open Questions - Один большой coverage window может снять seam-problem, но оказаться слишком тяжелым для host CPU budget; поэтому bounded cluster windows важнее, чем просто "один volume на весь мир". - Слишком агрессивное merge policy может раздуть rebuild cost; слишком слабое merge policy вернет seam-problem в другой форме. - Нужна аккуратная стратегия стабильных cluster ids, иначе scheduler и debug tooling будут шумными. - Возможно понадобится временный dual-mode rollout: region mode как fallback, clustered mode как новый primary pathing mode до подтверждения стабильности. ## Human Decisions Needed - none currently ## Decision Log - `2026-04-08` - подзадача выделена после smoke-test'а runtime NavMesh, который подтвердил локальную работоспособность build pipeline, но выявил `PathPartial` на границах region-based coverage. - `2026-04-08` - region-based primary pathing mode заменен на clustered coverage windows; дополнительно введены transient nav coverage hints для prewarm вдоль активного маршрута. ## Handoff Notes Эта задача не отменяет базовые решения `TASK-0023`, а уточняет основной runtime pathing mode. Не возвращать интеграцию к `Camera.main` или scene-scan-driven sample как к канонической архитектуре. Sample `NavMeshSurfaceVolumeUpdater` использовать только как источник идеи sliding coverage, но не как буквальную production integration model. Задача закрыта как переход на новый основной runtime pathing mode. Дополнительные улучшения interest composition, NPC interest expansion, debug visualization и route-aware coverage policy нужно развивать отдельными follow-up задачами.