refine runtime navmesh contracts and plan
This commit is contained in:
@@ -100,6 +100,7 @@
|
|||||||
Последствия:
|
Последствия:
|
||||||
- каноничность gameplay не должна зависеть от клиентского NavMesh
|
- каноничность gameplay не должна зависеть от клиентского NavMesh
|
||||||
- client NavMesh используется для локальных потребностей, но authoritative decisions по NPC остаются у хоста
|
- client NavMesh используется для локальных потребностей, но authoritative decisions по NPC остаются у хоста
|
||||||
|
- при одинаковом world state peers должны приходить к функционально эквивалентной walkable topology, но NavMesh не считается protocol-grade bit-identical артефактом, от которого зависит correctness multiplayer state
|
||||||
|
|
||||||
### 5. Будущие изменения проходимости мира передаются как authoritative world deltas
|
### 5. Будущие изменения проходимости мира передаются как authoritative world deltas
|
||||||
|
|
||||||
@@ -140,11 +141,12 @@
|
|||||||
- rebuild должен быть incremental, throttled и bounded
|
- rebuild должен быть incremental, throttled и bounded
|
||||||
- полносценовый bake вокруг камеры не подходит как каноническая модель
|
- полносценовый bake вокруг камеры не подходит как каноническая модель
|
||||||
|
|
||||||
### 7. Первая итерация NavMesh покрывает область вокруг player actor, но долгосрочный контракт расширяется до players + active NPC
|
### 7. Первая итерация NavMesh может приоритизировать одного player actor, но внешний interest-контракт сразу задается как actor set
|
||||||
|
|
||||||
Решение:
|
Решение:
|
||||||
- для первой проверки гипотезы build priority привязывается к player actor
|
- для первой проверки гипотезы scheduler может стартовать от одного player actor
|
||||||
- целевой контракт для multiplayer host: nav coverage должна учитывать игроков и активных NPC
|
- внешний reader/read-model контракт не должен жестко фиксировать single-point модель
|
||||||
|
- целевой контракт для multiplayer host: nav coverage должна учитывать игроков и активных NPC как actor-level interest set
|
||||||
|
|
||||||
Почему выбрано:
|
Почему выбрано:
|
||||||
- это минимальный объем для MVP-проверки без ранней переплаты за сложную interest model
|
- это минимальный объем для MVP-проверки без ранней переплаты за сложную interest model
|
||||||
@@ -158,6 +160,7 @@
|
|||||||
Последствия:
|
Последствия:
|
||||||
- в коде нельзя оставлять `Camera.main` как канонический источник world/nav interest
|
- в коде нельзя оставлять `Camera.main` как канонический источник world/nav interest
|
||||||
- target должен представлять actor-level interest, а не presentation-level camera
|
- target должен представлять actor-level interest, а не presentation-level camera
|
||||||
|
- reader-контракт для интереса должен уметь вернуть один или несколько actor-level interest points; даже если первая scene wiring временно дает только один player actor, это не должно цементироваться во внешний API
|
||||||
|
|
||||||
### 8. Для MVP поддерживается один тип NavMesh agent
|
### 8. Для MVP поддерживается один тип NavMesh agent
|
||||||
|
|
||||||
@@ -219,9 +222,10 @@
|
|||||||
- `VoxelWorldGenerator` пока содержит private nested types и внутренние детали, которые нельзя делать частью внешнего API
|
- `VoxelWorldGenerator` пока содержит private nested types и внутренние детали, которые нельзя делать частью внешнего API
|
||||||
|
|
||||||
Последствия:
|
Последствия:
|
||||||
- нужны contracts для `IChunkNavGeometryReader` и `IWorldInterestReader`
|
- нужны query contracts для чтения актуальных nav build sources чанков и actor-level interest set, например `IChunkNavSourceReader` и `IWorldInterestReader`
|
||||||
- нужны message types для `ChunkNavGeometryReady`, `ChunkNavGeometryRemoved` и `WorldInterestChanged`
|
- нужны message types для `ChunkNavGeometryReady`, `ChunkNavGeometryRemoved` и `WorldInterestChanged`
|
||||||
- `GlobalMessagePipe` не считается канонической точкой интеграции для feature-кода
|
- `GlobalMessagePipe` не считается канонической точкой интеграции для feature-кода
|
||||||
|
- world-to-navmesh contracts не должны делать `Transform`, `MeshCollider` и `BoxCollider` каноническим внешним состоянием там, где достаточно узких source descriptors для build/invalidation
|
||||||
|
|
||||||
## Long-Term Risks
|
## Long-Term Risks
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
- текущая test scene: `Assets/Features/VoxelWorld/Scenes/VoxelWorldTestScene.unity`
|
- текущая test scene: `Assets/Features/VoxelWorld/Scenes/VoxelWorldTestScene.unity`
|
||||||
- основной runtime генерации мира: `Assets/Features/VoxelWorld/Runtime/VoxelWorldGenerator.cs`
|
- основной runtime генерации мира: `Assets/Features/VoxelWorld/Runtime/VoxelWorldGenerator.cs`
|
||||||
- в проекте уже есть `ApplicationLifetimeScope` с `MessagePipe` registration
|
- в проекте уже есть `ApplicationLifetimeScope` с `MessagePipe` registration
|
||||||
- первая итерация NavMesh coverage строится вокруг player actor
|
- первая итерация scheduler может начинать приоритизацию от одного player actor
|
||||||
- долгосрочный контракт остается `players + active NPC`
|
- внешний interest-контракт сразу остается actor-level interest set: `players + active NPC`
|
||||||
- один тип агента
|
- один тип агента
|
||||||
- динамические изменения мира пока не реализуются, но контракты под них должны быть предусмотрены
|
- динамические изменения мира пока не реализуются, но контракты под них должны быть предусмотрены
|
||||||
- WebGL-host остается целевой платформой, поэтому базовый pipeline не зависит от потоков
|
- WebGL-host остается целевой платформой, поэтому базовый pipeline не зависит от потоков
|
||||||
@@ -55,16 +55,23 @@
|
|||||||
- один большой moving volume слишком дорог и плохо контролируется по бюджету
|
- один большой moving volume слишком дорог и плохо контролируется по бюджету
|
||||||
- region-based rebuild дает лучший компромисс между стоимостью и связностью
|
- region-based rebuild дает лучший компромисс между стоимостью и связностью
|
||||||
|
|
||||||
### 5. Источники build sources берутся из chunk colliders, публикуемых world feature
|
### 5. Целью считается эквивалентная walkable topology, а не bit-identical NavMesh artifact
|
||||||
|
|
||||||
|
Почему:
|
||||||
|
- runtime NavMesh остается derived cache, а не canonical network state
|
||||||
|
- gameplay correctness не должен опираться на клиентский NavMesh как на источник authority
|
||||||
|
- это не создает ложного требования к protocol-grade детерминизму там, где он не нужен для MVP
|
||||||
|
|
||||||
|
### 6. Источники build sources публикуются world feature как узкие source descriptors
|
||||||
|
|
||||||
Выбор:
|
Выбор:
|
||||||
- `GroundCollider` дает box source
|
- world feature отдает snapshot nav sources чанка через стабильный reader contract
|
||||||
- `MountainCollider.sharedMesh` дает mesh source
|
- текущая реализация `VoxelWorld` может внутри строить эти sources из `GroundCollider` и `MountainCollider`, но эта деталь не протекает в API sidecar-модуля
|
||||||
|
|
||||||
Почему:
|
Почему:
|
||||||
- не нужен scene-wide scanning
|
- не нужен scene-wide scanning
|
||||||
- не требуется отдельная nav-only геометрия на первом этапе
|
- не требуется отдельная nav-only геометрия на первом этапе
|
||||||
- это наиболее близкое к gameplay представление walkable/non-walkable world geometry
|
- sidecar-модуль не цементируется на конкретных `Collider`-компонентах и scene hierarchy мира
|
||||||
|
|
||||||
## Target Module Boundaries
|
## Target Module Boundaries
|
||||||
|
|
||||||
@@ -83,27 +90,41 @@
|
|||||||
|
|
||||||
### Reader Interfaces
|
### Reader Interfaces
|
||||||
|
|
||||||
- `IChunkNavGeometryReader`
|
- `IChunkNavSourceReader`
|
||||||
- `IWorldInterestReader`
|
- `IWorldInterestReader`
|
||||||
|
|
||||||
Минимальная ответственность:
|
Минимальная ответственность:
|
||||||
- `IChunkNavGeometryReader` умеет вернуть текущую nav-геометрию чанка и список уже загруженных чанков
|
- `IChunkNavSourceReader` умеет вернуть текущие nav build sources чанка и список уже загруженных чанков
|
||||||
- `IWorldInterestReader` умеет вернуть текущую primary interest point
|
- `IWorldInterestReader` умеет вернуть текущий actor-level interest set
|
||||||
|
|
||||||
### DTO / Contracts
|
### DTO / Contracts
|
||||||
|
|
||||||
- `ChunkNavGeometry`
|
- `ChunkNavSourceSnapshot`
|
||||||
|
- `ChunkNavBuildSourceDescriptor`
|
||||||
|
- `WorldInterestPoint`
|
||||||
|
|
||||||
Состав DTO:
|
Состав DTO:
|
||||||
|
- `ChunkNavSourceSnapshot`
|
||||||
- `Vector2Int Coord`
|
- `Vector2Int Coord`
|
||||||
- `Transform Root`
|
|
||||||
- `BoxCollider GroundCollider`
|
|
||||||
- `MeshCollider MountainCollider`
|
|
||||||
- `int Version`
|
- `int Version`
|
||||||
|
- `ChunkNavBuildSourceDescriptor[] Sources`
|
||||||
|
|
||||||
|
- `ChunkNavBuildSourceDescriptor`
|
||||||
|
- `NavMeshBuildSourceShape Shape`
|
||||||
|
- `Matrix4x4 Transform`
|
||||||
|
- `Vector3 Size` для box-source
|
||||||
|
- `Mesh Mesh` для mesh-source
|
||||||
|
- `int Area`
|
||||||
|
|
||||||
|
- `WorldInterestPoint`
|
||||||
|
- `Vector3 Position`
|
||||||
|
- `float Priority`
|
||||||
|
- `WorldInterestKind Kind`
|
||||||
|
|
||||||
Примечание:
|
Примечание:
|
||||||
- DTO должен содержать только то, что реально нужно для NavMesh source collection
|
- DTO должен содержать только то, что реально нужно для NavMesh source collection и build prioritization
|
||||||
- private nested types `VoxelWorldGenerator` не должны утекать наружу
|
- private nested types `VoxelWorldGenerator` не должны утекать наружу
|
||||||
|
- `Transform`, `MeshCollider` и `BoxCollider` не должны становиться каноническим внешним состоянием NavMesh integration, если достаточно source descriptors
|
||||||
|
|
||||||
### Message Types
|
### Message Types
|
||||||
|
|
||||||
@@ -132,7 +153,7 @@
|
|||||||
|
|
||||||
### 2. Реализовать reader interfaces
|
### 2. Реализовать reader interfaces
|
||||||
|
|
||||||
- `IChunkNavGeometryReader`
|
- `IChunkNavSourceReader`
|
||||||
- `IWorldInterestReader`
|
- `IWorldInterestReader`
|
||||||
|
|
||||||
### 3. Публиковать сообщения после world lifecycle changes
|
### 3. Публиковать сообщения после world lifecycle changes
|
||||||
@@ -140,7 +161,7 @@
|
|||||||
Нужно публиковать:
|
Нужно публиковать:
|
||||||
- `ChunkNavGeometryReadyMessage` после фактического применения collider mesh
|
- `ChunkNavGeometryReadyMessage` после фактического применения collider mesh
|
||||||
- `ChunkNavGeometryRemovedMessage` перед уничтожением чанка
|
- `ChunkNavGeometryRemovedMessage` перед уничтожением чанка
|
||||||
- `WorldInterestChangedMessage` при смене actor-level interest point
|
- `WorldInterestChangedMessage` при изменении actor-level interest set
|
||||||
|
|
||||||
### 4. Убрать каноническую зависимость от `Camera.main`
|
### 4. Убрать каноническую зависимость от `Camera.main`
|
||||||
|
|
||||||
@@ -183,12 +204,12 @@
|
|||||||
## NavMesh Service Responsibilities
|
## NavMesh Service Responsibilities
|
||||||
|
|
||||||
- подписаться на world lifecycle messages
|
- подписаться на world lifecycle messages
|
||||||
- на старте получить snapshot уже загруженных чанков через `IChunkNavGeometryReader`
|
- на старте получить snapshot уже загруженных чанков через `IChunkNavSourceReader`
|
||||||
- построить initial set dirty regions
|
- построить initial set dirty regions
|
||||||
- поддерживать `NavMeshData` по регионам
|
- поддерживать `NavMeshData` по регионам
|
||||||
- собирать `NavMeshBuildSource` из chunk colliders
|
- собирать `NavMeshBuildSource` из source descriptors, а не через прямой доступ к world colliders
|
||||||
- запускать throttled `UpdateNavMeshDataAsync`
|
- запускать throttled `UpdateNavMeshDataAsync`
|
||||||
- переоценивать build priority относительно current interest point
|
- переоценивать build priority относительно current interest set
|
||||||
- удалять region data, когда она выходит из активного диапазона и становится пустой
|
- удалять region data, когда она выходит из активного диапазона и становится пустой
|
||||||
|
|
||||||
## Region Runtime Data
|
## Region Runtime Data
|
||||||
@@ -223,15 +244,15 @@
|
|||||||
### Initial Sync
|
### Initial Sync
|
||||||
|
|
||||||
1. Сервис стартует.
|
1. Сервис стартует.
|
||||||
2. Через `IChunkNavGeometryReader` получает список уже загруженных чанков.
|
2. Через `IChunkNavSourceReader` получает список уже загруженных чанков.
|
||||||
3. Помечает соответствующие nav regions dirty.
|
3. Помечает соответствующие nav regions dirty.
|
||||||
4. Через `IWorldInterestReader` получает текущую точку интереса.
|
4. Через `IWorldInterestReader` получает текущий interest set.
|
||||||
5. Запускает scheduler.
|
5. Запускает scheduler.
|
||||||
|
|
||||||
### Incremental Update
|
### Incremental Update
|
||||||
|
|
||||||
1. Приходит `ChunkNavGeometryReadyMessage`.
|
1. Приходит `ChunkNavGeometryReadyMessage`.
|
||||||
2. Сервис читает актуальную geometry через `IChunkNavGeometryReader`.
|
2. Сервис читает актуальные sources через `IChunkNavSourceReader`.
|
||||||
3. Помечает nav region dirty.
|
3. Помечает nav region dirty.
|
||||||
4. Если chunk расположен на границе region, дополнительно маркирует соседний region.
|
4. Если chunk расположен на границе region, дополнительно маркирует соседний region.
|
||||||
|
|
||||||
@@ -244,19 +265,19 @@
|
|||||||
### Interest Update
|
### Interest Update
|
||||||
|
|
||||||
1. Приходит `WorldInterestChangedMessage`.
|
1. Приходит `WorldInterestChangedMessage`.
|
||||||
2. Сервис обновляет current interest point.
|
2. Сервис обновляет current interest set.
|
||||||
3. Scheduler пересчитывает порядок rebuild и warmup regions.
|
3. Scheduler пересчитывает порядок rebuild и warmup regions.
|
||||||
|
|
||||||
## Source Collection Rules
|
## Source Collection Rules
|
||||||
|
|
||||||
Для каждого затронутого region:
|
Для каждого затронутого region:
|
||||||
- собрать build sources только из чанков региона и соседнего margin
|
- собрать build sources только из чанков региона и соседнего margin
|
||||||
- использовать только известную geometry из reader interface
|
- использовать только известные source snapshots из reader interface
|
||||||
- не сканировать произвольные объекты сцены
|
- не сканировать произвольные объекты сцены
|
||||||
|
|
||||||
Для каждого chunk geometry:
|
Для каждого chunk snapshot:
|
||||||
- добавить `NavMeshBuildSourceShape.Box` из `GroundCollider`
|
- добавить sources из `ChunkNavBuildSourceDescriptor`
|
||||||
- добавить `NavMeshBuildSourceShape.Mesh` из `MountainCollider.sharedMesh`, если mesh не пустой
|
- если текущий `VoxelWorld` строит эти descriptors из `GroundCollider` и `MountainCollider`, это остается его внутренней деталью и не становится contract-level зависимостью NavMesh-модуля
|
||||||
|
|
||||||
## Performance Rules
|
## Performance Rules
|
||||||
|
|
||||||
@@ -283,6 +304,7 @@
|
|||||||
1. Проверить старт сервиса после world generator: missed events не должны ломать initial sync.
|
1. Проверить старт сервиса после world generator: missed events не должны ломать initial sync.
|
||||||
2. Проверить, что модуль работает только через DI-injected `MessagePipe` и reader interfaces.
|
2. Проверить, что модуль работает только через DI-injected `MessagePipe` и reader interfaces.
|
||||||
3. Проверить, что отключение регистрации `VoxelWorldNavMesh` не ломает world feature.
|
3. Проверить, что отключение регистрации `VoxelWorldNavMesh` не ломает world feature.
|
||||||
|
4. Проверить, что внешний interest contract допускает один или несколько interest points, даже если первая scene wiring пока подает только одного player actor.
|
||||||
|
|
||||||
### Performance
|
### Performance
|
||||||
|
|
||||||
|
|||||||
@@ -96,4 +96,6 @@ AI врагов (`TASK-0012`) опирается на NavMesh. Воксельн
|
|||||||
|
|
||||||
## Handoff Notes
|
## Handoff Notes
|
||||||
|
|
||||||
|
Реализация задачи должна идти с учетом принятых решений и уже проведенного ресерча в `docs/architecture/mvp-world-authority-navmesh.md`, `docs/plans/TASK-0023-runtime-navmesh-implementation-plan.md` и текущего runtime-контекста `Assets/Features/VoxelWorld/Runtime/VoxelWorldGenerator.cs`. Если формулировки task-card расходятся с каноническими решениями и зафиксированным ресерчем, приоритет у этих файлов.
|
||||||
|
|
||||||
Если в проекте нет пакета NavMeshComponents, возможно придется добавить его или реализовать минимальный runtime builder.
|
Если в проекте нет пакета NavMeshComponents, возможно придется добавить его или реализовать минимальный runtime builder.
|
||||||
|
|||||||
Reference in New Issue
Block a user