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 Lazy<CellLayer<byte>> MapHeight;
|
||||||
|
|
||||||
[FieldLoader.Ignore] public CellLayer<byte> CustomTerrain;
|
[FieldLoader.Ignore] public CellLayer<byte> CustomTerrain;
|
||||||
|
[FieldLoader.Ignore] CellLayer<short> cachedTerrainIndexes;
|
||||||
|
|
||||||
[FieldLoader.Ignore] bool initializedCellProjection;
|
[FieldLoader.Ignore] bool initializedCellProjection;
|
||||||
[FieldLoader.Ignore] CellLayer<PPos[]> cellProjection;
|
[FieldLoader.Ignore] CellLayer<PPos[]> cellProjection;
|
||||||
@@ -951,9 +952,32 @@ namespace OpenRA
|
|||||||
|
|
||||||
public byte GetTerrainIndex(CPos cell)
|
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 uv = cell.ToMPos(this);
|
||||||
var custom = CustomTerrain[uv];
|
var terrainIndex = cachedTerrainIndexes[uv];
|
||||||
return custom != byte.MaxValue ? custom : cachedTileSet.Value.GetTerrainIndex(MapTiles.Value[uv]);
|
|
||||||
|
// Cache terrain indexes per cell on demand.
|
||||||
|
if (terrainIndex == InvalidCachedTerrainIndex)
|
||||||
|
{
|
||||||
|
var custom = CustomTerrain[uv];
|
||||||
|
terrainIndex = cachedTerrainIndexes[uv] =
|
||||||
|
custom != byte.MaxValue ? custom : cachedTileSet.Value.GetTerrainIndex(MapTiles.Value[uv]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (byte)terrainIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TerrainTypeInfo GetTerrainInfo(CPos cell)
|
public TerrainTypeInfo GetTerrainInfo(CPos cell)
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ namespace OpenRA
|
|||||||
public readonly bool PickAny;
|
public readonly bool PickAny;
|
||||||
public readonly string Category;
|
public readonly string Category;
|
||||||
|
|
||||||
TerrainTileInfo[] tileInfo;
|
readonly TerrainTileInfo[] tileInfo;
|
||||||
|
|
||||||
public TerrainTemplateInfo(ushort id, string[] images, int2 size, byte[] tiles)
|
public TerrainTemplateInfo(ushort id, string[] images, int2 size, byte[] tiles)
|
||||||
{
|
{
|
||||||
@@ -177,7 +177,7 @@ namespace OpenRA
|
|||||||
public readonly bool IgnoreTileSpriteOffsets;
|
public readonly bool IgnoreTileSpriteOffsets;
|
||||||
|
|
||||||
[FieldLoader.Ignore]
|
[FieldLoader.Ignore]
|
||||||
public readonly Dictionary<ushort, TerrainTemplateInfo> Templates = new Dictionary<ushort, TerrainTemplateInfo>();
|
public readonly IReadOnlyDictionary<ushort, TerrainTemplateInfo> Templates;
|
||||||
|
|
||||||
[FieldLoader.Ignore]
|
[FieldLoader.Ignore]
|
||||||
public readonly TerrainTypeInfo[] TerrainInfo;
|
public readonly TerrainTypeInfo[] TerrainInfo;
|
||||||
@@ -217,7 +217,7 @@ namespace OpenRA
|
|||||||
|
|
||||||
// Templates
|
// Templates
|
||||||
Templates = yaml["Templates"].ToDictionary().Values
|
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)
|
public TileSet(string name, string id, string palette, TerrainTypeInfo[] terrainInfo)
|
||||||
|
|||||||
Reference in New Issue
Block a user