> 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/docs-es/datos-y-persistencia/json.md).

# Serialización JSON

Para guardar estructuras de datos más avanzadas, puedes serializarlas a JSON y almacenarlas en el sistema de guardado.

CSL puede serializar ciertas estructuras de datos a JSON por ti. Esto es especialmente útil cuando quieres guardar un “paquete” de campos relacionados (como progreso del jugador, mejoras, desbloqueos, etc.) sin tener que gestionar muchas claves de guardado separadas.

Internamente, esto usa las APIs JSON del sistema Save:

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

{% hint style="info" %}
El guardado/carga JSON es **por jugador** (toma un `jugador`). El guardado global del juego actualmente solo admite cadenas + enteros.
{% endhint %}

### ¿Qué se guarda?

Solo los campos marcados con `campos @ao_serialize` se incluyen en el JSON.

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

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

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

### Guardar JSON

Guarda toda la estructura bajo una clave:

```go
// Nota: Solo se escriben los campos @ao_serialize
Save.set_json(player, "progress", ref progress);
```

En Save JSON, `Item_Instance` los campos y los campos de elementos derivados se conservan como selecciones de cualquiera de los inventarios persistentes de ese jugador. Transferir un elemento a otro inventario invalida sus referencias, incluso para el mismo jugador. Guardar un elemento fuera de los inventarios persistentes de ese jugador genera un error. Las referencias faltantes o invalidadas y las discrepancias de tipo derivado se cargan como `null`. Crea inventarios con nombre antes de cargar el registro. La versión independiente `JSON.serialize` no proporciona este comportamiento de referencia de elementos.

### Cargando JSON (con valores predeterminados)

`Save.try_get_json` devuelve `false` si la clave falta o la cadena JSON está mal formada. Asigna memoria para los datos de la clase antes de cargar porque la ruta falsa no la asigna. Los campos faltantes conservan los valores predeterminados de su clase, y los campos desconocidos se ignoran.

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

    if !Save.try_get_json(player, "progress", ref progress) {
        // El nuevo jugador (o un JSON mal formado) ya tiene los valores predeterminados de la clase.
    }

    return progress;
}
```

{% hint style="warning" %}
Cambiar un campo almacenado a un tipo incompatible es una entrada inválida y puede fallar de forma ruidosa. Usa un campo nuevo o una nueva clave de guardado cuando el valor anterior no pueda convertirse de forma segura.
{% endhint %}

### Versionado y migraciones

Si esperas que tu esquema JSON cambie, incluye un `versión` campo en la estructura y migra después de cargar.

Buenas prácticas para mantener la compatibilidad:

* **Prefiere añadir nuevos campos** con valores predeterminados sensatos de la clase.
* Mantén un campo de versión cuando un nuevo valor deba derivarse de datos antiguos.
* Si necesitas un cambio radical, considera guardar bajo una **nueva clave** (por ejemplo, `"progress_v2"`) y mantener un cargador de respaldo.

Ejemplo de migración:

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

    if !Save.try_get_json(player, "progress", ref progress) {
        // Los valores predeterminados de la clase ya describen a un jugador nuevo.
    }

    // Migrar hacia adelante
    if progress.version < 2 {
        progress.version = 2;
        // Ejemplo: v2 introdujo unlocked_skins (inicialízalo)
        progress.unlocked_skins = .{};
    }

    // Escribe de nuevo la versión migrada
    Save.set_json(player, "progress", ref progress);
    return progress;
}
```

### Arrays fijos

La entrada de arreglo fijo está limitada por el destino:

* Los elementos JSON extra se ignoran.
* Los elementos faltantes dejan sin cambios los elementos restantes del destino.

### Cuándo usar JSON frente a claves simples

* Usa **claves simples** (`Save.set_int`, `Save.set_string`, etc.) para un puñado de valores que lees/escribes a menudo.
* Usa **JSON** cuando quieres almacenar una estructura cohesiva (progreso, equipamientos, desbloqueos) y mantener centralizada tu lógica de guardado.

### API JSON independiente

También puedes serializar/deserializar JSON independientemente del sistema Save (por ejemplo, para registro, red o almacenamiento personalizado):

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