Transparently cache results of GetTerrainIndex in Map.
This method performs an expensive calculation and is called often during pathfinding. We create a cache of the terrain indicies for the map to vastly reduce the cost.
This commit is contained in:
@@ -246,6 +246,7 @@ namespace OpenRA
|
||||
[FieldLoader.Ignore] public Lazy<CellLayer<byte>> MapHeight;
|
||||
|
||||
[FieldLoader.Ignore] public CellLayer<byte> CustomTerrain;
|
||||
[FieldLoader.Ignore] CellLayer<short> cachedTerrainIndexes;
|
||||
|
||||
[FieldLoader.Ignore] bool initializedCellProjection;
|
||||
[FieldLoader.Ignore] CellLayer<PPos[]> cellProjection;
|
||||
@@ -951,9 +952,32 @@ namespace OpenRA
|
||||
|
||||
public byte GetTerrainIndex(CPos cell)
|
||||
{
|
||||
const short InvalidCachedTerrainIndex = -1;
|
||||
|
||||
// Lazily initialize a cache for terrain indexes.
|
||||
if (cachedTerrainIndexes == null)
|
||||
{
|
||||
cachedTerrainIndexes = new CellLayer<short>(this);
|
||||
cachedTerrainIndexes.Clear(InvalidCachedTerrainIndex);
|
||||
|
||||
// Invalidate the entry for a cell if anything could cause the terrain index to change.
|
||||
Action<CPos> invalidateTerrainIndex = c => cachedTerrainIndexes[c] = InvalidCachedTerrainIndex;
|
||||
CustomTerrain.CellEntryChanged += invalidateTerrainIndex;
|
||||
MapTiles.Value.CellEntryChanged += invalidateTerrainIndex;
|
||||
}
|
||||
|
||||
var uv = cell.ToMPos(this);
|
||||
var terrainIndex = cachedTerrainIndexes[uv];
|
||||
|
||||
// Cache terrain indexes per cell on demand.
|
||||
if (terrainIndex == InvalidCachedTerrainIndex)
|
||||
{
|
||||
var custom = CustomTerrain[uv];
|
||||
return custom != byte.MaxValue ? custom : cachedTileSet.Value.GetTerrainIndex(MapTiles.Value[uv]);
|
||||
terrainIndex = cachedTerrainIndexes[uv] =
|
||||
custom != byte.MaxValue ? custom : cachedTileSet.Value.GetTerrainIndex(MapTiles.Value[uv]);
|
||||
}
|
||||
|
||||
return (byte)terrainIndex;
|
||||
}
|
||||
|
||||
public TerrainTypeInfo GetTerrainInfo(CPos cell)
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace OpenRA
|
||||
public readonly bool PickAny;
|
||||
public readonly string Category;
|
||||
|
||||
TerrainTileInfo[] tileInfo;
|
||||
readonly TerrainTileInfo[] tileInfo;
|
||||
|
||||
public TerrainTemplateInfo(ushort id, string[] images, int2 size, byte[] tiles)
|
||||
{
|
||||
@@ -177,7 +177,7 @@ namespace OpenRA
|
||||
public readonly bool IgnoreTileSpriteOffsets;
|
||||
|
||||
[FieldLoader.Ignore]
|
||||
public readonly Dictionary<ushort, TerrainTemplateInfo> Templates = new Dictionary<ushort, TerrainTemplateInfo>();
|
||||
public readonly IReadOnlyDictionary<ushort, TerrainTemplateInfo> Templates;
|
||||
|
||||
[FieldLoader.Ignore]
|
||||
public readonly TerrainTypeInfo[] TerrainInfo;
|
||||
@@ -217,7 +217,7 @@ namespace OpenRA
|
||||
|
||||
// Templates
|
||||
Templates = yaml["Templates"].ToDictionary().Values
|
||||
.Select(y => new TerrainTemplateInfo(this, y)).ToDictionary(t => t.Id);
|
||||
.Select(y => new TerrainTemplateInfo(this, y)).ToDictionary(t => t.Id).AsReadOnly();
|
||||
}
|
||||
|
||||
public TileSet(string name, string id, string palette, TerrainTypeInfo[] terrainInfo)
|
||||
|
||||
Reference in New Issue
Block a user