> 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

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

Bajo el capó, esto usa las API JSON del sistema Save:

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

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

### ¿Qué se guarda?

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

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

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

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

### Guardando JSON

Guarda toda la estructura bajo una sola clave:

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

### Carga de JSON (con valores predeterminados)

`Save.try_get_json` devuelve `false` si falta la clave o si la cadena JSON está mal formada. Asigna memoria para los datos de la clase antes de cargar, porque la rama false 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) {
        // Un jugador nuevo (o 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 explícita. Usa un campo o clave de guardado nuevos cuando el valor antiguo no se pueda convertir con seguridad.
{% endhint %}

### Versionado y migraciones

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

Buenas prácticas para mantener la compatibilidad:

* **Prefiere agregar nuevos campos** con valores predeterminados de clase sensatos.
* Mantén un campo de versión cuando un nuevo valor deba derivarse de datos antiguos.
* Si necesitas un cambio incompatible, 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 = .{};
    }

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

### Arreglos fijos

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

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

### Cuándo usar JSON vs claves simples

* Usa **claves simples** (`Save.set_int`, `Save.set_string`, etc.) para un puñado de valores que lees/escribes con frecuencia.
* Usa **JSON** cuando quieres almacenar una estructura cohesionada (progreso, equipamiento, desbloqueos) y mantener centralizada la lógica de guardado.

### API JSON independiente

También puedes serializar/deserializar JSON de forma independiente 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;
}
```
