Для сохранения более сложных структур данных вы можете сериализовать их в JSON и хранить в системе сохранения.
CSL может сериализовать определённые структуры данных в JSON для вас. Это особенно полезно, когда вы хотите сохранить «пакет» связанных полей (например, прогресс игрока, улучшения, разблокировки и т.д.) без управления множеством отдельных ключей сохранения.
Под капотом это использует JSON API системы Save:
Save.set_json(player, key, value)
Save.try_get_json(player, key, out) -> bool
Сохранение/загрузка в JSON является для каждого игрока (оно принимает игрока). Сохранение на уровне всей игры в настоящее время поддерживает только строки и целые числа.
Что сохраняется?
Только поля, помеченные @ao_serialize включаются в JSON.
Save.try_get_json возвращает false если ключ отсутствует или строка JSON испорчена. Если ключ существует, но структура изменилась (добавлены новые поля, удалены старые), оно возвращает true с отсутствующими полями, заполненными нулями.
Если вы переименуете/удалите сериализованные поля, старый JSON может не распарситься и вы попадёте в путь с значениями по умолчанию. Планируйте миграции заранее (см. ниже).
Версионирование и миграции
Если вы ожидаете, что схема JSON будет меняться, включите поле version в структуру и выполняйте миграцию после загрузки.
Лучшие практики для сохранения совместимости:
Предпочитайте добавление новых полей (старый JSON часто всё ещё парсится; заполните значения по умолчанию после загрузки)
Если вам нужен жёсткий разрыв, рассмотрите сохранение под новым ключом (например, "progress_v2") и сохранение загрузчика с резервным вариантом
Пример миграции:
Когда использовать JSON vs простые ключи
Используйте простые ключи (Save.set_int, Save.set_string, и т.д.) для нескольких значений, которые вы часто читаете/пишите.
Используйте JSON когда вы хотите хранить связную структуру (прогресс, наборы, разблокировки) и держать логику сохранения централизованной.
Автономный JSON API
Вы также можете сериализовать/десериализовать JSON независимо от системы Save (например, для логирования, сетевого взаимодействия или кастомного хранилища):
// Примечание: Записываются только поля с @ao_serialize
Save.set_json(player, "progress", ref progress);
load_progress :: proc(player: Player) -> Player_Progress {
progress: Player_Progress;
if !Save.try_get_json(player, "progress", ref progress) {
// Новый игрок (или старый JSON больше не соответствует) → значения по умолчанию
progress.version = 1;
progress.xp = 0;
progress.level = 1;
progress.unlocked_skins = .{};
}
return progress;
}