Решили: боевой скоуп закрывается scope.Dispose(), а не Object.Destroy(scope.gameObject). И мир
не регистрирует сам себя — VContainer делает это за него.
Почему: проверка захода по исходнику VContainer 1.18 (не по памяти и не по сайту) нашла две вещи.
LifetimeScope.Dispose() — это DisposeCore() синхронно плюс Destroy(gameObject) следом. Через
голый Destroy контейнер умирал только в конце кадра, а Close() + Open() рестарта происходят в
одном вызове: умирающий бой отвязывал показ уже ПОСЛЕ того, как новый привязался, и гасил арену только
что начавшегося боя. Защита «отвязываем только своё» это лечила, но лечила симптом; теперь порядок
верен по построению, а защита осталась страховкой.
InstallTo последней строкой делает builder.RegisterInstance<LifetimeScope>(this).AsSelf() — то есть
скоуп доступен инъекцией всегда. Наша ручная регистрация того же объекта была вторым владельцем факта
на ровном месте.
Грабли: сайт VContainer про Dispose говорит («to unload a child scope, call Dispose()»), но не
объясняет, чем это отличается от Destroy, — а отличие ровно в синхронности, и оно решает исход.
Проверять надо исходник.
Что проверено и оказалось верным (записано, чтобы не проверять заново):
- подписки боевых объектов на MessagePipe диспозятся своими
Dispose; брокеры живут в Root, поэтому автоматической отписки «по концу скоупа» тут НЕ будет, и это единственная причина, по которой всё держится на дисциплине; - где подписка идёт на объект того же скоупа (
BattleTapeDiagnostics→ диспетчер и симуляция), отписка не нужна: издатель умирает вместе с подписчиком; - асинхронная петля симуляции гасится честно:
AsyncStartableLoopItem.Dispose()зовётcts.Cancel(), а сам диспатчер диспозится вместе с контейнером; - делегаты
IBattleSession(часы, кнопка старта) отвязываются вDeploymentController.Dispose, а launch/reset/restart держит теперь мир, который вечен; - в боевом скоупе не осталось ни одного
RegisterComponentInHierarchy, поэтому известная ловушка «MonoBehaviour соScopedне уничтожается вместе со скоупом» нас не касается.
Владелец правды: Game/Flow/BattleHost.cs, Game/WorldLifetimeScope.cs.