Files
MVP1/Docs/Modules/Save.md
T
AlexanderandClaude Opus 5.5 b1a396e9a2 Лагеря разбойников (PvE) на карте мира
Модуль Мира (Bogatyri.World.Simulation, без Unity):
- 12 лагерей трёх уровней: Стан разбойников, Логово лиходеев, Становище Соловья-разбойника
  (гарнизон 6–9 / 14–17 / 26–29, добыча — еда, дерево, золото, металл)
- ставятся отдельным генератором после городов: замок, твой город и соседи остались на местах
- бой в поле (без стен), у разбойников нет осадных
- после победы лагерь разбит на 30 минут (CampRules.RespawnMs), напасть нельзя
- бои считаются по времени прихода: второе войско к разбитому лагерю — без боя, все домой, добычи нет
- секция сохранения world хранит разбитые лагеря (camps); сброс — все лагеря на месте
- MarchReturnedEvent.TargetEmpty, окно в городе пишет «лагерь уже был разбит»

Интерфейс карты:
- лагерь — фиолетовый круг с подписью «название, ур. N, гарнизон»; разбитый — серый с таймером
- окно атаки: уровень лагеря, «бой в поле» / «за стенами», прогноз с учётом стен
- окно «ЛАГЕРЬ ПУСТ», подсказка при нажатии на разбитый лагерь

Тесты: расстановка лагерей, бой в поле без осадных, разбит → второе войско находит пустым → сохранение → появляется снова.
Документы World, Battle, Save, Core, README обновлены. Числа требуют балансировки.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 16:46:54 +01:00

113 lines
7.6 KiB
Markdown
Raw 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=…`) |
| `population` | Население (простые строки: `civilians=…`, `lastTick=…` и др.) |
## Формат файла
Версия 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 уровня, постройки убраны, участки свободны;
- **Мир** — все походы отменены, все лагеря разбойников на месте;
- **Круг** — игрок ни в каком Круге, его Круги распущены;
- **Армия** — войск и походов нет;
- **Население** — стартовый город (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`. |
| 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. Запись до загрузки запрещена. Сохранение города вынесено в модуль Поселения, походов — в модуль Мира. |