2026-10-19 18:39:28 +02:00
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
// ТОЧКА СБОРКИ МОДУЛЕЙ (слой приложения). Документ: Docs/Modules/README.md
|
|
|
|
|
//
|
|
|
|
|
// Здесь и только здесь модули соединяются с остальной игрой:
|
|
|
|
|
// 1. регистрируются реализации контрактов, которые не регистрируются сами;
|
|
|
|
|
// 2. события модулей подключаются к системам, которые ещё не разнесены по модулям (GameProgress, Казармы).
|
|
|
|
|
// Модули друг о друге ничего не знают -- всю "проводку" видно в одном файле.
|
|
|
|
|
public static class GameModules
|
|
|
|
|
{
|
|
|
|
|
// После SubsystemRegistration (там ядро очищается) и раньше любых Awake
|
|
|
|
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
|
|
|
|
|
static void Register()
|
|
|
|
|
{
|
|
|
|
|
// Боевая система -- чистый C#, сама зарегистрироваться не может
|
|
|
|
|
GameServices.Register<IBattleSystem>(new BattleSystem());
|
|
|
|
|
|
2026-10-23 18:33:04 +02:00
|
|
|
// Армия -- чистый C#, единственное место хранения войск (секция "army")
|
|
|
|
|
var army = new ArmyService();
|
|
|
|
|
GameServices.Register<IArmy>(army);
|
|
|
|
|
SaveRegistry.Register(army);
|
|
|
|
|
EventBus.Subscribe<TroopsChangedEvent>(_ => { if (GameProgress.HasInstance) GameProgress.Instance.MarkChanged(); });
|
|
|
|
|
EventBus.Subscribe<GameLoadedEvent>(_ => MigrateLegacyArmy(army));
|
2026-10-19 18:39:28 +02:00
|
|
|
|
2026-10-19 19:07:45 +02:00
|
|
|
// Круг -- чистый C#, сам сохраняет, в каком Круге игрок (секция "circle")
|
|
|
|
|
var circle = new CircleService();
|
|
|
|
|
GameServices.Register<ICircle>(circle);
|
|
|
|
|
SaveRegistry.Register(circle);
|
|
|
|
|
|
|
|
|
|
// Чат -- чистый C#; история живёт, пока открыта игра (между сценами тоже)
|
|
|
|
|
GameServices.Register<IChat>(new ChatService(System.DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()));
|
|
|
|
|
|
2026-10-19 18:39:28 +02:00
|
|
|
// Казармы появляются в списке стройки кодом -- до восстановления зданий из сохранения
|
|
|
|
|
EventBus.Subscribe<SettlementRestoringEvent>(_ => BarracksBootstrap.Ensure());
|
|
|
|
|
|
|
|
|
|
// Статистика для заданий (GameProgress) -- по событиям Мира
|
|
|
|
|
EventBus.Subscribe<MarchStartedEvent>(OnMarchStarted);
|
|
|
|
|
EventBus.Subscribe<MarchReturnedEvent>(OnMarchReturned);
|
2026-10-23 18:33:04 +02:00
|
|
|
|
|
|
|
|
// Окно "ВОЙСКО ВЕРНУЛОСЬ" в городе
|
|
|
|
|
MarchReturnPopup.Reset();
|
|
|
|
|
EventBus.Subscribe<MarchReturnedEvent>(MarchReturnPopup.OnMarchReturned);
|
2026-10-19 18:39:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Сцена загружена, Awake всех объектов прошли, Start -- ещё нет (сохранение грузится в Start)
|
|
|
|
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
|
|
|
|
|
static void MigrateLegacyMarches()
|
|
|
|
|
{
|
|
|
|
|
// Раньше походы хранились в progress.json (GameProgress.Data.sashaMarches).
|
|
|
|
|
// Теперь их сохраняет модуль Мира в save.json, секция "world". Переносим один раз.
|
|
|
|
|
var data = GameProgress.Instance.Data;
|
|
|
|
|
if (data.sashaMarches == null || data.sashaMarches.Count == 0 || MarchManager.Instance == null) return;
|
|
|
|
|
|
|
|
|
|
// Если в save.json уже есть секция "world", загрузка сохранения заменит эти походы на сохранённые
|
|
|
|
|
MarchManager.Instance.LoadMarches(new System.Collections.Generic.List<Bogatyri.World.MarchData>(data.sashaMarches));
|
|
|
|
|
|
|
|
|
|
// Из progress.json убираем, только когда походы уже записаны в save.json -- иначе вылет игры их потеряет
|
|
|
|
|
EventBus.Subscribe<GameSavedEvent>(ClearLegacyMarches);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ClearLegacyMarches(GameSavedEvent e)
|
|
|
|
|
{
|
|
|
|
|
EventBus.Unsubscribe<GameSavedEvent>(ClearLegacyMarches);
|
|
|
|
|
GameProgress.Instance.Data.sashaMarches.Clear();
|
|
|
|
|
GameProgress.Instance.MarkChanged();
|
|
|
|
|
Debug.Log("[МОДУЛИ] Походы перенесены из progress.json в модуль Мира.");
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-23 18:33:04 +02:00
|
|
|
// Раньше войска хранились в progress.json (GameProgress.Data.troops и sashaMarchUnits моста ArmyBridge).
|
|
|
|
|
// Теперь -- в модуле Армии, save.json, секция "army". Переносим один раз, после загрузки сохранения.
|
|
|
|
|
static void MigrateLegacyArmy(ArmyService army)
|
|
|
|
|
{
|
|
|
|
|
var data = GameProgress.Instance.Data;
|
|
|
|
|
if (data.armyInModule) return;
|
|
|
|
|
|
|
|
|
|
if (!army.RestoredFromSave)
|
|
|
|
|
{
|
|
|
|
|
var legacyMarches = new System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<int, int[]>>();
|
|
|
|
|
foreach (var m in data.sashaMarchUnits)
|
|
|
|
|
legacyMarches.Add(new System.Collections.Generic.KeyValuePair<int, int[]>(m.marchId, m.units));
|
|
|
|
|
army.ImportLegacy(data.troops, legacyMarches);
|
|
|
|
|
Debug.Log($"[МОДУЛИ] Войска перенесены из progress.json в модуль Армии: в городе {army.SoldiersAtHome}, в походах {army.TroopsInMarches}.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Из progress.json убираем, только когда войска уже записаны в save.json -- иначе вылет игры их потеряет
|
|
|
|
|
if (army.RestoredFromSave) ClearLegacyArmy(default);
|
|
|
|
|
else EventBus.Subscribe<GameSavedEvent>(ClearLegacyArmy);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ClearLegacyArmy(GameSavedEvent e)
|
|
|
|
|
{
|
|
|
|
|
EventBus.Unsubscribe<GameSavedEvent>(ClearLegacyArmy);
|
|
|
|
|
var data = GameProgress.Instance.Data;
|
|
|
|
|
data.armyInModule = true;
|
|
|
|
|
System.Array.Clear(data.troops, 0, data.troops.Length);
|
|
|
|
|
data.sashaMarchUnits.Clear();
|
|
|
|
|
GameProgress.Instance.MarkChanged();
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-19 18:39:28 +02:00
|
|
|
static void OnMarchStarted(MarchStartedEvent e)
|
|
|
|
|
{
|
|
|
|
|
var data = GameProgress.Instance.Data;
|
|
|
|
|
data.marchesSent++;
|
|
|
|
|
data.dailyMarches++;
|
|
|
|
|
GameProgress.Instance.MarkChanged();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnMarchReturned(MarchReturnedEvent e)
|
|
|
|
|
{
|
|
|
|
|
if (!e.Victory) return;
|
|
|
|
|
GameProgress.Instance.Data.worldWins++;
|
|
|
|
|
GameProgress.Instance.MarkChanged();
|
|
|
|
|
}
|
|
|
|
|
}
|