Saltar al contenido principal

Sistema de guardado

MCE usa un sistema de guardado basado en JSON con guardados por ranuras, versionado y extensibilidad. El sistema de guardado persiste el estado completo del juego del jugador: equipo, inventario, posicion, medallas, progreso de misiones y variables del juego.

Arquitectura

El sistema de guardado esta compuesto por varios componentes:

ComponenteProposito
SavegameManagerOrquesta las operaciones de guardado/carga
SavableObjectClase base para cualquier objeto que necesita persistir datos
MCESavesSerializerManeja la serializacion y deserializacion JSON
GameVariablesAlmacen global de variables (booleanos, enteros, cadenas)
GameVariableReferencia a variable individual
GameVariableHolderWrapper MonoBehaviour para variables del juego
SavegameInstallerInstaller de Zenject para el sistema de guardado

SavableGlobalGameData

El contenedor principal de datos de guardado es SavableGlobalGameData (un componente en el GameObject GlobalGameData). Almacena:

DatoDescripcion
Posicion del jugadorEscena actual, coordenadas de tile, direccion
Equipo de monstruosTodos los monstruos del equipo con estado completo (especie, nivel, IVs, EVs, naturaleza, movimientos, PP, HP, estado, amistad, etc.)
Almacenamiento PCMonstruos almacenados en cajas
MochilaTodos los objetos y cantidades
DineroMoneda del jugador
MedallasMedallas de gimnasio obtenidas
MonsterDexSeguimiento de vistos/capturados por especie
Variables del juegoTodos los valores de GameVariable (usados por CommandGraph)
Progreso de misionesMisiones activas, objetivos completados, recompensas reclamadas
Tiempo de juegoTiempo total de juego

Ranuras de guardado

MCE soporta multiples ranuras de guardado. La configuracion predeterminada proporciona 3 ranuras, pero es configurable.

Guardar

// Through the SDK (all tiers)
engine.SaveSystem.Save(slotIndex); // 0, 1, or 2

// Or through the SavegameManager directly (Source tier)
savegameManager.Save(slotIndex);

Cargar

// Through the SDK (all tiers)
engine.SaveSystem.Load(slotIndex);

// Check if slot has data first
if (engine.SaveSystem.HasSaveData(slotIndex))
{
engine.SaveSystem.Load(slotIndex);
}

Eliminar

engine.SaveSystem.DeleteSave(slotIndex);

Ubicacion de archivos de guardado

Los archivos de guardado se almacenan usando Application.persistentDataPath de Unity:

PlataformaRuta
Windows%USERPROFILE%/AppData/LocalLow/<CompanyName>/<ProductName>/
macOS~/Library/Application Support/<CompanyName>/<ProductName>/
Linux~/.config/unity3d/<CompanyName>/<ProductName>/
AndroidAlmacenamiento interno (privado de la app)
iOSSandbox de la app

Cada ranura se guarda como un archivo JSON separado: save_0.json, save_1.json, save_2.json.

Versionado de guardado

MCE incluye versionado de guardado para manejar actualizaciones entre versiones del juego:

  • Cada archivo de guardado incluye un numero de version.
  • Al cargar un guardado antiguo, el MCESavesSerializer aplica pasos de migracion para actualizar la estructura de datos.
  • Esto previene la corrupcion de guardado cuando se anaden nuevos campos o se cambian formatos de datos entre actualizaciones.
Nombres de campos serializados

Nunca renombre campos serializados en clases relacionadas con guardado sin proporcionar una migracion. Si renombra un campo, los archivos de guardado existentes perderan esos datos al cargar. Use [FormerlySerializedAs("oldName")] para renombrar campos.

GameVariables

El sistema GameVariables es el almacen de estado global de MCE. Persiste datos clave-valor arbitrarios que pueden leerse y escribirse desde nodos de CommandGraph, scripts y archivos de guardado.

Tipos de variables

TipoDescripcionEjemplo
BooleanBanderas verdadero/falso"defeatedBrock" = true
IntegerContadores numericos"fishCaught" = 42
StringValores de texto"rivalName" = "Gary"

Uso en CommandGraph

  • Nodo SetVariable: Establecer el valor de una variable.
  • Nodo BranchOnVariable: Verificar una variable y ramificar.
  • Nodo AddToVariable: Incrementar una variable numerica.

Uso en codigo

// Read a variable
bool hasBadge = GameVariables.GetBool("defeatedBrock");
int fishCount = GameVariables.GetInt("fishCaught");

// Write a variable
GameVariables.SetBool("defeatedBrock", true);
GameVariables.SetInt("fishCaught", fishCount + 1);

Datos de guardado personalizados

Extender SavableObject (nivel Source)

Con codigo fuente, cree un nuevo SavableObject:

public class CustomSaveData : SavableObject
{
[SerializeField] private int customCounter;
[SerializeField] private List<string> unlockedFeatures;

public override void OnSave()
{
// Gather current state before save
customCounter = MySystem.Counter;
unlockedFeatures = MySystem.GetUnlockedFeatures();
}

public override void OnLoad()
{
// Apply loaded state
MySystem.Counter = customCounter;
MySystem.SetUnlockedFeatures(unlockedFeatures);
}
}

Cargar datos personalizados en paralelo (todos los niveles)

Sin acceso al codigo fuente, use los eventos de guardado para persistir sus propios datos junto con los guardados de MCE:

public class MySaveExtension : MonoBehaviour
{
[Inject] private ISaveSystem saveSystem;

[Serializable]
private class MyData
{
public int highScore;
public List<string> achievements;
}

private MyData data = new MyData();

private void OnEnable()
{
saveSystem.OnSaved += OnSaved;
saveSystem.OnLoaded += OnLoaded;
}

private void OnSaved(int slot)
{
string json = JsonUtility.ToJson(data);
File.WriteAllText(GetPath(slot), json);
}

private void OnLoaded(int slot)
{
string path = GetPath(slot);
if (File.Exists(path))
{
data = JsonUtility.FromJson<MyData>(File.ReadAllText(path));
}
}

private string GetPath(int slot)
{
return Path.Combine(Application.persistentDataPath, $"custom_{slot}.json");
}
}

Autoguardado

MCE soporta autoguardado en disparadores configurables:

  • Al cambiar de mapa: Guardar al entrar a una nueva escena.
  • Al descansar: Guardar al curarse en un punto de descanso.
  • Intervalo de tiempo: Guardar cada N minutos.

Configure el autoguardado en el ScriptableObject de configuracion del juego.

Mejores practicas de autoguardado
  • Siempre use una ranura de autoguardado dedicada (por ejemplo, ranura 0) separada de las ranuras de guardado manual.
  • Muestre un icono indicador de autoguardado cuando se este guardando.
  • No autoguarde durante batallas o cinematicas.

Formato del archivo de guardado

Los guardados de MCE son JSON plano para depuracion. Un ejemplo simplificado:

{
"version": 3,
"playerName": "Red",
"playTime": 12345.6,
"currentScene": "PalletTown",
"position": { "x": 8, "y": 12 },
"money": 5000,
"badges": ["BoulderBadge", "CascadeBadge"],
"roster": [
{
"species": 6,
"level": 36,
"nickname": "Charizard",
"currentHP": 120,
"moves": ["Flamethrower", "AirSlash", "DragonClaw", "SwordsDance"],
"ivs": [28, 31, 24, 30, 26, 31],
"evs": [0, 252, 0, 4, 0, 252]
}
],
"gameVariables": {
"defeatedBrock": true,
"defeatedMisty": true,
"fishCaught": 12
}
}
No edite archivos de guardado

Aunque los archivos de guardado son JSON legible por humanos, editarlos manualmente puede causar problemas si introduce datos invalidos (por ejemplo, un movimiento que no existe en la base de datos). Use las herramientas del juego o comandos de depuracion en su lugar.

Mejores practicas

  1. Pruebe ciclos de guardado/carga. Guarde, salga, recargue y verifique que todo esta intacto.
  2. Use GameVariables para banderas de eventos. Se persisten automaticamente y se integran con CommandGraph.
  3. Planifique la migracion de guardado. Si anade nuevos datos en una actualizacion, anade un paso de migracion.
  4. Proporcione multiples ranuras de guardado. Los jugadores esperan al menos 3 ranuras de guardado manual.
  5. Maneje los fallos de carga con gracia. Si un archivo de guardado esta corrupto, muestre un error claro en lugar de colgar.