Files

116 lines
8.0 KiB
Markdown
Raw Permalink Normal View History

# Сохранения
Игровое состояние: запись и загрузка `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=…`) |
| `population` | Население (простые строки: `civilians=…`, `jobs=…`, `lastTick=…` и др.) |
| `production` | Добыча (простые строки: `slots=…`, `eff=…`, `pending=…`) |
## Формат файла
Версия 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` (лимиты склада пересчитает `App/CitySync` по зданиям);
- **Добыча** — мест нет (построек нет);
- **Поселение** — Ратуша 1 уровня, постройки убраны, участки свободны;
- **Мир** — все походы отменены, все лагеря разбойников на месте;
- **Круг** — игрок ни в каком Круге, его Круги распущены;
- **Армия** — войск и походов нет;
- **Население** — стартовый город (270 жителей). После сброса `App/GameModules` выдаёт стартовое войско и ресурсы из `EconomyConfig`.
Новый модуль с данными обязан реализовать `ResetState()`, иначе он не скомпилируется: метод входит в контракт.
## События
**Публикует:**
- `GameLoadedEvent` — после загрузки (и когда файла сохранения нет — загрузка завершена, новая игра);
- `GameSavedEvent` — после записи;
- `GameResetEvent` — после сброса сохранений;
- `NewGameStartedEvent` — `GameBootstrap`: файла сохранения нет, первая игра на устройстве.
**Слушает:** ничего.
## Файлы
| Файл | Что это |
| --- | --- |
| `SaveManager.cs` | Запись и чтение секций, автосохранение, перенос версии 1. |
| `GameBootstrap.cs` | Загружает сохранение при старте сцены города. |
| `Assets/Editor/SaveResetMenu.cs` (редактор) | Меню Tools → Сбросить сохранения / Открыть папку сохранений. |
## Решения и план
- **Этап 0:** одно сохранение. `GameProgress` (`progress.json`: герой, задания, почта, магазин, арена) пока пишет свой файл. Его данные переводятся в секции по мере выноса в модули. Войска уже перенесены — секция `army`.
- Номер версии файла поднимать при каждом несовместимом изменении и дописывать перенос старой версии здесь.
## Журнал изменений
| Дата | Кто | Что |
| --- | --- | --- |
| 27.10.2026 | Claude | Секция `world`: добавлен список разбитых лагерей `camps`. |
| 27.10.2026 | Claude | Новая секция `production`; в секции `economy` — список `capacities` (лимиты склада). |
| 26.10.2026 | Claude | Новая секция `population` (модуль Населения). `GameBootstrap` публикует `NewGameStartedEvent`, если файла нет. |
| 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. Запись до загрузки запрещена. Сохранение города вынесено в модуль Поселения, походов — в модуль Мира. |