# 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-подсистем как подключаемых модулей - позволяет держать `VoxelWorld` core меньше и стабильнее - упрощает отключение 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` и `ISubscriber` через 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.