Модуль Армии (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>
6.8 KiB
6.8 KiB
Сохранения
Игровое состояние: запись и загрузка 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. Запись до загрузки запрещена. Сохранение города вынесено в модуль Поселения, походов — в модуль Мира. |