diff --git a/src/DotRecast.Detour/DtFindPathOption.cs b/src/DotRecast.Detour/DtFindPathOption.cs index 35c9220..bc130b1 100644 --- a/src/DotRecast.Detour/DtFindPathOption.cs +++ b/src/DotRecast.Detour/DtFindPathOption.cs @@ -2,7 +2,10 @@ { public readonly struct DtFindPathOption { - public static readonly DtFindPathOption Zero = new DtFindPathOption(DefaultQueryHeuristic.Default, 0, 0); + public static readonly DtFindPathOption NoOption = new DtFindPathOption(DefaultQueryHeuristic.Default, 0, 0); + + public static readonly DtFindPathOption AnyAngle = new DtFindPathOption(DefaultQueryHeuristic.Default, DtNavMeshQuery.DT_FINDPATH_ANY_ANGLE, float.MaxValue); + public static readonly DtFindPathOption ZeroScale = new DtFindPathOption(new DefaultQueryHeuristic(0.0f), 0, 0); public readonly IQueryHeuristic heuristic; public readonly int options; diff --git a/src/DotRecast.Detour/DtNavMeshQuery.cs b/src/DotRecast.Detour/DtNavMeshQuery.cs index 9385cd0..ab960e5 100644 --- a/src/DotRecast.Detour/DtNavMeshQuery.cs +++ b/src/DotRecast.Detour/DtNavMeshQuery.cs @@ -764,12 +764,17 @@ namespace DotRecast.Detour * The polygon filter to apply to the query. * @return Found path */ - public Result> FindPath(long startRef, long endRef, RcVec3f startPos, RcVec3f endPos, IDtQueryFilter filter, DtFindPathOption fpo) + public DtStatus FindPath(long startRef, long endRef, RcVec3f startPos, RcVec3f endPos, IDtQueryFilter filter, ref List path, DtFindPathOption fpo) { + if (null == path) + return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM; + + path.Clear(); + // Validate input if (!m_nav.IsValidPolyRef(startRef) || !m_nav.IsValidPolyRef(endRef) || !RcVec3f.IsFinite(startPos) || !RcVec3f.IsFinite(endPos) || null == filter) { - return Results.InvalidParam>(); + return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM; } var heuristic = fpo.heuristic; @@ -790,9 +795,8 @@ namespace DotRecast.Detour if (startRef == endRef) { - List singlePath = new List(1); - singlePath.Add(startRef); - return Results.Success(singlePath); + path.Add(startRef); + return DtStatus.DT_SUCCSESS; } m_nodePool.Clear(); @@ -810,7 +814,6 @@ namespace DotRecast.Detour DtNode lastBestNode = startNode; float lastBestNodeCost = startNode.total; - DtStatus status = DtStatus.DT_SUCCSESS; while (!m_openList.IsEmpty()) { @@ -910,9 +913,9 @@ namespace DotRecast.Detour List shortcut = null; if (tryLOS) { - status = Raycast(parentRef, parentNode.pos, neighbourPos, filter, + var rayStatus = Raycast(parentRef, parentNode.pos, neighbourPos, filter, DT_RAYCAST_USE_COSTS, grandpaRef, out var rayHit); - if (status.Succeeded()) + if (rayStatus.Succeeded()) { foundShortCut = rayHit.t >= 1.0f; if (foundShortCut) @@ -991,15 +994,13 @@ namespace DotRecast.Detour } } - var path = new List(); - GetPathToNode(lastBestNode, ref path); - + var status = GetPathToNode(lastBestNode, ref path); if (lastBestNode.id != endRef) { - status = DtStatus.DT_PARTIAL_RESULT; + status |= DtStatus.DT_PARTIAL_RESULT; } - return Results.Of(status, path); + return status; } /** @@ -1352,17 +1353,18 @@ namespace DotRecast.Detour // Reverse the path. if (m_query.lastBestNode.id != m_query.endRef) { - m_query.status = DtStatus.DT_PARTIAL_RESULT; + m_query.status |= DtStatus.DT_PARTIAL_RESULT; } GetPathToNode(m_query.lastBestNode, ref path); } - DtStatus status = m_query.status; + var details = m_query.status & DtStatus.DT_STATUS_DETAIL_MASK; + // Reset query. m_query = new DtQueryData(); - return Results.Of(status, path); + return Results.Of(DtStatus.DT_SUCCSESS | details, path); } /// Finalizes and returns the results of an incomplete sliced path query, returning the path to the furthest diff --git a/src/DotRecast.Recast.Demo/Tools/TestNavmeshTool.cs b/src/DotRecast.Recast.Demo/Tools/TestNavmeshTool.cs index c190131..e36cbf5 100644 --- a/src/DotRecast.Recast.Demo/Tools/TestNavmeshTool.cs +++ b/src/DotRecast.Recast.Demo/Tools/TestNavmeshTool.cs @@ -196,8 +196,8 @@ public class TestNavmeshTool : IRcTool { if (m_sposSet && m_eposSet && m_startRef != 0 && m_endRef != 0) { - m_polys = m_navQuery.FindPath(m_startRef, m_endRef, m_spos, m_epos, m_filter, - new(enableRaycast ? DtNavMeshQuery.DT_FINDPATH_ANY_ANGLE : 0, float.MaxValue)).result; + m_navQuery.FindPath(m_startRef, m_endRef, m_spos, m_epos, m_filter, ref m_polys, + new(enableRaycast ? DtNavMeshQuery.DT_FINDPATH_ANY_ANGLE : 0, float.MaxValue)); if (0 < m_polys.Count) { List polys = new(m_polys); @@ -330,8 +330,8 @@ public class TestNavmeshTool : IRcTool { if (m_sposSet && m_eposSet && m_startRef != 0 && m_endRef != 0) { - m_polys = m_navQuery.FindPath(m_startRef, m_endRef, m_spos, m_epos, m_filter, - new(enableRaycast ? DtNavMeshQuery.DT_FINDPATH_ANY_ANGLE : 0, float.MaxValue)).result; + m_navQuery.FindPath(m_startRef, m_endRef, m_spos, m_epos, m_filter, ref m_polys, + new(enableRaycast ? DtNavMeshQuery.DT_FINDPATH_ANY_ANGLE : 0, float.MaxValue)); if (0 < m_polys.Count) { // In case of partial path, make sure the end point is clamped to the last polygon. diff --git a/test/DotRecast.Detour.Dynamic.Test/DynamicNavMeshTest.cs b/test/DotRecast.Detour.Dynamic.Test/DynamicNavMeshTest.cs index 2d5dc7d..77e43c5 100644 --- a/test/DotRecast.Detour.Dynamic.Test/DynamicNavMeshTest.cs +++ b/test/DotRecast.Detour.Dynamic.Test/DynamicNavMeshTest.cs @@ -43,7 +43,8 @@ public class DynamicNavMeshTest query.FindNearestPoly(START_POS, EXTENT, filter, out var startRef, out var startPt, out var _); query.FindNearestPoly(END_POS, EXTENT, filter, out var endRef, out var endPt, out var _); - List path = query.FindPath(startRef, endRef, startPt, endPt, filter, new(DtNavMeshQuery.DT_FINDPATH_ANY_ANGLE, float.MaxValue)).result; + var path = new List(); + query.FindPath(startRef, endRef, startPt, endPt, filter, ref path, DtFindPathOption.AnyAngle); // check path length without any obstacles Assert.That(path.Count, Is.EqualTo(16)); @@ -61,7 +62,7 @@ public class DynamicNavMeshTest // find path again query.FindNearestPoly(START_POS, EXTENT, filter, out startRef, out startPt, out var _); query.FindNearestPoly(END_POS, EXTENT, filter, out endRef, out endPt, out var _); - path = query.FindPath(startRef, endRef, startPt, endPt, filter, new(DtNavMeshQuery.DT_FINDPATH_ANY_ANGLE, float.MaxValue)).result; + query.FindPath(startRef, endRef, startPt, endPt, filter, ref path, DtFindPathOption.AnyAngle); // check path length with obstacles Assert.That(path.Count, Is.EqualTo(19)); @@ -77,7 +78,7 @@ public class DynamicNavMeshTest // find path one more time query.FindNearestPoly(START_POS, EXTENT, filter, out startRef, out startPt, out var _); query.FindNearestPoly(END_POS, EXTENT, filter, out endRef, out endPt, out var _); - path = query.FindPath(startRef, endRef, startPt, endPt, filter, new(DtNavMeshQuery.DT_FINDPATH_ANY_ANGLE, float.MaxValue)).result; + query.FindPath(startRef, endRef, startPt, endPt, filter, ref path, DtFindPathOption.AnyAngle); // path length should be back to the initial value Assert.That(path.Count, Is.EqualTo(16)); diff --git a/test/DotRecast.Detour.Extras.Test/Unity/Astar/UnityAStarPathfindingImporterTest.cs b/test/DotRecast.Detour.Extras.Test/Unity/Astar/UnityAStarPathfindingImporterTest.cs index 4890a16..33e9f9d 100644 --- a/test/DotRecast.Detour.Extras.Test/Unity/Astar/UnityAStarPathfindingImporterTest.cs +++ b/test/DotRecast.Detour.Extras.Test/Unity/Astar/UnityAStarPathfindingImporterTest.cs @@ -96,7 +96,9 @@ public class UnityAStarPathfindingImporterTest IDtQueryFilter filter = new DtQueryDefaultFilter(); var polys = GetNearestPolys(mesh, startPos, endPos); - return query.FindPath(polys[0].refs, polys[1].refs, startPos, endPos, filter, DtFindPathOption.Zero); + var path = new List(); + var status = query.FindPath(polys[0].refs, polys[1].refs, startPos, endPos, filter, ref path, DtFindPathOption.NoOption); + return Results.Of(status, path); } private DtPolyPoint[] GetNearestPolys(DtNavMesh mesh, params RcVec3f[] positions) diff --git a/test/DotRecast.Detour.Test/FindPathTest.cs b/test/DotRecast.Detour.Test/FindPathTest.cs index 21bd095..4a5fe8b 100644 --- a/test/DotRecast.Detour.Test/FindPathTest.cs +++ b/test/DotRecast.Detour.Test/FindPathTest.cs @@ -28,7 +28,10 @@ public class FindPathTest : AbstractDetourTest { private static readonly DtStatus[] STATUSES = { - DtStatus.DT_SUCCSESS, DtStatus.DT_PARTIAL_RESULT, DtStatus.DT_SUCCSESS, DtStatus.DT_SUCCSESS, + DtStatus.DT_SUCCSESS, + DtStatus.DT_SUCCSESS | DtStatus.DT_PARTIAL_RESULT, + DtStatus.DT_SUCCSESS, + DtStatus.DT_SUCCSESS, DtStatus.DT_SUCCSESS }; @@ -132,18 +135,19 @@ public class FindPathTest : AbstractDetourTest public void TestFindPath() { IDtQueryFilter filter = new DtQueryDefaultFilter(); + var path = new List(); for (int i = 0; i < startRefs.Length; i++) { long startRef = startRefs[i]; long endRef = endRefs[i]; RcVec3f startPos = startPoss[i]; RcVec3f endPos = endPoss[i]; - Result> path = query.FindPath(startRef, endRef, startPos, endPos, filter, DtFindPathOption.Zero); - Assert.That(path.status, Is.EqualTo(STATUSES[i])); - Assert.That(path.result.Count, Is.EqualTo(RESULTS[i].Length)); + var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.NoOption); + Assert.That(status, Is.EqualTo(STATUSES[i])); + Assert.That(path.Count, Is.EqualTo(RESULTS[i].Length)); for (int j = 0; j < RESULTS[i].Length; j++) { - Assert.That(path.result[j], Is.EqualTo(RESULTS[i][j])); + Assert.That(path[j], Is.EqualTo(RESULTS[i][j])); } } } @@ -166,7 +170,7 @@ public class FindPathTest : AbstractDetourTest } Result> path = query.FinalizeSlicedFindPath(); - Assert.That(path.status, Is.EqualTo(STATUSES[i])); + Assert.That(path.status, Is.EqualTo(STATUSES[i]), $"index({i})"); Assert.That(path.result.Count, Is.EqualTo(RESULTS[i].Length)); for (int j = 0; j < RESULTS[i].Length; j++) { @@ -179,6 +183,7 @@ public class FindPathTest : AbstractDetourTest public void TestFindPathStraight() { IDtQueryFilter filter = new DtQueryDefaultFilter(); + var path = new List(); for (int i = 0; i < STRAIGHT_PATHS.Length; i++) { // startRefs.Length; i++) { @@ -186,9 +191,9 @@ public class FindPathTest : AbstractDetourTest long endRef = endRefs[i]; var startPos = startPoss[i]; var endPos = endPoss[i]; - Result> path = query.FindPath(startRef, endRef, startPos, endPos, filter, DtFindPathOption.Zero); + var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.NoOption); var straightPath = new List(); - query.FindStraightPath(startPos, endPos, path.result, ref straightPath, int.MaxValue, 0); + query.FindStraightPath(startPos, endPos, path, ref straightPath, int.MaxValue, 0); Assert.That(straightPath.Count, Is.EqualTo(STRAIGHT_PATHS[i].Length)); for (int j = 0; j < STRAIGHT_PATHS[i].Length; j++) { diff --git a/test/DotRecast.Detour.Test/TiledFindPathTest.cs b/test/DotRecast.Detour.Test/TiledFindPathTest.cs index 5e62bc9..0d6afbe 100644 --- a/test/DotRecast.Detour.Test/TiledFindPathTest.cs +++ b/test/DotRecast.Detour.Test/TiledFindPathTest.cs @@ -65,18 +65,19 @@ public class TiledFindPathTest public void TestFindPath() { IDtQueryFilter filter = new DtQueryDefaultFilter(); + var path = new List(); for (int i = 0; i < START_REFS.Length; i++) { long startRef = START_REFS[i]; long endRef = END_REFS[i]; RcVec3f startPos = START_POS[i]; RcVec3f endPos = END_POS[i]; - Result> path = query.FindPath(startRef, endRef, startPos, endPos, filter, DtFindPathOption.Zero); - Assert.That(path.status, Is.EqualTo(STATUSES[i])); - Assert.That(path.result.Count, Is.EqualTo(RESULTS[i].Length)); + var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.NoOption); + Assert.That(status, Is.EqualTo(STATUSES[i])); + Assert.That(path.Count, Is.EqualTo(RESULTS[i].Length)); for (int j = 0; j < RESULTS[i].Length; j++) { - Assert.That(RESULTS[i][j], Is.EqualTo(path.result[j])); + Assert.That(RESULTS[i][j], Is.EqualTo(path[j])); } } } diff --git a/test/DotRecast.Detour.TileCache.Test/TileCacheFindPathTest.cs b/test/DotRecast.Detour.TileCache.Test/TileCacheFindPathTest.cs index 19517de..d398eac 100644 --- a/test/DotRecast.Detour.TileCache.Test/TileCacheFindPathTest.cs +++ b/test/DotRecast.Detour.TileCache.Test/TileCacheFindPathTest.cs @@ -52,12 +52,13 @@ public class TileCacheFindPathTest : AbstractTileCacheTest query.FindNearestPoly(start, extents, filter, out var startRef, out var startPos, out var _); query.FindNearestPoly(end, extents, filter, out var endRef, out var endPos, out var _); - Result> path = query.FindPath(startRef, endRef, startPos, endPos, filter, DtFindPathOption.Zero); + var path = new List(); + var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.NoOption); int maxStraightPath = 256; int options = 0; var pathStr = new List(); - query.FindStraightPath(startPos, endPos, path.result, ref pathStr, maxStraightPath, options); + query.FindStraightPath(startPos, endPos, path, ref pathStr, maxStraightPath, options); Assert.That(pathStr.Count, Is.EqualTo(8)); } } \ No newline at end of file diff --git a/test/DotRecast.Detour.TileCache.Test/TileCacheNavigationTest.cs b/test/DotRecast.Detour.TileCache.Test/TileCacheNavigationTest.cs index 136ecb8..1cb7511 100644 --- a/test/DotRecast.Detour.TileCache.Test/TileCacheNavigationTest.cs +++ b/test/DotRecast.Detour.TileCache.Test/TileCacheNavigationTest.cs @@ -84,18 +84,19 @@ public class TileCacheNavigationTest : AbstractTileCacheTest public void TestFindPathWithDefaultHeuristic() { IDtQueryFilter filter = new DtQueryDefaultFilter(); + var path = new List(); for (int i = 0; i < startRefs.Length; i++) { long startRef = startRefs[i]; long endRef = endRefs[i]; RcVec3f startPos = startPoss[i]; RcVec3f endPos = endPoss[i]; - Result> path = query.FindPath(startRef, endRef, startPos, endPos, filter, DtFindPathOption.Zero); - Assert.That(path.status, Is.EqualTo(statuses[i])); - Assert.That(path.result.Count, Is.EqualTo(results[i].Length)); + var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.NoOption); + Assert.That(status, Is.EqualTo(statuses[i])); + Assert.That(path.Count, Is.EqualTo(results[i].Length)); for (int j = 0; j < results[i].Length; j++) { - Assert.That(path.result[j], Is.EqualTo(results[i][j])); // TODO : 확인 필요 + Assert.That(path[j], Is.EqualTo(results[i][j])); // TODO : 확인 필요 } } } @@ -104,19 +105,19 @@ public class TileCacheNavigationTest : AbstractTileCacheTest public void TestFindPathWithNoHeuristic() { IDtQueryFilter filter = new DtQueryDefaultFilter(); + var path = new List(); for (int i = 0; i < startRefs.Length; i++) { long startRef = startRefs[i]; long endRef = endRefs[i]; RcVec3f startPos = startPoss[i]; RcVec3f endPos = endPoss[i]; - Result> path = query.FindPath(startRef, endRef, startPos, endPos, filter, new(new DefaultQueryHeuristic(0.0f), - 0, 0)); - Assert.That(path.status, Is.EqualTo(statuses[i])); - Assert.That(path.result.Count, Is.EqualTo(results[i].Length)); + var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.ZeroScale); + Assert.That(status, Is.EqualTo(statuses[i])); + Assert.That(path.Count, Is.EqualTo(results[i].Length)); for (int j = 0; j < results[i].Length; j++) { - Assert.That(path.result[j], Is.EqualTo(results[i][j])); // TODO : 확인 필요 + Assert.That(path[j], Is.EqualTo(results[i][j])); // TODO : 확인 필요 } } }