diff --git a/OpenRA.Game/Map/ProjectedCellLayer.cs b/OpenRA.Game/Map/ProjectedCellLayer.cs index c95bd1c74e..f3482fba20 100644 --- a/OpenRA.Game/Map/ProjectedCellLayer.cs +++ b/OpenRA.Game/Map/ProjectedCellLayer.cs @@ -15,6 +15,8 @@ namespace OpenRA { public sealed class ProjectedCellLayer : CellLayerBase { + public int MaxIndex { get { return Size.Width * Size.Height; } } + public ProjectedCellLayer(Map map) : base(map) { } @@ -27,6 +29,11 @@ namespace OpenRA return uv.V * Size.Width + uv.U; } + public PPos PPosFromIndex(int index) + { + return new PPos(index % Size.Width, index / Size.Width); + } + public T this[int index] { get diff --git a/OpenRA.Game/Traits/Player/Shroud.cs b/OpenRA.Game/Traits/Player/Shroud.cs index c64b59d14c..aa4e44cf5e 100644 --- a/OpenRA.Game/Traits/Player/Shroud.cs +++ b/OpenRA.Game/Traits/Player/Shroud.cs @@ -165,9 +165,14 @@ namespace OpenRA.Traits if (OnShroudChanged == null) return; - foreach (var puv in map.ProjectedCells) + // PERF: Parts of this loop are very hot. + // We loop over the direct index that represents the PPos in + // the ProjectedCellLayers, converting to a PPos only if + // it is needed (which is the uncommon case.) + var maxIndex = touched.MaxIndex; + for (var index = 0; index < maxIndex; index++) { - var index = touched.Index(puv); + // PERF: Most cells are not touched if (!touched[index]) continue; @@ -187,11 +192,14 @@ namespace OpenRA.Traits } } + // PERF: Most cells are unchanged var oldResolvedType = resolvedType[index]; if (type != oldResolvedType) { resolvedType[index] = type; - OnShroudChanged(puv); + var uv = touched.PPosFromIndex(index); + if (map.Contains(uv)) + OnShroudChanged(uv); } }