Files
TheDeclineOfWarriors/docs/tasks/items/TASK-0025.md
T
Alexander Borisov b76b6e0cc0 add host-authoritative player navigation task
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.
2026-04-08 12:08:44 +03:00

20 KiB
Raw Blame History

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-0002
TASK-0023
docs/tasks/Index.md
docs/architecture/mvp-world-authority-navmesh.md
docs/plans/TASK-0023-runtime-navmesh-implementation-plan.md
Assets/Scripts/Players/PlayerMoving.cs
Assets/Features/VoxelWorld/Prefabs/TestPlayer.prefab
Assets/Features/VoxelWorld/Scenes/VoxelWorldTestScene.unity
Assets/Features/VoxelWorld/Runtime/VoxelWorldGenerator.cs
Assets/Features/VoxelWorld/Contracts/NavMeshWorldContracts.cs
Assets/Features/VoxelWorldNavMesh/Runtime/VoxelWorldNavMeshService.cs

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.md
  • docs/plans/TASK-0023-runtime-navmesh-implementation-plan.md
  • фактический player/network/world flow в текущем коде проекта

Read First

  • Assets/Scripts/Players/PlayerMoving.cs
  • Assets/Scripts/Players/CameraFollow.cs
  • Assets/Features/VoxelWorld/Prefabs/TestPlayer.prefab
  • Assets/Features/VoxelWorld/Scenes/VoxelWorldTestScene.unity
  • Assets/Features/VoxelWorld/Runtime/VoxelWorldGenerator.cs
  • Assets/Features/VoxelWorld/Contracts/NavMeshWorldContracts.cs
  • Assets/Features/VoxelWorldNavMesh/Runtime/VoxelWorldNavMeshService.cs
  • Assets/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

  1. Игрок выбирает destination.
  2. Input layer определяет world point.
  3. Optional: строит provisional local preview path для UX owner-клиента.
  4. Отправляет host command с sequence id и requested destination.

Host

  1. Проверяет ownership и допустимость команды.
  2. Проверяет movement lock/state.
  3. Проверяет nav readiness для области.
  4. Делает NavMesh.SamplePosition.
  5. Делает NavMesh.CalculatePath.
  6. Если путь валиден, обновляет canonical movement state.
  7. Публикует/реплицирует accepted authoritative path и path preview.
  8. Если путь невалиден, отправляет reject reason.

Host tick

  1. Берет текущий active path.
  2. Вычисляет движение к текущему corner.
  3. Двигает player actor через explicit mover.
  4. Продвигает current corner index.
  5. По завершении очищает active path preview и переводит actor в Idle.

Clients

  1. Получают authoritative movement state.
  2. Сглаживают presentation.
  3. Отображают authoritative debug path preview для всех moving players.

Assembly boundaries

Рекомендуется отдельный feature-модуль:

  • Assets/Features/PlayerNavigation/Contracts/PlayerNavigation.Contracts.asmdef
  • Assets/Features/PlayerNavigation/Runtime/PlayerNavigation.Runtime.asmdef

Нельзя вшивать player navigation hardwired внутрь VoxelWorldGenerator или VoxelWorldNavMeshService.

DI and integration model

Использовать:

  • contracts;
  • DI через VContainer;
  • typed MessagePipe publishers/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

Нужны как минимум:

  • IPlayerMovementStateReader
  • IPlayerPathPreviewReader
  • ISpawnNavReadinessReader или эквивалентный узкий readiness contract

Минимальная ответственность:

  • IPlayerMovementStateReader умеет вернуть current movement snapshot игрока;
  • IPlayerPathPreviewReader умеет вернуть active authoritative preview для игрока или списка игроков;
  • ISpawnNavReadinessReader умеет ответить, готова ли nav coverage для spawn/first-move области.

DTO / snapshots

Ожидаются как минимум:

  • PlayerMovementStateSnapshot
  • PlayerPathPreviewSnapshot
  • PlayerMoveRequest
  • PlayerMoveCommandResult

Минимальный состав 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

Нужны как минимум:

  • PlayerMovementStatus
  • PlayerMoveRejectReason

Примерные состояния:

  • Idle
  • AwaitingPath
  • Moving
  • Blocked
  • Completed
  • Cancelled
  • Rejected

Примерные reject reasons:

  • NoNavCoverage
  • DestinationNotOnNavMesh
  • PathInvalid
  • PathPartial
  • MovementLocked
  • NotOwner

Required Messages

Нужны typed MessagePipe messages для:

  • PlayerMoveRequestedMessage
  • PlayerMoveAcceptedMessage
  • PlayerMoveRejectedMessage
  • PlayerMoveStateChangedMessage
  • PlayerPathPreviewChangedMessage
  • PlayerMovementStoppedMessage

Если для 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 NavMeshAgent attach 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-0023 runtime-поверхности.

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 инициатора.