Fix tileset templates to appear in the map editor in their order in YAML.
Fixes regression from 649e7e8c28. When the Templates was changed from a Dictionary to a FrozenDictionary, this caused the items to be reordered. Some code was relying on the previous behaviour where the Dictionary ordering would happen to remain the same as the YAML input.
Fix this by creating a TemplatesInDefinitionOrder which can be used to iterate in the same ordering as given in YAML. Code that depends on the ordering can use this, and other code that does lookups can use the FrozenDictionary.
This commit is contained in:
committed by
Paul Chote
parent
2c0a4f5873
commit
c47ebfbb52
@@ -434,7 +434,7 @@ namespace OpenRA.Mods.Common.MapGenerator
|
||||
/// <summary>Load a named MultiBrush collection from a map's tileset.</summary>
|
||||
public static ImmutableArray<MultiBrush> 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();
|
||||
|
||||
@@ -87,6 +87,8 @@ namespace OpenRA.Mods.Common.Terrain
|
||||
[FieldLoader.Ignore]
|
||||
public readonly FrozenDictionary<ushort, TerrainTemplateInfo> Templates;
|
||||
[FieldLoader.Ignore]
|
||||
public readonly ImmutableArray<TerrainTemplateInfo> TemplatesInDefinitionOrder;
|
||||
[FieldLoader.Ignore]
|
||||
public readonly FrozenDictionary<string, ImmutableArray<MultiBrushInfo>> 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<string> ITemplatedTerrainInfo.EditorTemplateOrder => EditorTemplateOrder;
|
||||
FrozenDictionary<ushort, TerrainTemplateInfo> ITemplatedTerrainInfo.Templates => Templates;
|
||||
ImmutableArray<TerrainTemplateInfo> ITemplatedTerrainInfo.TemplatesInDefinitionOrder => TemplatesInDefinitionOrder;
|
||||
FrozenDictionary<string, ImmutableArray<MultiBrushInfo>> ITemplatedTerrainInfo.MultiBrushCollections => MultiBrushCollections;
|
||||
|
||||
void IDumpSheetsTerrainInfo.DumpSheets(string terrainName, ImmutablePalette palette, ref int sheetCount)
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace OpenRA.Mods.Common.Terrain
|
||||
{
|
||||
ImmutableArray<string> EditorTemplateOrder { get; }
|
||||
FrozenDictionary<ushort, TerrainTemplateInfo> Templates { get; }
|
||||
ImmutableArray<TerrainTemplateInfo> TemplatesInDefinitionOrder { get; }
|
||||
FrozenDictionary<string, ImmutableArray<MultiBrushInfo>> MultiBrushCollections { get; }
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
||||
}
|
||||
|
||||
readonly ITemplatedTerrainInfo terrainInfo;
|
||||
readonly TileSelectorTemplate[] allTemplates;
|
||||
readonly ImmutableArray<TileSelectorTemplate> 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()
|
||||
|
||||
@@ -276,7 +276,7 @@ namespace OpenRA.Mods.D2k.UtilityCommands
|
||||
Map map;
|
||||
Size mapSize;
|
||||
DefaultTerrain terrainInfo;
|
||||
List<TerrainTemplateInfo> tileSetsFromYaml;
|
||||
List<DefaultTerrainTemplateInfo> 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<DefaultTerrainTemplateInfo>()
|
||||
.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<DefaultTerrainTemplateInfo>()
|
||||
.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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user