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.
110 lines
3.4 KiB
C#
110 lines
3.4 KiB
C#
#region Copyright & License Information
|
|
/*
|
|
* Copyright (c) The OpenRA Developers and Contributors
|
|
* This file is part of OpenRA, which is free software. It is made
|
|
* available to you under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation, either version 3 of
|
|
* the License, or (at your option) any later version. For more
|
|
* information, see COPYING.
|
|
*/
|
|
#endregion
|
|
|
|
using System.Collections.Frozen;
|
|
using System.Collections.Immutable;
|
|
using OpenRA.Mods.Common.MapGenerator;
|
|
|
|
namespace OpenRA.Mods.Common.Terrain
|
|
{
|
|
public interface ITemplatedTerrainInfo : ITerrainInfo
|
|
{
|
|
ImmutableArray<string> EditorTemplateOrder { get; }
|
|
FrozenDictionary<ushort, TerrainTemplateInfo> Templates { get; }
|
|
ImmutableArray<TerrainTemplateInfo> TemplatesInDefinitionOrder { get; }
|
|
FrozenDictionary<string, ImmutableArray<MultiBrushInfo>> MultiBrushCollections { get; }
|
|
}
|
|
|
|
public interface ITerrainInfoNotifyMapCreated : ITerrainInfo
|
|
{
|
|
void MapCreated(Map map);
|
|
}
|
|
|
|
public class TerrainTemplateInfo
|
|
{
|
|
public readonly ushort Id;
|
|
public readonly int2 Size;
|
|
public readonly bool PickAny;
|
|
public readonly ImmutableArray<string> Categories;
|
|
|
|
readonly TerrainTileInfo[] tileInfo;
|
|
|
|
public TerrainTemplateInfo(ITerrainInfo terrainInfo, MiniYaml my)
|
|
{
|
|
FieldLoader.Load(this, my);
|
|
|
|
var nodes = my.NodeWithKey("Tiles").Value.Nodes;
|
|
|
|
if (!PickAny)
|
|
{
|
|
tileInfo = new TerrainTileInfo[Size.X * Size.Y];
|
|
foreach (var node in nodes)
|
|
{
|
|
if (!int.TryParse(node.Key, out var key))
|
|
throw new YamlException(
|
|
$"Tileset `{terrainInfo.Id}` template `{Id}` defines a frame `{node.Key}` that is not a valid integer.");
|
|
|
|
if (key < 0 || key >= tileInfo.Length)
|
|
throw new YamlException(
|
|
$"Tileset `{terrainInfo.Id}` template `{Id}` references frame {key}, " +
|
|
$"but only [0..{tileInfo.Length - 1}] are valid for a {Size.X}x{Size.Y} Size template.");
|
|
|
|
tileInfo[key] = LoadTileInfo(terrainInfo, node.Value);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tileInfo = new TerrainTileInfo[nodes.Length];
|
|
|
|
var i = 0;
|
|
foreach (var node in nodes)
|
|
{
|
|
if (!int.TryParse(node.Key, out var key))
|
|
throw new YamlException($"Tileset `{terrainInfo.Id}` template `{Id}` defines a frame `{node.Key}` that is not a valid integer.");
|
|
|
|
if (key != i++)
|
|
throw new YamlException($"Tileset `{terrainInfo.Id}` template `{Id}` is missing a definition for frame {i - 1}.");
|
|
|
|
tileInfo[key] = LoadTileInfo(terrainInfo, node.Value);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual TerrainTileInfo LoadTileInfo(ITerrainInfo terrainInfo, MiniYaml my)
|
|
{
|
|
var tile = new TerrainTileInfo();
|
|
FieldLoader.Load(tile, my);
|
|
|
|
// Terrain type must be converted from a string to an index
|
|
tile.GetType().GetField(nameof(tile.TerrainType)).SetValue(tile, terrainInfo.GetTerrainIndex(my.Value));
|
|
|
|
// Fall back to the terrain-type color if necessary
|
|
var overrideColor = terrainInfo.TerrainTypes[tile.TerrainType].Color;
|
|
if (tile.MinColor == default)
|
|
tile.GetType().GetField(nameof(tile.MinColor)).SetValue(tile, overrideColor);
|
|
|
|
if (tile.MaxColor == default)
|
|
tile.GetType().GetField(nameof(tile.MaxColor)).SetValue(tile, overrideColor);
|
|
|
|
return tile;
|
|
}
|
|
|
|
public TerrainTileInfo this[int index] => tileInfo[index];
|
|
|
|
public bool Contains(int index)
|
|
{
|
|
return index >= 0 && index < tileInfo.Length;
|
|
}
|
|
|
|
public int TilesCount => tileInfo.Length;
|
|
}
|
|
}
|