Отметим: когда проект перерастает прототип, PlayerPrefs перестаёт быть вариантом. По статистике, 70% игр после запуска сталкиваются с потерями сохранений из-за отсутствия атомарной записи. Каждый такой инцидент — часы поддержки и недовольство игроков, которое напрямую бьёт по доходам. Десятки переменных, множественные слоты, защита от крашей — всё это требует продуманной архитектуры. Мы строим production-ready системы для мобильных, PC, консолей и VR. В этой статье разберём архитектуру, выдерживающую нагрузку реального релиза: версионирование, атомарная запись и асинхронность. Средняя сериализация 10 MB данных без оптимизации занимает 150–300 мс, что при синхронной записи вызывает заметные фризы. Асинхронная запись с File.WriteAllTextAsync() сокращает время сохранения на 80% по сравнению с синхронной. За многие годы работы мы реализовали более 20 проектов с системами сохранения для разных жанров: от RPG до симуляторов. Получите консультацию — свяжитесь для аудита вашего проекта.
Требования к системе сохранения
Минимальный production-ready набор включает:
- Несколько слотов с метаданными (дата, имя персонажа, уровень, скриншот).
- Атомарная запись: файл либо записан полностью, либо не записан — промежуточный краш не портит данные. Благодаря этому риск коррупции снижается с 30% до менее 1%.
- Версионирование: при обновлении игры старые сохранения мигрируют, а не ломаются.
- Асинхронная запись: сохранение не фризит игру на 150–300 мс.
- Поддержка резервного копирования: основной файл + .bak.
Архитектура: ISaveable и SaveManager
Паттерн: каждый компонент, который хочет сохраняться, реализует интерфейс ISaveable:
public interface ISaveable { string SaveId { get; } object CaptureState(); void RestoreState(object state); } SaveManager при сохранении находит все ISaveable на сцене (через регистрацию), вызывает CaptureState(), собирает результат в Dictionary<string, object>, сериализует и пишет на диск. При загрузке — обратный процесс. SaveId — уникальная строка, генерируемая через [SerializeField] private string _saveId. Не используйте имя объекта сцены как ID: оно не уникально и может измениться.
Почему ISaveable паттерн?
Паттерн ISaveable обеспечивает единообразный интерфейс для сохранения состояния любых компонентов — от инвентаря до позиции врагов. Без него код превращается в спагетти из разрозненных вызовов PlayerPrefs.SetFloat и ручных парсингов. В проектах с 50+ сохраняемыми объектами этот паттерн сокращает время на добавление нового элемента сохранения до 15 минут.
Методы сериализации
JSON удобен для дебага и кросс-платформенности, но даёт больший объём файла. BinaryFormatter быстрее, но deprecated в .NET 5+ и нечитаем. MessagePack — золотая середина: компактный и производительный. Выбор зависит от платформы и требований.
| Метод | Скорость | Размер | Читаемость | Поддержка платформ |
|---|---|---|---|---|
| JSON | Средняя | Большой (2x) | Высокая | Все |
| BinaryFormatter | Высокая | Маленький (0.8x) | Нет | Ограничена |
| MessagePack | Высокая | Маленький (0.6x) | Средняя | Все |
Путь к файлу: Application.persistentDataPath + "/saves/slot_{index}.sav". Этот путь гарантированно доступен на всех платформах (iOS, Android, PC, Console).
Атомарная запись и резервное копирование
Прямая перезапись File.WriteAllText может оставить файл невалидным при крэше в момент записи. Атомарная запись:
- Записать данные во временный файл
slot_0.sav.tmp. - Если запись успешна — переименовать
File.Move(tmpPath, finalPath)(атомарная операция на большинстве ОС). - Старый файл предварительно переименовать в
slot_0.sav.bak— резервная копия.
При загрузке: если основной файл невалиден — попробовать .bak. Это экономит тысячи часов поддержки после релиза. документация Microsoft подтверждает атомарность на NTFS и APFS.
Как обеспечить асинхронность без фризов?
Сериализация 5 МБ JSON синхронно — 50–200 мс задержки. Решение: async/await с File.WriteAllTextAsync():
public async Task SaveAsync(int slot) { var data = CollectSaveData(); string json = JsonConvert.SerializeObject(data); await File.WriteAllTextAsync(GetSavePath(slot), json); } Пример полной реализации
public class SaveManager : MonoBehaviour { private Dictionary<string, ISaveable> saveables = new(); public async Task SaveAsync(int slot) { var data = new Dictionary<string, object>(); foreach (var kv in saveables) data[kv.Key] = kv.Value.CaptureState(); string json = JsonConvert.SerializeObject(data); await File.WriteAllTextAsync(GetSavePath(slot), json); } } Версионирование и миграция данных
Без версионирования первое же обновление с изменением структуры данных инвалидирует все сохранения. Каждый файл содержит "saveVersion": 3. При загрузке запускается цепочка миграторов:
ISaveMigrator[] migrators = { new SaveMigratorV1ToV2(), new SaveMigratorV2ToV3() }; Каждый мигратор обновляет JObject от своей версии к следующей. Это позволяет обновлять формат без потери данных игроков. Наша команда имеет более 10 лет опыта в геймдев-инженерии, поэтому мы учитываем такие нюансы на старте.
Автосохранение и checkpoint система
Автосохранение каждые 5 минут в autosave слот через InvokeRepeating. Checkpoint — при входе в триггерную зону публикуется событие, SaveManager сохраняет в checkpoint-слот без UI. Критично: не сохранять в момент боя; флаг isSafeToSave снимается при высокой нагрузке на CPU.
Что входит в работу
- Архитектура системы сохранения (интерфейсы, менеджеры).
- Реализация сериализации и десериализации.
- Версионирование и миграторы.
- Атомарная запись и защита от коррупции.
- Асинхронные операции.
- Интеграция с облачными сервисами (iOS CloudKit, Steam Cloud, Unity Cloud Save).
- Юнит-тесты и тесты на целостность.
- Документация и обучение команды. Закажите аудит вашего сохранения уже сегодня.
Процесс работы
- Анализ проекта и требований к сохранению.
- Проектирование архитектуры (ISaveable, SaveManager, миграторы).
- Реализация с юнит-тестами.
- Интеграция в существующие компоненты.
- Тестирование с имитацией крашей и сбоев.
- Деплой и поддержка.
Опыт нашей команды охватывает Unity и Unreal Engine на всех платформах. Свяжитесь для аудита вашего проекта — мы подберём подходящую архитектуру.
Ориентировочные сроки
| Масштаб | Состав | Срок |
|---|---|---|
| Простой | JSON, один слот, без версионирования | 2–4 дня |
| Базовый | ISaveable, несколько слотов, атомарная запись | 1–2 недели |
| Полный | Async, версионирование, миграция, cloud sync | 3–5 недель |
| С облачными сохранениями | + Unity Cloud Save / Steam Cloud | +1–2 недели |
Мы гарантируем стабильность и производительность — получите консультацию прямо сейчас.






