Перейти к содержанию

NetworkOwnershipVisibility

Серверный компонент: делает перечисленные дочерние NetworkIdentity player-префаба приватными для владельца. Они спавнятся у всех (AlwaysVisible), а после назначения owner куллятся у всех, кроме owner + сервера. Здесь — про сам компонент и почему flow именно такой. Пошаговый порядок спавна, как выглядят реплики и флоу инициализации (старт хоста / клиент / реконнект) — в SpawnFlow.md. Сама система взаимодействий — в ../README.md.

Компонент

На руте player-префаба, работает только на сервере:

  • visibilityAsset — правило после owner (обычно NoVisibility).
  • targets — что приватизировать (PlayerInteractor, NetworkInventory; публичный аватар — НЕ сюда).
  • applyInLateUpdate (дефолт on) — см. «SpawnerIfClientOnly и applyInLateUpdate».
  • OnSpawned/OnOwnerChanged при наличии owner делают для каждого target SetVisibilityRules(visibilityAsset) + EvaluateVisibility().

Почему AlwaysVisible-then-cull, а не статический NoVisibility

Статический NoVisibility в оверрайдах отсекает identity и от самого owner: на спавне owner ещё не назначен (видимость считается до ownership — см. «Порядок спавна» в SpawnFlow.md), а пересчёта по смене owner нет → владелец свою приватку так и не получит. Поэтому: спавним AlwaysVisible (весь префаб приезжает атомарно, кросс-ссылки целы), а NoVisibility вешаем рантаймом после owner. Чужие отписываются, поздние подключения куллятся правилом автоматически.

Инвариант: инвентарь пуст на спавне

Пока identity AlwaysVisible, её начальное состояние уходит всем текущим наблюдателям в spawn-пакете, и отозвать байты нельзя. Значит до cull SyncDictionary обязан быть пуст (сервер наполняет его только после перехода в NoVisibility — предметы приходят от взаимодействий позже). Иначе — утечка.

Активность vs видимость

NetworkOwnershipToggle управляет локальной активностью (SetActive / Behaviour|Collider|Renderer.enabled), а не observers — приватность синка им не обеспечить (кому летит SyncDictionary, решают observers). Он для камеры/ввода владельца; приватность инвентаря — на видимости (этот компонент). Как это проявляется на репликах — в SpawnFlow.md, раздел «Как выглядят реплики».

SpawnerIfClientOnly и applyInLateUpdate

При DefaultOwner = SpawnerIfClientOnly AutoAssignOwnership даёт серверному спавну транзиентного владельца-хоста, поэтому OnOwnerChanged на сервере фаерится дважды: null→host, затем host→owner. Приватность owner-зависима, так что Privatize() при owner == host куллит реального клиента и лишь потом на host→owner его возвращает — spawn→despawn→respawn в кадре спавна. (Это observers, а не активность, поэтому force-refresh тоглера сюда не относится вовсе.)

applyInLateUpdate это гасит: OnSpawned/OnOwnerChanged только ставят dirty-флаг, а сам Privatize() идёт один раз в LateUpdate — к этому моменту owner уже финальный (оба присвоения синхронны и происходят до LateUpdate; детали — «Порядок спавна» в SpawnFlow.md). Промежуточного Privatize(owner==host) нет. Механика — аналог NetworkOwnershipToggle._applyInLateUpdate (коалесцирование; идемпотентный force-refresh к owner-зависимой видимости неприменим). Оговорка: кастомный спавн, отдающий ownership кадром позже спавна, коалесцирование обошёл бы (он сломал бы и тоглер).

Финальный конфиг

DefaultOwner = None + applyInLateUpdate включён. None убирает транзиентного владельца в корне; applyInLateUpdate оставлен как страховка (и делает компонент устойчивым к любому DefaultOwner).