public static List <string> UpdateMod(ModData modData, UpdateRule rule, out YamlFileSet files, HashSet <string> externalFilenames) { var manualSteps = new List <string>(); var modRules = LoadModYaml(modData, FilterExternalModFiles(modData, modData.Manifest.Rules, externalFilenames)); var modWeapons = LoadModYaml(modData, FilterExternalModFiles(modData, modData.Manifest.Weapons, externalFilenames)); var modTilesets = LoadModYaml(modData, FilterExternalModFiles(modData, modData.Manifest.TileSets, externalFilenames)); var modChromeLayout = LoadModYaml(modData, FilterExternalModFiles(modData, modData.Manifest.ChromeLayout, externalFilenames)); // Find and add shared map includes foreach (var package in modData.MapCache.EnumerateMapPackagesWithoutCaching()) { using (var mapStream = package.GetStream("map.yaml")) { if (mapStream == null) { continue; } var yaml = new MiniYaml(null, MiniYaml.FromStream(mapStream, package.Name, false)); var mapRulesNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Rules"); if (mapRulesNode != null) { foreach (var f in LoadExternalMapYaml(modData, mapRulesNode.Value, externalFilenames)) { if (!modRules.Any(m => m.Item1 == f.Item1 && m.Item2 == f.Item2)) { modRules.Add(f); } } } var mapWeaponsNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Weapons"); if (mapWeaponsNode != null) { foreach (var f in LoadExternalMapYaml(modData, mapWeaponsNode.Value, externalFilenames)) { if (!modWeapons.Any(m => m.Item1 == f.Item1 && m.Item2 == f.Item2)) { modWeapons.Add(f); } } } } } manualSteps.AddRange(rule.BeforeUpdate(modData)); manualSteps.AddRange(ApplyTopLevelTransform(modData, modRules, rule.UpdateActorNode)); manualSteps.AddRange(ApplyTopLevelTransform(modData, modWeapons, rule.UpdateWeaponNode)); manualSteps.AddRange(ApplyTopLevelTransform(modData, modTilesets, rule.UpdateTilesetNode)); manualSteps.AddRange(ApplyChromeTransform(modData, modChromeLayout, rule.UpdateChromeNode)); manualSteps.AddRange(rule.AfterUpdate(modData)); files = modRules.ToList(); files.AddRange(modWeapons); files.AddRange(modTilesets); files.AddRange(modChromeLayout); return(manualSteps); }
/// <summary> /// Run a given update rule on a map. /// The rule is only applied to internal files - external includes are assumed to be handled separately /// but are noted in the externalFilenames list for informational purposes. /// </summary> public static List <string> UpdateMap(ModData modData, IReadWritePackage mapPackage, UpdateRule rule, out YamlFileSet files, HashSet <string> externalFilenames) { var manualSteps = new List <string>(); using (var mapStream = mapPackage.GetStream("map.yaml")) { if (mapStream == null) { // Not a valid map files = new YamlFileSet(); return(manualSteps); } var yaml = new MiniYaml(null, MiniYaml.FromStream(mapStream, mapPackage.Name, false)); files = new YamlFileSet() { Tuple.Create(mapPackage, "map.yaml", yaml.Nodes) }; manualSteps.AddRange(rule.BeforeUpdate(modData)); var mapRulesNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Rules"); if (mapRulesNode != null) { var mapRules = LoadInternalMapYaml(modData, mapPackage, mapRulesNode.Value, externalFilenames); manualSteps.AddRange(ApplyTopLevelTransform(modData, mapRules, rule.UpdateActorNode)); files.AddRange(mapRules); } var mapWeaponsNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Weapons"); if (mapWeaponsNode != null) { var mapWeapons = LoadInternalMapYaml(modData, mapPackage, mapWeaponsNode.Value, externalFilenames); manualSteps.AddRange(ApplyTopLevelTransform(modData, mapWeapons, rule.UpdateWeaponNode)); files.AddRange(mapWeapons); } var mapSequencesNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Sequences"); if (mapSequencesNode != null) { var mapSequences = LoadInternalMapYaml(modData, mapPackage, mapSequencesNode.Value, externalFilenames); manualSteps.AddRange(ApplyTopLevelTransform(modData, mapSequences, rule.UpdateWeaponNode)); files.AddRange(mapSequences); } manualSteps.AddRange(rule.AfterUpdate(modData)); } return(manualSteps); }
static void ApplyRules(ModData modData, IEnumerable <UpdateRule> rules, bool skipMaps) { Console.WriteLine(); var logWriter = File.CreateText("update.log"); logWriter.AutoFlush = true; var externalFilenames = new HashSet <string>(); foreach (var rule in rules) { var manualSteps = new List <string>(); var allFiles = new YamlFileSet(); LogLine(logWriter, "{0}: {1}", rule.GetType().Name, rule.Name); try { Log(logWriter, " Updating mod... "); manualSteps.AddRange(UpdateUtils.UpdateMod(modData, rule, out allFiles, externalFilenames)); LogLine(logWriter, "COMPLETE"); } catch (Exception ex) { Console.WriteLine("FAILED"); LogLine(logWriter); LogLine(logWriter, " The automated changes for this rule were not applied because of an error."); LogLine(logWriter, " After the issue reported below is resolved you should run the updater"); LogLine(logWriter, " with SOURCE set to {0} to retry these changes", rule.GetType().Name); LogLine(logWriter); LogLine(logWriter, " The exception reported was:"); LogLine(logWriter, " " + ex.ToString().Replace("\n", "\n ")); continue; } Log(logWriter, " Updating system maps... "); if (!skipMaps) { var mapsFailed = false; var mapExternalFilenames = new HashSet <string>(); foreach (var package in modData.MapCache.EnumerateMapPackagesWithoutCaching()) { try { var mapSteps = UpdateUtils.UpdateMap(modData, package, rule, out var mapFiles, mapExternalFilenames); allFiles.AddRange(mapFiles); if (mapSteps.Any()) { manualSteps.Add("Map: " + package.Name + ":\n" + UpdateUtils.FormatMessageList(mapSteps)); } } catch (Exception ex) { LogLine(logWriter, "FAILED"); LogLine(logWriter); LogLine(logWriter, " The automated changes for this rule were not applied because of an error."); LogLine(logWriter, " After the issue reported below is resolved you should run the updater"); LogLine(logWriter, " with SOURCE set to {0} to retry these changes", rule.GetType().Name); LogLine(logWriter); LogLine(logWriter, " The map that caused the error was:"); LogLine(logWriter, " " + package.Name); LogLine(logWriter); LogLine(logWriter, " The exception reported was:"); LogLine(logWriter, " " + ex.ToString().Replace("\n", "\n ")); mapsFailed = true; break; } } if (mapsFailed) { continue; } LogLine(logWriter, "COMPLETE"); } else { LogLine(logWriter, "SKIPPED"); } // Files are saved after each successful automated rule update allFiles.Save(); if (manualSteps.Any()) { LogLine(logWriter, " Manual changes are required to complete this update:"); LogLine(logWriter, UpdateUtils.FormatMessageList(manualSteps, 1)); } LogLine(logWriter); } if (externalFilenames.Any()) { LogLine(logWriter, "The following external mod files have been ignored:"); LogLine(logWriter, UpdateUtils.FormatMessageList(externalFilenames)); LogLine(logWriter, "These files should be updated by running --update-mod on the referenced mod(s)"); LogLine(logWriter); } Console.WriteLine("Semi-automated update complete."); Console.WriteLine("Please review the messages above for any manual actions that must be applied."); Console.WriteLine("These messages have also been written to an update.log file in the current directory."); }