diff --git a/OpenRA.Mods.Common/MapGenerator/MultiBrush.cs b/OpenRA.Mods.Common/MapGenerator/MultiBrush.cs index b4be1beb9d..7376f22a3a 100644 --- a/OpenRA.Mods.Common/MapGenerator/MultiBrush.cs +++ b/OpenRA.Mods.Common/MapGenerator/MultiBrush.cs @@ -434,7 +434,7 @@ namespace OpenRA.Mods.Common.MapGenerator /// Load a named MultiBrush collection from a map's tileset. public static ImmutableArray LoadCollection(Map map, string name) { - var templatedTerrainInfo = map.Rules.TerrainInfo as ITemplatedTerrainInfo; + var templatedTerrainInfo = (ITemplatedTerrainInfo)map.Rules.TerrainInfo; return templatedTerrainInfo.MultiBrushCollections[name] .Select(info => new MultiBrush(map, info)) .ToImmutableArray(); diff --git a/OpenRA.Mods.Common/Terrain/DefaultTerrain.cs b/OpenRA.Mods.Common/Terrain/DefaultTerrain.cs index 5142be3eba..92b093e70a 100644 --- a/OpenRA.Mods.Common/Terrain/DefaultTerrain.cs +++ b/OpenRA.Mods.Common/Terrain/DefaultTerrain.cs @@ -87,6 +87,8 @@ namespace OpenRA.Mods.Common.Terrain [FieldLoader.Ignore] public readonly FrozenDictionary Templates; [FieldLoader.Ignore] + public readonly ImmutableArray TemplatesInDefinitionOrder; + [FieldLoader.Ignore] public readonly FrozenDictionary> MultiBrushCollections; [FieldLoader.Ignore] @@ -125,10 +127,11 @@ namespace OpenRA.Mods.Common.Terrain defaultWalkableTerrainIndex = GetTerrainIndex("Clear"); // Templates - Templates = yaml["Templates"].ToDictionary().Values - .Select(y => (TerrainTemplateInfo)new DefaultTerrainTemplateInfo(this, y)) - .ToDictionary(t => t.Id) - .ToFrozenDictionary(); + TemplatesInDefinitionOrder = yaml["Templates"].Nodes + .Select(n => (TerrainTemplateInfo)new DefaultTerrainTemplateInfo(this, n.Value)) + .ToImmutableArray(); + Templates = TemplatesInDefinitionOrder + .ToFrozenDictionary(t => t.Id); MultiBrushCollections = yaml.TryGetValue("MultiBrushCollections", out var collectionDefinitions) @@ -187,10 +190,11 @@ namespace OpenRA.Mods.Common.Terrain float ITerrainInfo.MinHeightColorBrightness => MinHeightColorBrightness; float ITerrainInfo.MaxHeightColorBrightness => MaxHeightColorBrightness; - TerrainTile ITerrainInfo.DefaultTerrainTile => new(Templates.First().Key, 0); + TerrainTile ITerrainInfo.DefaultTerrainTile => new(TemplatesInDefinitionOrder[0].Id, 0); ImmutableArray ITemplatedTerrainInfo.EditorTemplateOrder => EditorTemplateOrder; FrozenDictionary ITemplatedTerrainInfo.Templates => Templates; + ImmutableArray ITemplatedTerrainInfo.TemplatesInDefinitionOrder => TemplatesInDefinitionOrder; FrozenDictionary> ITemplatedTerrainInfo.MultiBrushCollections => MultiBrushCollections; void IDumpSheetsTerrainInfo.DumpSheets(string terrainName, ImmutablePalette palette, ref int sheetCount) diff --git a/OpenRA.Mods.Common/Terrain/TerrainInfo.cs b/OpenRA.Mods.Common/Terrain/TerrainInfo.cs index fb969668d0..3d57a02b03 100644 --- a/OpenRA.Mods.Common/Terrain/TerrainInfo.cs +++ b/OpenRA.Mods.Common/Terrain/TerrainInfo.cs @@ -19,6 +19,7 @@ namespace OpenRA.Mods.Common.Terrain { ImmutableArray EditorTemplateOrder { get; } FrozenDictionary Templates { get; } + ImmutableArray TemplatesInDefinitionOrder { get; } FrozenDictionary> MultiBrushCollections { get; } } diff --git a/OpenRA.Mods.Common/Traits/World/TilingPathTool.cs b/OpenRA.Mods.Common/Traits/World/TilingPathTool.cs index 4c986a6b3e..3f2726fb0b 100644 --- a/OpenRA.Mods.Common/Traits/World/TilingPathTool.cs +++ b/OpenRA.Mods.Common/Traits/World/TilingPathTool.cs @@ -341,7 +341,7 @@ namespace OpenRA.Mods.Common.Traits World = self.World; TraitInfo = info; - var templatedTerrainInfo = World.Map.Rules.TerrainInfo as ITemplatedTerrainInfo; + var templatedTerrainInfo = (ITemplatedTerrainInfo)World.Map.Rules.TerrainInfo; SegmentedBrushes = templatedTerrainInfo.MultiBrushCollections.Keys .Order() diff --git a/OpenRA.Mods.Common/Widgets/Logic/Editor/TileSelectorLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Editor/TileSelectorLogic.cs index 1a5ab98701..67cf6790b0 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Editor/TileSelectorLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Editor/TileSelectorLogic.cs @@ -43,7 +43,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic } readonly ITemplatedTerrainInfo terrainInfo; - readonly TileSelectorTemplate[] allTemplates; + readonly ImmutableArray allTemplates; [ObjectCreator.UseCtor] public TileSelectorLogic(Widget widget, ModData modData, World world, WorldRenderer worldRenderer) @@ -53,7 +53,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic if (terrainInfo == null) throw new InvalidDataException("TileSelectorLogic requires a template-based tileset."); - allTemplates = terrainInfo.Templates.Values.Select(t => new TileSelectorTemplate(t)).ToArray(); + allTemplates = terrainInfo.TemplatesInDefinitionOrder.Select(t => new TileSelectorTemplate(t)).ToImmutableArray(); allCategories = allTemplates.SelectMany(t => t.Categories) .Distinct() diff --git a/OpenRA.Mods.D2k/UtilityCommands/D2kMapImporter.cs b/OpenRA.Mods.D2k/UtilityCommands/D2kMapImporter.cs index a285249f53..189b2d37a9 100644 --- a/OpenRA.Mods.D2k/UtilityCommands/D2kMapImporter.cs +++ b/OpenRA.Mods.D2k/UtilityCommands/D2kMapImporter.cs @@ -276,7 +276,7 @@ namespace OpenRA.Mods.D2k.UtilityCommands Map map; Size mapSize; DefaultTerrain terrainInfo; - List tileSetsFromYaml; + List tileSetsFromYaml; int playerCount; D2kMapImporter(string filename, string tileset, Ruleset rules) @@ -338,11 +338,10 @@ namespace OpenRA.Mods.D2k.UtilityCommands // Get all templates from the tileset YAML file that have at least one frame and an Image property corresponding to the requested tileset // Each frame is a tile from the Dune 2000 tileset files, with the Frame ID being the index of the tile in the original file - tileSetsFromYaml = terrainInfo.Templates.Where(t => - { - var templateInfo = (DefaultTerrainTemplateInfo)t.Value; - return templateInfo.Frames != null && string.Equals(templateInfo.Images[0], tilesetName, StringComparison.InvariantCultureIgnoreCase); - }).Select(ts => ts.Value).ToList(); + tileSetsFromYaml = terrainInfo.TemplatesInDefinitionOrder + .Cast() + .Where(templateInfo => templateInfo.Frames != null && string.Equals(templateInfo.Images[0], tilesetName, StringComparison.InvariantCultureIgnoreCase)) + .ToList(); var players = new MapPlayers(map.Rules, playerCount); map.PlayerDefinitions = players.ToMiniYaml(); @@ -505,16 +504,14 @@ namespace OpenRA.Mods.D2k.UtilityCommands } // Get the first tileset template that contains the Frame ID of the original map's tile with the requested index - var template = tileSetsFromYaml.FirstOrDefault(x => ((DefaultTerrainTemplateInfo)x).Frames.Contains(tileIndex)); + var template = tileSetsFromYaml.FirstOrDefault(x => x.Frames.Contains(tileIndex)); // HACK: The arrakis.yaml tileset file seems to be missing some tiles, so just get a replacement for them // Also used for duplicate tiles that are taken from only tileset // Just get a template that contains a tile with the same ID as requested - template ??= terrainInfo.Templates.FirstOrDefault(t => - { - var templateInfo = (DefaultTerrainTemplateInfo)t.Value; - return templateInfo.Frames != null && templateInfo.Frames.Contains(tileIndex); - }).Value; + template ??= terrainInfo.TemplatesInDefinitionOrder + .Cast() + .FirstOrDefault(templateInfo => templateInfo.Frames != null && templateInfo.Frames.Contains(tileIndex)); if (template == null) { @@ -525,7 +522,7 @@ namespace OpenRA.Mods.D2k.UtilityCommands } var templateIndex = template.Id; - var frameIndex = ((DefaultTerrainTemplateInfo)template).Frames.IndexOf(tileIndex); + var frameIndex = template.Frames.IndexOf(tileIndex); return new TerrainTile(templateIndex, (byte)((frameIndex == -1) ? 0 : frameIndex)); }