El sistema de guardado proporciona un sistema de almacenamiento de datos clave-valor para conservar el progreso y las preferencias de los jugadores entre sesiones.
El sistema de guardado es un simple almacén clave-valor. Le das una clave de tipo cadena (como "xp"), y almacena un valor que seguirá ahí la próxima vez que el jugador entre.
Hay dos tipos de datos guardados:
Guardado del jugador: los datos personales de un jugador (XP, mejoras, ajustes, inventario, etc.)
Guardado global del juego: compartido por todos en el juego (récords del mundo, ajustes del servidor, contadores globales, etc.)
No uses el sistema de guardado para almacenar compras que los jugadores hicieron con chispas. Usa el APIs de compra/productos en su lugar.
Inicio rápido (guardar + cargar una estadística)
El patrón más común es:
Cargar valores guardados en ao_start
Guardar de nuevo cada vez que cambie el valor
Player::class:Player_Base{xp:s64;level:s64;ao_start::method(){// Los valores predeterminados se usan para jugadores completamente nuevosxp=Save.get_int(this,"xp",0);level=Save.get_int(this,"level",1);}}add_xp::proc(player:Player,amount:s64){player.xp+=amount;// ... tu lógica de subida de nivel aquí ...// Guardar inmediatamente cuando cambieSave.set_int(player,"xp",player.xp);Save.set_int(player,"level",player.level);}
Guardado del jugador (datos por jugador)
El guardado del jugador tiene ámbito para un solo jugador. Cada jugador tiene sus propios datos aislados de clave/valor.
Tipos compatibles:
Cadena: Save.set_string / Save.get_string
Entero (s64): Save.set_int / Save.get_int (nota: actualmente los valores se truncan internamente a 32 bits)
Proporciona siempre un valor predeterminado sensato al leer. Los jugadores nuevos todavía no tendrán claves, y get_* devolverá tu valor predeterminado.
Guardar datos “más grandes” (JSON)
Si tienes un pequeño conjunto de campos (como progreso + elementos desbloqueados), a menudo es mejor guardarlo como un solo bloque JSON.
Solo los campos marcados con @ao_serialize se guardan.
Save.try_get_json devuelve false si la clave no existe o la cadena JSON está mal formada. Si la clave existe pero la estructura ha cambiado (se añadieron campos nuevos, se eliminaron campos antiguos), devuelve true con los campos faltantes rellenados con cero. Trata el false caso como “empezar desde cero con valores predeterminados”.
Versionado del guardado (migrar datos antiguos de forma segura)
Si alguna vez cambias el formato de tu guardado, conserva una clave versión y migra los guardados antiguos hacia adelante.
Guardado global del juego (compartido por todos)
El guardado global del juego se comparte en todo el juego, no por jugador.
Usa Save.increment_game_int para contadores que varios jugadores podrían actualizar al mismo tiempo (muertes, entradas, rondas jugadas, etc.).
Patrones comunes
Booleanos
Guarda los booleanos como 0/1:
Nomenclatura de claves
Las claves son solo cadenas, así que elige nombres que no entren en conflicto más adelante:
"xp", "level", "selected_skin"
"tycoon.cash", "tycoon.upgrades.mouth_level"
Si tienes varios juegos conectados mediante parentado de juegos (hub + minijuegos), consulta Productos/datos entre juegos para ver cómo se pueden compartir los datos guardados.
Player :: class : Player_Base {
hp: f64;
ao_start :: method() {
save_version := Save.get_int(this, "version", 0);
if save_version < 6 {
// Ejemplo de migración: hp antes era un int, ahora es un float
save_version = 6;
old_hp := Save.get_int(this, "hp", 100);
Save.delete_key(this, "hp");
Save.set_f64(this, "hp", old_hp.(f64));
}
Save.set_int(this, "version", save_version);
// Cargar formato actual
hp = Save.get_f64(this, "hp", 100);
}
}
// Poseedor del récord global
Save.set_game_string("world_record_holder", player->get_username());
holder := Save.get_game_string("world_record_holder", "nadie aún");
// Contadores globales (incremento atómico, seguro cuando muchos jugadores lo actualizan)
Save.increment_game_int("total_games_played", 1);
total := Save.get_game_int("total_games_played", 0);