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

108 lines
6.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Сохранения
Игровое состояние: запись и загрузка `save.json`. Модуль не знает, что хранят другие модули: каждый модуль сам отдаёт свою секцию.
- **Сборка:** `Bogatyri.Save`.
- **Папка:** `Assets/Scripts/Modules/Save`.
- **Зависит от:** ядра.
## Контракт `ISaveSystem`
| Член | Что делает |
| --- | --- |
| `HasSave` | Есть ли файл сохранения. |
| `SaveNow()` | Сохранить сейчас. |
| `DeleteSave()` | Только стереть файл (состояние модулей в памяти не меняется). |
| `ResetAll()` | **Сброс сохранений**: все модули возвращаются к новой игре, файл сразу перезаписывается. |
Для слоя приложения остаются `SaveManager.Instance.SaveGame()`, `LoadGame()`, `HasSaveFile()`, `DeleteSave()`.
## Как модуль подключает свои данные
```csharp
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. Запись до загрузки запрещена. Сохранение города вынесено в модуль Поселения, походов — в модуль Мира. |