Решили: сценные презентеры боя (CombatPresenter, CombatDebugDraw, CombatAreaFlash)
регистрируются в мировом скоупе и получают инъекцией только мировую половину зависимостей. Боевую —
симуляцию, ленту, диспетчер, dev-режим — им выдаёт BattlePresenterBinder на время жизни боя и
забирает, когда бой уходит.
Почему: это объекты персист-сцены, они переживают бои по построению, а инъекция в них случается ровно один раз. «Родить их вместе с боем» невозможно физически. Альтернатива — оставить всё в боевом скоупе и пересоздавать сцену на каждый бой — это возврат к загрузке сцены под каждый узел, от чего persist-мир и уходил.
Грабли:
Updateпрезентера начинался сif (_simulation == null) return;— то есть без боя показ не делал вообще ничего. Пока симуляция была вечной, это читалось как проверка готовности; теперь это означало бы чёрную арену во дворе гильдии. Признак готовности сменился на мировой (_stage), а боевые куски проверяются по месту.- Виды хоронит отсутствие в кадре, поэтому «кадра нет» и «кадр пустой» обязаны вести себя
одинаково. Раньше при отсутствии кадра
SyncViewsToFrameне звалась вовсе — юниты последнего боя остались бы стоять на пустой арене. - Подписка живёт на пересечении двух условий — бой привязан И объект включён. Поэтому она вынесена
из тела
OnEnableв отдельный метод: иначе бой, начавшийся при выключенном объекте, оставил бы презентер немым, а включение при живом бое подписало бы его дважды. - Найдено попутно: с 29.07 не работали статус-кольца и пул боевых VFX. Коммит
1bdd43ac7, переводивший показ на ленту, удалил старый блок подписок вместе с двумя строкамиEnsureStatusOverlay()иEnsureVfx(), стоявшими в его конце._vfxс тех пор всегда былnull, и дуга взмаха с пылью под ногами молча не заводились. Вызовы вернулись на свои новые места: пул VFX — вConstruct(переживает бои), статус-кольца — вBindBattle(читают симуляцию напрямую, поэтому умирают вместе с боем).
Владелец правды: Game/Flow/BattlePresenterBinder.cs, тест ScenePresenterScopeTests.