document modular navmesh and agent prompts

Update the runtime NavMesh architecture to a DI and MessagePipe sidecar model, and add reusable agent prompt templates that capture the project's current multiplayer, WebGL, and modularity constraints.
This commit is contained in:
Alexander Borisov
2026-04-08 02:19:03 +03:00
parent 36c67558dd
commit 6227542d2d
6 changed files with 707 additions and 164 deletions
@@ -2,16 +2,17 @@
## Status
Этот документ считается каноническим для решений по детерминированному миру, authority model и runtime NavMesh, пока его явно не заменят более новым архитектурным решением.
Этот документ считается каноническим для решений по детерминированному миру, authority model, модульным границам и runtime NavMesh, пока его явно не заменят более новым архитектурным решением.
## Purpose
Зафиксировать долгосрочные решения для MVP, чтобы downstream-задачи по FishNet, worldgen, AI и persistence не уехали в разные стороны.
Зафиксировать долгосрочные решения для MVP, чтобы downstream-задачи по FishNet, worldgen, DI, AI и persistence не уехали в разные стороны.
## Scope
- deterministic voxel world generation
- authority model для session gameplay
- модульные границы feature-подсистем
- runtime NavMesh в procedural world
- риски WebGL-host режима
@@ -79,7 +80,7 @@
Последствия:
- изменения чанка в будущем пойдут не через owner migration, а через authoritative world deltas от хоста
### 4. Runtime NavMesh строится локально на каждом peer по фактической локальной геометрии чанка
### 4. Runtime NavMesh строится локально на каждом peer по фактической локальной геометрии мира
Решение:
- NavMesh не реплицируется по сети как data blob
@@ -175,23 +176,52 @@
Последствия:
- при появлении разных классов существ нужно отдельно пересмотреть agent taxonomy
### 9. В этой фазе решение остается scene-local и не привязывается к VContainer или Addressables
### 9. Runtime NavMesh реализуется как sidecar-модуль, а не как hardwired часть world generator
Решение:
- runtime NavMesh реализуется как часть текущего scene-local world runtime
- VContainer и Addressables в этой задаче не вводятся
- `VoxelWorld` остается владельцем world state и chunk lifecycle
- NavMesh реализуется отдельным подключаемым модулем в собственной assembly
- модуль подключается через DI и может быть отключен без переписывания world feature
Почему выбрано:
- в проекте пока нет production-ready composition root поверх gameplay world
- принудительное добавление DI boundary сейчас даст больше шума, чем пользы
- Addressables не подключены и не требуются для гипотезы NavMesh generation
- это соответствует целевой модели feature-подсистем как подключаемых модулей
- позволяет держать `VoxelWorld` core меньше и стабильнее
- упрощает отключение NavMesh в сценах или режимах, где он не нужен
Почему не выбран ранний DI/bootstrap refactor:
- это отвлекает от основной гипотезы по производительности и корректности NavMesh
- возникает преждевременная архитектурная сложность при еще нестабильных правилах мира
Почему не выбран partial-вариант внутри `VoxelWorldGenerator`:
- он быстрее в реализации, но цементирует NavMesh внутрь world feature
- делает отключение модуля искусственным
- увеличивает связанность и мешает дальнейшему DI-разделению
Последствия:
- код должен оставаться достаточно изолированным, чтобы позже его можно было вынести в runtime service
- world feature обязан публиковать стабильные контракты для sidecar-потребителей
- NavMesh-модуль не должен зависеть от private nested runtime types `VoxelWorldGenerator`
### 10. Для модульной интеграции используется комбинация MessagePipe и reader-интерфейсов
Решение:
- `MessagePipe` используется для событий world lifecycle и invalidation
- отдельные reader-интерфейсы используются для получения актуального snapshot state
- NavMesh service получает `IPublisher<T>` и `ISubscriber<T>` через DI, а не через global lookup
Почему выбрано:
- сообщения хорошо решают слабую связность и optional-subscription
- одних сообщений недостаточно, потому что модуль может стартовать позже и пропустить часть lifecycle events
- reader-интерфейсы позволяют восстановить текущее состояние без зависимости от конкретной реализации мира
Почему не выбран message-only подход:
- missed events ломают начальную инициализацию и late subscription
- пришлось бы тащить тяжелые mutable runtime objects прямо в сообщения
- модуль становился бы хрупким при reorder startup sequence
Почему не выбран direct-reference подход:
- прямые ссылки на `VoxelWorldGenerator` убивают модульность
- `VoxelWorldGenerator` пока содержит private nested types и внутренние детали, которые нельзя делать частью внешнего API
Последствия:
- нужны contracts для `IChunkNavGeometryReader` и `IWorldInterestReader`
- нужны message types для `ChunkNavGeometryReady`, `ChunkNavGeometryRemoved` и `WorldInterestChanged`
- `GlobalMessagePipe` не считается канонической точкой интеграции для feature-кода
## Long-Term Risks
@@ -205,15 +235,17 @@
- Цель в `50` активных NPC может упереться не в один subsystem, а в суммарный CPU budget хоста.
- Будущие изменения геометрии потребуют точной invalidation strategy по nav regions; без нее rebuild cost быстро выйдет из-под контроля.
- Если client movement в будущем начнет опираться на локальный NavMesh как на authority source, появятся расхождения с host simulation.
- Если contracts world feature окажутся слишком узкими или, наоборот, будут протекать внутренними типами генератора, sidecar-модуль быстро потеряет изоляцию.
### Medium
- Late join требует не только `seed/config`, но и корректного воспроизведения authoritative world deltas.
- Если region size выбрать слишком крупным, rebuild будет дорогим; если слишком мелким, возрастет число build operations и seam-risk на границах.
- Неаккуратное использование `GlobalMessagePipe` вместо DI-инъекции создаст скрытую runtime-зависимость и усложнит тестирование.
## Downstream Implications
- `TASK-0001`: этот документ закрывает часть канонических MVP-решений по world/authority/navmesh.
- `TASK-0001`: этот документ закрывает часть канонических MVP-решений по world/authority/navmesh/module boundaries.
- `TASK-0002`: session handshake должен включать world seed, config/version и protocol compatibility checks.
- `TASK-0012`: enemy AI проектируется только как host-authoritative.
- `TASK-0023`: runtime NavMesh обязан быть local-build, throttled и без camera-driven assumptions.
- `TASK-0023`: runtime NavMesh обязан быть local-build, throttled, sidecar-модулем и не должен иметь camera-driven assumptions.