Created
December 24, 2025 12:56
-
-
Save ninpl/ccf06259867be4b5b4cf0f1ce62b3570 to your computer and use it in GitHub Desktop.
Example of asynchronous sequential save/load. (Unity)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #region Librerias | |
| using UnityEngine; | |
| using UnityEngine.SceneManagement; | |
| using System; | |
| using System.Threading; | |
| using System.IO; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using Cysharp.Threading.Tasks; | |
| using Pandora.Nucleo; | |
| #endregion | |
| namespace Pandora | |
| { | |
| /// <summary> | |
| /// <para>Hestia, guardiana del fuego eterno, conserva los recuerdos del mundo. Un sistema de guardado | |
| /// centralizado asincrono en segundo plano. A traves de ella, los actos del jugador no se desvanecen, | |
| /// sino que se graban en la llama. Gestiona el ciclo de guardado y carga, protegiendo lo que debe perdurar.</para> | |
| /// </summary> | |
| public class Hestia : MonoBehaviour | |
| { | |
| #region Constantes | |
| /// <summary> | |
| /// <para>Nombre de archivo de ajustes.</para> | |
| /// </summary> | |
| public const string ARCH_GUARDADO = "Alexandria.nvl"; | |
| #endregion | |
| #region Variables Globales | |
| /// <summary> | |
| /// <para>Instancia de <see cref="Hestia"/>.</para> | |
| /// </summary> | |
| private static Hestia instancia = null; | |
| #endregion | |
| #region Variables Privadas | |
| /// <summary> | |
| /// <para>Cancelador del segundo plano.</para> | |
| /// </summary> | |
| private CancellationTokenSource _ctsGuardado; | |
| /// <summary> | |
| /// <para>Sistemas persistentes.</para> | |
| /// </summary> | |
| private readonly List<IPersistente> _sistemas = new(); | |
| #endregion | |
| #region Propiedades | |
| /// <summary> | |
| /// <para>Instancia de <see cref="Hestia"/>.</para> | |
| /// </summary> | |
| public static Hestia I | |
| { | |
| get => instancia; | |
| set => instancia = value; | |
| } | |
| #endregion | |
| #region Inicializadores | |
| /// <summary> | |
| /// <para>Inicializador de <see cref="Hestia"/>.</para> | |
| /// </summary> | |
| public void Awake() => I = this; | |
| #endregion | |
| #region API | |
| /// <summary> | |
| /// <para>Guarda los datos del juego.</para> | |
| /// </summary> | |
| public void Guardar() | |
| { | |
| // Si hay una operación previa en curso, cancelarla | |
| this._ctsGuardado?.Cancel(); | |
| this._ctsGuardado?.Dispose(); | |
| // Nuevo token para esta ejecución | |
| this._ctsGuardado = new CancellationTokenSource(); | |
| this.EjecutarGuardadoSecuencial(this._ctsGuardado.Token).Forget(); | |
| } | |
| /// <summary> | |
| /// <para>Carga los datos del juego.</para> | |
| /// </summary> | |
| public void CargarSistemas() | |
| { | |
| if (ES3.KeyExists("CARDINAL", ARCH_GUARDADO)) | |
| { | |
| ECardinal car = ES3.Load<ECardinal>("CARDINAL", ARCH_GUARDADO); | |
| Cardinal c = Cardinal.I; | |
| Alexandria.I.tiempoTotal = car.tiempoTotal; | |
| c.modo.dificultad = car.dif; | |
| c.modo.mapa = car.map; | |
| c.registro.enCurso = car.enCurso; | |
| c.registro.dia = car.dia; | |
| c.lord = Atenea.I.Lords.Obtener(car.lord); | |
| c.modo.cantidadRecompensas = car.cantidadRecompensas; | |
| c.modo.cantidadReliqRecompensas = car.cantidadReliqRecompensas; | |
| c.modo.cantidadReclutas = car.cantidadReclutas; | |
| c.modo.cantidadSalas = car.cantidadSalas; | |
| c.modo.cantidadEleccionReliquias = car.cantidadEleccionReliquias; | |
| c.modo.cantidadBotin = car.cantidadBotin; | |
| c.modo.puntuacion = car.puntuacion; | |
| c.modo.enemigos = car.enemigos; | |
| c.modo.campeones = car.campeones; | |
| c.modo.jefes = car.jefes; | |
| c.modo.eventos = car.eventos; | |
| c.modo.botines = car.botines; | |
| c.modo.objetos = car.objetos; | |
| c.modo.reliquias = car.reliquias; | |
| c.modo.salas = car.salas; | |
| c.modo.unidades = car.unidades; | |
| c.modo.agoge = car.agoge; | |
| c.modo.comidas = car.comidas; | |
| c.modo.trabajos = car.decretos; | |
| c.renombre = car.renombre; | |
| c.mejoras.mejora0 = car.mejora0; | |
| c.mejoras.mejora1 = car.mejora1; | |
| c.mejoras.mejora2 = car.mejora2; | |
| c.mejoras.mejora3 = car.mejora3; | |
| c.mejoras.mejora4 = car.mejora4; | |
| c.mejoras.mejora5 = car.mejora5; | |
| c.mejoras.mejora6 = car.mejora6; | |
| c.mejoras.mejora7 = car.mejora7; | |
| c.mejoras.mejora8 = car.mejora8; | |
| c.mejoras.mejora9 = car.mejora9; | |
| c.mejoras.mejora10 = car.mejora10; | |
| c.mejoras.mejora11 = car.mejora11; | |
| c.mejoras.mejora12 = car.mejora12; | |
| c.mejoras.mejora13 = car.mejora13; | |
| c.mejoras.mejora14 = car.mejora14; | |
| c.mejoras.mejora15 = car.mejora15; | |
| c.mejoras.mejora16 = car.mejora16; | |
| c.mejoras.mejora17 = car.mejora17; | |
| c.mejoras.mejora18 = car.mejora18; | |
| c.mejoras.mejora19 = car.mejora19; | |
| c.mejoras.mejora20 = car.mejora20; | |
| c.mejoras.mejora21 = car.mejora21; | |
| c.mejoras.mejora22 = car.mejora22; | |
| c.mejoras.mejora23 = car.mejora23; | |
| c.mejoras.mejora24 = car.mejora24; | |
| c.mejoras.mejora25 = car.mejora25; | |
| c.mejoras.mejora26 = car.mejora26; | |
| c.mejoras.mejora27 = car.mejora27; | |
| c.mejoras.mejora28 = car.mejora28; | |
| c.mejoras.mejora29 = car.mejora29; | |
| c.mejoras.mejora30 = car.mejora30; | |
| c.mejoras.mejora31 = car.mejora31; | |
| c.mejoras.mejora32 = car.mejora32; | |
| c.mejoras.mejora33 = car.mejora33; | |
| c.mejoras.mejora34 = car.mejora34; | |
| c.preInicio = new PreInicio(); | |
| c.preInicio.cantidadUnidades = Mathf.Max(1, car.preInicio.cantidadUnidades); | |
| c.preInicio.cantidadUnidadesEx = Mathf.Max(1,car.preInicio.cantidadUnidadesEx); | |
| c.preInicio.cantidadSalas = Mathf.Max(1,car.preInicio.cantidadSalas); | |
| c.preInicio.cantidadSalasEx = Mathf.Max(1,car.preInicio.cantidadSalasEx); | |
| c.preInicio.unidadesIniciales = new List<PreInicio.UContenido>(); | |
| foreach (var ui in car.preInicio.unidadesIniciales) | |
| { | |
| c.preInicio.unidadesIniciales.Add(new PreInicio.UContenido(ui.uID, ui.uIDH, ui.nombre)); | |
| } | |
| c.preInicio.salasIniciales = new List<int>(); | |
| foreach (var si in car.preInicio.salasIniciales) | |
| { | |
| c.preInicio.salasIniciales.Add(si); | |
| } | |
| c.preInicio.unidadesExcluidas = new List<int>(); | |
| foreach (var ue in car.preInicio.unidadesExcluidas) | |
| { | |
| c.preInicio.unidadesExcluidas.Add(ue); | |
| } | |
| c.preInicio.salasExcluidas = new List<int>(); | |
| foreach (var se in car.preInicio.salasExcluidas) | |
| { | |
| c.preInicio.salasExcluidas.Add(se); | |
| } | |
| c.preInicio.unidadesBolsa = new List<PreInicio.UContenido>(); | |
| foreach (var ub in car.preInicio.unidadesBolsa) | |
| { | |
| c.preInicio.unidadesBolsa.Add(new PreInicio.UContenido(ub.uID, ub.uIDH, ub.nombre)); | |
| } | |
| c.preInicio.salasBolsa = new List<int>(); | |
| foreach (var sb in car.preInicio.salasBolsa) | |
| { | |
| c.preInicio.salasBolsa.Add(sb); | |
| } | |
| var mapaDif = car.dificultades.ToDictionary(x => x.uID, x => x.desbloq); | |
| foreach (var d in Atenea.I.Dificultades.dificultades) | |
| { | |
| if (mapaDif.TryGetValue(d.uID, out bool desbloq)) d.desbloqueada = desbloq; | |
| } | |
| } | |
| if (ES3.KeyExists("ORDINAL", ARCH_GUARDADO)) | |
| { | |
| EOrdinal ord = ES3.Load<EOrdinal>("ORDINAL", ARCH_GUARDADO); | |
| Ordinal o = Ordinal.I; | |
| o.multiplicadorOro = ord.multiplicadorOro; | |
| o.reduccionOro = ord.reduccionOro; | |
| o.oroDiario = ord.oroDiario; | |
| o.reintentos = ord.reintentos; | |
| o.multiplicadorSalasBonus = ord.multiplicadorSalasBonus; | |
| o.multiplicadorUnidadesBonus = ord.multiplicadorUnidadesBonus; | |
| o.tiempoEsperaOleada = ord.tiempoEspera; | |
| o.nocturnia = ord.nocturnia; | |
| o.nigromante = ord.nigromante; | |
| o.eventoJusticiaDivina = ord.eventoJusticiaDivina; | |
| o.minimapa = ord.minimapa; | |
| o.lordQuemadura = ord.lordQuemadura; | |
| o.costeOroUnidad = ord.costeOroUnidad; | |
| o.costeOroSala = ord.costeOroSala; | |
| o.costeOroComprarUnidad = ord.costeOroComprarUnidad; | |
| o.cantidadAccionesCampamento = ord.cantidadAccionesCampamento; | |
| o.costeOroAgogeUnidad = ord.costeOroAgogeUnidad; | |
| o.costeOroConsagrarHabilidad = ord.costeOroConsagrarHabilidad; | |
| o.costeOroPurgarHabilidad = ord.costeOroPurgarHabilidad; | |
| o.costeFormacion = ord.costeFormacion; | |
| o.probabilidadAumentarAtri = ord.probabilidadAumentarAtri; | |
| o.multiplicadorAturdimiento = ord.multiplicadorAturdimiento; | |
| o.dpsExtraGeneral = ord.dpsExtraGeneral; | |
| o.dpsExtraFisico = ord.dpsExtraFisico; | |
| o.dpsExtraMagico = ord.dpsExtraMagico; | |
| o.dpsExtraAventurero = ord.dpsExtraAventurero; | |
| o.dpsExtraArquero = ord.dpsExtraArquero; | |
| o.dpsExtraCaballero = ord.dpsExtraCaballero; | |
| o.dpsExtraMagoBlanco = ord.dpsExtraMagoBlanco; | |
| o.dpsExtraMagoNegro = ord.dpsExtraMagoNegro; | |
| o.regeneracionBonusSala = ord.regeneracionBonusSala; | |
| o.quemaduraBonusSala = ord.quemaduraBonusSala; | |
| o.venenoBonusSala = ord.venenoBonusSala; | |
| o.sangradoBonusSala = ord.sangradoBonusSala; | |
| o.espinasBonusSala = ord.espinasBonusSala; | |
| o.aumentoFuerza = ord.aumentoFuerza; | |
| o.aumentoVitalidad = ord.aumentoVitalidad; | |
| o.aumentoAgilidad = ord.aumentoAgilidad; | |
| o.aumentoDestreza = ord.aumentoDestreza; | |
| o.aumentoMagia = ord.aumentoMagia; | |
| o.aumentoSuerte = ord.aumentoSuerte; | |
| o.bonusGracia = ord.bonusGracia; | |
| o.valorMano = ord.valorMano; | |
| o.valorArch = ord.valorArch; | |
| o.valorSabio = ord.valorSabio; | |
| o.valorSombra = ord.valorSombra; | |
| o.valorMaestro = ord.valorMaestro; | |
| o.trabajoColoso = ord.trabajoColoso; | |
| o.trabajoFenix = ord.trabajoFenix; | |
| o.trabajoTalos = ord.trabajoTalos; | |
| o.ulisesCapturado = ord.ulisesCapturado; | |
| o.primeraHabGratis = ord.primeraHabGratis; | |
| o.aumentarSaludDia = ord.aumentarSaludDia; | |
| o.influenciaPoseidon = ord.influenciaPoseidon; | |
| o.influenciaAtenea = ord.influenciaAtenea; | |
| } | |
| if (ES3.KeyExists("LORDS", ARCH_GUARDADO)) | |
| { | |
| ELords lords = ES3.Load<ELords>("LORDS", ARCH_GUARDADO); | |
| for (int n = 0; n < Atenea.I.Lords.lords.Count; n++) | |
| { | |
| Atenea.I.Lords.lords[n].nvl._nivel = lords.lords[n].nivel; | |
| Atenea.I.Lords.lords[n].nvl._exp = lords.lords[n].xp; | |
| Atenea.I.Lords.lords[n].nvl._expMaxima = lords.lords[n].xpMax; | |
| Atenea.I.Lords.lords[n].aspecto = lords.lords[n].aspecto; | |
| Atenea.I.Lords.lords[n].fases[0].Desbloqueada = lords.lords[n].fase0; | |
| Atenea.I.Lords.lords[n].fases[1].Desbloqueada = lords.lords[n].fase1; | |
| Atenea.I.Lords.lords[n].fases[2].Desbloqueada = lords.lords[n].fase2; | |
| Atenea.I.Lords.lords[n].fases[3].Desbloqueada = lords.lords[n].fase3; | |
| Atenea.I.Lords.lords[n].fases[4].Desbloqueada = lords.lords[n].fase4; | |
| Atenea.I.Lords.lords[n].hitos.derrotas = lords.lords[n].hito0; | |
| Atenea.I.Lords.lords[n].hitos.diaMaximo = lords.lords[n].hito1; | |
| Atenea.I.Lords.lords[n].hitos.enemigosEliminados = lords.lords[n].hito2; | |
| Atenea.I.Lords.lords[n].hitos.campeonesEliminados = lords.lords[n].hito3; | |
| Atenea.I.Lords.lords[n].hitos.jefesEliminados = lords.lords[n].hito4; | |
| Atenea.I.Lords.lords[n].hitos.maximaPuntuacion = lords.lords[n].hito5; | |
| Atenea.I.Lords.lords[n].gestas[0].desbloqueado = lords.lords[n].gesta0; | |
| Atenea.I.Lords.lords[n].gestas[1].desbloqueado = lords.lords[n].gesta1; | |
| Atenea.I.Lords.lords[n].gestas[2].desbloqueado = lords.lords[n].gesta2; | |
| Atenea.I.Lords.lords[n].gestas[3].desbloqueado = lords.lords[n].gesta3; | |
| Atenea.I.Lords.lords[n].gestas[4].desbloqueado = lords.lords[n].gesta4; | |
| Atenea.I.Lords.lords[n].gestas[5].desbloqueado = lords.lords[n].gesta5; | |
| } | |
| } | |
| if (ES3.KeyExists("LINAJE", ARCH_GUARDADO)) | |
| { | |
| ELinaje linaje = ES3.Load<ELinaje>("LINAJE", ARCH_GUARDADO); | |
| var dicSalas = Atenea.I.Salas.salas.ToDictionary(s => s.uID); | |
| foreach (var salaLinaje in linaje.salas) | |
| { | |
| if (dicSalas.TryGetValue(salaLinaje.uID, out var sala)) sala.desbloqueado = salaLinaje.desbloq; | |
| } | |
| var dicMapas = Atenea.I.Mapas.mapas.ToDictionary(s => s.uID); | |
| foreach (var mapaLinaje in linaje.mapas) | |
| { | |
| if (dicMapas.TryGetValue(mapaLinaje.uID, out var mapa)) mapa.desbloqueado = mapaLinaje.desbloq; | |
| } | |
| /*var dicDifi = Atenea.I.Dificultades.dificultades.ToDictionary(s => s.uID); | |
| foreach (var difLinaje in linaje.dif) | |
| { | |
| if (dicDifi.TryGetValue(difLinaje.uID, out var dif)) dif.desbloqueada = difLinaje.desbloq; | |
| }*/ | |
| var dicUnid = Atenea.I.Unidades.unidades.ToDictionary(s => s.uID); | |
| foreach (var unidLinaje in linaje.unidades) | |
| { | |
| if (dicUnid.TryGetValue(unidLinaje.uID, out var uni)) uni.desbloqueado = unidLinaje.desbloq; | |
| } | |
| var dicEven = Atenea.I.Eventos.eventos.ToDictionary(s => s.uID); | |
| foreach (var evenLinaje in linaje.eventos) | |
| { | |
| if (dicEven.TryGetValue(evenLinaje.uID, out var eve)) eve.desbloqueado = evenLinaje.desbloq; | |
| } | |
| var dicObjs = Atenea.I.Objetos.objetos.ToDictionary(s => s.uID); | |
| foreach (var objsLinaje in linaje.objetos) | |
| { | |
| if (dicObjs.TryGetValue(objsLinaje.uID, out var obj)) obj.desbloqueado = objsLinaje.desbloq; | |
| } | |
| var dicReliq = Atenea.I.Reliquias.reliquias.ToDictionary(s => s.uID); | |
| foreach (var reliLinaje in linaje.reliquias) | |
| { | |
| if (dicReliq.TryGetValue(reliLinaje.uID, out var rel)) rel.desbloqueado = reliLinaje.desbloq; | |
| } | |
| if (linaje.equipos != null) | |
| { | |
| var dicEquip = Atenea.I.Equipos.equipos.ToDictionary(s => s.uID); | |
| foreach (var eqliLinaje in linaje.equipos) | |
| { | |
| if (dicEquip.TryGetValue(eqliLinaje.uID, out var rel)) rel.desbloqueado = eqliLinaje.desbloq; | |
| } | |
| } | |
| } | |
| if (ES3.KeyExists("CRONICAS", ARCH_GUARDADO)) | |
| { | |
| ECronicas cronicas = ES3.Load<ECronicas>("CRONICAS", ARCH_GUARDADO); | |
| for (int n = 0; n < Atenea.I.Cronicas.cronicas.Count; n++) | |
| { | |
| Atenea.I.Cronicas.cronicas[n].completado = cronicas.cronicas[n].completado; | |
| Atenea.I.Cronicas.cronicas[n].cantidadActual = cronicas.cronicas[n].progreso; | |
| Atenea.I.Cronicas.cronicas[n].obtenido = cronicas.cronicas[n].obtenido; | |
| } | |
| } | |
| this.CargarConfiguracion(); | |
| } | |
| /// <summary> | |
| /// <para>Carga los datos del juego.</para> | |
| /// </summary> | |
| public void CargarConfiguracion() | |
| { | |
| if (ES3.KeyExists("CONFIGURACION", ARCH_GUARDADO)) | |
| { | |
| EConfiguracion con = ES3.Load<EConfiguracion>("CONFIGURACION", ARCH_GUARDADO); | |
| Cardinal c = Cardinal.I; | |
| Eco e = Eco.I; | |
| e.mute = con.silenciado; | |
| e.volGlobal = con.volGlobal; | |
| e.volMusica = con.volMusica; | |
| e.volSonido = con.volSonido; | |
| e.volUI = con.volUI; | |
| c.configuracion.idioma = con.idioma; | |
| c.configuracion.mostrarDPS = con.mostrarDps; | |
| c.configuracion.mostrarBarra = con.mostrarBarra; | |
| c.configuracion.animTexto = con.animTexto; | |
| c.configuracion.modoBrillo = con.modoBrillo; | |
| c.configuracion.autoOro = con.autoOro; | |
| c.configuracion.modoRapido = con.modoRapido; | |
| c.configuracion.rectDatos = con.recDatos; | |
| c.configuracion.resolucionAncho = con.anchores; | |
| c.configuracion.resolucionAlto = con.altores; | |
| c.configuracion.framerate = con.framerate; | |
| c.configuracion.indiceMonitor = con.indiceMonitor; | |
| c.configuracion.usarPantallaCompleta = con.usarPantallaCompleta; | |
| c.configuracion.usarPantallaCompletaSinBordes = con.usarPantallaCompletaSinBordes; | |
| c.configuracion.usarVSync = con.usarVSync; | |
| } | |
| } | |
| /// <summary> | |
| /// <para>Carga la partida del juego.</para> | |
| /// </summary> | |
| public void CargarPartida() | |
| { | |
| if (ES3.KeyExists("MAZMORRA", ARCH_GUARDADO)) | |
| { | |
| EMazmorra maz = ES3.Load<EMazmorra>("MAZMORRA", ARCH_GUARDADO); | |
| Mazmorra m = Cardinal.I.Mazmorra; | |
| if (m != null) | |
| { | |
| m.Oro = maz.oro; | |
| //m.expansiones = maz.expansiones; | |
| m.tiempoTotal = maz.tiempoTotal; | |
| //m.DeserializarSalas(maz.salas); | |
| ETrono es = maz.trono; | |
| foreach (var eus in es.unidades) | |
| { | |
| // Posición en la grilla | |
| Vector2Int pos = Vector2Int.RoundToInt(eus.posSala); | |
| // Instanciar el prefab o usar tu fábrica | |
| UnidadDatos ud = Atenea.I.Unidades.Obtener(eus.unidad.uID); | |
| IUnidad unidad = m.CrearUnidad(ud); | |
| unidad.Datos.nivel = eus.unidad.nivel; | |
| unidad.Datos.elite = eus.unidad.elite; | |
| unidad.Datos.AsignarAtributosDesde(eus.unidad); | |
| if (ud.elite) | |
| { | |
| unidad.transform.Find("Visual").GetComponent<SpriteRenderer>().sprite = m.elite; | |
| var borde = unidad.transform.Find("Visual/Borde"); | |
| if (borde != null) borde.gameObject.SetActive(false); | |
| var icono = unidad.transform.Find("Visual/Icono"); | |
| if (icono != null) | |
| { | |
| icono.GetComponent<SpriteRenderer>().sprite = unidad.Datos.avatarElite; | |
| icono.localPosition = new Vector3(0.02f, 0f, 0.019f); | |
| icono.localScale = new Vector3(0.2f, 0.2f, 1f); | |
| } | |
| var mascara = unidad.transform.Find("Visual/Mascara"); | |
| if (mascara != null) mascara.GetComponent<SpriteMask>().sprite = Cardinal.I.Mazmorra.campamento.spriteElite; | |
| } | |
| m.trono.AsignarUnidad(unidad, pos, false); | |
| unidad.nombre = eus.unidad.nombre; | |
| unidad.Salud = eus.unidad.saludActual; | |
| unidad.Mana = (int)eus.unidad.manaActual; | |
| unidad.gracia.Grado = eus.unidad.graciaGrado; | |
| unidad.gracia.GraciaActual = eus.unidad.graciaActual; | |
| unidad.gracia.GraciaMaxima = eus.unidad.graciaMaxima; | |
| unidad.valorAumentadoPorSala = eus.unidad.valorAumentadoPorSala; | |
| var unidadComp = unidad.GetComponent<Unidad>(); | |
| // Asegurarse de que la lista de habilidades tenga al menos 4 elementos | |
| while (unidadComp.habilidades.Count < 4) | |
| unidadComp.habilidades.Add(null); | |
| for (int i = 0; i < 4; i++) | |
| { | |
| // Debug para ver estado de las listas | |
| //Debug.Log($"[Debug Habilidades] i={i}, eus.unidad.habilidades.Count={eus.unidad.habilidades.Count}, valorId={eus.unidad.habilidades[i]}, unidad.habilidades.Count={unidadComp.habilidades.Count}"); | |
| if (eus.unidad.habilidades[i] != -1) | |
| { | |
| // Debug antes de asignar | |
| // Debug.Log($"Asignando habilidad ID {eus.unidad.habilidades[i]} al slot {i}"); | |
| unidadComp.habilidades[i] = Atenea.I.Habilidades.ObtenerHabilidad(eus.unidad.habilidades[i]); | |
| } | |
| else | |
| { | |
| unidadComp.habilidades[i] = null; | |
| } | |
| } | |
| // 🔹 Purga de nulls por seguridad (opcional, por si algo se coló) | |
| unidadComp.habilidades = unidadComp.habilidades.Where(h => h != null).ToList(); | |
| if (eus.unidad.estadosHabilidades == null || eus.unidad.estadosHabilidades.Count == 0) | |
| { | |
| // Si no existe o está vacío, asignamos true por defecto | |
| unidadComp.estadosHabilidades = new List<bool> { true, true, true, true, true }; | |
| } | |
| else | |
| { | |
| // Asegurarse de que unidadComp tenga suficientes elementos | |
| while (unidadComp.estadosHabilidades.Count < eus.unidad.estadosHabilidades.Count) | |
| unidadComp.estadosHabilidades.Add(true); // valor por defecto | |
| for (int n = 0; n < eus.unidad.estadosHabilidades.Count; n++) | |
| { | |
| // Si el valor en eus.unidad.estadosHabilidades[n] es null (si fuera nullable), asignamos true | |
| unidadComp.estadosHabilidades[n] = eus.unidad.estadosHabilidades[n]; | |
| } | |
| } | |
| unidad.efectosEstado = new List<EfectoEstado>(); | |
| foreach (var e in eus.unidad.efectos.efectos) | |
| { | |
| EfectoEstado ef = new EfectoEstado(Atenea.I.Efectos.ObtenerEfectoEstado(e.uID)); | |
| ef.cargas = e.cargas; | |
| ef.valor = e.valor; | |
| unidad.efectosEstado.Add(ef); | |
| } | |
| unidad.idObjMano = eus.unidad.idObjMano; | |
| unidad.idObjPecho = eus.unidad.idObjPecho; | |
| unidad.idObjAcc = eus.unidad.idObjAcc; | |
| if (eus.unidad.idObjMano != -1) Atenea.I.Equipos.ObtenerEquipo(eus.unidad.idObjMano).Equipar(unidad); | |
| if (eus.unidad.idObjPecho != -1) Atenea.I.Equipos.ObtenerEquipo(eus.unidad.idObjPecho).Equipar(unidad); | |
| if (eus.unidad.idObjAcc != -1) Atenea.I.Equipos.ObtenerEquipo(eus.unidad.idObjAcc).Equipar(unidad); | |
| unidad.Salud = unidad.SaludMaxima; | |
| unidad.Mana = unidad.ManaMax; | |
| } | |
| m.DeserializarObjetos(maz.objetos); | |
| m.DeserializarRelicario(maz.reliquias); | |
| m.DeserializarBaulEventos(maz.baulEventos); | |
| m.DeserializarBaulObjetos(maz.baulObjetos); | |
| m.DeserializarBaulReliMeno(maz.baulReliqMenores); | |
| m.DeserializarBaulReliMayo(maz.baulReliqMayores); | |
| m.campamento.CantidadUnidades = maz.cantidadUniOleadas; | |
| m.campamento.tiempoEspera = maz.tiempoEsperaOleadas; | |
| m.campamento.intervalo = maz.intervaloOleadas; | |
| m.lord.GetComponent<Lord>().costeHabilidades[0] = maz.costeA; | |
| m.lord.GetComponent<Lord>().costeHabilidades[1] = maz.costeB; | |
| m.lord.GetComponent<Lord>().costeHabilidades[2] = maz.costeC; | |
| m.lord.GetComponent<Lord>().costeHabilidades[3] = maz.costeD; | |
| m.lord.Salud = maz.saludLord; | |
| m.lord.Mana = maz.manaLord; | |
| m.lord.ManaMax = maz.manaMaxLord; | |
| m.lord.gracia.Grado = maz.graciaGradoLord; | |
| m.lord.gracia.GraciaActual = maz.graciaActualLord; | |
| m.lord.gracia.GraciaMaxima = maz.graciaMaximaLord; | |
| m.lord.Datos.atributos.fuerza.valor = maz.fuerza; | |
| m.lord.Datos.atributos.fuerza.valorOculto = maz.fuerzaInt; | |
| m.lord.Datos.atributos.vitalidad.valor = maz.vitalidad; | |
| m.lord.Datos.atributos.vitalidad.valorOculto = maz.vitalidadInt; | |
| m.lord.Datos.atributos.destreza.valor = maz.destreza; | |
| m.lord.Datos.atributos.destreza.valorOculto = maz.destrezaInt; | |
| m.lord.Datos.atributos.agilidad.valor = maz.agilidad; | |
| m.lord.Datos.atributos.agilidad.valorOculto = maz.agilidadInt; | |
| m.lord.Datos.atributos.magia.valor = maz.magia; | |
| m.lord.Datos.atributos.magia.valorOculto = maz.magiaInt; | |
| m.lord.Datos.atributos.suerte.valor = maz.suerte; | |
| m.lord.Datos.atributos.suerte.valorOculto = maz.suerteInt; | |
| m.lord.efectosEstado = new List<EfectoEstado>(); | |
| foreach (var e in maz.efectosLord.efectos) | |
| { | |
| EfectoEstado ef = new EfectoEstado(Atenea.I.Efectos.ObtenerEfectoEstado(e.uID)); | |
| ef.cargas = e.cargas; | |
| ef.valor = e.valor; | |
| m.lord.efectosEstado.Add(ef); | |
| } | |
| m.lord.idObjMano = maz.lordidObjMano; | |
| m.lord.idObjPecho = maz.lordidObjPecho; | |
| m.lord.idObjAcc = maz.lordidObjAcc; | |
| if (m.lord.idObjMano != -1) Atenea.I.Equipos.ObtenerEquipo(m.lord.idObjMano).Equipar(m.lord); | |
| if (m.lord.idObjPecho != -1) Atenea.I.Equipos.ObtenerEquipo(m.lord.idObjPecho).Equipar(m.lord); | |
| if (m.lord.idObjAcc != -1) Atenea.I.Equipos.ObtenerEquipo(m.lord.idObjAcc).Equipar(m.lord); | |
| m.unidadesBuscando = new List<int>(maz.unidadesBuscando); | |
| m.salasBuscando = new List<int>(maz.salasBuscando); | |
| m.panelConsejo.consejo.manoDesbloqueada = maz.conseMano; | |
| m.panelConsejo.consejo.archiDesbloqueado = maz.conseArchi; | |
| m.panelConsejo.consejo.sabioDesbloqueado = maz.conseSabio; | |
| m.panelConsejo.consejo.sombraDesbloqueado = maz.conseSombra; | |
| m.panelConsejo.consejo.maestroDesbloqueado = maz.conseMaestro; | |
| m.ComprobarConsejo(); | |
| } | |
| } | |
| if (ES3.KeyExists("TRAYECTO", ARCH_GUARDADO)) | |
| { | |
| ETrayecto tra = ES3.Load<ETrayecto>("TRAYECTO", ARCH_GUARDADO); | |
| Trayecto t = Cardinal.I.Trayecto; | |
| if (t != null) | |
| { | |
| t.Dia = tra.dia; | |
| t.Columna = tra.col; | |
| t.Fila = tra.fil; | |
| t.Nodos = t.DeserializarNodos(tra.nodos); | |
| } | |
| } | |
| if (ES3.KeyExists("TESORO", ARCH_GUARDADO)) | |
| { | |
| ETesoro tes = ES3.Load<ETesoro>("TESORO", ARCH_GUARDADO); | |
| Tesoro t = Cardinal.I.Mazmorra.tesoro; | |
| if (t != null) | |
| { | |
| t.DeserializarUnidades(tes.unidades); | |
| t.DeserializarSalas(tes.salas); | |
| t.DeserializarEquipos(tes.equipos); | |
| } | |
| } | |
| } | |
| #endregion | |
| #region Metodos Privados | |
| /// <summary> | |
| /// <para>Ejecuta un guardado secuencial. Interno. No usar.</para> | |
| /// </summary> | |
| /// <param name="token"></param> | |
| private async UniTask EjecutarGuardadoSecuencial(CancellationToken token) | |
| { | |
| try | |
| { | |
| Log.Nuevo(TipoLog.Info, "Guardado", "Inicio de guardado secuencial..."); | |
| ECardinal car = new ECardinal(Cardinal.I, Alexandria.I); | |
| EOrdinal ord = new EOrdinal(Ordinal.I); | |
| EConfiguracion con = new EConfiguracion(Eco.I, Cardinal.I.configuracion); | |
| ELords lrd = new ELords(Atenea.I.Lords.lords); | |
| ELinaje lin = new ELinaje(Atenea.I); | |
| ECronicas cro = new ECronicas(Atenea.I.Cronicas.cronicas); | |
| EMazmorra? maz = null; | |
| ETrayecto? tra = null; | |
| ETesoro? tes = null; | |
| if (SceneManager.GetActiveScene().name == "juego") | |
| { | |
| maz = new EMazmorra(Cardinal.I.Mazmorra); | |
| tra = new ETrayecto(Cardinal.I.Trayecto); | |
| tes = new ETesoro(Cardinal.I.Mazmorra.tesoro); | |
| } | |
| await GuardadoInterno(token, car, ord, con, lrd, lin, cro); | |
| if (SceneManager.GetActiveScene().name == "juego") | |
| { | |
| await GuardarPartidaInterno(token, maz.Value, tra.Value, tes.Value); | |
| } | |
| Log.Nuevo(TipoLog.Debug, "Guardar", "Guardado completado"); | |
| } | |
| catch (OperationCanceledException) | |
| { | |
| Log.Nuevo(TipoLog.Advertencia, "Guardado", "Guardado cancelado por nueva llamada."); | |
| } | |
| catch (Exception ex) | |
| { | |
| Log.Nuevo(TipoLog.Error, "Guardado", $"Error durante guardado: {ex}"); | |
| } | |
| } | |
| /// <summary> | |
| /// <para>Guarda los sistemas.</para> | |
| /// </summary> | |
| /// <param name="token"></param> | |
| /// <param name="car"></param> | |
| private async UniTask GuardadoInterno(CancellationToken token, ECardinal car, EOrdinal ord, EConfiguracion con, ELords lor, ELinaje lin, ECronicas cro) | |
| { | |
| // Comprobar cancelación antes de empezar | |
| token.ThrowIfCancellationRequested(); | |
| // Cardinal | |
| await UniTask.RunOnThreadPool(() => | |
| { | |
| token.ThrowIfCancellationRequested(); | |
| try | |
| { | |
| ES3Settings aj = new ES3Settings(ARCH_GUARDADO); | |
| ES3.Save("CARDINAL", car, aj); | |
| } | |
| catch (UnauthorizedAccessException ex) | |
| { | |
| // Error relacionado con permisos | |
| Log.Nuevo(TipoLog.Error, "Guardar Sistemas", $"Permiso denegado al intentar guardar sistemas: {ex}"); | |
| } | |
| catch (PathTooLongException ex) | |
| { | |
| // El nombre del archivo o la ruta es demasiado largo | |
| Log.Nuevo(TipoLog.Error, "Guardar Sistemas", $"Ruta de archivo demasiado larga: {ex}"); | |
| } | |
| catch (FileNotFoundException ex) | |
| { | |
| // El archivo no existe | |
| Log.Nuevo(TipoLog.Error, "Guardar Sistemas", $"Archivo no encontrado: {ex}"); | |
| } | |
| catch (IOException ex) | |
| { | |
| // Error de I/O general | |
| Log.Nuevo(TipoLog.Error, "Guardar Sistemas", $"Error de I/O al guardar sistemas: {ex}"); | |
| } | |
| catch (Exception ex) | |
| { | |
| // Cualquier otra excepción general | |
| Log.Nuevo(TipoLog.Error, "Guardar Sistemas", $"Error inesperado al guardar sistemas: {ex}"); | |
| } | |
| }, cancellationToken: token); | |
| // Comprobar cancelación antes de la siguiente parte | |
| token.ThrowIfCancellationRequested(); | |
| // Ordinal | |
| await UniTask.RunOnThreadPool(() => | |
| { | |
| token.ThrowIfCancellationRequested(); | |
| try | |
| { | |
| ES3Settings aj = new ES3Settings(ARCH_GUARDADO); | |
| ES3.Save("ORDINAL", ord, aj); | |
| } | |
| catch (UnauthorizedAccessException ex) | |
| { | |
| // Error relacionado con permisos | |
| Log.Nuevo(TipoLog.Error, "Guardar Sistemas", $"Permiso denegado al intentar guardar sistemas: {ex}"); | |
| } | |
| catch (PathTooLongException ex) | |
| { | |
| // El nombre del archivo o la ruta es demasiado largo | |
| Log.Nuevo(TipoLog.Error, "Guardar Sistemas", $"Ruta de archivo demasiado larga: {ex}"); | |
| } | |
| catch (FileNotFoundException ex) | |
| { | |
| // El archivo no existe | |
| Log.Nuevo(TipoLog.Error, "Guardar Sistemas", $"Archivo no encontrado: {ex}"); | |
| } | |
| catch (IOException ex) | |
| { | |
| // Error de I/O general | |
| Log.Nuevo(TipoLog.Error, "Guardar Sistemas", $"Error de I/O al guardar sistemas: {ex}"); | |
| } | |
| catch (Exception ex) | |
| { | |
| // Cualquier otra excepción general | |
| Log.Nuevo(TipoLog.Error, "Guardar Sistemas", $"Error inesperado al guardar sistemas: {ex}"); | |
| } | |
| }, cancellationToken: token); | |
| // Comprobar cancelación antes de la siguiente parte | |
| token.ThrowIfCancellationRequested(); | |
| // Configuracion | |
| await UniTask.RunOnThreadPool(() => | |
| { | |
| token.ThrowIfCancellationRequested(); | |
| try | |
| { | |
| ES3Settings aj = new ES3Settings(ARCH_GUARDADO); | |
| ES3.Save("CONFIGURACION", con, aj); | |
| } | |
| catch (UnauthorizedAccessException ex) | |
| { | |
| // Error relacionado con permisos | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Permiso denegado al intentar guardar configuracion: {ex}"); | |
| } | |
| catch (PathTooLongException ex) | |
| { | |
| // El nombre del archivo o la ruta es demasiado largo | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Ruta de archivo demasiado larga: {ex}"); | |
| } | |
| catch (FileNotFoundException ex) | |
| { | |
| // El archivo no existe | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Archivo no encontrado: {ex}"); | |
| } | |
| catch (IOException ex) | |
| { | |
| // Error de I/O general | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Error de I/O al guardar configuracion: {ex}"); | |
| } | |
| catch (Exception ex) | |
| { | |
| // Cualquier otra excepción general | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Error inesperado al guardar configuracion: {ex}"); | |
| } | |
| }, cancellationToken: token); | |
| // Comprobar cancelación antes de la siguiente parte | |
| token.ThrowIfCancellationRequested(); | |
| // Lords | |
| await UniTask.RunOnThreadPool(() => | |
| { | |
| token.ThrowIfCancellationRequested(); | |
| try | |
| { | |
| ES3Settings aj = new ES3Settings(ARCH_GUARDADO); | |
| ES3.Save("LORDS", lor, aj); | |
| } | |
| catch (UnauthorizedAccessException ex) | |
| { | |
| // Error relacionado con permisos | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Permiso denegado al intentar guardar configuracion: {ex}"); | |
| } | |
| catch (PathTooLongException ex) | |
| { | |
| // El nombre del archivo o la ruta es demasiado largo | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Ruta de archivo demasiado larga: {ex}"); | |
| } | |
| catch (FileNotFoundException ex) | |
| { | |
| // El archivo no existe | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Archivo no encontrado: {ex}"); | |
| } | |
| catch (IOException ex) | |
| { | |
| // Error de I/O general | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Error de I/O al guardar configuracion: {ex}"); | |
| } | |
| catch (Exception ex) | |
| { | |
| // Cualquier otra excepción general | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Error inesperado al guardar configuracion: {ex}"); | |
| } | |
| }, cancellationToken: token); | |
| // Comprobar cancelación antes de la siguiente parte | |
| token.ThrowIfCancellationRequested(); | |
| // Linaje | |
| await UniTask.RunOnThreadPool(() => | |
| { | |
| token.ThrowIfCancellationRequested(); | |
| try | |
| { | |
| ES3Settings aj = new ES3Settings(ARCH_GUARDADO); | |
| ES3.Save("LINAJE", lin, aj); | |
| } | |
| catch (UnauthorizedAccessException ex) | |
| { | |
| // Error relacionado con permisos | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Permiso denegado al intentar guardar configuracion: {ex}"); | |
| } | |
| catch (PathTooLongException ex) | |
| { | |
| // El nombre del archivo o la ruta es demasiado largo | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Ruta de archivo demasiado larga: {ex}"); | |
| } | |
| catch (FileNotFoundException ex) | |
| { | |
| // El archivo no existe | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Archivo no encontrado: {ex}"); | |
| } | |
| catch (IOException ex) | |
| { | |
| // Error de I/O general | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Error de I/O al guardar configuracion: {ex}"); | |
| } | |
| catch (Exception ex) | |
| { | |
| // Cualquier otra excepción general | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Error inesperado al guardar configuracion: {ex}"); | |
| } | |
| }, cancellationToken: token); | |
| // Comprobar cancelación antes de la siguiente parte | |
| token.ThrowIfCancellationRequested(); | |
| // Cronicas | |
| await UniTask.RunOnThreadPool(() => | |
| { | |
| token.ThrowIfCancellationRequested(); | |
| try | |
| { | |
| ES3Settings aj = new ES3Settings(ARCH_GUARDADO); | |
| ES3.Save("CRONICAS", cro, aj); | |
| } | |
| catch (UnauthorizedAccessException ex) | |
| { | |
| // Error relacionado con permisos | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Permiso denegado al intentar guardar configuracion: {ex}"); | |
| } | |
| catch (PathTooLongException ex) | |
| { | |
| // El nombre del archivo o la ruta es demasiado largo | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Ruta de archivo demasiado larga: {ex}"); | |
| } | |
| catch (FileNotFoundException ex) | |
| { | |
| // El archivo no existe | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Archivo no encontrado: {ex}"); | |
| } | |
| catch (IOException ex) | |
| { | |
| // Error de I/O general | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Error de I/O al guardar configuracion: {ex}"); | |
| } | |
| catch (Exception ex) | |
| { | |
| // Cualquier otra excepción general | |
| Log.Nuevo(TipoLog.Error, "Guardar Configuracion", $"Error inesperado al guardar configuracion: {ex}"); | |
| } | |
| }, cancellationToken: token); | |
| } | |
| /// <summary> | |
| /// <para>Guarda la partida.</para> | |
| /// </summary> | |
| /// <param name="token"></param> | |
| /// <param name="maz"></param> | |
| /// <param name="tra"></param> | |
| private async UniTask GuardarPartidaInterno(CancellationToken token, EMazmorra maz, ETrayecto tra, ETesoro tes) | |
| { | |
| // Comprobar cancelación antes de empezar | |
| token.ThrowIfCancellationRequested(); | |
| // Cardinal | |
| await UniTask.RunOnThreadPool(() => | |
| { | |
| token.ThrowIfCancellationRequested(); | |
| try | |
| { | |
| ES3Settings aj = new ES3Settings(ARCH_GUARDADO); | |
| ES3.Save("MAZMORRA", maz, aj); | |
| } | |
| catch (UnauthorizedAccessException ex) | |
| { | |
| // Error relacionado con permisos | |
| Log.Nuevo(TipoLog.Error, "Guardar Mazmorra", $"Permiso denegado al intentar guardar mazmorra: {ex}"); | |
| } | |
| catch (PathTooLongException ex) | |
| { | |
| // El nombre del archivo o la ruta es demasiado largo | |
| Log.Nuevo(TipoLog.Error, "Guardar Mazmorra", $"Ruta de archivo demasiado larga: {ex}"); | |
| } | |
| catch (FileNotFoundException ex) | |
| { | |
| // El archivo no existe | |
| Log.Nuevo(TipoLog.Error, "Guardar Mazmorra", $"Archivo no encontrado: {ex}"); | |
| } | |
| catch (IOException ex) | |
| { | |
| // Error de I/O general | |
| Log.Nuevo(TipoLog.Error, "Guardar Mazmorra", $"Error de I/O al guardar mazmorra: {ex}"); | |
| } | |
| catch (Exception ex) | |
| { | |
| // Cualquier otra excepción general | |
| Log.Nuevo(TipoLog.Error, "Guardar Mazmorra", $"Error inesperado al guardar mazmorra: {ex}"); | |
| } | |
| }, cancellationToken: token); | |
| // Comprobar cancelación antes de la siguiente parte | |
| token.ThrowIfCancellationRequested(); | |
| // Trayecto | |
| await UniTask.RunOnThreadPool(() => | |
| { | |
| token.ThrowIfCancellationRequested(); | |
| try | |
| { | |
| ES3Settings aj = new ES3Settings(ARCH_GUARDADO); | |
| ES3.Save("TRAYECTO", tra, aj); | |
| } | |
| catch (UnauthorizedAccessException ex) | |
| { | |
| // Error relacionado con permisos | |
| Log.Nuevo(TipoLog.Error, "Guardar Trayecto", $"Permiso denegado al intentar guardar trayecto: {ex}"); | |
| } | |
| catch (PathTooLongException ex) | |
| { | |
| // El nombre del archivo o la ruta es demasiado largo | |
| Log.Nuevo(TipoLog.Error, "Guardar Trayecto", $"Ruta de archivo demasiado larga: {ex}"); | |
| } | |
| catch (FileNotFoundException ex) | |
| { | |
| // El archivo no existe | |
| Log.Nuevo(TipoLog.Error, "Guardar Trayecto", $"Archivo no encontrado: {ex}"); | |
| } | |
| catch (IOException ex) | |
| { | |
| // Error de I/O general | |
| Log.Nuevo(TipoLog.Error, "Guardar Trayecto", $"Error de I/O al guardar trayecto: {ex}"); | |
| } | |
| catch (Exception ex) | |
| { | |
| // Cualquier otra excepción general | |
| Log.Nuevo(TipoLog.Error, "Guardar Trayecto", $"Error inesperado al guardar trayecto: {ex}"); | |
| } | |
| }, cancellationToken: token); | |
| // Tesoro | |
| await UniTask.RunOnThreadPool(() => | |
| { | |
| token.ThrowIfCancellationRequested(); | |
| try | |
| { | |
| ES3Settings aj = new ES3Settings(ARCH_GUARDADO); | |
| ES3.Save("TESORO", tes, aj); | |
| } | |
| catch (UnauthorizedAccessException ex) | |
| { | |
| // Error relacionado con permisos | |
| Log.Nuevo(TipoLog.Error, "Guardar Mazmorra", $"Permiso denegado al intentar guardar mazmorra: {ex}"); | |
| } | |
| catch (PathTooLongException ex) | |
| { | |
| // El nombre del archivo o la ruta es demasiado largo | |
| Log.Nuevo(TipoLog.Error, "Guardar Mazmorra", $"Ruta de archivo demasiado larga: {ex}"); | |
| } | |
| catch (FileNotFoundException ex) | |
| { | |
| // El archivo no existe | |
| Log.Nuevo(TipoLog.Error, "Guardar Mazmorra", $"Archivo no encontrado: {ex}"); | |
| } | |
| catch (IOException ex) | |
| { | |
| // Error de I/O general | |
| Log.Nuevo(TipoLog.Error, "Guardar Mazmorra", $"Error de I/O al guardar mazmorra: {ex}"); | |
| } | |
| catch (Exception ex) | |
| { | |
| // Cualquier otra excepción general | |
| Log.Nuevo(TipoLog.Error, "Guardar Mazmorra", $"Error inesperado al guardar mazmorra: {ex}"); | |
| } | |
| }, cancellationToken: token); | |
| // Comprobar cancelación antes de la siguiente parte | |
| token.ThrowIfCancellationRequested(); | |
| } | |
| #endregion | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment