diff --git a/OpenRA.Game/Map/Map.cs b/OpenRA.Game/Map/Map.cs index 6a61deec2eb0..dcb4b5eb459f 100644 --- a/OpenRA.Game/Map/Map.cs +++ b/OpenRA.Game/Map/Map.cs @@ -15,6 +15,7 @@ using System.Linq; using System.Reflection; using System.Text; +using System.Text.RegularExpressions; using OpenRA.FileFormats; using OpenRA.FileSystem; using OpenRA.Graphics; @@ -152,6 +153,7 @@ public void Serialize(Map map, List nodes) public class Map : IReadOnlyFileSystem { public const int SupportedMapFormat = 11; + public const int CurrentMapFormat = 12; /// Defines the order of the fields in map.yaml static readonly MapField[] YamlFields = @@ -252,7 +254,7 @@ public class Map : IReadOnlyFileSystem internal Translation Translation; - public static string ComputeUID(IReadOnlyPackage package) + public static string ComputeUID(IReadOnlyPackage package, int format) { // UID is calculated by taking an SHA1 of the yaml and binary data var requiredFiles = new[] { "map.yaml", "map.bin" }; @@ -265,7 +267,7 @@ public static string ComputeUID(IReadOnlyPackage package) try { foreach (var filename in contents) - if (filename.EndsWith(".yaml") || filename.EndsWith(".bin") || filename.EndsWith(".lua")) + if (filename.EndsWith(".yaml") || filename.EndsWith(".bin") || filename.EndsWith(".lua") || (format >= 12 && filename == "map.png")) streams.Add(package.GetStream(filename)); // Take the SHA1 @@ -285,6 +287,26 @@ public static string ComputeUID(IReadOnlyPackage package) } } + // PERF This is a way to get MapFormat without expensive yaml parsing + public static int GetMapFormat(IReadOnlyPackage p) + { + var result = ""; + foreach (var a in p.GetStream("map.yaml").ReadAllLines()) + { + var search = Regex.Match(a, "MapFormat: (.?\\d)"); + if (search.Success && search.Groups.Count > 0) + { + result = search.Groups[1].Value; + break; + } + } + + if (result == "") + throw new InvalidDataException($"Does not contain MapFormat"); + + return Convert.ToInt32(result); + } + /// /// Initializes a new map created by the editor or importer. /// The map will not receive a valid UID until after it has been saved and reloaded. @@ -332,7 +354,7 @@ public Map(ModData modData, IReadOnlyPackage package) foreach (var field in YamlFields) field.Deserialize(this, yaml.Nodes); - if (MapFormat != SupportedMapFormat) + if (MapFormat < SupportedMapFormat) throw new InvalidDataException($"Map format {MapFormat} is not supported.\n File: {package.Name}"); PlayerDefinitions = MiniYaml.NodesOrEmpty(yaml, "Players"); @@ -400,7 +422,7 @@ public Map(ModData modData, IReadOnlyPackage package) PostInit(); - Uid = ComputeUID(Package); + Uid = ComputeUID(Package, MapFormat); } void PostInit() @@ -587,7 +609,7 @@ PPos[] ProjectCellInner(MPos uv) public void Save(IReadWritePackage toPackage) { - MapFormat = SupportedMapFormat; + MapFormat = CurrentMapFormat; var root = new List(); foreach (var field in YamlFields) @@ -612,7 +634,7 @@ public void Save(IReadWritePackage toPackage) Package = toPackage; // Update UID to match the newly saved data - Uid = ComputeUID(toPackage); + Uid = ComputeUID(toPackage, MapFormat); } public byte[] SaveBinaryData() diff --git a/OpenRA.Game/Map/MapCache.cs b/OpenRA.Game/Map/MapCache.cs index c6f41ebabfc1..9b4ef34cb34f 100644 --- a/OpenRA.Game/Map/MapCache.cs +++ b/OpenRA.Game/Map/MapCache.cs @@ -101,7 +101,7 @@ public void LoadMaps() if (mapPackage == null) continue; - var uid = Map.ComputeUID(mapPackage); + var uid = Map.ComputeUID(mapPackage, Map.GetMapFormat(mapPackage)); previews[uid].UpdateFromMap(mapPackage, kv.Key, kv.Value, modData.Manifest.MapCompatibility, mapGrid.Type); } } diff --git a/OpenRA.Game/Map/MapPreview.cs b/OpenRA.Game/Map/MapPreview.cs index 38c99e78b75f..2226af549157 100644 --- a/OpenRA.Game/Map/MapPreview.cs +++ b/OpenRA.Game/Map/MapPreview.cs @@ -323,7 +323,7 @@ public void UpdateFromMap(IReadOnlyPackage p, IReadOnlyPackage parent, MapClassi if (yaml.TryGetValue("MapFormat", out var temp)) { var format = FieldLoader.GetValue("MapFormat", temp.Value); - if (format != Map.SupportedMapFormat) + if (format < Map.SupportedMapFormat) throw new InvalidDataException($"Map format {format} is not supported."); } diff --git a/OpenRA.Mods.Common/Lint/CheckMapMetadata.cs b/OpenRA.Mods.Common/Lint/CheckMapMetadata.cs index 9cfd157babf4..66d4291e8178 100644 --- a/OpenRA.Mods.Common/Lint/CheckMapMetadata.cs +++ b/OpenRA.Mods.Common/Lint/CheckMapMetadata.cs @@ -29,8 +29,8 @@ void ILintServerMapPass.Run(Action emitError, Action emitWarning void Run(Action emitError, int mapFormat, string author, string title, string[] categories) { - if (mapFormat != Map.SupportedMapFormat) - emitError($"Map format {mapFormat} does not match the supported version {Map.SupportedMapFormat}."); + if (mapFormat < Map.SupportedMapFormat) + emitError($"Map format {mapFormat} does not match the supported version {Map.CurrentMapFormat}."); if (author == null) emitError("Map does not define a valid author."); diff --git a/OpenRA.Mods.Common/UtilityCommands/GetMapHashCommand.cs b/OpenRA.Mods.Common/UtilityCommands/GetMapHashCommand.cs index 3981e264c606..1313a5113c76 100644 --- a/OpenRA.Mods.Common/UtilityCommands/GetMapHashCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/GetMapHashCommand.cs @@ -27,7 +27,7 @@ bool IUtilityCommand.ValidateArguments(string[] args) void IUtilityCommand.Run(Utility utility, string[] args) { using (var package = new Folder(Platform.EngineDir).OpenPackage(args[1], utility.ModData.ModFiles)) - Console.WriteLine(Map.ComputeUID(package)); + Console.WriteLine(Map.ComputeUID(package, Map.GetMapFormat(package))); } } }