From c7f03d00ff6749ed00942d2daf0202028d328050 Mon Sep 17 00:00:00 2001 From: ikpil Date: Wed, 22 May 2024 01:33:15 +0900 Subject: [PATCH] Changed `Dictionary>` to `DtMeshTile[]` to optimize memory usage --- CHANGELOG.md | 1 + src/DotRecast.Detour/DtMeshTile.cs | 1 + src/DotRecast.Detour/DtNavMesh.cs | 168 +++++++++++------- src/DotRecast.Detour/DtNavMeshQuery.cs | 32 ++-- .../Tools/RcTileTool.cs | 4 +- .../Io/MeshSetReaderTest.cs | 75 +++++--- .../Io/MeshSetReaderWriterTest.cs | 24 ++- .../TempObstaclesTest.cs | 29 ++- 8 files changed, 205 insertions(+), 129 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f8fdef..affc210 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Changed `PolyQueryInvoker` to `DtActionPolyQuery` - Changed `DtTileCacheBuilder` to a static class - Changed `DtTileCacheLayerHeaderReader` to a static class +- Changed `Dictionary>` to `DtMeshTile[]` to optimize memory usage ### Removed - Nothing diff --git a/src/DotRecast.Detour/DtMeshTile.cs b/src/DotRecast.Detour/DtMeshTile.cs index 3f56287..b285b24 100644 --- a/src/DotRecast.Detour/DtMeshTile.cs +++ b/src/DotRecast.Detour/DtMeshTile.cs @@ -33,6 +33,7 @@ namespace DotRecast.Detour public DtLink[] links; // The tile links. [Size: dtMeshHeader::maxLinkCount] public int flags; //< Tile flags. (See: #dtTileFlags) + public DtMeshTile next; //< The next free tile, or the next tile in the spatial grid. public DtMeshTile(int index) { diff --git a/src/DotRecast.Detour/DtNavMesh.cs b/src/DotRecast.Detour/DtNavMesh.cs index d3f2bf6..5a1a9ac 100644 --- a/src/DotRecast.Detour/DtNavMesh.cs +++ b/src/DotRecast.Detour/DtNavMesh.cs @@ -39,8 +39,8 @@ namespace DotRecast.Detour private int m_tileLutSize; //< Tile hash lookup size (must be pot). private int m_tileLutMask; // < Tile hash lookup mask. - private Dictionary> m_posLookup; //< Tile hash lookup. - private LinkedList m_nextFree; //< Freelist of tiles. + private DtMeshTile[] m_posLookup; //< Tile hash lookup. + private DtMeshTile m_nextFree; //< Freelist of tiles. private DtMeshTile[] m_tiles; //< List of tiles. /** The maximum number of vertices per navigation polygon. */ @@ -62,15 +62,16 @@ namespace DotRecast.Detour if (0 == m_tileLutSize) m_tileLutSize = 1; m_tileLutMask = m_tileLutSize - 1; - + m_tiles = new DtMeshTile[m_maxTiles]; - m_posLookup = new Dictionary>(); - m_nextFree = new LinkedList(); - for (int i = 0; i < m_maxTiles; i++) + m_posLookup = new DtMeshTile[m_tileLutSize]; + m_nextFree = null; + for (int i = m_maxTiles-1; i >= 0; --i) { m_tiles[i] = new DtMeshTile(i); m_tiles[i].salt = 1; - m_nextFree.AddLast(m_tiles[i]); + m_tiles[i].next = m_nextFree; + m_nextFree = m_tiles[i]; } return DtStatus.DT_SUCCESS; @@ -384,15 +385,13 @@ namespace DotRecast.Detour DtMeshTile tile = null; if (lastRef == 0) { - // Make sure we could allocate a tile. - if (0 == m_nextFree.Count) + if (null != m_nextFree) { - throw new Exception("Could not allocate a tile"); + tile = m_nextFree; + m_nextFree = tile.next; + tile.next = null; + m_tileCount++; } - - tile = m_nextFree.First?.Value; - m_nextFree.RemoveFirst(); - m_tileCount++; } else { @@ -405,14 +404,25 @@ namespace DotRecast.Detour // Try to find the specific tile id from the free list. DtMeshTile target = m_tiles[tileIndex]; - // Remove from freelist - if (!m_nextFree.Remove(target)) + DtMeshTile prev = null; + tile = m_nextFree; + + while (null != tile && tile != target) { - // Could not find the correct location. - return DtStatus.DT_FAILURE | DtStatus.DT_OUT_OF_MEMORY; + prev = tile; + tile = tile.next; } - tile = target; + // Could not find the correct location. + if (tile != target) + return DtStatus.DT_FAILURE | DtStatus.DT_OUT_OF_MEMORY; + + // Remove from freelist + if (null == prev) + m_nextFree = tile.next; + else + prev.next = tile.next; + // Restore salt. tile.salt = DecodePolyIdSalt(lastRef); } @@ -424,7 +434,10 @@ namespace DotRecast.Detour } // Insert tile into the position lut. - GetTileListByPos(header.x, header.y).Add(tile); + int h = ComputeTileHash(header.x, header.y, m_tileLutMask); + tile.next = m_posLookup[h]; + m_posLookup[h] = tile; + // Patch header pointers. tile.data = data; @@ -450,13 +463,19 @@ namespace DotRecast.Detour tile.flags = flags; ConnectIntLinks(tile); + // Base off-mesh connections to their starting polygons and connect connections inside the tile. BaseOffMeshLinks(tile); ConnectExtOffMeshLinks(tile, tile, -1); + // Create connections with neighbour tiles. + const int MAX_NEIS = 32; + DtMeshTile[] neis = new DtMeshTile[MAX_NEIS]; + int nneis; + // Connect with layers in current tile. - List neis = GetTilesAt(header.x, header.y); - for (int j = 0; j < neis.Count; ++j) + nneis = GetTilesAt(header.x, header.y, neis, MAX_NEIS); + for (int j = 0; j < nneis; ++j) { if (neis[j] == tile) { @@ -472,8 +491,8 @@ namespace DotRecast.Detour // Connect with neighbour tiles. for (int i = 0; i < 8; ++i) { - neis = GetNeighbourTilesAt(header.x, header.y, i); - for (int j = 0; j < neis.Count; ++j) + nneis = GetNeighbourTilesAt(header.x, header.y, i, neis, MAX_NEIS); + for (int j = 0; j < nneis; ++j) { ConnectExtLinks(tile, neis[j], i); ConnectExtLinks(neis[j], tile, DtUtils.OppositeTile(i)); @@ -516,30 +535,44 @@ namespace DotRecast.Detour } // Remove tile from hash lookup. - GetTileListByPos(tile.data.header.x, tile.data.header.y).Remove(tile); - - // Remove connections to neighbour tiles. - // Create connections with neighbour tiles. - - // Disconnect from other layers in current tile. - List nneis = GetTilesAt(tile.data.header.x, tile.data.header.y); - foreach (DtMeshTile j in nneis) + int h = ComputeTileHash(tile.data.header.x, tile.data.header.y, m_tileLutMask); + DtMeshTile prev = null; + DtMeshTile cur = m_posLookup[h]; + while (null != cur) { - if (j == tile) + if (cur == tile) { - continue; + if (null != prev) + prev.next = cur.next; + else + m_posLookup[h] = cur.next; + break; } - UnconnectLinks(j, tile); + prev = cur; + cur = cur.next; + } + + // Remove connections to neighbour tiles. + const int MAX_NEIS = 32; + DtMeshTile[] neis = new DtMeshTile[MAX_NEIS]; + int nneis = 0; + + // Disconnect from other layers in current tile. + nneis = GetTilesAt(tile.data.header.x, tile.data.header.y, neis, MAX_NEIS); + for (int j = 0; j < nneis; ++j) + { + if (neis[j] == tile) continue; + UnconnectLinks(neis[j], tile); } // Disconnect from neighbour tiles. for (int i = 0; i < 8; ++i) { - nneis = GetNeighbourTilesAt(tile.data.header.x, tile.data.header.y, i); - foreach (DtMeshTile j in nneis) + nneis = GetNeighbourTilesAt(tile.data.header.x, tile.data.header.y, i, neis, MAX_NEIS); + for (int j = 0; j < nneis; ++j) { - UnconnectLinks(j, tile); + UnconnectLinks(neis[j], tile); } } @@ -557,7 +590,8 @@ namespace DotRecast.Detour } // Add to free list. - m_nextFree.AddFirst(tile); + tile.next = m_nextFree; + m_nextFree = tile; m_tileCount--; return GetTileRef(tile); } @@ -1270,19 +1304,27 @@ namespace DotRecast.Detour DtMeshTile GetTileAt(int x, int y, int layer) { - foreach (DtMeshTile tile in GetTileListByPos(x, y)) + // Find tile based on hash. + int h = ComputeTileHash(x, y, m_tileLutMask); + DtMeshTile tile = m_posLookup[h]; + while (null != tile) { - if (tile.data.header != null && tile.data.header.x == x && tile.data.header.y == y - && tile.data.header.layer == layer) + if (null != tile.data && + null != tile.data.header && + tile.data.header.x == x && + tile.data.header.y == y && + tile.data.header.layer == layer) { return tile; } + + tile = tile.next; } return null; } - List GetNeighbourTilesAt(int x, int y, int side) + int GetNeighbourTilesAt(int x, int y, int side, DtMeshTile[] tiles, int maxTiles) { int nx = x, ny = y; switch (side) @@ -1317,21 +1359,31 @@ namespace DotRecast.Detour break; } - return GetTilesAt(nx, ny); + return GetTilesAt(nx, ny, tiles, maxTiles); } - public List GetTilesAt(int x, int y) + public int GetTilesAt(int x, int y, DtMeshTile[] tiles, int maxTiles) { - List tiles = new List(); - foreach (DtMeshTile tile in GetTileListByPos(x, y)) + int n = 0; + + // Find tile based on hash. + int h = ComputeTileHash(x, y, m_tileLutMask); + DtMeshTile tile = m_posLookup[h]; + while (null != tile) { - if (tile.data.header != null && tile.data.header.x == x && tile.data.header.y == y) + if (null != tile.data && + null != tile.data.header && + tile.data.header.x == x && + tile.data.header.y == y) { - tiles.Add(tile); + if (n < maxTiles) + tiles[n++] = tile; } + + tile = tile.next; } - return tiles; + return n; } public long GetTileRefAt(int x, int y, int layer) @@ -1453,9 +1505,9 @@ namespace DotRecast.Detour return m_tileCount; } - public int GetAvailableTileCount() + public bool IsAvailableTileCount() { - return m_nextFree.Count; + return null != m_nextFree; } public DtStatus SetPolyFlags(long refs, int flags) @@ -1613,18 +1665,6 @@ namespace DotRecast.Detour return center; } - private List GetTileListByPos(int x, int z) - { - var tileHash = ComputeTileHash(x, z, m_tileLutMask); - if (!m_posLookup.TryGetValue(tileHash, out var tiles)) - { - tiles = new List(); - m_posLookup.Add(tileHash, tiles); - } - - return tiles; - } - public void ComputeBounds(out RcVec3f bmin, out RcVec3f bmax) { bmin = new RcVec3f(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); diff --git a/src/DotRecast.Detour/DtNavMeshQuery.cs b/src/DotRecast.Detour/DtNavMeshQuery.cs index 040eb5d..c73cd30 100644 --- a/src/DotRecast.Detour/DtNavMeshQuery.cs +++ b/src/DotRecast.Detour/DtNavMeshQuery.cs @@ -764,39 +764,27 @@ namespace DotRecast.Detour // Find tiles the query touches. RcVec3f bmin = RcVec3f.Subtract(center, halfExtents); RcVec3f bmax = RcVec3f.Add(center, halfExtents); - foreach (var t in QueryTiles(center, halfExtents)) - { - QueryPolygonsInTile(t, bmin, bmax, filter, query); - } - return DtStatus.DT_SUCCESS; - } - - /** - * Finds tiles that overlap the search box. - */ - public IList QueryTiles(RcVec3f center, RcVec3f halfExtents) - { - if (!center.IsFinite() || !halfExtents.IsFinite()) - { - return RcImmutableArray.Empty; - } - - RcVec3f bmin = RcVec3f.Subtract(center, halfExtents); - RcVec3f bmax = RcVec3f.Add(center, halfExtents); + // Find tiles the query touches. m_nav.CalcTileLoc(bmin, out var minx, out var miny); m_nav.CalcTileLoc(bmax, out var maxx, out var maxy); - List tiles = new List(); + const int MAX_NEIS = 32; + DtMeshTile[] neis = new DtMeshTile[MAX_NEIS]; + for (int y = miny; y <= maxy; ++y) { for (int x = minx; x <= maxx; ++x) { - tiles.AddRange(m_nav.GetTilesAt(x, y)); + int nneis = m_nav.GetTilesAt(x, y, neis, MAX_NEIS); + for (int j = 0; j < nneis; ++j) + { + QueryPolygonsInTile(neis[j], bmin, bmax, filter, query); + } } } - return tiles; + return DtStatus.DT_SUCCESS; } /// @par diff --git a/src/DotRecast.Recast.Toolset/Tools/RcTileTool.cs b/src/DotRecast.Recast.Toolset/Tools/RcTileTool.cs index 38d93dc..b4410c5 100644 --- a/src/DotRecast.Recast.Toolset/Tools/RcTileTool.cs +++ b/src/DotRecast.Recast.Toolset/Tools/RcTileTool.cs @@ -68,8 +68,8 @@ namespace DotRecast.Recast.Toolset.Tools tileTriCount = 0; // ... tileMemUsage = 0; // ... - var availableTileCount = navMesh.GetAvailableTileCount(); - if (0 >= availableTileCount) + var availableTile = navMesh.IsAvailableTileCount(); + if (!availableTile) { return false; } diff --git a/test/DotRecast.Detour.Test/Io/MeshSetReaderTest.cs b/test/DotRecast.Detour.Test/Io/MeshSetReaderTest.cs index e2bf949..d93ffb9 100644 --- a/test/DotRecast.Detour.Test/Io/MeshSetReaderTest.cs +++ b/test/DotRecast.Detour.Test/Io/MeshSetReaderTest.cs @@ -24,7 +24,6 @@ using NUnit.Framework; namespace DotRecast.Detour.Test.Io; - public class MeshSetReaderTest { private readonly DtMeshSetReader reader = new DtMeshSetReader(); @@ -39,20 +38,28 @@ public class MeshSetReaderTest Assert.That(mesh.GetMaxTiles(), Is.EqualTo(128)); Assert.That(mesh.GetParams().maxPolys, Is.EqualTo(0x8000)); Assert.That(mesh.GetParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f)); - List tiles = mesh.GetTilesAt(4, 7); - Assert.That(tiles.Count, Is.EqualTo(1)); + + const int MAX_NEIS = 32; + DtMeshTile[] tiles = new DtMeshTile[MAX_NEIS]; + int nneis = 0; + + nneis = mesh.GetTilesAt(4, 7, tiles, MAX_NEIS); + Assert.That(nneis, Is.EqualTo(1)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(7)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(22 * 3)); - tiles = mesh.GetTilesAt(1, 6); - Assert.That(tiles.Count, Is.EqualTo(1)); + + nneis = mesh.GetTilesAt(1, 6, tiles, MAX_NEIS); + Assert.That(nneis, Is.EqualTo(1)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(7)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(26 * 3)); - tiles = mesh.GetTilesAt(6, 2); - Assert.That(tiles.Count, Is.EqualTo(1)); + + nneis = mesh.GetTilesAt(6, 2, tiles, MAX_NEIS); + Assert.That(nneis, Is.EqualTo(1)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(1)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(4 * 3)); - tiles = mesh.GetTilesAt(7, 6); - Assert.That(tiles.Count, Is.EqualTo(1)); + + nneis = mesh.GetTilesAt(7, 6, tiles, MAX_NEIS); + Assert.That(nneis, Is.EqualTo(1)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(8)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(24 * 3)); } @@ -68,20 +75,28 @@ public class MeshSetReaderTest Assert.That(mesh.GetMaxTiles(), Is.EqualTo(128)); Assert.That(mesh.GetParams().maxPolys, Is.EqualTo(0x8000)); Assert.That(mesh.GetParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f)); - List tiles = mesh.GetTilesAt(6, 9); - Assert.That(tiles.Count, Is.EqualTo(1)); + + const int MAX_NEIS = 32; + DtMeshTile[] tiles = new DtMeshTile[MAX_NEIS]; + int nneis = 0; + + nneis = mesh.GetTilesAt(6, 9, tiles, MAX_NEIS); + Assert.That(nneis, Is.EqualTo(1)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(7 * 3)); - tiles = mesh.GetTilesAt(2, 9); - Assert.That(tiles.Count, Is.EqualTo(1)); + + nneis = mesh.GetTilesAt(2, 9, tiles, MAX_NEIS); + Assert.That(nneis, Is.EqualTo(1)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(9 * 3)); - tiles = mesh.GetTilesAt(4, 3); - Assert.That(tiles.Count, Is.EqualTo(1)); + + nneis = mesh.GetTilesAt(4, 3, tiles, MAX_NEIS); + Assert.That(nneis, Is.EqualTo(1)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(3)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(6 * 3)); - tiles = mesh.GetTilesAt(2, 8); - Assert.That(tiles.Count, Is.EqualTo(1)); + + nneis = mesh.GetTilesAt(2, 8, tiles, MAX_NEIS); + Assert.That(nneis, Is.EqualTo(1)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(5)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(17 * 3)); } @@ -97,21 +112,29 @@ public class MeshSetReaderTest Assert.That(mesh.GetMaxTiles(), Is.EqualTo(128)); Assert.That(mesh.GetParams().maxPolys, Is.EqualTo(0x8000)); Assert.That(mesh.GetParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f)); - List tiles = mesh.GetTilesAt(6, 9); - Assert.That(tiles.Count, Is.EqualTo(1)); + + const int MAX_NEIS = 32; + DtMeshTile[] tiles = new DtMeshTile[MAX_NEIS]; + int nneis = 0; + + nneis = mesh.GetTilesAt(6, 9, tiles, MAX_NEIS); + Assert.That(nneis, Is.EqualTo(1)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(7 * 3)); - tiles = mesh.GetTilesAt(2, 9); - Assert.That(tiles.Count, Is.EqualTo(1)); + + nneis = mesh.GetTilesAt(2, 9, tiles, MAX_NEIS); + Assert.That(nneis, Is.EqualTo(1)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(9 * 3)); - tiles = mesh.GetTilesAt(4, 3); - Assert.That(tiles.Count, Is.EqualTo(1)); + + nneis = mesh.GetTilesAt(4, 3, tiles, MAX_NEIS); + Assert.That(nneis, Is.EqualTo(1)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(3)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(6 * 3)); - tiles = mesh.GetTilesAt(2, 8); - Assert.That(tiles.Count, Is.EqualTo(1)); + + nneis = mesh.GetTilesAt(2, 8, tiles, MAX_NEIS); + Assert.That(nneis, Is.EqualTo(1)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(5)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(17 * 3)); } -} +} \ No newline at end of file diff --git a/test/DotRecast.Detour.Test/Io/MeshSetReaderWriterTest.cs b/test/DotRecast.Detour.Test/Io/MeshSetReaderWriterTest.cs index 02ca48e..af50c50 100644 --- a/test/DotRecast.Detour.Test/Io/MeshSetReaderWriterTest.cs +++ b/test/DotRecast.Detour.Test/Io/MeshSetReaderWriterTest.cs @@ -107,20 +107,28 @@ public class MeshSetReaderWriterTest Assert.That(mesh.GetMaxTiles(), Is.EqualTo(128)); Assert.That(mesh.GetParams().maxPolys, Is.EqualTo(0x8000)); Assert.That(mesh.GetParams().tileWidth, Is.EqualTo(9.6f).Within(0.001f)); - List tiles = mesh.GetTilesAt(6, 9); - Assert.That(tiles.Count, Is.EqualTo(1)); + + const int MAX_NEIS = 32; + DtMeshTile[] tiles = new DtMeshTile[MAX_NEIS]; + int nneis = 0; + + nneis = mesh.GetTilesAt(6, 9, tiles, MAX_NEIS); + Assert.That(nneis, Is.EqualTo(1)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(7 * 3)); - tiles = mesh.GetTilesAt(2, 9); - Assert.That(tiles.Count, Is.EqualTo(1)); + + nneis = mesh.GetTilesAt(2, 9, tiles, MAX_NEIS); + Assert.That(nneis, Is.EqualTo(1)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(2)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(9 * 3)); - tiles = mesh.GetTilesAt(4, 3); - Assert.That(tiles.Count, Is.EqualTo(1)); + + nneis = mesh.GetTilesAt(4, 3, tiles, MAX_NEIS); + Assert.That(nneis, Is.EqualTo(1)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(3)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(6 * 3)); - tiles = mesh.GetTilesAt(2, 8); - Assert.That(tiles.Count, Is.EqualTo(1)); + + nneis = mesh.GetTilesAt(2, 8, tiles, MAX_NEIS); + Assert.That(nneis, Is.EqualTo(1)); Assert.That(tiles[0].data.polys.Length, Is.EqualTo(5)); Assert.That(tiles[0].data.verts.Length, Is.EqualTo(17 * 3)); } diff --git a/test/DotRecast.Detour.TileCache.Test/TempObstaclesTest.cs b/test/DotRecast.Detour.TileCache.Test/TempObstaclesTest.cs index a894e41..add9cfc 100644 --- a/test/DotRecast.Detour.TileCache.Test/TempObstaclesTest.cs +++ b/test/DotRecast.Detour.TileCache.Test/TempObstaclesTest.cs @@ -26,7 +26,6 @@ using NUnit.Framework; namespace DotRecast.Detour.TileCache.Test; - public class TempObstaclesTest : AbstractTileCacheTest { [Test] @@ -43,21 +42,29 @@ public class TempObstaclesTest : AbstractTileCacheTest tc.BuildNavMeshTile(refs); } - List tiles = tc.GetNavMesh().GetTilesAt(1, 4); + const int MAX_NEIS = 32; + DtMeshTile[] tiles = new DtMeshTile[MAX_NEIS]; + int nneis = 0; + + nneis = tc.GetNavMesh().GetTilesAt(1, 4, tiles, MAX_NEIS); DtMeshTile tile = tiles[0]; Assert.That(tile.data.header.vertCount, Is.EqualTo(16)); Assert.That(tile.data.header.polyCount, Is.EqualTo(6)); + long o = tc.AddObstacle(new RcVec3f(-1.815208f, 9.998184f, -20.307983f), 1f, 2f); bool upToDate = tc.Update(); Assert.That(upToDate, Is.True); - tiles = tc.GetNavMesh().GetTilesAt(1, 4); + + nneis = tc.GetNavMesh().GetTilesAt(1, 4, tiles, MAX_NEIS); tile = tiles[0]; Assert.That(tile.data.header.vertCount, Is.EqualTo(22)); Assert.That(tile.data.header.polyCount, Is.EqualTo(11)); + tc.RemoveObstacle(o); upToDate = tc.Update(); Assert.That(upToDate, Is.True); - tiles = tc.GetNavMesh().GetTilesAt(1, 4); + + nneis = tc.GetNavMesh().GetTilesAt(1, 4, tiles, MAX_NEIS); tile = tiles[0]; Assert.That(tile.data.header.vertCount, Is.EqualTo(16)); Assert.That(tile.data.header.polyCount, Is.EqualTo(6)); @@ -77,24 +84,32 @@ public class TempObstaclesTest : AbstractTileCacheTest tc.BuildNavMeshTile(refs); } - List tiles = tc.GetNavMesh().GetTilesAt(1, 4); + const int MAX_NEIS = 32; + DtMeshTile[] tiles = new DtMeshTile[MAX_NEIS]; + int nneis = 0; + + nneis = tc.GetNavMesh().GetTilesAt(1, 4, tiles, MAX_NEIS); DtMeshTile tile = tiles[0]; Assert.That(tile.data.header.vertCount, Is.EqualTo(16)); Assert.That(tile.data.header.polyCount, Is.EqualTo(6)); + long o = tc.AddBoxObstacle( new RcVec3f(-2.315208f, 9.998184f, -20.807983f), new RcVec3f(-1.315208f, 11.998184f, -19.807983f) ); bool upToDate = tc.Update(); Assert.That(upToDate, Is.True); - tiles = tc.GetNavMesh().GetTilesAt(1, 4); + + nneis = tc.GetNavMesh().GetTilesAt(1, 4, tiles, MAX_NEIS); tile = tiles[0]; Assert.That(tile.data.header.vertCount, Is.EqualTo(22)); Assert.That(tile.data.header.polyCount, Is.EqualTo(11)); + tc.RemoveObstacle(o); upToDate = tc.Update(); Assert.That(upToDate, Is.True); - tiles = tc.GetNavMesh().GetTilesAt(1, 4); + + nneis = tc.GetNavMesh().GetTilesAt(1, 4, tiles, MAX_NEIS); tile = tiles[0]; Assert.That(tile.data.header.vertCount, Is.EqualTo(16)); Assert.That(tile.data.header.polyCount, Is.EqualTo(6));