From f01f8d92b3ccc8f556ad5c6fe69ea3c5b3d7b107 Mon Sep 17 00:00:00 2001 From: RoosterDragon Date: Tue, 9 Dec 2014 23:00:48 +0000 Subject: [PATCH] Cache the initial path layer for faster path search startups. Reinitializing the initial cell info layer for the path search took a fair bit of time. We cache this initial setup so it only has to be done each time the map size changes. A CopyValuesFrom method in CellLayer is provided which copies values between layers by just copying the internal arrays for super speed. This speeds up InitCellInfo 10x. --- OpenRA.Game/Map/CellLayer.cs | 11 +++++++++++ OpenRA.Mods.RA/Move/PathSearch.cs | 25 ++++++++++++++++++++----- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/OpenRA.Game/Map/CellLayer.cs b/OpenRA.Game/Map/CellLayer.cs index a78d803455..4ff0287aa2 100644 --- a/OpenRA.Game/Map/CellLayer.cs +++ b/OpenRA.Game/Map/CellLayer.cs @@ -34,6 +34,17 @@ namespace OpenRA entries = new T[size.Width * size.Height]; } + public void CopyValuesFrom(CellLayer anotherLayer) + { + if (Size != anotherLayer.Size || Shape != anotherLayer.Shape) + throw new ArgumentException( + "layers must have a matching size and shape.", "anotherLayer"); + if (CellEntryChanged != null) + throw new InvalidOperationException( + "Cannot copy values when there are listeners attached to the CellEntryChanged event."); + Array.Copy(anotherLayer.entries, entries, entries.Length); + } + // Resolve an array index from cell coordinates int Index(CPos cell) { diff --git a/OpenRA.Mods.RA/Move/PathSearch.cs b/OpenRA.Mods.RA/Move/PathSearch.cs index f8fe07beaa..46e04bb103 100755 --- a/OpenRA.Mods.RA/Move/PathSearch.cs +++ b/OpenRA.Mods.RA/Move/PathSearch.cs @@ -285,6 +285,8 @@ namespace OpenRA.Mods.RA.Move } static readonly Queue> CellInfoPool = new Queue>(); + static readonly object defaultCellInfoLayerSync = new object(); + static CellLayer defaultCellInfoLayer; static CellLayer GetFromPool() { @@ -301,7 +303,8 @@ namespace OpenRA.Mods.RA.Move CellLayer InitCellInfo() { CellLayer result = null; - var mapSize = new Size(self.World.Map.MapSize.X, self.World.Map.MapSize.Y); + var map = self.World.Map; + var mapSize = new Size(map.MapSize.X, map.MapSize.Y); // HACK: Uses a static cache so that double-ended searches (which have two PathSearch instances) // can implicitly share data. The PathFinder should allocate the CellInfo array and pass it @@ -309,7 +312,7 @@ namespace OpenRA.Mods.RA.Move while (CellInfoPool.Count > 0) { var cellInfo = GetFromPool(); - if (cellInfo.Size != mapSize || cellInfo.Shape != self.World.Map.TileShape) + if (cellInfo.Size != mapSize || cellInfo.Shape != map.TileShape) { Log.Write("debug", "Discarding old pooled CellInfo of wrong size."); continue; @@ -320,10 +323,22 @@ namespace OpenRA.Mods.RA.Move } if (result == null) - result = new CellLayer(self.World.Map); + result = new CellLayer(map); + + lock (defaultCellInfoLayerSync) + { + if (defaultCellInfoLayer == null || + defaultCellInfoLayer.Size != mapSize || + defaultCellInfoLayer.Shape != map.TileShape) + { + defaultCellInfoLayer = new CellLayer(map); + foreach (var cell in map.Cells) + defaultCellInfoLayer[cell] = new CellInfo(int.MaxValue, cell, false); + } + + result.CopyValuesFrom(defaultCellInfoLayer); + } - foreach (var cell in self.World.Map.Cells) - result[cell] = new CellInfo(int.MaxValue, cell, false); return result; }