Решили: мероприятие (забег, а дальше Двор, Ристалище, PvP, дев-арена) получает свой скоуп.
ActivityHost в корне рождает его на входе и хоронит на выходе; в него уехали петля акта, узлы,
награды, передышка, магазин, последствия ивентов, рукопожатие боя и владелец боевого скоупа.
Верхняя петля игры (GameFlow) осталась в корне и теперь только открывает занятие, ведёт его и
закрывает.
Почему раньше Сессии: критерий фазы Сессии — «RunStateService уезжает вниз» — недостижим, пока
забеговый флоу живёт в корне: контейнер смотрит вверх, и корневые потребители перестали бы видеть
состояние. Зависимость идёт снизу вверх (решение Макса 02.08.2026, порядок фаз 2 и 3 поменян).
Что это дало сразу: из RunActAsync ушли две строки, которыми конец забега объявлялся вручную —
RequestReset и SetPhase(None). Теперь забег кончился ⇒ кончилось занятие ⇒ ушли бой, его скоуп и
часы. Каждая забытая такая строка раньше делала следующий забег чужим.
Грабли:
- Компилятор не ловит разъехавшуюся композицию. Регистрации уехали вниз, а корневые потребители
(
UiRootBootstrap,UiNavigator,RunAudioPresenter) продолжали инжектитьIBattleClock— все 23 сборки при этом зелёные, потому что ошибка живёт в контейнере, а не в типах. Ловится только грепом по потребителям и прогоном. - Часам понадобился роутер — тот же приём, что у кадра показа (
StageFrameRouter):ActivityClockRouterв корне делегирует часам текущего занятия, а вне занятия отвечает «боя нет». Прямая ссылка означала бы фазу мероприятия, которое давно кончилось. Событие смены фазы он переподписывает сам: роутер вечен, часы под ним меняются.
Владелец правды: Game/Activity/ActivityHost.cs, Game/Activity/ActivityInstaller.cs,
Game/Activity/ActivityClockRouter.cs.