/// <summary> /// Restores live entity backup from Current /// </summary> /// <returns>Success state</returns> public bool RestoreLiveBackup() { LiveData liveDataAccessor = new LiveData(); string currentBackupDirectory = liveDataAccessor.BaseDirectory + liveDataAccessor.CurrentDirectoryName; //No backup directory? No live data. if (!Directory.Exists(currentBackupDirectory)) { return(false); } LoggingUtility.Log("World restored from current live INITIATED.", LogChannels.Backup, false); try { //dont load players here List <IEntity> entitiesToLoad = new List <IEntity>(); IEnumerable <Type> implimentedTypes = typeof(EntityPartial).Assembly.GetTypes().Where(ty => ty.GetInterfaces().Contains(typeof(IEntity)) && ty.IsClass && !ty.IsAbstract && !ty.GetCustomAttributes <IgnoreAutomatedBackupAttribute>().Any()); foreach (Type type in implimentedTypes.OrderByDescending(type => type == typeof(Gaia) ? 6 : type == typeof(Zone) ? 5 : type == typeof(Locale) ? 3 : type == typeof(Room) ? 3 : type == typeof(Pathway) ? 2 : 0)) { if (!Directory.Exists(currentBackupDirectory + type.Name)) { continue; } DirectoryInfo entityFilesDirectory = new DirectoryInfo(currentBackupDirectory + type.Name); foreach (FileInfo file in entityFilesDirectory.EnumerateFiles()) { entitiesToLoad.Add(liveDataAccessor.ReadEntity(file, type)); } } //Check we found actual data if (!entitiesToLoad.Any(ent => ent.GetType() == typeof(Gaia))) { throw new Exception("No Worlds found, failover."); } if (!entitiesToLoad.Any(ent => ent.GetType() == typeof(Zone))) { throw new Exception("No zones found, failover."); } //Shove them all into the live system first foreach (IEntity entity in entitiesToLoad.OrderBy(ent => ent.Birthdate)) { entity.UpsertToLiveWorldCache(); entity.KickoffProcesses(); } //We need to pick up any places that aren't already live from the file system incase someone added them during the last session\ foreach (IGaiaTemplate thing in TemplateCache.GetAll <IGaiaTemplate>().Where(dt => !entitiesToLoad.Any(ent => ent.TemplateId.Equals(dt.Id) && ent.Birthdate >= dt.LastRevised))) { IGaia entityThing = Activator.CreateInstance(thing.EntityClass, new object[] { thing }) as IGaia; entityThing.SpawnNewInWorld(); } foreach (IZoneTemplate thing in TemplateCache.GetAll <IZoneTemplate>().Where(dt => !entitiesToLoad.Any(ent => ent.TemplateId.Equals(dt.Id) && ent.Birthdate >= dt.LastRevised))) { IZone entityThing = Activator.CreateInstance(thing.EntityClass, new object[] { thing }) as IZone; entityThing.SpawnNewInWorld(); } foreach (ILocaleTemplate thing in TemplateCache.GetAll <ILocaleTemplate>().Where(dt => !entitiesToLoad.Any(ent => ent.TemplateId.Equals(dt.Id) && ent.Birthdate >= dt.LastRevised))) { ILocale entityThing = Activator.CreateInstance(thing.EntityClass, new object[] { thing }) as ILocale; entityThing.ParentLocation = entityThing.ParentLocation.GetLiveInstance(); entityThing.SpawnNewInWorld(); } foreach (IRoomTemplate thing in TemplateCache.GetAll <IRoomTemplate>().Where(dt => !entitiesToLoad.Any(ent => ent.TemplateId.Equals(dt.Id) && ent.Birthdate >= dt.LastRevised))) { IRoom entityThing = Activator.CreateInstance(thing.EntityClass, new object[] { thing }) as IRoom; entityThing.ParentLocation = entityThing.Template <IRoomTemplate>().ParentLocation.GetLiveInstance(); entityThing.SpawnNewInWorld(); } foreach (IPathwayTemplate thing in TemplateCache.GetAll <IPathwayTemplate>().Where(dt => !entitiesToLoad.Any(ent => ent.TemplateId.Equals(dt.Id) && ent.Birthdate >= dt.LastRevised))) { IPathway entityThing = Activator.CreateInstance(thing.EntityClass, new object[] { thing }) as IPathway; entityThing.SpawnNewInWorld(); } //We have the containers contents and the birthmarks from the deserial //I don't know how we can even begin to do this type agnostically since the collections are held on type specific objects without some super ugly reflection foreach (Room entity in entitiesToLoad.Where(ent => ent.GetType() == typeof(Room))) { foreach (IInanimate obj in entity.Contents.EntitiesContained()) { IInanimate fullObj = LiveCache.Get <IInanimate>(new LiveCacheKey(obj)); entity.MoveFrom(obj); entity.MoveInto(fullObj); } foreach (INonPlayerCharacter obj in entity.MobilesInside.EntitiesContained()) { INonPlayerCharacter fullObj = LiveCache.Get <INonPlayerCharacter>(new LiveCacheKey(obj)); entity.MoveFrom(obj); entity.MoveInto(fullObj); } } foreach (NonPlayerCharacter entity in entitiesToLoad.Where(ent => ent.GetType() == typeof(NonPlayerCharacter))) { foreach (IInanimate obj in entity.Inventory.EntitiesContained()) { IInanimate fullObj = LiveCache.Get <IInanimate>(new LiveCacheKey(obj)); entity.MoveFrom(obj); entity.MoveInto(fullObj); } } foreach (Inanimate entity in entitiesToLoad.Where(ent => ent.GetType() == typeof(Inanimate))) { foreach (Tuple <string, IInanimate> obj in entity.Contents.EntitiesContainedByName()) { IInanimate fullObj = LiveCache.Get <IInanimate>(new LiveCacheKey(obj.Item2)); entity.MoveFrom(obj.Item2); entity.MoveInto(fullObj, obj.Item1); } foreach (Tuple <string, IInanimate> obj in entity.Contents.EntitiesContainedByName()) { INonPlayerCharacter fullObj = LiveCache.Get <INonPlayerCharacter>(new LiveCacheKey(obj.Item2)); entity.MoveFrom((INonPlayerCharacter)obj.Item2); entity.MoveInto(fullObj, obj.Item1); } } //We need to poll the WorldMaps here and give all the rooms their coordinates as well as the zones their sub-maps ParseDimension(); LoggingUtility.Log("World restored from current live.", LogChannels.Backup, false); return(true); } catch (Exception ex) { LoggingUtility.LogError(ex); } return(false); }