From 8ea1da10466547895b5d9ab5fda3d3e40d41fbce Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Mon, 19 Mar 2018 06:00:26 +0000 Subject: [PATCH] Apply map upgrade rules without instantiating the Map object. This avoids a crash that stops the maps from being updated when the base mod ruleset is not valid (e.g. a trait is missing a FieldLoader.Required property). This also significantly improves the upgrade performance. --- OpenRA.Game/Map/MapCache.cs | 12 +++-- .../UtilityCommands/UpgradeMapCommand.cs | 54 ++++++++++++++----- .../UtilityCommands/UpgradeModCommand.cs | 8 +-- 3 files changed, 55 insertions(+), 19 deletions(-) diff --git a/OpenRA.Game/Map/MapCache.cs b/OpenRA.Game/Map/MapCache.cs index 195d7602ba..1bf040f7fc 100644 --- a/OpenRA.Game/Map/MapCache.cs +++ b/OpenRA.Game/Map/MapCache.cs @@ -122,7 +122,7 @@ namespace OpenRA } } - public IEnumerable EnumerateMapsWithoutCaching(MapClassification classification = MapClassification.System) + public IEnumerable EnumerateMapPackagesWithoutCaching(MapClassification classification = MapClassification.System) { // Utility mod that does not support maps if (!modData.Manifest.Contains()) @@ -155,14 +155,20 @@ namespace OpenRA { foreach (var map in package.Contents) { - var mapPackage = package.OpenPackage(map, modData.ModFiles); + var mapPackage = package.OpenPackage(map, modData.ModFiles) as IReadWritePackage; if (mapPackage != null) - yield return new Map(modData, mapPackage); + yield return mapPackage; } } } } + public IEnumerable EnumerateMapsWithoutCaching(MapClassification classification = MapClassification.System) + { + foreach (var mapPackage in EnumerateMapPackagesWithoutCaching(classification)) + yield return new Map(modData, mapPackage); + } + public void QueryRemoteMapDetails(string repositoryUrl, IEnumerable uids, Action mapDetailsReceived = null, Action queryFailed = null) { var maps = uids.Distinct() diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs index 2ef1a06081..2858b8402d 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs @@ -12,6 +12,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; using OpenRA.FileSystem; @@ -28,7 +29,16 @@ namespace OpenRA.Mods.Common.UtilityCommands delegate void UpgradeAction(ModData modData, int engineVersion, ref List nodes, MiniYamlNode parent, int depth); - static void ProcessYaml(ModData modData, Map map, MiniYaml yaml, int engineDate, UpgradeAction processYaml) + static Stream Open(string filename, IReadOnlyPackage package, IReadOnlyFileSystem fallback) + { + // Explicit package paths never refer to a map + if (!filename.Contains("|") && package.Contains(filename)) + return package.GetStream(filename); + + return fallback.Open(filename); + } + + static void ProcessYaml(ModData modData, IReadOnlyPackage package, MiniYaml yaml, int engineDate, UpgradeAction processYaml) { if (yaml == null) return; @@ -38,16 +48,16 @@ namespace OpenRA.Mods.Common.UtilityCommands var files = FieldLoader.GetValue("value", yaml.Value); foreach (var filename in files) { - var fileNodes = MiniYaml.FromStream(map.Open(filename), filename); + var fileNodes = MiniYaml.FromStream(Open(filename, package, modData.DefaultFileSystem), filename); processYaml(modData, engineDate, ref fileNodes, null, 0); // HACK: Obtain the writable save path using knowledge of the underlying filesystem workings var packagePath = filename; - var package = map.Package; + var p = package; if (filename.Contains("|")) - modData.DefaultFileSystem.TryGetPackageContaining(filename, out package, out packagePath); + modData.DefaultFileSystem.TryGetPackageContaining(filename, out p, out packagePath); - ((IReadWritePackage)package).Update(packagePath, Encoding.ASCII.GetBytes(fileNodes.WriteToString())); + ((IReadWritePackage)p).Update(packagePath, Encoding.ASCII.GetBytes(fileNodes.WriteToString())); } } @@ -65,13 +75,33 @@ namespace OpenRA.Mods.Common.UtilityCommands return; } - var map = new Map(modData, package); - ProcessYaml(modData, map, map.WeaponDefinitions, engineDate, UpgradeRules.UpgradeWeaponRules); - ProcessYaml(modData, map, map.RuleDefinitions, engineDate, UpgradeRules.UpgradeActorRules); - ProcessYaml(modData, map, map.SequenceDefinitions, engineDate, UpgradeRules.UpgradeSequences); - UpgradeRules.UpgradePlayers(modData, engineDate, ref map.PlayerDefinitions, null, 0); - UpgradeRules.UpgradeActors(modData, engineDate, ref map.ActorDefinitions, null, 0); - map.Save(package); + var mapStream = package.GetStream("map.yaml"); + if (mapStream == null) + return; + + var yaml = new MiniYaml(null, MiniYaml.FromStream(mapStream, package.Name)); + + var rules = yaml.Nodes.FirstOrDefault(n => n.Key == "Rules"); + if (rules != null) + ProcessYaml(modData, package, rules.Value, engineDate, UpgradeRules.UpgradeActorRules); + + var weapons = yaml.Nodes.FirstOrDefault(n => n.Key == "Weapons"); + if (weapons != null) + ProcessYaml(modData, package, weapons.Value, engineDate, UpgradeRules.UpgradeWeaponRules); + + var sequences = yaml.Nodes.FirstOrDefault(n => n.Key == "Sequences"); + if (sequences != null) + ProcessYaml(modData, package, sequences.Value, engineDate, UpgradeRules.UpgradeSequences); + + var players = yaml.Nodes.FirstOrDefault(n => n.Key == "Players"); + if (players != null) + UpgradeRules.UpgradePlayers(modData, engineDate, ref players.Value.Nodes, null, 0); + + var actors = yaml.Nodes.FirstOrDefault(n => n.Key == "Actors"); + if (actors != null) + UpgradeRules.UpgradeActors(modData, engineDate, ref actors.Value.Nodes, null, 0); + + package.Update("map.yaml", Encoding.UTF8.GetBytes(yaml.Nodes.WriteToString())); } [Desc("MAP", "OLDENGINE", "Upgrade map rules to the latest engine version.")] diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeModCommand.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeModCommand.cs index f682a150df..49fb281ce5 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeModCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeModCommand.cs @@ -77,16 +77,16 @@ namespace OpenRA.Mods.Common.UtilityCommands // The map cache won't be valid if there was a map format upgrade, so walk the map packages manually // Only upgrade system maps - user maps must be updated manually using --upgrade-map Console.WriteLine("Processing System Maps:"); - foreach (var map in modData.MapCache.EnumerateMapsWithoutCaching()) + foreach (var package in modData.MapCache.EnumerateMapPackagesWithoutCaching()) { try { - Console.WriteLine(map.Package.Name); - UpgradeMapCommand.UpgradeMap(modData, (IReadWritePackage)map.Package, engineDate); + Console.WriteLine(package.Name); + UpgradeMapCommand.UpgradeMap(modData, package, engineDate); } catch (Exception e) { - Console.WriteLine("Failed to upgrade map {0}", map); + Console.WriteLine("Failed to upgrade map {0}", package.Name); Console.WriteLine("Error was: {0}", e.ToString()); } }