From 34910cd128e9c97e0a77609f124f57bc97ef3182 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sat, 6 Feb 2016 14:04:02 +0000 Subject: [PATCH] Move map format upgrades to an explicit upgrade rule. --- OpenRA.Game/Map/Map.cs | 68 +------------- OpenRA.Mods.Common/Lint/CheckMapMetadata.cs | 6 +- .../UtilityCommands/UpgradeMapCommand.cs | 3 +- .../UtilityCommands/UpgradeModCommand.cs | 25 ++--- .../UtilityCommands/UpgradeRules.cs | 93 +++++++++++++++++++ 5 files changed, 114 insertions(+), 81 deletions(-) diff --git a/OpenRA.Game/Map/Map.cs b/OpenRA.Game/Map/Map.cs index a896e00751..868fd757ae 100644 --- a/OpenRA.Game/Map/Map.cs +++ b/OpenRA.Game/Map/Map.cs @@ -109,7 +109,7 @@ namespace OpenRA public class Map { - public const int MinimumSupportedMapFormat = 6; + public const int SupportedMapFormat = 8; public const int MaxTilesInCircleRange = 50; public readonly MapGrid Grid; @@ -312,73 +312,9 @@ namespace OpenRA var yaml = new MiniYaml(null, MiniYaml.FromStream(Container.GetStream("map.yaml"), path)); FieldLoader.Load(this, yaml); - // Support for formats 1-3 dropped 2011-02-11. - // Use release-20110207 to convert older maps to format 4 - // Use release-20110511 to convert older maps to format 5 - // Use release-20141029 to convert older maps to format 6 - if (MapFormat < MinimumSupportedMapFormat) + if (MapFormat != SupportedMapFormat) throw new InvalidDataException("Map format {0} is not supported.\n File: {1}".F(MapFormat, path)); - var nd = yaml.ToDictionary(); - - // Format 6 -> 7 combined the Selectable and UseAsShellmap flags into the Class enum - if (MapFormat < 7) - { - MiniYaml useAsShellmap; - if (nd.TryGetValue("UseAsShellmap", out useAsShellmap) && bool.Parse(useAsShellmap.Value)) - Visibility = MapVisibility.Shellmap; - else if (Type == "Mission" || Type == "Campaign") - Visibility = MapVisibility.MissionSelector; - } - - // Format 7 -> 8 replaced normalized HSL triples with rgb(a) hex colors - if (MapFormat < 8) - { - var players = yaml.Nodes.FirstOrDefault(n => n.Key == "Players"); - if (players != null) - { - bool noteHexColors = false; - bool noteColorRamp = false; - foreach (var player in players.Value.Nodes) - { - var colorRampNode = player.Value.Nodes.FirstOrDefault(n => n.Key == "ColorRamp"); - if (colorRampNode != null) - { - Color dummy; - var parts = colorRampNode.Value.Value.Split(','); - if (parts.Length == 3 || parts.Length == 4) - { - // Try to convert old normalized HSL value to a rgb hex color - try - { - HSLColor color = new HSLColor( - (byte)Exts.ParseIntegerInvariant(parts[0].Trim()).Clamp(0, 255), - (byte)Exts.ParseIntegerInvariant(parts[1].Trim()).Clamp(0, 255), - (byte)Exts.ParseIntegerInvariant(parts[2].Trim()).Clamp(0, 255)); - colorRampNode.Value.Value = FieldSaver.FormatValue(color); - noteHexColors = true; - } - catch (Exception) - { - throw new InvalidDataException("Invalid ColorRamp value.\n File: " + path); - } - } - else if (parts.Length != 1 || !HSLColor.TryParseRGB(parts[0], out dummy)) - throw new InvalidDataException("Invalid ColorRamp value.\n File: " + path); - - colorRampNode.Key = "Color"; - noteColorRamp = true; - } - } - - Console.WriteLine("Converted " + path + " to MapFormat 8."); - if (noteHexColors) - Console.WriteLine("ColorRamp is now called Color and uses rgb(a) hex value - rrggbb[aa]."); - else if (noteColorRamp) - Console.WriteLine("ColorRamp is now called Color."); - } - } - SpawnPoints = Exts.Lazy(() => { var spawns = new List(); diff --git a/OpenRA.Mods.Common/Lint/CheckMapMetadata.cs b/OpenRA.Mods.Common/Lint/CheckMapMetadata.cs index 359c6c9eac..3882fdb2b4 100644 --- a/OpenRA.Mods.Common/Lint/CheckMapMetadata.cs +++ b/OpenRA.Mods.Common/Lint/CheckMapMetadata.cs @@ -17,9 +17,9 @@ namespace OpenRA.Mods.Common.Lint { public void Run(Action emitError, Action emitWarning, Map map) { - if (map.MapFormat < Map.MinimumSupportedMapFormat) - emitError("Map format {0} is older than the minimum supported version {1}." - .F(map.MapFormat, Map.MinimumSupportedMapFormat)); + if (map.MapFormat != Map.SupportedMapFormat) + emitError("Map format {0} does not match the supported version {1}." + .F(map.MapFormat, Map.SupportedMapFormat)); if (map.Author == null) emitError("Map does not define a valid author."); diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs index 1be5311942..831e3f8538 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeMapCommand.cs @@ -25,9 +25,10 @@ namespace OpenRA.Mods.Common.UtilityCommands // HACK: The engine code assumes that Game.modData is set. Game.ModData = modData; + UpgradeRules.UpgradeMapFormat(modData, args[1]); + var map = new Map(args[1]); var engineDate = Exts.ParseIntegerInvariant(args[2]); - UpgradeRules.UpgradeWeaponRules(engineDate, ref map.WeaponDefinitions, null, 0); UpgradeRules.UpgradeActorRules(engineDate, ref map.RuleDefinitions, null, 0); UpgradeRules.UpgradePlayers(engineDate, ref map.PlayerDefinitions, null, 0); diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeModCommand.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeModCommand.cs index 1b35b63570..f03f8857b1 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeModCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeModCommand.cs @@ -28,12 +28,12 @@ namespace OpenRA.Mods.Common.UtilityCommands { // HACK: The engine code assumes that Game.modData is set. Game.ModData = modData; - Game.ModData.MapCache.LoadMaps(); + modData.MapCache.LoadMaps(); var engineDate = Exts.ParseIntegerInvariant(args[1]); Console.WriteLine("Processing Rules:"); - foreach (var filename in Game.ModData.Manifest.Rules) + foreach (var filename in modData.Manifest.Rules) { Console.WriteLine("\t" + filename); var yaml = MiniYaml.FromFile(filename); @@ -44,7 +44,7 @@ namespace OpenRA.Mods.Common.UtilityCommands } Console.WriteLine("Processing Weapons:"); - foreach (var filename in Game.ModData.Manifest.Weapons) + foreach (var filename in modData.Manifest.Weapons) { Console.WriteLine("\t" + filename); var yaml = MiniYaml.FromFile(filename); @@ -55,7 +55,7 @@ namespace OpenRA.Mods.Common.UtilityCommands } Console.WriteLine("Processing Tilesets:"); - foreach (var filename in Game.ModData.Manifest.TileSets) + foreach (var filename in modData.Manifest.TileSets) { Console.WriteLine("\t" + filename); var yaml = MiniYaml.FromFile(filename); @@ -66,7 +66,7 @@ namespace OpenRA.Mods.Common.UtilityCommands } Console.WriteLine("Processing Cursors:"); - foreach (var filename in Game.ModData.Manifest.Cursors) + foreach (var filename in modData.Manifest.Cursors) { Console.WriteLine("\t" + filename); var yaml = MiniYaml.FromFile(filename); @@ -77,7 +77,7 @@ namespace OpenRA.Mods.Common.UtilityCommands } Console.WriteLine("Processing Chrome Metrics:"); - foreach (var filename in Game.ModData.Manifest.ChromeMetrics) + foreach (var filename in modData.Manifest.ChromeMetrics) { Console.WriteLine("\t" + filename); var yaml = MiniYaml.FromFile(filename); @@ -88,7 +88,7 @@ namespace OpenRA.Mods.Common.UtilityCommands } Console.WriteLine("Processing Chrome Layout:"); - foreach (var filename in Game.ModData.Manifest.ChromeLayout) + foreach (var filename in modData.Manifest.ChromeLayout) { Console.WriteLine("\t" + filename); var yaml = MiniYaml.FromFile(filename); @@ -99,13 +99,16 @@ namespace OpenRA.Mods.Common.UtilityCommands } Console.WriteLine("Processing Maps:"); - var maps = Game.ModData.MapCache + var mapPaths = modData.MapCache .Where(m => m.Status == MapStatus.Available) - .Select(m => new Map(m.Path)); + .Select(m => m.Path); - foreach (var map in maps) + foreach (var path in mapPaths) { - Console.WriteLine("\t" + map.Path); + Console.WriteLine("\t" + path); + UpgradeRules.UpgradeMapFormat(modData, path); + + var map = new Map(path); UpgradeRules.UpgradeActorRules(engineDate, ref map.RuleDefinitions, null, 0); UpgradeRules.UpgradeWeaponRules(engineDate, ref map.WeaponDefinitions, null, 0); UpgradeRules.UpgradePlayers(engineDate, ref map.PlayerDefinitions, null, 0); diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs index 5a9475ad5e..d770a2755d 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs @@ -12,7 +12,9 @@ using System; using System.Collections.Generic; using System.Drawing; using System.Globalization; +using System.IO; using System.Linq; +using System.Text; using OpenRA.Graphics; using OpenRA.Traits; @@ -3598,5 +3600,96 @@ namespace OpenRA.Mods.Common.UtilityCommands UpgradeActors(engineVersion, ref node.Value.Nodes, node, depth + 1); } } + + internal static void UpgradeMapFormat(ModData modData, string path) + { + using (var package = modData.ModFiles.OpenWritablePackage(path)) + { + if (package == null) + return; + + var yamlStream = package.GetStream("map.yaml"); + if (yamlStream == null) + return; + + var yaml = new MiniYaml(null, MiniYaml.FromStream(yamlStream, path)); + var nd = yaml.ToDictionary(); + var mapFormat = FieldLoader.GetValue("MapFormat", nd["MapFormat"].Value); + if (mapFormat < 6) + throw new InvalidDataException("Map format {0} is not supported.\n File: {1}".F(mapFormat, path)); + + // Nothing to do + if (mapFormat >= 8) + return; + + // Format 6 -> 7 combined the Selectable and UseAsShellmap flags into the Class enum + if (mapFormat < 7) + { + MiniYaml useAsShellmap; + if (nd.TryGetValue("UseAsShellmap", out useAsShellmap) && bool.Parse(useAsShellmap.Value)) + yaml.Nodes.Add(new MiniYamlNode("Visibility", new MiniYaml("Shellmap"))); + else if (nd["Type"].Value == "Mission" || nd["Type"].Value == "Campaign") + yaml.Nodes.Add(new MiniYamlNode("Visibility", new MiniYaml("MissionSelector"))); + } + + // Format 7 -> 8 replaced normalized HSL triples with rgb(a) hex colors + if (mapFormat < 8) + { + var players = yaml.Nodes.FirstOrDefault(n => n.Key == "Players"); + if (players != null) + { + bool noteHexColors = false; + bool noteColorRamp = false; + foreach (var player in players.Value.Nodes) + { + var colorRampNode = player.Value.Nodes.FirstOrDefault(n => n.Key == "ColorRamp"); + if (colorRampNode != null) + { + Color dummy; + var parts = colorRampNode.Value.Value.Split(','); + if (parts.Length == 3 || parts.Length == 4) + { + // Try to convert old normalized HSL value to a rgb hex color + try + { + HSLColor color = new HSLColor( + (byte)Exts.ParseIntegerInvariant(parts[0].Trim()).Clamp(0, 255), + (byte)Exts.ParseIntegerInvariant(parts[1].Trim()).Clamp(0, 255), + (byte)Exts.ParseIntegerInvariant(parts[2].Trim()).Clamp(0, 255)); + colorRampNode.Value.Value = FieldSaver.FormatValue(color); + noteHexColors = true; + } + catch (Exception) + { + throw new InvalidDataException("Invalid ColorRamp value.\n File: " + path); + } + } + else if (parts.Length != 1 || !HSLColor.TryParseRGB(parts[0], out dummy)) + throw new InvalidDataException("Invalid ColorRamp value.\n File: " + path); + + colorRampNode.Key = "Color"; + noteColorRamp = true; + } + } + + Console.WriteLine("Converted " + path + " to MapFormat 8."); + if (noteHexColors) + Console.WriteLine("ColorRamp is now called Color and uses rgb(a) hex value - rrggbb[aa]."); + else if (noteColorRamp) + Console.WriteLine("ColorRamp is now called Color."); + } + } + + var entries = new Dictionary(); + entries.Add("map.yaml", Encoding.UTF8.GetBytes(yaml.Nodes.WriteToString())); + foreach (var file in package.Contents) + { + if (file == "map.yaml") + continue; + + entries.Add(file, package.GetStream(file).ReadAllBytes()); + } + } + } } }