Document the player-on-NavMesh movement target state, including server-side path planning, explicit nav readiness, and shared authoritative debug path previews for all clients.
20 KiB
id, title, summary, priority, area, owner, created, updated, execution_time, depends_on, canonical_docs, related_files
| id | title | summary | priority | area | owner | created | updated | execution_time | depends_on | canonical_docs | related_files | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| TASK-0025 | Host-authoritative player navigation с shared debug path preview | Перевести player movement на host-authoritative NavMesh pipeline с server-side path planning, authoritative path following и общим debug path preview для всех клиентов. | Highest | gameplay-core | unassigned | 2026-04-08 | 2026-04-08 | 3d |
|
|
|
TASK-0025 - Host-authoritative player navigation с shared debug path preview
Status
Статус задачи ведется в docs/tasks/Index.md и является каноническим там.
Why
Если игрок тоже должен двигаться по NavMesh, текущий local/client-authoritative movement pipeline становится архитектурно слабым для multiplayer:
- клиент не должен быть источником канонического movement outcome;
- локальный
NavMeshAgentне должен быть authoritative mover для player actor; - path planning и path following должны принадлежать хосту;
- shared debug path preview для движущихся игроков должен отображать именно authoritative path, который принят хостом, а не локальную клиентскую догадку.
Без этого возрастает риск:
- desync между client local movement и host state;
- race-condition между player spawn и nav coverage readiness;
- неотлаживаемых расхождений path preview между peers;
- ошибок вроде
Failed to create agent because it is not close enough to the NavMesh, если movement pipeline завязан на lifecycle локальногоNavMeshAgent.
Expected Outcome
- Игрок отправляет только команду перемещения, а не итог движения.
- Хост валидирует destination на своем NavMesh, строит authoritative path и двигает actor канонически.
- Клиенты получают authoritative movement state и сглаживают presentation.
- Для каждого движущегося игрока существует authoritative debug path preview, который видят все клиенты.
- Player spawn и first move command не зависят от hidden scene hacks и не требуют client-authoritative
NavMeshAgent.
Current Context
В проекте уже зафиксированы и частично реализованы базовые решения по миру и runtime NavMesh:
TASK-0023ввел runtime NavMesh как sidecar-модуль поверх voxel world.VoxelWorldGeneratorуже публикует nav source snapshots и world interest.VoxelWorldNavMeshServiceстроит NavMesh локально на каждом peer по region-based схеме.
При этом current player flow пока не соответствует целевой модели:
Assets/Scripts/Players/PlayerMoving.csориентирован на локальное movement execution;Assets/Features/VoxelWorld/Prefabs/TestPlayer.prefabвсе еще держит player movement в client-oriented конфигурации;- spawn/nav readiness для player-on-navmesh еще не оформлены как отдельный контракт;
- shared debug path preview для player movement отсутствует.
Source Of Truth
docs/architecture/mvp-world-authority-navmesh.mddocs/plans/TASK-0023-runtime-navmesh-implementation-plan.md- фактический player/network/world flow в текущем коде проекта
Read First
Assets/Scripts/Players/PlayerMoving.csAssets/Scripts/Players/CameraFollow.csAssets/Features/VoxelWorld/Prefabs/TestPlayer.prefabAssets/Features/VoxelWorld/Scenes/VoxelWorldTestScene.unityAssets/Features/VoxelWorld/Runtime/VoxelWorldGenerator.csAssets/Features/VoxelWorld/Contracts/NavMeshWorldContracts.csAssets/Features/VoxelWorldNavMesh/Runtime/VoxelWorldNavMeshService.csAssets/Scripts/VoxelWorld/VoxelWorldNavMeshLifetimeScope.cs
Fixed Decisions
1. Player movement outcome is host-authoritative
Клиент отправляет только move intent. Канонические:
- target acceptance/rejection;
- path corners;
- progress по path;
- итоговая позиция;
- movement completion/cancel.
Все это вычисляется и хранится на хосте.
2. Player uses NavMesh for movement, but client NavMesh is not authoritative
Клиент может использовать локальный NavMesh только для optional preview/query UX, но не как source of truth для gameplay movement state.
3. Do not use client-local NavMeshAgent as canonical player mover
Нельзя строить player movement correctness на NavMeshAgent, который локально двигает owner-клиента.
Предпочтительный путь:
- host-side
NavMesh.SamplePosition; - host-side
NavMesh.CalculatePath; - host-side explicit path follower;
- movement execution через контролируемый mover, предпочтительно
CharacterController.Moveили эквивалентный deterministic-ish explicit mover.
4. Client does not send path corners or final movement outcome
Клиенту нельзя отправлять:
- path corners;
- velocity как authoritative instruction;
- final position;
- movement completion.
Клиент отправляет только request:
- sequence id;
- requested destination;
- при необходимости легкий UX/debug metadata, не влияющий на authority.
5. Shared debug path preview must be authoritative-path-based
Обязательный debug preview, который видят все клиенты, должен строиться из authoritative path, рассчитанного хостом.
Допустим временный local provisional preview у инициирующего клиента, но он:
- не считается каноническим;
- должен визуально отличаться;
- должен исчезать или заменяться после host accept/reject.
6. Spawn/nav readiness must be explicit
Нельзя строить pipeline по модели:
- player actor spawned;
- NavMesh может быть еще не готов;
- movement runtime надеется, что agent потом сам корректно «встанет» на NavMesh.
Нужен явный readiness contract или equivalent bootstrap policy для spawn regions / first move command.
Scope In
- host-authoritative player movement по NavMesh;
- client command pipeline для выбора destination;
- host-side destination validation;
- host-side path planning;
- host-side path following;
- replication authoritative movement state на клиентов;
- shared debug path preview для каждого движущегося игрока на всех клиентах;
- optional local provisional preview для owner-клиента;
- nav-aware spawn/bootstrap и первый move command;
- интеграция через contracts + DI + MessagePipe, совместимая с
TASK-0023.
Scope Out
- NPC navigation system;
- crowd simulation;
- сложная prediction/reconciliation система для player nav movement;
- production UI polish path markers;
- ownership migration;
- репликация NavMesh data blob;
- multi-agent support beyond current single-agent MVP;
- сохранение movement path через reconnect/persistence beyond current runtime session.
Required Architecture
Movement flow
Client
- Игрок выбирает destination.
- Input layer определяет world point.
- Optional: строит provisional local preview path для UX owner-клиента.
- Отправляет host command с sequence id и requested destination.
Host
- Проверяет ownership и допустимость команды.
- Проверяет movement lock/state.
- Проверяет nav readiness для области.
- Делает
NavMesh.SamplePosition. - Делает
NavMesh.CalculatePath. - Если путь валиден, обновляет canonical movement state.
- Публикует/реплицирует accepted authoritative path и path preview.
- Если путь невалиден, отправляет reject reason.
Host tick
- Берет текущий active path.
- Вычисляет движение к текущему corner.
- Двигает player actor через explicit mover.
- Продвигает current corner index.
- По завершении очищает active path preview и переводит actor в
Idle.
Clients
- Получают authoritative movement state.
- Сглаживают presentation.
- Отображают authoritative debug path preview для всех moving players.
Assembly boundaries
Рекомендуется отдельный feature-модуль:
Assets/Features/PlayerNavigation/Contracts/PlayerNavigation.Contracts.asmdefAssets/Features/PlayerNavigation/Runtime/PlayerNavigation.Runtime.asmdef
Нельзя вшивать player navigation hardwired внутрь VoxelWorldGenerator или VoxelWorldNavMeshService.
DI and integration model
Использовать:
- contracts;
- DI через
VContainer; - typed
MessagePipepublishers/subscribers; - reader interfaces для текущего snapshot state.
Не использовать GlobalMessagePipe.
Message vs reader split
Через MessagePipe:
- lifecycle movement events;
- accept/reject events;
- preview invalidation/update events.
Через reader contracts:
- текущее состояние movement state;
- текущее состояние authoritative path preview;
- nav readiness / spawn readiness snapshot, если требуется queryable access.
Required New Contracts
Reader interfaces
Нужны как минимум:
IPlayerMovementStateReaderIPlayerPathPreviewReaderISpawnNavReadinessReaderили эквивалентный узкий readiness contract
Минимальная ответственность:
IPlayerMovementStateReaderумеет вернуть current movement snapshot игрока;IPlayerPathPreviewReaderумеет вернуть active authoritative preview для игрока или списка игроков;ISpawnNavReadinessReaderумеет ответить, готова ли nav coverage для spawn/first-move области.
DTO / snapshots
Ожидаются как минимум:
PlayerMovementStateSnapshotPlayerPathPreviewSnapshotPlayerMoveRequestPlayerMoveCommandResult
Минимальный состав PlayerMovementStateSnapshot:
- player network id;
- status;
- command sequence;
- current position;
- target position;
- move speed;
- current corner index;
- authoritative path corners;
- updated timestamp/network tick.
Минимальный состав PlayerPathPreviewSnapshot:
- player network id;
- command sequence;
- corners;
IsAuthoritative;IsActive.
Enums
Нужны как минимум:
PlayerMovementStatusPlayerMoveRejectReason
Примерные состояния:
IdleAwaitingPathMovingBlockedCompletedCancelledRejected
Примерные reject reasons:
NoNavCoverageDestinationNotOnNavMeshPathInvalidPathPartialMovementLockedNotOwner
Required Messages
Нужны typed MessagePipe messages для:
PlayerMoveRequestedMessagePlayerMoveAcceptedMessagePlayerMoveRejectedMessagePlayerMoveStateChangedMessagePlayerPathPreviewChangedMessagePlayerMovementStoppedMessage
Если для spawn/bootstrap это необходимо, допустим дополнительный readiness message, но только как supplement к reader contract, а не как единственный источник истины.
Required Runtime Responsibilities
1. Client input sender
Должен:
- собирать local click-to-move input;
- вычислять world destination;
- отправлять network command хосту;
- optional: запускать provisional local preview.
Не должен:
- канонически двигать actor;
- принимать final authoritative решения по path validity.
2. Host command validator / planner
Должен:
- валидировать ownership;
- валидировать destination;
- делать
NavMesh.SamplePosition; - делать
NavMesh.CalculatePath; - обновлять canonical movement state;
- публиковать accepted/rejected results.
3. Host path follower
Должен:
- исполнять movement по accepted path;
- отслеживать current corner index;
- завершать, отменять или репланить путь;
- синхронизировать authoritative transform/state.
4. Shared preview state + renderer
Должны:
- хранить authoritative debug path data;
- раздавать snapshot presentation-слою;
- визуализировать active path preview для всех observed players.
Shared preview не должен строиться заново локально на каждом клиенте по его client NavMesh. Источник preview для всех клиентов должен быть authoritative path state от хоста.
FishNet Requirements
Client -> Host
Использовать ServerRpc для move command:
RequestMoveTo(uint sequence, Vector3 requestedWorldPoint)
Host -> Clients
Допустимы:
- authoritative replicated movement state;
- отдельные
TargetRpc/ObserversRpcдля accept/reject; - отдельная lightweight replication для shared path preview.
Клиент не должен иметь возможности двигать чужого player actor.
Required Changes In Existing Code
Assets/Scripts/Players/PlayerMoving.cs
Нужно перестроить из local movement executor в input sender / thin player navigation entrypoint.
Assets/Features/VoxelWorld/Prefabs/TestPlayer.prefab
Нужно пересмотреть:
- текущий movement pipeline;
- конфигурацию
NetworkTransform; - player navigation components;
- visual debug preview attachment points.
Client-authoritative movement не должен оставаться каноническим режимом для nav-based player movement.
Assets/Features/VoxelWorld/Scenes/VoxelWorldTestScene.unity
Нужно проверить:
- spawn bootstrap;
- nav warmup around spawn points;
- наличие всего необходимого для тестирования shared path preview.
Nav readiness bootstrap
Нужно добавить явную стратегию, чтобы player spawn / first command не зависели от случайного отсутствия NavMesh в стартовой области.
Debug Path Preview Requirements
Это обязательная часть задачи.
Functional requirement
Каждый движущийся игрок должен иметь debug path preview, который видят все клиенты.
Примеры:
- игрок A движется -> path видят A, B, C;
- игрок B движется -> path видят A, B, C.
Canonical rule
Shared preview должен отображать именно authoritative path, рассчитанный хостом.
Optional owner-local preview
Допустим provisional local preview до host ответа, но он должен:
- визуально отличаться;
- не считаться каноническим;
- исчезать или заменяться после accept/reject.
Minimal rendering expectation
Минимально допустимо:
LineRendererили эквивалентный lightweight renderer;- обновление при accept/replan/stop/complete;
- очистка при completion/cancel/reject.
Acceptance Criteria
- Клиент может отправить move request по клику в мир.
- Хост валидирует destination на своем NavMesh.
- Хост строит authoritative path.
- Игрок движется по host-side path, а не по client-authoritative local mover.
- Недопустимые destination/path корректно reject'ятся с reason.
- Для каждого moving player существует authoritative path preview.
- Этот preview виден на всех клиентах.
- Preview корректно обновляется при новой команде, replan, stop, cancel и completion.
- Если реализован provisional local preview, он визуально отделен от authoritative shared preview.
- Player spawn и first move command не зависят от hidden
NavMeshAgentattach hacks. - Pipeline не опирается на
Camera.mainкак канонический источник authority/interest.
Verification
- ручной тест: single host, single client, move command accepted/rejected;
- ручной тест: host + 2 clients, оба клиента видят preview друг друга;
- ручной тест: invalid destination вне walkable area, host reject без runtime errors;
- ручной тест: новая команда во время движения корректно заменяет active path;
- ручной тест: late join видит текущее движение и active preview moving players;
- ручной тест: первый move command после старта сцены не приводит к runtime ошибкам из-за отсутствия nav coverage;
- ручной тест: completion/cancel очищает preview на всех клиентах.
Risks / Open Questions
- Если оставить рядом client-authoritative movement и host-side nav movement, возникнет двойная симуляция и несогласованное состояние.
- Если shared preview строить по локальному client NavMesh, разные peers могут видеть разный path debug.
- Если spawn/nav readiness не будет оформлен явно, lifecycle race останется даже при правильном movement flow.
- Возможно потребуется отдельный узкий contract для nav coverage readiness, которого пока нет в
TASK-0023runtime-поверхности.
Human Decisions Needed
- none currently
Decision Log
2026-04-08- задача создана после фиксации runtime NavMesh sidecar и обсуждения правильной host-authoritative модели player movement по NavMesh.
Handoff Notes
Реализация задачи должна опираться на уже принятые решения по world authority и runtime NavMesh. Если в ходе реализации возникнет соблазн повесить NavMeshAgent на player prefab как client-local authoritative mover, это нужно считать архитектурно неправильным shortcut'ом и не делать.
Shared debug path preview обязателен и должен отображать authoritative path для всех клиентов, а не purely local preview инициатора.