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.
18 KiB
MVP World, Authority And Runtime NavMesh
Status
Этот документ считается каноническим для решений по детерминированному миру, authority model, модульным границам и runtime NavMesh, пока его явно не заменят более новым архитектурным решением.
Purpose
Зафиксировать долгосрочные решения для MVP, чтобы downstream-задачи по FishNet, worldgen, DI, AI и persistence не уехали в разные стороны.
Scope
- deterministic voxel world generation
- authority model для session gameplay
- модульные границы feature-подсистем
- runtime NavMesh в procedural world
- риски WebGL-host режима
Fixed Decisions
1. Базовый мир генерируется детерминированно и локально на каждом peer
Решение:
- базовая геометрия мира не стримится от хоста по сети
- каждый peer генерирует чанк локально из одинакового
seed, одинаковогоVoxelWorldConfigи одинаковой версии world rules
Почему выбрано:
- для WebGL и peer-host модели это минимизирует сетевой трафик
- убирает постоянную сетевую репликацию геометрии чанков
- снимает с хоста роль единственной точки генерации базового мира
- хорошо сочетается с уже существующим
VoxelWorldGenerator, который строит чанк из deterministic inputs
Почему не выбран host-generated world streaming:
- хост получал бы лишнюю CPU-нагрузку на генерацию и лишнюю сетевую нагрузку на раздачу чанков
- late join и догрузка дальних областей становились бы тяжелее по сети
- это хуже укладывается в бюджет WebGL-host
Последствия:
seed, world config и их версия становятся частью session handshake- любое расхождение по config/version между peers недопустимо и должно считаться protocol drift
2. Host остается authoritative для NPC, AI и другого gameplay state
Решение:
- NPC симулируются на хосте
- pathfinding NPC, агро, боевые решения и каноническое положение NPC принадлежат хосту
- клиенты получают состояние NPC по сети и могут делать только визуальное сглаживание
Почему выбрано:
- NPC влияют на бой, урон, столкновения и progression, значит их нельзя отдавать в authority случайному клиенту
- это радикально снижает риск читов и эксплуатационных багов
- упрощает late join, reconnect и дебаг сетевой симуляции
Почему не выбран client-owned NPC:
- ownership у первого встретившего игрока нестабилен при совместной игре
- миграция owner во время боя ломает воспроизводимость path state, aggro state и hit timing
- возрастает риск desync и эксплойтов
- резко усложняется отладка и сопровождение
Последствия:
client-authorityдопустим только для ввода игрока и только при отдельной валидации на сервере- для NPC authority migration в MVP не используется
3. У чанков нет owner и нет chunk ownership migration
Решение:
- чанк не закрепляется за конкретным игроком как за владельцем
- базовый чанк является общей детерминированной сущностью мира, а не network-owned объектом
Почему выбрано:
- при deterministic world generation ownership чанка не дает полезного выигрыша
- chunk ownership добавляет coordination cost, миграцию ответственности и новые классы сетевых гонок без пользы для MVP
- это плохо совместимо с late join и с будущими world deltas
Почему не выбран owner-per-chunk:
- первый увидевший чанк игрок не является надежным authority source
- потребуется сложная логика передачи владения при сближении игроков и при disconnect
- любые расхождения по владельцу чанка приводят к hidden state drift
Последствия:
- изменения чанка в будущем пойдут не через owner migration, а через authoritative world deltas от хоста
4. Runtime NavMesh строится локально на каждом peer по фактической локальной геометрии мира
Решение:
- NavMesh не реплицируется по сети как data blob
- каждый peer строит NavMesh у себя локально из актуальной локальной геометрии мира
- NavMesh всегда считается производным кэшем от world state, а не каноническим состоянием сессии
Почему выбрано:
- NavMesh data тяжелая и плохо подходит для сетевой репликации в peer-host модели
- при deterministic base world и одинаковых world deltas peers могут независимо прийти к одинаковой walkable topology
- это сохраняет сеть для gameplay state, а не для производных навигационных артефактов
Почему не выбран network-streamed NavMesh:
- лишний трафик и высокая сложность синхронизации
- плохая масштабируемость для догрузки чанков и late join
- NavMesh все равно пришлось бы пересобирать при локальных изменениях геометрии
Последствия:
- каноничность gameplay не должна зависеть от клиентского NavMesh
- client NavMesh используется для локальных потребностей, но authoritative decisions по NPC остаются у хоста
5. Будущие изменения проходимости мира передаются как authoritative world deltas
Решение:
- базовый мир идет из deterministic generation
- любые будущие баррикады, спеллы, разрушаемость, carve и другие изменения мира передаются как authoritative deltas от хоста
- после применения delta каждый peer локально перестраивает затронутые nav regions
Почему выбрано:
- это отделяет immutable base generation от mutable session state
- обеспечивает late join: новому игроку можно отдать base seed/config и журнал world deltas
- не требует вводить ownership migration для чанков
Почему не выбран fully local mutable world:
- local-first изменения мира не могут быть каноническими в кооперативной сетевой игре
- конфликтуют с античитом, late join и persistence
Последствия:
- NavMesh pipeline обязан уметь маркировать локальные nav regions как dirty после world delta
6. NavMesh pipeline должен работать в single-thread budget; многопоточность в WebGL считается только опциональным ускорением
Решение:
- архитектура runtime NavMesh не должна зависеть от наличия потоков
- базовый режим должен укладываться в бюджет кадра на одном потоке
- если deployment позже подтвердит поддержку
SharedArrayBufferиCOOP/COEP, можно добавить threaded optimization, но не делать ее обязательной
Почему выбрано:
- WebGL-host остается одной из целевых платформ
- WebGL multithreading требует специальных заголовков и эксплуатационной дисциплины на стороне хостинга
- завязка critical gameplay pipeline на эту инфраструктуру слишком рискованна для MVP
Почему не выбран threaded-only pipeline:
- он может работать в editor/desktop и развалиться в реальном WebGL deployment
- создаст ложное ощущение приемлемого бюджета, которого не будет на production-hosting
Последствия:
- rebuild должен быть incremental, throttled и bounded
- полносценовый bake вокруг камеры не подходит как каноническая модель
7. Первая итерация NavMesh покрывает область вокруг player actor, но долгосрочный контракт расширяется до players + active NPC
Решение:
- для первой проверки гипотезы build priority привязывается к player actor
- целевой контракт для multiplayer host: nav coverage должна учитывать игроков и активных NPC
Почему выбрано:
- это минимальный объем для MVP-проверки без ранней переплаты за сложную interest model
- при этом заранее фиксируется, что player-only coverage не является конечной архитектурой
Почему не выбран camera-driven center:
- камера не является каноническим gameplay actor
- в multiplayer и especially on host камера может не совпадать с зоной активной симуляции
- привязка к
Camera.mainломает переносимость решения из test scene в сетевую сессию
Последствия:
- в коде нельзя оставлять
Camera.mainкак канонический источник world/nav interest - target должен представлять actor-level interest, а не presentation-level camera
8. Для MVP поддерживается один тип NavMesh agent
Решение:
- сейчас поддерживается только один
agentTypeID
Почему выбрано:
- проект на стадии hypothesis/MVP
- это уменьшает стоимость runtime bake и настройки AI Navigation
- не раздувает матрицу тестирования до появления реальной необходимости
Почему не выбран multi-agent bake сразу:
- рост CPU и memory costs
- усложнение отладки при почти нулевой текущей пользе
Последствия:
- при появлении разных классов существ нужно отдельно пересмотреть agent taxonomy
9. Runtime NavMesh реализуется как sidecar-модуль, а не как hardwired часть world generator
Решение:
VoxelWorldостается владельцем world state и chunk lifecycle- NavMesh реализуется отдельным подключаемым модулем в собственной assembly
- модуль подключается через DI и может быть отключен без переписывания world feature
Почему выбрано:
- это соответствует целевой модели feature-подсистем как подключаемых модулей
- позволяет держать
VoxelWorldcore меньше и стабильнее - упрощает отключение NavMesh в сценах или режимах, где он не нужен
Почему не выбран partial-вариант внутри VoxelWorldGenerator:
- он быстрее в реализации, но цементирует NavMesh внутрь world feature
- делает отключение модуля искусственным
- увеличивает связанность и мешает дальнейшему DI-разделению
Последствия:
- 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
Critical
- WebGL-host может не выдержать одновременно world streaming, runtime NavMesh rebuild и server-authoritative NPC AI.
- Любой drift по
seed,VoxelWorldConfigили world rules между peers приведет к расхождению геометрии и локального NavMesh.
High
- Цель в
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/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, sidecar-модулем и не должен иметь camera-driven assumptions.