> For the complete documentation index, see [llms.txt](https://docs.allout.game/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.allout.game/all-out-docs/ru/dannye-i-sokhranenie/json.md).

# Сериализация JSON

CSL может сериализовать для вас определённые структуры данных в JSON. Это особенно полезно, когда вы хотите сохранить «набор» связанных полей (например, прогресс игрока, улучшения, разблокировки и т. д.) без управления множеством отдельных ключей сохранения.

Под капотом это использует JSON-API системы Save:

* `Save.set_json(player, key, value)`
* `Save.try_get_json(player, key, out) -> bool`

{% hint style="info" %}
Сохранение/загрузка JSON выполняется **для каждого игрока** (оно принимает `игрока`). Сохранение на уровне всей игры сейчас поддерживает только строки и целые числа.
{% endhint %}

### Что сохраняется?

В JSON включаются только поля, помеченные `@ao_serialize` .

```go
Player_Progress :: class {
    version: s64 = 1 @ao_serialize;

    xp: s64 @ao_serialize;
    level: s64 = 1 @ao_serialize;

    unlocked_skins: [..]string @ao_serialize;
}
```

### Сохранение JSON

Сохраняйте всю структуру под одним ключом:

```go
// Примечание: записываются только поля @ao_serialize
Save.set_json(player, "progress", ref progress);
```

### Загрузка JSON (со значениями по умолчанию)

`Save.try_get_json` возвращает `false` если ключ отсутствует или строка JSON имеет неверный формат. Выделите память под данные класса до загрузки, потому что путь false не выполняет выделение. Отсутствующие поля сохраняют значения по умолчанию своего класса, а неизвестные поля игнорируются.

```go
load_progress :: proc(player: Player) -> Player_Progress {
    progress := new(Player_Progress);

    if !Save.try_get_json(player, "progress", ref progress) {
        // У нового игрока (или при неверном JSON) уже есть значения по умолчанию класса.
    }

    return progress;
}
```

{% hint style="warning" %}
Изменение сохранённого поля на несовместимый тип — недопустимый ввод, и это может завершиться с явной ошибкой. Используйте новое поле или ключ сохранения, когда старое значение нельзя безопасно преобразовать.
{% endhint %}

### Версионирование и миграции

Если вы ожидаете, что схема JSON изменится, добавьте `поле` version

в структуру и выполняйте миграцию после загрузки.

* **Рекомендации по сохранению совместимости:** Предпочитайте добавлять новые поля
* с разумными значениями по умолчанию класса.
* Если вам нужен жёсткий разрыв, рассмотрите сохранение под **новым ключом** (например, `"progress_v2"`) и наличие резервного загрузчика.

Пример миграции:

```go
load_progress_and_migrate :: proc(player: Player) -> Player_Progress {
    progress := new(Player_Progress);

    if !Save.try_get_json(player, "progress", ref progress) {
        // Значения по умолчанию класса уже описывают нового игрока.
    }

    // Миграция вперёд
    if progress.version < 2 {
        progress.version = 2;
        // Пример: в v2 было добавлено unlocked_skins (инициализируем его)
        progress.unlocked_skins = .{};
    }

    // Записываем обратно мигрированную версию
    Save.set_json(player, "progress", ref progress);
    return progress;
}
```

### Фиксированные массивы

Ввод фиксированного массива ограничивается назначением:

* Лишние элементы JSON игнорируются.
* Отсутствующие элементы оставляют остальные элементы назначения без изменений.

### Когда использовать JSON, а когда простые ключи

* Используйте **простые ключи** (`Save.set_int`, `Save.set_string`, и т. д.) для нескольких значений, которые вы часто читаете/записываете.
* Используйте **JSON** когда вы хотите хранить связную структуру (прогресс, наборы снаряжения, разблокировки) и централизовать логику сохранения.

### Автономный JSON API

Вы также можете сериализовать/десериализовать JSON независимо от системы Save (например, для логирования, сетевого взаимодействия или пользовательского хранилища):

```go
JSON :: struct {
    serialize       :: proc(obj: ref $T) -> string;
    try_deserialize :: proc(json: string, out_value: ref $T) -> bool;
}
```
