non allocate

This commit is contained in:
ikpil 2023-06-23 07:33:03 +09:00
parent a5fc55ab71
commit 05c50e8d12
9 changed files with 64 additions and 48 deletions

View File

@ -2,7 +2,10 @@
{ {
public readonly struct DtFindPathOption 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 IQueryHeuristic heuristic;
public readonly int options; public readonly int options;

View File

@ -764,12 +764,17 @@ namespace DotRecast.Detour
* The polygon filter to apply to the query. * The polygon filter to apply to the query.
* @return Found path * @return Found path
*/ */
public Result<List<long>> 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<long> path, DtFindPathOption fpo)
{ {
if (null == path)
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
path.Clear();
// Validate input // Validate input
if (!m_nav.IsValidPolyRef(startRef) || !m_nav.IsValidPolyRef(endRef) || !RcVec3f.IsFinite(startPos) || !RcVec3f.IsFinite(endPos) || null == filter) if (!m_nav.IsValidPolyRef(startRef) || !m_nav.IsValidPolyRef(endRef) || !RcVec3f.IsFinite(startPos) || !RcVec3f.IsFinite(endPos) || null == filter)
{ {
return Results.InvalidParam<List<long>>(); return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
} }
var heuristic = fpo.heuristic; var heuristic = fpo.heuristic;
@ -790,9 +795,8 @@ namespace DotRecast.Detour
if (startRef == endRef) if (startRef == endRef)
{ {
List<long> singlePath = new List<long>(1); path.Add(startRef);
singlePath.Add(startRef); return DtStatus.DT_SUCCSESS;
return Results.Success(singlePath);
} }
m_nodePool.Clear(); m_nodePool.Clear();
@ -810,7 +814,6 @@ namespace DotRecast.Detour
DtNode lastBestNode = startNode; DtNode lastBestNode = startNode;
float lastBestNodeCost = startNode.total; float lastBestNodeCost = startNode.total;
DtStatus status = DtStatus.DT_SUCCSESS;
while (!m_openList.IsEmpty()) while (!m_openList.IsEmpty())
{ {
@ -910,9 +913,9 @@ namespace DotRecast.Detour
List<long> shortcut = null; List<long> shortcut = null;
if (tryLOS) 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); DT_RAYCAST_USE_COSTS, grandpaRef, out var rayHit);
if (status.Succeeded()) if (rayStatus.Succeeded())
{ {
foundShortCut = rayHit.t >= 1.0f; foundShortCut = rayHit.t >= 1.0f;
if (foundShortCut) if (foundShortCut)
@ -991,15 +994,13 @@ namespace DotRecast.Detour
} }
} }
var path = new List<long>(); var status = GetPathToNode(lastBestNode, ref path);
GetPathToNode(lastBestNode, ref path);
if (lastBestNode.id != endRef) 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. // Reverse the path.
if (m_query.lastBestNode.id != m_query.endRef) 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); GetPathToNode(m_query.lastBestNode, ref path);
} }
DtStatus status = m_query.status; var details = m_query.status & DtStatus.DT_STATUS_DETAIL_MASK;
// Reset query. // Reset query.
m_query = new DtQueryData(); 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 /// Finalizes and returns the results of an incomplete sliced path query, returning the path to the furthest

View File

@ -196,8 +196,8 @@ public class TestNavmeshTool : IRcTool
{ {
if (m_sposSet && m_eposSet && m_startRef != 0 && m_endRef != 0) 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, 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)).result; new(enableRaycast ? DtNavMeshQuery.DT_FINDPATH_ANY_ANGLE : 0, float.MaxValue));
if (0 < m_polys.Count) if (0 < m_polys.Count)
{ {
List<long> polys = new(m_polys); List<long> polys = new(m_polys);
@ -330,8 +330,8 @@ public class TestNavmeshTool : IRcTool
{ {
if (m_sposSet && m_eposSet && m_startRef != 0 && m_endRef != 0) 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, 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)).result; new(enableRaycast ? DtNavMeshQuery.DT_FINDPATH_ANY_ANGLE : 0, float.MaxValue));
if (0 < m_polys.Count) if (0 < m_polys.Count)
{ {
// In case of partial path, make sure the end point is clamped to the last polygon. // In case of partial path, make sure the end point is clamped to the last polygon.

View File

@ -43,7 +43,8 @@ public class DynamicNavMeshTest
query.FindNearestPoly(START_POS, EXTENT, filter, out var startRef, out var startPt, out var _); 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 _); query.FindNearestPoly(END_POS, EXTENT, filter, out var endRef, out var endPt, out var _);
List<long> path = query.FindPath(startRef, endRef, startPt, endPt, filter, new(DtNavMeshQuery.DT_FINDPATH_ANY_ANGLE, float.MaxValue)).result; var path = new List<long>();
query.FindPath(startRef, endRef, startPt, endPt, filter, ref path, DtFindPathOption.AnyAngle);
// check path length without any obstacles // check path length without any obstacles
Assert.That(path.Count, Is.EqualTo(16)); Assert.That(path.Count, Is.EqualTo(16));
@ -61,7 +62,7 @@ public class DynamicNavMeshTest
// find path again // find path again
query.FindNearestPoly(START_POS, EXTENT, filter, out startRef, out startPt, out var _); query.FindNearestPoly(START_POS, EXTENT, filter, out startRef, out startPt, out var _);
query.FindNearestPoly(END_POS, EXTENT, filter, out endRef, out endPt, 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 // check path length with obstacles
Assert.That(path.Count, Is.EqualTo(19)); Assert.That(path.Count, Is.EqualTo(19));
@ -77,7 +78,7 @@ public class DynamicNavMeshTest
// find path one more time // find path one more time
query.FindNearestPoly(START_POS, EXTENT, filter, out startRef, out startPt, out var _); query.FindNearestPoly(START_POS, EXTENT, filter, out startRef, out startPt, out var _);
query.FindNearestPoly(END_POS, EXTENT, filter, out endRef, out endPt, 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 // path length should be back to the initial value
Assert.That(path.Count, Is.EqualTo(16)); Assert.That(path.Count, Is.EqualTo(16));

View File

@ -96,7 +96,9 @@ public class UnityAStarPathfindingImporterTest
IDtQueryFilter filter = new DtQueryDefaultFilter(); IDtQueryFilter filter = new DtQueryDefaultFilter();
var polys = GetNearestPolys(mesh, startPos, endPos); var polys = GetNearestPolys(mesh, startPos, endPos);
return query.FindPath(polys[0].refs, polys[1].refs, startPos, endPos, filter, DtFindPathOption.Zero); var path = new List<long>();
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) private DtPolyPoint[] GetNearestPolys(DtNavMesh mesh, params RcVec3f[] positions)

View File

@ -28,7 +28,10 @@ public class FindPathTest : AbstractDetourTest
{ {
private static readonly DtStatus[] STATUSES = 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 DtStatus.DT_SUCCSESS
}; };
@ -132,18 +135,19 @@ public class FindPathTest : AbstractDetourTest
public void TestFindPath() public void TestFindPath()
{ {
IDtQueryFilter filter = new DtQueryDefaultFilter(); IDtQueryFilter filter = new DtQueryDefaultFilter();
var path = new List<long>();
for (int i = 0; i < startRefs.Length; i++) for (int i = 0; i < startRefs.Length; i++)
{ {
long startRef = startRefs[i]; long startRef = startRefs[i];
long endRef = endRefs[i]; long endRef = endRefs[i];
RcVec3f startPos = startPoss[i]; RcVec3f startPos = startPoss[i];
RcVec3f endPos = endPoss[i]; RcVec3f endPos = endPoss[i];
Result<List<long>> path = query.FindPath(startRef, endRef, startPos, endPos, filter, DtFindPathOption.Zero); var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.NoOption);
Assert.That(path.status, Is.EqualTo(STATUSES[i])); Assert.That(status, Is.EqualTo(STATUSES[i]));
Assert.That(path.result.Count, Is.EqualTo(RESULTS[i].Length)); Assert.That(path.Count, Is.EqualTo(RESULTS[i].Length));
for (int j = 0; j < RESULTS[i].Length; j++) 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<List<long>> path = query.FinalizeSlicedFindPath(); Result<List<long>> 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)); Assert.That(path.result.Count, Is.EqualTo(RESULTS[i].Length));
for (int j = 0; j < RESULTS[i].Length; j++) for (int j = 0; j < RESULTS[i].Length; j++)
{ {
@ -179,6 +183,7 @@ public class FindPathTest : AbstractDetourTest
public void TestFindPathStraight() public void TestFindPathStraight()
{ {
IDtQueryFilter filter = new DtQueryDefaultFilter(); IDtQueryFilter filter = new DtQueryDefaultFilter();
var path = new List<long>();
for (int i = 0; i < STRAIGHT_PATHS.Length; i++) for (int i = 0; i < STRAIGHT_PATHS.Length; i++)
{ {
// startRefs.Length; i++) { // startRefs.Length; i++) {
@ -186,9 +191,9 @@ public class FindPathTest : AbstractDetourTest
long endRef = endRefs[i]; long endRef = endRefs[i];
var startPos = startPoss[i]; var startPos = startPoss[i];
var endPos = endPoss[i]; var endPos = endPoss[i];
Result<List<long>> 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<StraightPathItem>(); var straightPath = new List<StraightPathItem>();
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)); Assert.That(straightPath.Count, Is.EqualTo(STRAIGHT_PATHS[i].Length));
for (int j = 0; j < STRAIGHT_PATHS[i].Length; j++) for (int j = 0; j < STRAIGHT_PATHS[i].Length; j++)
{ {

View File

@ -65,18 +65,19 @@ public class TiledFindPathTest
public void TestFindPath() public void TestFindPath()
{ {
IDtQueryFilter filter = new DtQueryDefaultFilter(); IDtQueryFilter filter = new DtQueryDefaultFilter();
var path = new List<long>();
for (int i = 0; i < START_REFS.Length; i++) for (int i = 0; i < START_REFS.Length; i++)
{ {
long startRef = START_REFS[i]; long startRef = START_REFS[i];
long endRef = END_REFS[i]; long endRef = END_REFS[i];
RcVec3f startPos = START_POS[i]; RcVec3f startPos = START_POS[i];
RcVec3f endPos = END_POS[i]; RcVec3f endPos = END_POS[i];
Result<List<long>> path = query.FindPath(startRef, endRef, startPos, endPos, filter, DtFindPathOption.Zero); var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.NoOption);
Assert.That(path.status, Is.EqualTo(STATUSES[i])); Assert.That(status, Is.EqualTo(STATUSES[i]));
Assert.That(path.result.Count, Is.EqualTo(RESULTS[i].Length)); Assert.That(path.Count, Is.EqualTo(RESULTS[i].Length));
for (int j = 0; j < RESULTS[i].Length; j++) 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]));
} }
} }
} }

View File

@ -52,12 +52,13 @@ public class TileCacheFindPathTest : AbstractTileCacheTest
query.FindNearestPoly(start, extents, filter, out var startRef, out var startPos, out var _); 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 _); query.FindNearestPoly(end, extents, filter, out var endRef, out var endPos, out var _);
Result<List<long>> path = query.FindPath(startRef, endRef, startPos, endPos, filter, DtFindPathOption.Zero); var path = new List<long>();
var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.NoOption);
int maxStraightPath = 256; int maxStraightPath = 256;
int options = 0; int options = 0;
var pathStr = new List<StraightPathItem>(); var pathStr = new List<StraightPathItem>();
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)); Assert.That(pathStr.Count, Is.EqualTo(8));
} }
} }

View File

@ -84,18 +84,19 @@ public class TileCacheNavigationTest : AbstractTileCacheTest
public void TestFindPathWithDefaultHeuristic() public void TestFindPathWithDefaultHeuristic()
{ {
IDtQueryFilter filter = new DtQueryDefaultFilter(); IDtQueryFilter filter = new DtQueryDefaultFilter();
var path = new List<long>();
for (int i = 0; i < startRefs.Length; i++) for (int i = 0; i < startRefs.Length; i++)
{ {
long startRef = startRefs[i]; long startRef = startRefs[i];
long endRef = endRefs[i]; long endRef = endRefs[i];
RcVec3f startPos = startPoss[i]; RcVec3f startPos = startPoss[i];
RcVec3f endPos = endPoss[i]; RcVec3f endPos = endPoss[i];
Result<List<long>> path = query.FindPath(startRef, endRef, startPos, endPos, filter, DtFindPathOption.Zero); var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.NoOption);
Assert.That(path.status, Is.EqualTo(statuses[i])); Assert.That(status, Is.EqualTo(statuses[i]));
Assert.That(path.result.Count, Is.EqualTo(results[i].Length)); Assert.That(path.Count, Is.EqualTo(results[i].Length));
for (int j = 0; j < results[i].Length; j++) 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() public void TestFindPathWithNoHeuristic()
{ {
IDtQueryFilter filter = new DtQueryDefaultFilter(); IDtQueryFilter filter = new DtQueryDefaultFilter();
var path = new List<long>();
for (int i = 0; i < startRefs.Length; i++) for (int i = 0; i < startRefs.Length; i++)
{ {
long startRef = startRefs[i]; long startRef = startRefs[i];
long endRef = endRefs[i]; long endRef = endRefs[i];
RcVec3f startPos = startPoss[i]; RcVec3f startPos = startPoss[i];
RcVec3f endPos = endPoss[i]; RcVec3f endPos = endPoss[i];
Result<List<long>> path = query.FindPath(startRef, endRef, startPos, endPos, filter, new(new DefaultQueryHeuristic(0.0f), var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.ZeroScale);
0, 0)); Assert.That(status, Is.EqualTo(statuses[i]));
Assert.That(path.status, Is.EqualTo(statuses[i])); Assert.That(path.Count, Is.EqualTo(results[i].Length));
Assert.That(path.result.Count, Is.EqualTo(results[i].Length));
for (int j = 0; j < results[i].Length; j++) 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 : 확인 필요
} }
} }
} }