Files
AlexanderandClaude Opus 5.5 f10fb3b3aa Модуль Армии хранит войска; окно «Войско вернулось» в городе
Модуль Армии (Bogatyri.Army, без Unity):
- ArmyService — единственное хранилище войск (4 типа), секция сохранения "army"
- IArmy расширен: войска по типам, обучение (AddTroops), потери (LoseFraction), войска в походах
- событие TroopsChangedEvent — по нему перерисовываются панели HUD
- GameProgress и панели работают с войсками только через IArmy
- перенос из progress.json (troops, sashaMarchUnits) при первой загрузке;
  старые данные удаляются только после записи save.json (флаг armyInModule)
- ArmyBridge удалён: контракты и перенос сохранений проверены тестами
- тесты: поход не создаёт и не теряет солдат, потери по типам, сохранение, перенос, сброс

Окно «ВОЙСКО ВЕРНУЛОСЬ» в городе (UI/MarchReturnPopup):
- куда ходили, победа/поражение, сколько вернулось из скольких, добыча
- показывается и за походы, закончившиеся пока игра была закрыта; несколько — по очереди
- в MarchReturnedEvent добавлены Sent, TargetName, LootText

GameLoadedEvent публикуется и без файла сохранения. Документы Army, Core, Save, World, README обновлены.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 18:33:04 +02:00

6.8 KiB
Raw Permalink Blame History

Сохранения

Игровое состояние: запись и загрузка save.json. Модуль не знает, что хранят другие модули: каждый модуль сам отдаёт свою секцию.

  • Сборка: Bogatyri.Save.
  • Папка: Assets/Scripts/Modules/Save.
  • Зависит от: ядра.

Контракт ISaveSystem

Член Что делает
HasSave Есть ли файл сохранения.
SaveNow() Сохранить сейчас.
DeleteSave() Только стереть файл (состояние модулей в памяти не меняется).
ResetAll() Сброс сохранений: все модули возвращаются к новой игре, файл сразу перезаписывается.

Для слоя приложения остаются SaveManager.Instance.SaveGame(), LoadGame(), HasSaveFile(), DeleteSave().

Как модуль подключает свои данные

public class MyModule : ISaveParticipant
{
    public string SaveKey => "mymodule";
    public string Capture() => JsonUtility.ToJson(data); // null -- оставить то, что уже в файле
    public void Restore(string json) { data = JsonUtility.FromJson<MyData>(json); }
    public void ResetState() { data = new MyData(); } // новая игра
}
SaveRegistry.Register(myModule); // при запуске модуля
Секция Модуль
economy Экономика
settlement Поселение
world Глобальный мир
circle Круг (простые строки, не JSON — модуль без Unity)
army Армия (простые строки: troops=…, march=…)

Формат файла

Версия 2: { "version": 2, "sections": [ { "key": "economy", "json": "..." } ] }.

Версия 1 (старый плоский save.json) читается сама: файл целиком отдаётся Экономике и Поселению, их секции берут поля по старым именам.

Когда сохраняется

  • Автоматически:
    • автосохранение каждые 30 секунд;
    • при сворачивании и закрытии игры;
    • перед переходом между сценами (SceneNavigator);
    • после событий походов.
  • Защиты:
    • пока сохранение не загружено, запись пропускается — иначе стартовые нули модулей затёрли бы файл;
    • секция модуля, которого сейчас нет (например, город на карте мира), не пропадает.

Сброс сохранений

Откуда Что происходит
Настройки → «Сбросить весь прогресс» GameProgress.ResetAll(): удаляет progress.json, вызывает ISaveSystem.ResetAll(), создаёт новый прогресс (герой, задания, почта, войска).
ISaveSystem.ResetAll() Стирает save.json, вызывает ResetState() у каждого модуля, сразу записывает новую игру, публикует GameResetEvent.
Tools → Сбросить сохранения (редактор) В Play Mode — то же, что кнопка в Настройках. Вне Play Mode — удаляет save.json и progress.json.
Tools → Открыть папку сохранений Открывает Application.persistentDataPath.

Что сбрасывает каждый модуль:

  • Экономика — стартовые ресурсы из Inspector ResourceManager;
  • Поселение — Ратуша 1 уровня, постройки убраны, участки свободны;
  • Мир — все походы отменены;
  • Круг — игрок ни в каком Круге, его Круги распущены;
  • Армия — войск и походов нет.

Новый модуль с данными обязан реализовать ResetState(), иначе он не скомпилируется: метод входит в контракт.

События

Публикует:

  • GameLoadedEvent — после загрузки (и когда файла сохранения нет — загрузка завершена, новая игра);
  • GameSavedEvent — после записи;
  • GameResetEvent — после сброса сохранений.

Слушает: ничего.

Файлы

Файл Что это
SaveManager.cs Запись и чтение секций, автосохранение, перенос версии 1.
GameBootstrap.cs Загружает сохранение при старте сцены города.
Assets/Editor/SaveResetMenu.cs (редактор) Меню Tools → Сбросить сохранения / Открыть папку сохранений.

Решения и план

  • Этап 0: одно сохранение. GameProgress (progress.json: герой, задания, почта, магазин, арена) пока пишет свой файл. Его данные переводятся в секции по мере выноса в модули. Войска уже перенесены — секция army.
  • Номер версии файла поднимать при каждом несовместимом изменении и дописывать перенос старой версии здесь.

Журнал изменений

Дата Кто Что
23.10.2026 Claude Новая секция army (модуль Армии). GameLoadedEvent публикуется и без файла сохранения.
19.10.2026 Claude Новая секция circle (модуль Круга).
19.10.2026 Claude Сброс сохранений: ISaveSystem.ResetAll(), ResetState() у модулей, GameResetEvent, меню редактора. Кнопка в Настройках теперь сбрасывает и походы, и память Поселения.
19.10.2026 Claude SaveManager переписан на секции модулей (ISaveParticipant), формат v2 с переносом v1. Запись до загрузки запрещена. Сохранение города вынесено в модуль Поселения, походов — в модуль Мира.