/// <summary>Apply content data to the game.</summary> /// <param name="compoundData">Compound data loaded from the content packs.</param> public void ApplyPatches(out Compound compoundData) { // track info Dictionary <IContentPack, Tilesheet[]> seasonalTilesheetsByContentPack = new Dictionary <IContentPack, Tilesheet[]>(); HashSet <string> customLocationNames = new HashSet <string>(); Dictionary <string, Point> mapSizes = new Dictionary <string, Point>(); Dictionary <string, Map> mapCache = new Dictionary <string, Map>(); Dictionary <string, List <string> > tilesheetCache = new Dictionary <string, List <string> >(); List <Tile> dynamicTiles = new List <Tile>(); List <Property> dynamicProperties = new List <Property>(); List <Warp> dynamicWarps = new List <Warp>(); List <Conditional> conditionals = new List <Conditional>(); List <TeleporterList> teleporters = new List <TeleporterList>(); List <ShopConfig> shops = new List <ShopConfig>(); // apply content packs foreach (ContentPackData pack in this.Data) { this.Monitor.Log($"Applying {pack.ContentPack.Manifest.Name}...", LogLevel.Debug); string stage = "entry"; try { // collect tilesheet info IDictionary <string, Tilesheet[]> tilesheetQueue = pack.Tilesheets .GroupBy(p => p.MapName) .ToDictionary(p => p.Key, p => p.ToArray(), StringComparer.InvariantCultureIgnoreCase); IList <Tilesheet> seasonalTilesheets = new List <Tilesheet>(); // apply custom locations stage = "locations"; foreach (Location location in pack.Locations) { if (Game1.getLocationFromName(location.MapName) != null) { this.Monitor.Log($" Can't add location {location.MapName}, it already exists.", LogLevel.Warn); continue; } try { // cache info Map map = pack.ContentPack.LoadAsset <Map>(location.FileName); mapSizes.Add(location.MapName, new Point(map.DisplayWidth, map.DisplayHeight)); mapCache.Add(location.MapName, map); customLocationNames.Add(location.MapName); // preload tilesheets if (tilesheetQueue.TryGetValue(location.MapName, out Tilesheet[] tilesheets)) { tilesheetQueue.Remove(location.MapName); foreach (Tilesheet tilesheet in tilesheets) { Processors.ApplyTilesheet(this.CoreContentHelper, pack.ContentPack, tilesheet, map); if (tilesheet.Seasonal) { seasonalTilesheets.Add(tilesheet); } } } // load location Processors.ApplyLocation(pack.ContentPack, location); }
public static void ApplyPatches() { int stage = 0; try { stage++; // 1 SecondaryLocationManifest1_2 trueCompound = new SecondaryLocationManifest1_2(); AdvancedLocationLoaderMod.Logger.Log("Applying Patches...", LogLevel.Trace); // First we need to check any things we couldnt before foreach (Location obj in Compound.Locations) { if (Game1.getLocationFromName(obj.MapName) != null) { AdvancedLocationLoaderMod.Logger.Log("Unable to add location, it already exists: " + obj.ToString(), LogLevel.Error); } else { try { xTile.Map map = new LocalizedContentManager(Game1.content.ServiceProvider, Path.GetDirectoryName(obj.FileName)).Load <xTile.Map>(Path.GetFileName(obj.FileName)); MapSizes.Add(obj.MapName, new Point(map.DisplayWidth, map.DisplayHeight)); MapCache.Add(obj.MapName, map); AffectedLocations.Add(obj.MapName); trueCompound.Locations.Add(obj); } catch (Exception err) { AdvancedLocationLoaderMod.Logger.Log(LogLevel.Error, "Unable to add location, the map file caused a error when loaded: " + obj.ToString(), err); } } } stage++; // 2 foreach (Override obj in Compound.Overrides) { if (Game1.getLocationFromName(obj.MapName) == null) { AdvancedLocationLoaderMod.Logger.Log("Unable to override location, it does not exist: " + obj.ToString(), LogLevel.Error); } else { try { xTile.Map map = new LocalizedContentManager(Game1.content.ServiceProvider, Path.GetDirectoryName(obj.FileName)).Load <xTile.Map>(Path.GetFileName(obj.FileName)); MapSizes.Add(obj.MapName, new Point(map.DisplayWidth, map.DisplayHeight)); trueCompound.Overrides.Add(obj); } catch (Exception err) { AdvancedLocationLoaderMod.Logger.Log(LogLevel.Error, "Unable to override location, the map file caused a error when loaded: " + obj.ToString(), err); } } } stage++; // 3 trueCompound.Redirects = Compound.Redirects; stage++; // 4 foreach (Tilesheet obj in Compound.Tilesheets) { if (Game1.getLocationFromName(obj.MapName) == null && !AffectedLocations.Contains(obj.MapName)) { AdvancedLocationLoaderMod.Logger.Log("Unable to patch tilesheet, location does not exist: " + obj.ToString(), LogLevel.Error); } else { trueCompound.Tilesheets.Add(obj); } } stage++; // 5 foreach (Tile obj in Compound.Tiles) { string info = CheckTileInfo(obj); if (info != null) { if (info != "OPTIONAL") { AdvancedLocationLoaderMod.Logger.Log("Unable to apply tile patch, " + info + ":" + obj.ToString(), LogLevel.Error); continue; } } else if (obj.SheetId != null && (!TilesheetCache.ContainsKey(obj.MapName) || !TilesheetCache[obj.MapName].Contains(obj.SheetId))) { xTile.Map map = MapCache.ContainsKey(obj.MapName) ? MapCache[obj.MapName] : Game1.getLocationFromName(obj.MapName).map; if (map.GetTileSheet(obj.SheetId) == null) { AdvancedLocationLoaderMod.Logger.Log("Unable to apply tile patch, tilesheet does not exist:" + obj.ToString(), LogLevel.Error); continue; } } trueCompound.Tiles.Add(obj); } stage++; // 6 foreach (Property obj in Compound.Properties) { string info = CheckTileInfo(obj); if (info != null) { if (info != "OPTIONAL") { AdvancedLocationLoaderMod.Logger.Log("Unable to apply property patch, " + info + ":" + obj.ToString(), LogLevel.Error); } } else { trueCompound.Properties.Add(obj); } } stage++; // 7 foreach (Warp obj in Compound.Warps) { string info = CheckTileInfo(obj); if (info != null) { if (info != "OPTIONAL") { AdvancedLocationLoaderMod.Logger.Log("Unable to apply warp patch, " + info + ":" + obj.ToString(), LogLevel.Error); } } trueCompound.Warps.Add(obj); } stage++; // 8 foreach (Conditional obj in Compound.Conditionals) { Configs.Compound.Conditionals.Add(obj); } stage++; // 9 foreach (TeleporterList obj in Compound.Teleporters) { Configs.Compound.Teleporters.Add(obj); } stage++; // 10 // At this point any edits that showed problems have been removed, so now we can actually process everything foreach (Location obj in trueCompound.Locations) { Processors.ApplyLocation(obj); } stage++; // 11 foreach (Override obj in trueCompound.Overrides) { Processors.ApplyOverride(obj); } stage++; // 12 foreach (Redirect obj in trueCompound.Redirects) { EntoFramework.GetContentRegistry().RegisterXnb(obj.FromFile, obj.ToFile); } stage++; // 13 foreach (Tilesheet obj in trueCompound.Tilesheets) { Processors.ApplyTilesheet(obj); if (obj.Seasonal) { Configs.Compound.SeasonalTilesheets.Add(obj); } } stage++; // 14 foreach (Tile obj in trueCompound.Tiles) { Processors.ApplyTile(obj); if (!string.IsNullOrEmpty(obj.Conditions)) { Configs.Compound.DynamicTiles.Add(obj); } } stage++; // 15 foreach (Property obj in trueCompound.Properties) { Processors.ApplyProperty(obj); if (!string.IsNullOrEmpty(obj.Conditions)) { Configs.Compound.DynamicProperties.Add(obj); } } stage++; // 16 foreach (Warp obj in trueCompound.Warps) { Processors.ApplyWarp(obj); if (!string.IsNullOrEmpty(obj.Conditions)) { Configs.Compound.DynamicWarps.Add(obj); } } stage++; // 17 NPC.populateRoutesFromLocationToLocationList(); stage++; // 18 Compound = null; Conditionals = null; AffectedLocations = null; MapSizes = null; stage++; // 19 VerifyPatchIntegrity(); stage++; // 20 AdvancedLocationLoaderMod.Logger.Log("Patches have been applied", LogLevel.Debug); } catch (Exception err) { AdvancedLocationLoaderMod.Logger.ExitGameImmediately("Unable to patch the game, a unexpected error occured at stage " + stage.ToString(), err); } }
/// <summary>Apply content data to the game.</summary> /// <param name="compoundData">Compound data loaded from the content packs.</param> public void ApplyPatches(out Compound compoundData) { // track info var seasonalTilesheetsByContentPack = new Dictionary <IContentPack, Tilesheet[]>(); var customLocationNames = new HashSet <string>(); var mapSizes = new Dictionary <string, Point>(); var mapCache = new Dictionary <string, xTile.Map>(); var tilesheetCache = new Dictionary <string, List <string> >(); var dynamicTiles = new List <Tile>(); var dynamicProperties = new List <Property>(); var dynamicWarps = new List <Warp>(); var conditionals = new List <Conditional>(); var teleporters = new List <TeleporterList>(); var shops = new List <ShopConfig>(); // apply content packs foreach (ContentPackData pack in this.Data) { this.Monitor.Log($"Applying {pack.ContentPack.Manifest.Name}...", LogLevel.Debug); string stage = "entry"; try { // apply locations stage = "locations"; foreach (Location obj in pack.Locations) { if (Game1.getLocationFromName(obj.MapName) != null) { this.Monitor.Log($" Can't add location {obj.MapName}, it already exists.", LogLevel.Warn); continue; } try { // cache info xTile.Map map = pack.ContentPack.LoadAsset <xTile.Map>(obj.FileName); mapSizes.Add(obj.MapName, new Point(map.DisplayWidth, map.DisplayHeight)); mapCache.Add(obj.MapName, map); customLocationNames.Add(obj.MapName); Processors.ApplyLocation(pack.ContentPack, obj); } catch (Exception err) { this.Monitor.Log($" Can't add location {obj.MapName}, an error occurred.", LogLevel.Error, err); } } // apply overrides stage = "overrides"; foreach (Override obj in pack.Overrides) { if (Game1.getLocationFromName(obj.MapName) == null) { this.Monitor.Log($" Can't override location {obj.MapName}, it doesn't exist.", LogLevel.Error); continue; } try { xTile.Map map = pack.ContentPack.LoadAsset <xTile.Map>(obj.FileName); mapSizes.Add(obj.MapName, new Point(map.DisplayWidth, map.DisplayHeight)); Processors.ApplyOverride(pack.ContentPack, obj); } catch (Exception err) { this.Monitor.Log($" Can't override location {obj.MapName}, an error occurred.", LogLevel.Error, err); } } // apply redirects stage = "redirects"; { HashSet <string> redirCache = new HashSet <string>(); foreach (Redirect obj in pack.Redirects) { if (!redirCache.Contains(obj.ToFile)) { string toAssetPath = pack.ContentPack.GetRelativePath(fromAbsolutePath: ModEntry.SHelper.DirectoryPath, toLocalPath: obj.ToFile); this.CoreContentHelper.RegisterXnbReplacement(obj.FromFile, toAssetPath); redirCache.Add(obj.ToFile); } } } // apply tilesheets stage = "tilesheets"; IList <Tilesheet> seasonalTilesheets = new List <Tilesheet>(); foreach (Tilesheet obj in pack.Tilesheets) { if (Game1.getLocationFromName(obj.MapName) == null && !customLocationNames.Contains(obj.MapName)) { this.Monitor.Log($" Can't apply tilesheet '{obj.SheetId}', location '{obj.MapName}' doesn't exist.", LogLevel.Error); continue; } Processors.ApplyTilesheet(this.CoreContentHelper, pack.ContentPack, obj); if (obj.Seasonal) { seasonalTilesheets.Add(obj); } } if (seasonalTilesheets.Any()) { seasonalTilesheetsByContentPack[pack.ContentPack] = seasonalTilesheets.ToArray(); } // apply tiles stage = "tiles"; foreach (Tile obj in pack.Tiles) { if (!this.PreprocessTile(obj, customLocationNames, mapSizes, out string error)) { if (error != null) { this.Monitor.Log($" Can't apply tile {obj}: {error}", LogLevel.Error); } } else if (obj.SheetId != null && (!tilesheetCache.ContainsKey(obj.MapName) || !tilesheetCache[obj.MapName].Contains(obj.SheetId))) { xTile.Map map = mapCache.ContainsKey(obj.MapName) ? mapCache[obj.MapName] : Game1.getLocationFromName(obj.MapName).map; if (map.GetTileSheet(obj.SheetId) == null && (!tilesheetCache.ContainsKey(map.Id) || !tilesheetCache[map.Id].Contains(obj.SheetId))) { this.Monitor.Log($" Can't apply tile {obj}, tilesheet doesn't exist.", LogLevel.Error); continue; } } Processors.ApplyTile(obj); if (!string.IsNullOrEmpty(obj.Conditions)) { dynamicTiles.Add(obj); } } // apply properties stage = "properties"; foreach (Property obj in pack.Properties) { if (!this.PreprocessTile(obj, customLocationNames, mapSizes, out string error)) { if (error != null) { this.Monitor.Log($" Can't apply property patch {obj}: {error}.", LogLevel.Error); } continue; } Processors.ApplyProperty(obj); if (!string.IsNullOrEmpty(obj.Conditions)) { dynamicProperties.Add(obj); } } // apply warps stage = "warps"; foreach (Warp obj in pack.Warps) { if (!this.PreprocessTile(obj, customLocationNames, mapSizes, out string error)) { if (error != null) { this.Monitor.Log($" Can't apply warp {obj}: {error}.", LogLevel.Error); } continue; } Processors.ApplyWarp(obj); if (!string.IsNullOrEmpty(obj.Conditions)) { dynamicWarps.Add(obj); } } // save conditionals stage = "conditionals"; foreach (Conditional obj in pack.Conditionals) { conditionals.Add(obj); } // save teleporters stage = "teleporters"; foreach (TeleporterList obj in pack.Teleporters) { teleporters.Add(obj); } // save shops stage = "shops"; foreach (ShopConfig obj in pack.Shops) { shops.Add(obj); } } catch (Exception ex) { this.Monitor.ExitGameImmediately($"Failed applying changes from the {pack.ContentPack.Manifest.Name} content pack ({stage} step).", ex); } } // postprocess try { NPC.populateRoutesFromLocationToLocationList(); VerifyGameIntegrity(); this.Monitor.Log("Patches applied!", LogLevel.Debug); } catch (Exception ex) { this.Monitor.ExitGameImmediately("Failed post-processing after content pack changes.", ex); } // create compound info compoundData = new Compound(seasonalTilesheetsByContentPack, dynamicTiles, dynamicProperties, dynamicWarps, conditionals, teleporters, shops); }