--- 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. ## Handoff Notes Эта задача не отменяет базовые решения `TASK-0023`, а уточняет основной runtime pathing mode. Не возвращать интеграцию к `Camera.main` или scene-scan-driven sample как к канонической архитектуре. Sample `NavMeshSurfaceVolumeUpdater` использовать только как источник идеи sliding coverage, но не как буквальную production integration model.