Перейти к основному содержимому

Система сохранений

MCE использует систему сохранений на основе JSON со слотами, версионированием и расширяемостью. Система сохранений фиксирует всё состояние игры -- ростер, инвентарь, позицию, значки, прогресс квестов и игровые переменные.

Архитектура​

Система сохранений состоит из нескольких компонентов:

КомпонентНазначение
SavegameManagerОркестрирует операции сохранения/загрузки
SavableObjectБазовый класс для любого объекта, нуждающегося в сохранении данных
MCESavesSerializerОбрабатывает JSON-сериализацию и десериализацию
GameVariablesГлобальное хранилище переменных (булевы, целые, строки)
GameVariableСсылка на отдельную переменную
GameVariableHolderMonoBehaviour-обёртка для игровых переменных
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, ручное редактирование может вызвать проблемы при введении недопустимых данных (например, приём, не существующий в базе данных). Используйте внутриигровые инструменты или команды отладки.

Лучшие практики​

  1. Тестируйте циклы сохранения/загрузки. Сохраните, выйдите, перезагрузите и проверьте, что всё на месте.
  2. Используйте GameVariables для флагов событий. Они сохраняются автоматически и интегрируются с CommandGraph.
  3. Планируйте миграцию сохранений. При добавлении новых данных в обновлении добавьте шаг миграции.
  4. Предоставьте несколько слотов сохранения. Игроки ожидают как минимум 3 слота ручного сохранения.
  5. Обрабатывайте ошибки загрузки корректно. При повреждении файла сохранения показывайте понятную ошибку, а не вылет.