Система сохранений
MCE использует систему сохранений на основе JSON со слотами, версионированием и расширяемостью. Система сохранений фиксирует всё состояние игры -- ростер, инвентарь, позицию, значки, прогресс квестов и игровые переменные.
Архитектура
Система сохранений сос тоит из нескольких компонентов:
| Компонент | Назначение |
|---|---|
SavegameManager | Оркестрирует операции сохранения/загрузки |
SavableObject | Базовый класс для любого объекта, нуждающегося в сохранении данных |
MCESavesSerializer | Обрабатывает JSON-сериализацию и десериализацию |
GameVariables | Глобальное хранилище переменных (булевы, целые, строки) |
GameVariable | Ссылка на отдельную переменную |
GameVariableHolder | MonoBehaviour-обёртка для игровых переменных |
SavegameInstaller | Инсталлер Zenject для системы сохранений |
SavableGlobalGameData
Основной контейнер данных сохранения -- SavableGlobalGameData (компонент на GameObject GlobalGameData). Он хранит:
| Данные | Описание |
|---|---|
| Позиция игрока | Текущая сцена, координаты тайла, направление взгляда |
| Ростер монстров | Все монстры отряда с полным состоянием (вид, у ровень, IVs, EVs, природа, приёмы, PP, HP, статус, дружба и т.д.) |
| Хранилище ПК | Монстры в ячейках |
| Инвентарь | Все предметы и их количество |
| Деньги | Валюта игрока |
| Значки | Заработанные значки залов |
| MonsterDex | Отслеживание увиденных/пойманных по видам |
| Игровые переменные | Все значения GameVariable (используемые CommandGraph) |
| Прогресс квестов | Активные квесты, выполненные цели, полученные награды |
| Время игры | Общее время игры |
Слоты сохранения
MCE поддерживает несколько слотов сохранения. Конфигурация по умолчанию предоставляет 3 слота, но это настраивается.
Сохранение
// Через SDK (все уровни)
engine.SaveSystem.Save(slotIndex); // 0, 1, or 2
// Или через SavegameManager напрямую (уровень Source)
savegameManager.Save(slotIndex);
Загрузка
// Через SDK (все уровни)
engine.SaveSystem.Load(slotIndex);
// Сначала проверьте наличие данных в слоте
if (engine.SaveSystem.HasSaveData(slotIndex))
{
engine.SaveSystem.Load(slotIndex);
}
Удаление
engine.SaveSystem.DeleteSave(slotIndex);
Расположение файлов сохранения
Файлы сохранения хранятся через Application.persistentDataPath Unity:
| Платформа | Путь |
|---|---|
| Windows | %USERPROFILE%/AppData/LocalLow/<CompanyName>/<ProductName>/ |
| macOS | ~/Library/Application Support/<CompanyName>/<ProductName>/ |
| Linux | ~/.config/unity3d/<CompanyName>/<ProductName>/ |
| Android | Внутреннее хранилище (приватное для приложения) |
| iOS | Песочница приложения |
Каждый слот сохраняется как отдельный JSON-файл: save_0.json, save_1.json, save_2.json.
Версионирование сохранений
MCE включает версионирование сохранений для обработки обновлений между версиями игры:
- Каждый файл сохранения содержит номер версии.
- При загрузке более старого сохранения
MCESavesSerializerприменяет шаги миграции для обновления структуры данных. - Это предотвращает повреждение сохранений при добавлении новых полей или изменении форматов данных между обновлениями.
Никогда не переименовывайте сериализуемые поля в классах, связанных с сохранениями, без предоставления миграции. Если вы переименуете по ле, существующие файлы сохранений потеряют эти данные при загрузке. Используйте [FormerlySerializedAs("oldName")] для переименования полей.
GameVariables
Система GameVariables -- глобальное хранилище состояния MCE. Она сохраняет произвольные данные ключ-значение, которые можно читать и записывать из узлов CommandGraph, скриптов и файлов сохранения.
Типы переменных
| Тип | Описание | Пример |
|---|---|---|
| Boolean | Флаги истина/ложь | "defeatedBrock" = true |
| Integer | Числовые счётчики | "fishCaught" = 42 |
| String | Текстовые значения | "rivalName" = "Gary" |
Использование в CommandGraph
- Узел SetVariable: Установить значение переменной.
- Узел BranchOnVariable: Проверить переменную и разветвить.
- Узел AddToVariable: Увеличить числовую переменную.
Использование в коде
// Чтение переменной
bool hasBadge = GameVariables.GetBool("defeatedBrock");
int fishCount = GameVariables.GetInt("fishCaught");
// Запись переменной
GameVariables.SetBool("defeatedBrock", true);
GameVariables.SetInt("fishCaught", fishCount + 1);
Пользовательские данные сохранения
Расширение SavableObject (уровень Source)
С исходным кодом создайте новый SavableObject:
public class CustomSaveData : SavableObject
{
[SerializeField] private int customCounter;
[SerializeField] private List<string> unlockedFeatures;
public override void OnSave()
{
// Gather current state before save
customCounter = MySystem.Counter;
unlockedFeatures = MySystem.GetUnlockedFeatures();
}
public override void OnLoad()
{
// Apply loaded state
MySystem.Counter = customCounter;
MySystem.SetUnlockedFeatures(unlockedFeatures);
}
}
Загрузка пользовательских данных (все уровни)
Без доступа к исходному коду используйте события сохранения для сохранения ваших данных параллельно с сохранениями MCE:
public class MySaveExtension : MonoBehaviour
{
[Inject] private ISaveSystem saveSystem;
[Serializable]
private class MyData
{
public int highScore;
public List<string> achievements;
}
private MyData data = new MyData();
private void OnEnable()
{
saveSystem.OnSaved += OnSaved;
saveSystem.OnLoaded += OnLoaded;
}
private void OnSaved(int slot)
{
string json = JsonUtility.ToJson(data);
File.WriteAllText(GetPath(slot), json);
}
private void OnLoaded(int slot)
{
string path = GetPath(slot);
if (File.Exists(path))
{
data = JsonUtility.FromJson<MyData>(File.ReadAllText(path));
}
}
private string GetPath(int slot)
{
return Path.Combine(Application.persistentDataPath, $"custom_{slot}.json");
}
}
Автосохранение
MCE поддерживает автосохранение по настраиваемым триггерам:
- При переходе между картами: Сохранение при входе в новую сцену.
- При отдыхе: Сохранение при лечении в точке отдыха.
- По временному интервалу: Сохранение каждые N минут.
Настройте автосохранение в ScriptableObject конфигурации игры.
- Всегда используйте выделенный слот автосохранения (например, слот 0) отдельно от слотов ручного сохранения.
- Показывайте индикатор автосохранения при сохранении.
- Не выполняйте автосохранение во время сражений или катсцен.
Формат файла сохранения
Сохранения MCE -- простой JSON для отладки. Упрощённый пример:
{
"version": 3,
"playerName": "Red",
"playTime": 12345.6,
"currentScene": "PalletTown",
"position": { "x": 8, "y": 12 },
"money": 5000,
"badges": ["BoulderBadge", "CascadeBadge"],
"roster": [
{
"species": 6,
"level": 36,
"nickname": "Charizard",
"currentHP": 120,
"moves": ["Flamethrower", "AirSlash", "DragonClaw", "SwordsDance"],
"ivs": [28, 31, 24, 30, 26, 31],
"evs": [0, 252, 0, 4, 0, 252]
}
],
"gameVariables": {
"defeatedBrock": true,
"defeatedMisty": true,
"fishCaught": 12
}
}
Хотя файлы сохранений -- читаемый JSON, ручное редактирование может вызвать проблемы при введении недопустимых данных (например, приём, не существующий в базе данных). Используйте внутриигровые инструменты или команды отладки.
Лучшие практики
- Тестируйте циклы сохранения/загрузки. Сохраните, выйдите, перезагрузите и проверьте, что всё на месте.
- Используйте GameVariables для флагов событий. Они сохран яются автоматически и интегрируются с CommandGraph.
- Планируйте миграцию сохранений. При добавлении новых данных в обновлении добавьте шаг миграции.
- Предоставьте несколько слотов сохранения. Игроки ожидают как минимум 3 слота ручного сохранения.
- Обрабатывайте ошибки загрузки корректно. При повреждении файла сохранения показывайте понятную ошибку, а не вылет.