diff --git a/CHANGELOG.md b/CHANGELOG.md index 0306ad1..dd5d6d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] - yyyy-mm-dd ### Added - +- Added DtNodePool.GetNode, FindNode, FindNodes tests + ### Fixed +- Fixed SOH issue in dtNavMeshQuery.Raycast +- Fixed SOH issue in DtProximityGrid.QueryItems ### Changed diff --git a/src/DotRecast.Detour/DtNavMeshQuery.cs b/src/DotRecast.Detour/DtNavMeshQuery.cs index 940d754..c91e3ce 100644 --- a/src/DotRecast.Detour/DtNavMeshQuery.cs +++ b/src/DotRecast.Detour/DtNavMeshQuery.cs @@ -3400,15 +3400,18 @@ namespace DotRecast.Detour return m_nav; } - /** - * Gets a path from the explored nodes in the previous search. - * - * @param endRef - * The reference id of the end polygon. - * @returns An ordered list of polygon references representing the path. (Start to end.) - * @remarks The result of this function depends on the state of the query object. For that reason it should only be - * used immediately after one of the two Dijkstra searches, findPolysAroundCircle or findPolysAroundShape. - */ + /// Gets a path from the explored nodes in the previous search. + /// @param[in] endRef The reference id of the end polygon. + /// @param[out] path An ordered list of polygon references representing the path. (Start to end.) + /// [(polyRef) * @p pathCount] + /// @param[out] pathCount The number of polygons returned in the @p path array. + /// @param[in] maxPath The maximum number of polygons the @p path array can hold. [Limit: >= 0] + /// @returns The status flags. Returns DT_FAILURE | DT_INVALID_PARAM if any parameter is wrong, or if + /// @p endRef was not explored in the previous search. Returns DT_SUCCESS | DT_BUFFER_TOO_SMALL + /// if @p path cannot contain the entire path. In this case it is filled to capacity with a partial path. + /// Otherwise returns DT_SUCCESS. + /// @remarks The result of this function depends on the state of the query object. For that reason it should only + /// be used immediately after one of the two Dijkstra searches, findPolysAroundCircle or findPolysAroundShape. public DtStatus GetPathFromDijkstraSearch(long endRef, ref List path) { if (!m_nav.IsValidPolyRef(endRef) || null == path) @@ -3418,18 +3421,14 @@ namespace DotRecast.Detour path.Clear(); - List nodes = m_nodePool.FindNodes(endRef); - if (nodes.Count != 1) - { - return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM; - } - - DtNode endNode = nodes[0]; - if ((endNode.flags & DtNodeFlags.DT_NODE_CLOSED) == 0) + if (m_nodePool.FindNodes(endRef, out var endNodes) != 1 + || (endNodes[0].flags & DtNodeFlags.DT_NODE_CLOSED) == 0) { return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM; } + DtNode endNode = endNodes[0]; + return GetPathToNode(endNode, ref path); } @@ -3462,10 +3461,11 @@ namespace DotRecast.Detour return DtStatus.DT_SUCCESS; } - /** - * The closed list is the list of polygons that were fully evaluated during the last navigation graph search. (A* or - * Dijkstra) - */ + /// @par + /// + /// The closed list is the list of polygons that were fully evaluated during + /// the last navigation graph search. (A* or Dijkstra) + /// public bool IsInClosedList(long refs) { if (m_nodePool == null) @@ -3473,9 +3473,10 @@ namespace DotRecast.Detour return false; } - foreach (DtNode n in m_nodePool.FindNodes(refs)) + int n = m_nodePool.FindNodes(refs, out var nodes); + for (int i = 0; i < n; ++i) { - if ((n.flags & DtNodeFlags.DT_NODE_CLOSED) != 0) + if ((nodes[i].flags & DtNodeFlags.DT_NODE_CLOSED) != 0) { return true; } diff --git a/src/DotRecast.Detour/DtNodePool.cs b/src/DotRecast.Detour/DtNodePool.cs index c334095..2b840e8 100644 --- a/src/DotRecast.Detour/DtNodePool.cs +++ b/src/DotRecast.Detour/DtNodePool.cs @@ -37,22 +37,20 @@ namespace DotRecast.Detour m_map.Clear(); } - public List FindNodes(long id) + public int FindNodes(long id, out List nodes) { - var hasNode = m_map.TryGetValue(id, out var nodes); - ; - if (nodes == null) + var hasNode = m_map.TryGetValue(id, out nodes); + if (hasNode) { - nodes = new List(); + return nodes.Count; } - return nodes; + return 0; } public DtNode FindNode(long id) { var hasNode = m_map.TryGetValue(id, out var nodes); - ; if (nodes != null && 0 != nodes.Count) { return nodes[0]; diff --git a/test/DotRecast.Detour.Test/DtNodePoolTest.cs b/test/DotRecast.Detour.Test/DtNodePoolTest.cs new file mode 100644 index 0000000..1fe8b84 --- /dev/null +++ b/test/DotRecast.Detour.Test/DtNodePoolTest.cs @@ -0,0 +1,62 @@ +using System.Collections.Immutable; +using NUnit.Framework; + +namespace DotRecast.Detour.Test; + +public class DtNodePoolTest +{ + [Test] + public void TestGetNode() + { + var pool = new DtNodePool(); + + var node1St = pool.GetNode(0); + var node2St = pool.GetNode(0); + Assert.That(node1St, Is.SameAs(node2St)); + + node1St.state = 1; + var node3St = pool.GetNode(0); + Assert.That(node1St, Is.Not.SameAs(node3St)); + } + + [Test] + public void TestFindNode() + { + var pool = new DtNodePool(); + + var counts = ImmutableArray.Create(2, 3, 5); + + // get and create + for (int i = 0; i < counts.Length; ++i) + { + var count = counts[i]; + for (int ii = 0; ii < count; ++ii) + { + var node = pool.GetNode(i); + node.state = ii + 1; + } + } + + // check count + for (int i = 0; i < counts.Length; ++i) + { + var count = counts[i]; + var n = pool.FindNodes(i, out var nodes); + Assert.That(n, Is.EqualTo(count)); + Assert.That(nodes, Has.Count.EqualTo(count)); + + var node = pool.FindNode(i); + Assert.That(nodes[0], Is.SameAs(node)); + + var node2 = pool.FindNode(i); + Assert.That(nodes[0], Is.SameAs(node2)); + } + + // check other count + { + var n = pool.FindNodes(4, out var nodes); + Assert.That(n, Is.EqualTo(0)); + Assert.That(nodes, Is.Null); + } + } +} \ No newline at end of file