Process shared map includes as part of the mod rules.

This ensures that they are only updated once instead
of repeating the updates for every map that includes them.
This commit is contained in:
Paul Chote
2018-03-30 16:04:58 +00:00
committed by abcdefg30
parent 02f769964e
commit 2400b152ea
3 changed files with 98 additions and 39 deletions

View File

@@ -21,7 +21,10 @@ namespace OpenRA.Mods.Common.UpdateRules
public static class UpdateUtils public static class UpdateUtils
{ {
static YamlFileSet LoadYaml(ModData modData, IEnumerable<string> files) /// <summary>
/// Loads a YamlFileSet from a list of mod files.
/// </summary>
static YamlFileSet LoadModYaml(ModData modData, IEnumerable<string> files)
{ {
var yaml = new YamlFileSet(); var yaml = new YamlFileSet();
foreach (var filename in files) foreach (var filename in files)
@@ -40,7 +43,22 @@ namespace OpenRA.Mods.Common.UpdateRules
return yaml; return yaml;
} }
static YamlFileSet LoadMapYaml(ModData modData, IReadWritePackage mapPackage, MiniYaml yaml) /// <summary>
/// Loads a YamlFileSet containing any external yaml definitions referenced by a map yaml block.
/// </summary>
static YamlFileSet LoadExternalMapYaml(ModData modData, MiniYaml yaml)
{
return FieldLoader.GetValue<string[]>("value", yaml.Value)
.Where(f => f.Contains("|"))
.SelectMany(f => LoadModYaml(modData, new[] { f }))
.ToList();
}
/// <summary>
/// Loads a YamlFileSet containing any internal definitions yaml referenced by a map yaml block.
/// External references or internal references to missing files are ignored.
/// </summary>
static YamlFileSet LoadInternalMapYaml(ModData modData, IReadWritePackage mapPackage, MiniYaml yaml, HashSet<string> externalFilenames)
{ {
var fileSet = new YamlFileSet() var fileSet = new YamlFileSet()
{ {
@@ -50,60 +68,91 @@ namespace OpenRA.Mods.Common.UpdateRules
var files = FieldLoader.GetValue<string[]>("value", yaml.Value); var files = FieldLoader.GetValue<string[]>("value", yaml.Value);
foreach (var filename in files) foreach (var filename in files)
{ {
// Ignore any files that aren't in the map bundle
if (!filename.Contains("|") && mapPackage.Contains(filename)) if (!filename.Contains("|") && mapPackage.Contains(filename))
fileSet.Add(Tuple.Create(mapPackage, filename, MiniYaml.FromStream(mapPackage.GetStream(filename), filename))); fileSet.Add(Tuple.Create(mapPackage, filename, MiniYaml.FromStream(mapPackage.GetStream(filename), filename)));
else else if (modData.ModFiles.Exists(filename))
fileSet.AddRange(LoadYaml(modData, new[] { filename })); externalFilenames.Add(filename);
} }
return fileSet; return fileSet;
} }
public static List<string> UpdateMap(ModData modData, IReadWritePackage mapPackage, UpdateRule rule, out YamlFileSet files) /// <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>(); var manualSteps = new List<string>();
var mapStream = mapPackage.GetStream("map.yaml"); using (var mapStream = mapPackage.GetStream("map.yaml"))
if (mapStream == null)
{ {
// Not a valid map if (mapStream == null)
files = new YamlFileSet(); {
return manualSteps; // Not a valid map
files = new YamlFileSet();
return manualSteps;
}
var yaml = new MiniYaml(null, MiniYaml.FromStream(mapStream, mapPackage.Name));
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);
}
manualSteps.AddRange(rule.AfterUpdate(modData));
} }
var yaml = new MiniYaml(null, MiniYaml.FromStream(mapStream, mapPackage.Name));
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 = LoadMapYaml(modData, mapPackage, mapRulesNode.Value);
manualSteps.AddRange(ApplyTopLevelTransform(modData, mapRules, rule.UpdateActorNode));
files.AddRange(mapRules);
}
var mapWeaponsNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Weapons");
if (mapWeaponsNode != null)
{
var mapWeapons = LoadMapYaml(modData, mapPackage, mapWeaponsNode.Value);
manualSteps.AddRange(ApplyTopLevelTransform(modData, mapWeapons, rule.UpdateWeaponNode));
files.AddRange(mapWeapons);
}
manualSteps.AddRange(rule.AfterUpdate(modData));
return manualSteps; return manualSteps;
} }
public static List<string> UpdateMod(ModData modData, UpdateRule rule, out YamlFileSet files) public static List<string> UpdateMod(ModData modData, UpdateRule rule, out YamlFileSet files)
{ {
var manualSteps = new List<string>(); var manualSteps = new List<string>();
var modRules = LoadYaml(modData, modData.Manifest.Rules); var modRules = LoadModYaml(modData, modData.Manifest.Rules);
var modWeapons = LoadYaml(modData, modData.Manifest.Weapons); var modWeapons = LoadModYaml(modData, modData.Manifest.Weapons);
var modTilesets = LoadYaml(modData, modData.Manifest.TileSets); var modTilesets = LoadModYaml(modData, modData.Manifest.TileSets);
var modChromeLayout = LoadYaml(modData, modData.Manifest.ChromeLayout); var modChromeLayout = LoadModYaml(modData, modData.Manifest.ChromeLayout);
// 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));
var mapRulesNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Rules");
if (mapRulesNode != null)
foreach (var f in LoadExternalMapYaml(modData, mapRulesNode.Value))
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))
if (!modWeapons.Any(m => m.Item1 == f.Item1 && m.Item2 == f.Item2))
modWeapons.Add(f);
}
}
manualSteps.AddRange(rule.BeforeUpdate(modData)); manualSteps.AddRange(rule.BeforeUpdate(modData));
manualSteps.AddRange(ApplyTopLevelTransform(modData, modRules, rule.UpdateActorNode)); manualSteps.AddRange(ApplyTopLevelTransform(modData, modRules, rule.UpdateActorNode));

View File

@@ -82,9 +82,10 @@ namespace OpenRA.Mods.Common.UtilityCommands
Console.Write(" Updating map... "); Console.Write(" Updating map... ");
var externalFilenames = new HashSet<string>();
try try
{ {
manualSteps = UpdateUtils.UpdateMap(modData, mapPackage, rule, out mapFiles); manualSteps = UpdateUtils.UpdateMap(modData, mapPackage, rule, out mapFiles, externalFilenames);
} }
catch (Exception ex) catch (Exception ex)
{ {
@@ -104,6 +105,13 @@ namespace OpenRA.Mods.Common.UtilityCommands
mapFiles.Save(); mapFiles.Save();
Console.WriteLine("COMPLETE"); Console.WriteLine("COMPLETE");
if (externalFilenames.Any())
{
Console.WriteLine(" The following shared yaml files referenced by the map have been ignored:");
Console.WriteLine(UpdateUtils.FormatMessageList(externalFilenames, 1));
Console.WriteLine(" These files are assumed to have already been updated by the --update-mod command");
}
if (manualSteps.Any()) if (manualSteps.Any())
{ {
Console.WriteLine(" Manual changes are required to complete this update:"); Console.WriteLine(" Manual changes are required to complete this update:");

View File

@@ -146,15 +146,17 @@ namespace OpenRA.Mods.Common.UtilityCommands
} }
Console.Write(" Updating system maps... "); Console.Write(" Updating system maps... ");
if (!skipMaps) if (!skipMaps)
{ {
var mapsFailed = false; var mapsFailed = false;
var externalFilenames = new HashSet<string>();
foreach (var package in modData.MapCache.EnumerateMapPackagesWithoutCaching()) foreach (var package in modData.MapCache.EnumerateMapPackagesWithoutCaching())
{ {
try try
{ {
YamlFileSet mapFiles; YamlFileSet mapFiles;
var mapSteps = UpdateUtils.UpdateMap(modData, package, rule, out mapFiles); var mapSteps = UpdateUtils.UpdateMap(modData, package, rule, out mapFiles, externalFilenames);
allFiles.AddRange(mapFiles); allFiles.AddRange(mapFiles);
if (mapSteps.Any()) if (mapSteps.Any())