Changed `List<DtStraightPath>` to `Span<DtStraightPath>` for enhanced memory efficiency

This commit is contained in:
ikpil 2024-05-23 02:16:03 +09:00 committed by Ikpil
parent 5b6905bd8f
commit 99224251dc
13 changed files with 179 additions and 167 deletions

View File

@ -19,6 +19,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Changed `DtTileCacheLayerHeaderReader` to a static class
- Changed `Dictionary<int, List<DtMeshTile>>` to `DtMeshTile[]` to optimize memory usage
- Changed `MAX_STEER_POINTS` from class constant to local.
- Changed `List<DtStraightPath>` to `Span<DtStraightPath>` for enhanced memory efficiency
### Removed
- Nothing

View File

@ -944,13 +944,13 @@ namespace DotRecast.Detour.Crowd
}
// Find corners for steering
ag.corridor.FindCorners(ref ag.corners, DtCrowdConst.DT_CROWDAGENT_MAX_CORNERS, _navQuery, _filters[ag.option.queryFilterType]);
ag.ncorners = ag.corridor.FindCorners(ag.corners, DtCrowdConst.DT_CROWDAGENT_MAX_CORNERS, _navQuery, _filters[ag.option.queryFilterType]);
// Check to see if the corner after the next corner is directly visible,
// and short cut to there.
if ((ag.option.updateFlags & DtCrowdAgentUpdateFlags.DT_CROWD_OPTIMIZE_VIS) != 0 && ag.corners.Count > 0)
if ((ag.option.updateFlags & DtCrowdAgentUpdateFlags.DT_CROWD_OPTIMIZE_VIS) != 0 && ag.ncorners > 0)
{
RcVec3f target = ag.corners[Math.Min(1, ag.corners.Count - 1)].pos;
RcVec3f target = ag.corners[Math.Min(1, ag.ncorners - 1)].pos;
ag.corridor.OptimizePathVisibility(target, ag.option.pathOptimizationRange, _navQuery,
_filters[ag.option.queryFilterType]);
@ -1000,7 +1000,7 @@ namespace DotRecast.Detour.Crowd
// Adjust the path over the off-mesh connection.
long[] refs = new long[2];
if (ag.corridor.MoveOverOffmeshConnection(ag.corners[ag.corners.Count - 1].refs, refs, ref anim.startPos,
if (ag.corridor.MoveOverOffmeshConnection(ag.corners[ag.ncorners - 1].refs, refs, ref anim.startPos,
ref anim.endPos, _navQuery))
{
anim.initPos = ag.npos;
@ -1010,7 +1010,7 @@ namespace DotRecast.Detour.Crowd
anim.tmax = (RcVecUtils.Dist2D(anim.startPos, anim.endPos) / ag.option.maxSpeed) * 0.5f;
ag.state = DtCrowdAgentState.DT_CROWDAGENT_STATE_OFFMESH;
ag.corners.Clear();
ag.ncorners = 0;
ag.neis.Clear();
continue;
}

View File

@ -61,7 +61,10 @@ namespace DotRecast.Detour.Crowd
public DtCrowdAgentParams option;
/// The local path corridor corners for the agent.
public List<DtStraightPath> corners = new List<DtStraightPath>();
public DtStraightPath[] corners = new DtStraightPath[DtCrowdConst.DT_CROWDAGENT_MAX_CORNERS];
/// The number of corners.
public int ncorners;
public DtMoveRequestState targetState; // < State of the movement request.
public long targetRef; // < Target polyref of the movement request.
@ -100,16 +103,16 @@ namespace DotRecast.Detour.Crowd
public bool OverOffmeshConnection(float radius)
{
if (0 == corners.Count)
if (0 == ncorners)
return false;
bool offMeshConnection = ((corners[corners.Count - 1].flags
bool offMeshConnection = ((corners[ncorners - 1].flags
& DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
? true
: false;
if (offMeshConnection)
{
float distSq = RcVecUtils.Dist2DSqr(npos, corners[corners.Count - 1].pos);
float distSq = RcVecUtils.Dist2DSqr(npos, corners[ncorners - 1].pos);
if (distSq < radius * radius)
return true;
}
@ -119,12 +122,12 @@ namespace DotRecast.Detour.Crowd
public float GetDistanceToGoal(float range)
{
if (0 == corners.Count)
if (0 == ncorners)
return range;
bool endOfPath = ((corners[corners.Count - 1].flags & DtStraightPathFlags.DT_STRAIGHTPATH_END) != 0) ? true : false;
bool endOfPath = ((corners[ncorners - 1].flags & DtStraightPathFlags.DT_STRAIGHTPATH_END) != 0) ? true : false;
if (endOfPath)
return Math.Min(RcVecUtils.Dist2D(npos, corners[corners.Count - 1].pos), range);
return Math.Min(RcVecUtils.Dist2D(npos, corners[ncorners - 1].pos), range);
return range;
}
@ -132,10 +135,10 @@ namespace DotRecast.Detour.Crowd
public RcVec3f CalcSmoothSteerDirection()
{
RcVec3f dir = new RcVec3f();
if (0 < corners.Count)
if (0 < ncorners)
{
int ip0 = 0;
int ip1 = Math.Min(1, corners.Count - 1);
int ip1 = Math.Min(1, ncorners - 1);
var p0 = corners[ip0].pos;
var p1 = corners[ip1].pos;
@ -161,7 +164,7 @@ namespace DotRecast.Detour.Crowd
public RcVec3f CalcStraightSteerDirection()
{
RcVec3f dir = new RcVec3f();
if (0 < corners.Count)
if (0 < ncorners)
{
dir = RcVec3f.Subtract(corners[0].pos, npos);
dir.Y = 0;

View File

@ -133,42 +133,42 @@ namespace DotRecast.Detour.Crowd
/// @param[in] navquery The query object used to build the corridor.
/// @param[in] filter The filter to apply to the operation.
/// @return The number of corners returned in the corner buffers. [0 <= value <= @p maxCorners]
public int FindCorners(ref List<DtStraightPath> corners, int maxCorners, DtNavMeshQuery navquery, IDtQueryFilter filter)
public int FindCorners(Span<DtStraightPath> corners, int maxCorners, DtNavMeshQuery navquery, IDtQueryFilter filter)
{
const float MIN_TARGET_DIST = 0.01f;
var result = navquery.FindStraightPath(m_pos, m_target, m_path, m_npath, ref corners, maxCorners, 0);
if (result.Succeeded())
{
int ncorners = 0;
navquery.FindStraightPath(m_pos, m_target, m_path, m_npath, corners, out ncorners, maxCorners, 0);
// Prune points in the beginning of the path which are too close.
int start = 0;
foreach (DtStraightPath spi in corners)
while (0 < ncorners)
{
if ((spi.flags & DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0
|| RcVecUtils.Dist2DSqr(spi.pos, m_pos) > RcMath.Sqr(MIN_TARGET_DIST))
if ((corners[0].flags & DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0 ||
RcVecUtils.Dist2DSqr(corners[0].pos, m_pos) > RcMath.Sqr(MIN_TARGET_DIST))
{
break;
}
start++;
ncorners--;
if (0 < ncorners)
{
RcSpans.Move(corners, 1, 0, 3);
}
}
int end = corners.Count;
// Prune points after an off-mesh connection.
for (int i = start; i < corners.Count; i++)
for (int i = 0; i < ncorners; ++i)
{
DtStraightPath spi = corners[i];
if ((spi.flags & DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
if ((corners[i].flags & DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
{
end = i + 1;
ncorners = i + 1;
break;
}
}
corners = corners.GetRange(start, end - start);
}
return corners.Count;
return ncorners;
}
/**

View File

@ -20,9 +20,7 @@ freely, subject to the following restrictions:
using System;
using System.Collections.Generic;
using System.Reflection;
using DotRecast.Core;
using DotRecast.Core.Collections;
using DotRecast.Core.Numerics;
namespace DotRecast.Detour
@ -1485,24 +1483,27 @@ namespace DotRecast.Detour
return DtStatus.DT_SUCCESS | details;
}
protected DtStatus AppendVertex(RcVec3f pos, int flags, long refs, ref List<DtStraightPath> straightPath,
int maxStraightPath)
protected DtStatus AppendVertex(RcVec3f pos, int flags, long refs, Span<DtStraightPath> straightPath, ref int straightPathCount, int maxStraightPath)
{
if (straightPath.Count > 0 && DtUtils.VEqual(straightPath[straightPath.Count - 1].pos, pos))
if (straightPathCount > 0 && DtUtils.VEqual(straightPath[straightPathCount - 1].pos, pos))
{
// The vertices are equal, update flags and poly.
straightPath[straightPath.Count - 1] = new DtStraightPath(straightPath[straightPath.Count - 1].pos, flags, refs);
straightPath[straightPathCount - 1] = new DtStraightPath(straightPath[straightPathCount - 1].pos, flags, refs);
}
else
{
if (straightPath.Count < maxStraightPath)
{
// Append new vertex.
straightPath.Add(new DtStraightPath(pos, flags, refs));
straightPath[straightPathCount] = new DtStraightPath(pos, flags, refs);
straightPathCount++;
// If there is no space to append more vertices, return.
if (straightPathCount >= maxStraightPath)
{
return DtStatus.DT_SUCCESS | DtStatus.DT_BUFFER_TOO_SMALL;
}
// If reached end of path or there is no space to append more vertices, return.
if (flags == DtStraightPathFlags.DT_STRAIGHTPATH_END || straightPath.Count >= maxStraightPath)
// If reached end of path, return.
if (flags == DtStraightPathFlags.DT_STRAIGHTPATH_END)
{
return DtStatus.DT_SUCCESS;
}
@ -1512,9 +1513,9 @@ namespace DotRecast.Detour
}
protected DtStatus AppendPortals(int startIdx, int endIdx, RcVec3f endPos, List<long> path,
ref List<DtStraightPath> straightPath, int maxStraightPath, int options)
Span<DtStraightPath> straightPath, ref int straightPathCount, int maxStraightPath, int options)
{
var startPos = straightPath[straightPath.Count - 1].pos;
var startPos = straightPath[straightPathCount - 1].pos;
// Append or update last vertex
DtStatus stat;
for (int i = startIdx; i < endIdx; i++)
@ -1553,7 +1554,7 @@ namespace DotRecast.Detour
if (DtUtils.IntersectSegSeg2D(startPos, endPos, left, right, out var _, out var t))
{
var pt = RcVec3f.Lerp(left, right, t);
stat = AppendVertex(pt, 0, path[i + 1], ref straightPath, maxStraightPath);
stat = AppendVertex(pt, 0, path[i + 1], straightPath, ref straightPathCount, maxStraightPath);
if (!stat.InProgress())
{
return stat;
@ -1590,17 +1591,22 @@ namespace DotRecast.Detour
/// @param[in] maxStraightPath The maximum number of points the straight path arrays can hold. [Limit: > 0]
/// @param[in] options Query options. (see: #dtStraightPathOptions)
/// @returns The status flags for the query.
public virtual DtStatus FindStraightPath(RcVec3f startPos, RcVec3f endPos, List<long> path, int pathSize,
ref List<DtStraightPath> straightPath,
int maxStraightPath, int options)
public virtual DtStatus FindStraightPath(RcVec3f startPos, RcVec3f endPos,
List<long> path, int pathSize,
Span<DtStraightPath> straightPath, out int straightPathCount, int maxStraightPath,
int options)
{
if (!startPos.IsFinite() || !endPos.IsFinite() || null == straightPath
|| null == path || pathSize <= 0 || path[0] == 0 || maxStraightPath <= 0)
straightPathCount = 0;
if (!startPos.IsFinite() || !endPos.IsFinite() ||
null == straightPath ||
null == path || pathSize <= 0 || path[0] == 0
|| maxStraightPath <= 0)
{
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM;
}
straightPath.Clear();
DtStatus stat = DtStatus.DT_STATUS_NOTHING;
// TODO: Should this be callers responsibility?
var closestStartPosRes = ClosestPointOnPolyBoundary(path[0], startPos, out var closestStartPos);
@ -1616,7 +1622,7 @@ namespace DotRecast.Detour
}
// Add start point.
DtStatus stat = AppendVertex(closestStartPos, DtStraightPathFlags.DT_STRAIGHTPATH_START, path[0], ref straightPath, maxStraightPath);
stat = AppendVertex(closestStartPos, DtStraightPathFlags.DT_STRAIGHTPATH_START, path[0], straightPath, ref straightPathCount, maxStraightPath);
if (!stat.InProgress())
{
return stat;
@ -1663,13 +1669,13 @@ namespace DotRecast.Detour
if ((options & (DtStraightPathOptions.DT_STRAIGHTPATH_AREA_CROSSINGS | DtStraightPathOptions.DT_STRAIGHTPATH_ALL_CROSSINGS)) != 0)
{
// Ignore status return value as we're just about to return anyway.
AppendPortals(apexIndex, i, closestEndPos, path, ref straightPath, maxStraightPath, options);
AppendPortals(apexIndex, i, closestEndPos, path, straightPath, ref straightPathCount, maxStraightPath, options);
}
// Ignore status return value as we're just about to return anyway.
AppendVertex(closestEndPos, 0, path[i], ref straightPath, maxStraightPath);
AppendVertex(closestEndPos, 0, path[i], straightPath, ref straightPathCount, maxStraightPath);
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM | (straightPath.Count >= maxStraightPath ? DtStatus.DT_BUFFER_TOO_SMALL : DtStatus.DT_STATUS_NOTHING);
return DtStatus.DT_FAILURE | DtStatus.DT_INVALID_PARAM | (straightPathCount >= maxStraightPath ? DtStatus.DT_BUFFER_TOO_SMALL : DtStatus.DT_STATUS_NOTHING);
}
// If starting really close the portal, advance.
@ -1705,7 +1711,7 @@ namespace DotRecast.Detour
// Append portals along the current straight path segment.
if ((options & (DtStraightPathOptions.DT_STRAIGHTPATH_AREA_CROSSINGS | DtStraightPathOptions.DT_STRAIGHTPATH_ALL_CROSSINGS)) != 0)
{
stat = AppendPortals(apexIndex, leftIndex, portalLeft, path, ref straightPath, maxStraightPath, options);
stat = AppendPortals(apexIndex, leftIndex, portalLeft, path, straightPath, ref straightPathCount, maxStraightPath, options);
if (!stat.InProgress())
{
return stat;
@ -1728,7 +1734,7 @@ namespace DotRecast.Detour
long refs = leftPolyRef;
// Append or update vertex
stat = AppendVertex(portalApex, flags, refs, ref straightPath, maxStraightPath);
stat = AppendVertex(portalApex, flags, refs, straightPath, ref straightPathCount, maxStraightPath);
if (!stat.InProgress())
{
return stat;
@ -1761,7 +1767,7 @@ namespace DotRecast.Detour
// Append portals along the current straight path segment.
if ((options & (DtStraightPathOptions.DT_STRAIGHTPATH_AREA_CROSSINGS | DtStraightPathOptions.DT_STRAIGHTPATH_ALL_CROSSINGS)) != 0)
{
stat = AppendPortals(apexIndex, rightIndex, portalRight, path, ref straightPath, maxStraightPath, options);
stat = AppendPortals(apexIndex, rightIndex, portalRight, path, straightPath, ref straightPathCount, maxStraightPath, options);
if (!stat.InProgress())
{
return stat;
@ -1784,7 +1790,7 @@ namespace DotRecast.Detour
long refs = rightPolyRef;
// Append or update vertex
stat = AppendVertex(portalApex, flags, refs, ref straightPath, maxStraightPath);
stat = AppendVertex(portalApex, flags, refs, straightPath, ref straightPathCount, maxStraightPath);
if (!stat.InProgress())
{
return stat;
@ -1806,7 +1812,7 @@ namespace DotRecast.Detour
// Append portals along the current straight path segment.
if ((options & (DtStraightPathOptions.DT_STRAIGHTPATH_AREA_CROSSINGS | DtStraightPathOptions.DT_STRAIGHTPATH_ALL_CROSSINGS)) != 0)
{
stat = AppendPortals(apexIndex, pathSize - 1, closestEndPos, path, ref straightPath, maxStraightPath, options);
stat = AppendPortals(apexIndex, pathSize - 1, closestEndPos, path, straightPath, ref straightPathCount, maxStraightPath, options);
if (!stat.InProgress())
{
return stat;
@ -1815,8 +1821,8 @@ namespace DotRecast.Detour
}
// Ignore status return value as we're just about to return anyway.
AppendVertex(closestEndPos, DtStraightPathFlags.DT_STRAIGHTPATH_END, 0, ref straightPath, maxStraightPath);
return DtStatus.DT_SUCCESS | (straightPath.Count >= maxStraightPath ? DtStatus.DT_BUFFER_TOO_SMALL : DtStatus.DT_STATUS_NOTHING);
AppendVertex(closestEndPos, DtStraightPathFlags.DT_STRAIGHTPATH_END, 0, straightPath, ref straightPathCount, maxStraightPath);
return DtStatus.DT_SUCCESS | (straightPathCount >= maxStraightPath ? DtStatus.DT_BUFFER_TOO_SMALL : DtStatus.DT_STATUS_NOTHING);
}
/// @par

View File

@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using DotRecast.Core.Numerics;
namespace DotRecast.Detour
{
public class DtNavMeshQueryMock : DtNavMeshQuery
{
private readonly DtStraightPath[] _straightPath;
private readonly DtStatus _status;
public DtNavMeshQueryMock(DtStraightPath[] straightPath, DtStatus status)
: base(null)
{
_straightPath = straightPath;
_status = status;
}
public override DtStatus FindStraightPath(RcVec3f startPos, RcVec3f endPos,
List<long> path, int pathSize,
Span<DtStraightPath> straightPath, out int straightPathCount, int maxStraightPath,
int options)
{
straightPathCount = 0;
for (int i = 0; i < _straightPath.Length && i < maxStraightPath; ++i)
{
straightPath[i] = _straightPath[i];
straightPathCount += 1;
}
return _status;
}
}
}

View File

@ -40,8 +40,8 @@ namespace DotRecast.Detour
steerPosRef = 0;
// Find steer target.
var straightPath = new List<DtStraightPath>(MAX_STEER_POINTS);
var result = navQuery.FindStraightPath(startPos, endPos, path, pathSize, ref straightPath, MAX_STEER_POINTS, 0);
Span<DtStraightPath> straightPath = stackalloc DtStraightPath[MAX_STEER_POINTS];
var result = navQuery.FindStraightPath(startPos, endPos, path, pathSize, straightPath, out var nsteerPath, MAX_STEER_POINTS, 0);
if (result.Failed())
{
return false;
@ -49,7 +49,7 @@ namespace DotRecast.Detour
// Find vertex far enough to steer to.
int ns = 0;
while (ns < straightPath.Count)
while (ns < nsteerPath)
{
// Stop at Off-Mesh link or when point is further than slop away.
if (((straightPath[ns].flags & DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
@ -59,7 +59,7 @@ namespace DotRecast.Detour
}
// Failed to find good point to steer to.
if (ns >= straightPath.Count)
if (ns >= nsteerPath)
return false;
steerPos = straightPath[ns].pos;

View File

@ -251,10 +251,10 @@ public class CrowdSampleTool : ISampleTool
if (_showCorners)
{
if (0 < ag.corners.Count)
if (0 < ag.ncorners)
{
dd.Begin(LINES, 2.0f);
for (int j = 0; j < ag.corners.Count; ++j)
for (int j = 0; j < ag.ncorners; ++j)
{
RcVec3f va = j == 0 ? pos : ag.corners[j - 1].pos;
RcVec3f vb = ag.corners[j].pos;
@ -262,10 +262,10 @@ public class CrowdSampleTool : ISampleTool
dd.Vertex(vb.X, vb.Y + radius, vb.Z, DuRGBA(128, 0, 0, 192));
}
if ((ag.corners[ag.corners.Count - 1].flags
if ((ag.corners[ag.ncorners - 1].flags
& DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION) != 0)
{
RcVec3f v = ag.corners[ag.corners.Count - 1].pos;
RcVec3f v = ag.corners[ag.ncorners - 1].pos;
dd.Vertex(v.X, v.Y, v.Z, DuRGBA(192, 0, 0, 192));
dd.Vertex(v.X, v.Y + radius * 2, v.Z, DuRGBA(192, 0, 0, 192));
}

View File

@ -57,7 +57,8 @@ public class TestNavmeshSampleTool : ISampleTool
private bool m_hitResult;
private float m_distanceToWall;
private List<DtStraightPath> m_straightPath;
private DtStraightPath[] m_straightPath;
private int m_straightPathCount;
private List<long> m_polys;
private List<long> m_parent;
private float m_neighbourhoodRadius;
@ -77,6 +78,8 @@ public class TestNavmeshSampleTool : ISampleTool
SampleAreaModifications.SAMPLE_POLYFLAGS_DISABLED,
new float[] { 1f, 1f, 1f, 1f, 2f, 1.5f }
);
m_straightPath = new DtStraightPath[MAX_POLYS];
m_straightPathCount = 0;
}
public void Layout()
@ -284,7 +287,7 @@ public class TestNavmeshSampleTool : ISampleTool
int spathCol = DuRGBA(64, 16, 0, 220);
int offMeshCol = DuRGBA(128, 96, 0, 220);
dd.Begin(LINES, 2.0f);
for (int i = 0; i < m_straightPath.Count - 1; ++i)
for (int i = 0; i < m_straightPathCount - 1; ++i)
{
DtStraightPath straightPathItem = m_straightPath[i];
DtStraightPath straightPathItem2 = m_straightPath[i + 1];
@ -304,7 +307,7 @@ public class TestNavmeshSampleTool : ISampleTool
dd.End();
dd.Begin(POINTS, 6.0f);
for (int i = 0; i < m_straightPath.Count; ++i)
for (int i = 0; i < m_straightPathCount; ++i)
{
DtStraightPath straightPathItem = m_straightPath[i];
int col;
@ -349,7 +352,7 @@ public class TestNavmeshSampleTool : ISampleTool
dd.DepthMask(false);
int spathCol = m_hitResult ? DuRGBA(64, 16, 0, 220) : DuRGBA(240, 240, 240, 220);
dd.Begin(LINES, 2.0f);
for (int i = 0; i < m_straightPath.Count - 1; ++i)
for (int i = 0; i < m_straightPathCount - 1; ++i)
{
DtStraightPath straightPathItem = m_straightPath[i];
DtStraightPath straightPathItem2 = m_straightPath[i + 1];
@ -359,7 +362,7 @@ public class TestNavmeshSampleTool : ISampleTool
dd.End();
dd.Begin(POINTS, 4.0f);
for (int i = 0; i < m_straightPath.Count; ++i)
for (int i = 0; i < m_straightPathCount; ++i)
{
DtStraightPath straightPathItem = m_straightPath[i];
dd.Vertex(straightPathItem.pos.X, straightPathItem.pos.Y + 0.4f, straightPathItem.pos.Z, spathCol);
@ -666,18 +669,18 @@ public class TestNavmeshSampleTool : ISampleTool
else if (_mode == RcTestNavmeshToolMode.PATHFIND_STRAIGHT)
{
_tool.FindStraightPath(navQuery, m_startRef, m_endRef, m_spos, m_epos, m_filter, _enableRaycast,
ref m_polys, ref m_straightPath, _straightPathOption);
ref m_polys, m_straightPath, out m_straightPathCount, MAX_POLYS, _straightPathOption);
}
else if (_mode == RcTestNavmeshToolMode.PATHFIND_SLICED)
{
m_polys?.Clear();
m_straightPath?.Clear();
m_straightPathCount = 0;
m_pathFindStatus = _tool.InitSlicedFindPath(navQuery, m_startRef, m_endRef, m_spos, m_epos, m_filter, _enableRaycast);
}
else if (_mode == RcTestNavmeshToolMode.RAYCAST)
{
_tool.Raycast(navQuery, m_startRef, m_endRef, m_spos, m_epos, m_filter,
ref m_polys, ref m_straightPath, ref m_hitPos, ref m_hitNormal, ref m_hitResult);
ref m_polys, m_straightPath, out m_straightPathCount, MAX_POLYS, ref m_hitPos, ref m_hitNormal, ref m_hitResult);
}
else if (_mode == RcTestNavmeshToolMode.DISTANCE_TO_WALL)
{
@ -712,7 +715,7 @@ public class TestNavmeshSampleTool : ISampleTool
if (m_pathFindStatus.InProgress())
{
m_pathFindStatus = _tool.UpdateSlicedFindPath(navQuery, 1, m_endRef, m_spos, m_epos, ref m_polys, ref m_straightPath);
m_pathFindStatus = _tool.UpdateSlicedFindPath(navQuery, 1, m_endRef, m_spos, m_epos, ref m_polys, m_straightPath, out m_straightPathCount, MAX_POLYS);
}
}
}

View File

@ -11,7 +11,6 @@ namespace DotRecast.Recast.Toolset.Tools
public const int MAX_POLYS = 256;
public const int MAX_SMOOTH = 2048;
public RcTestNavMeshTool()
{
}
@ -172,15 +171,15 @@ namespace DotRecast.Recast.Toolset.Tools
}
public DtStatus FindStraightPath(DtNavMeshQuery navQuery, long startRef, long endRef, RcVec3f startPt, RcVec3f endPt, IDtQueryFilter filter, bool enableRaycast,
ref List<long> polys, ref List<DtStraightPath> straightPath, int straightPathOptions)
ref List<long> polys, Span<DtStraightPath> straightPath, out int straightPathCount, int maxStraightPath, int straightPathOptions)
{
straightPathCount = 0;
if (startRef == 0 || endRef == 0)
{
return DtStatus.DT_FAILURE;
}
polys ??= new List<long>();
straightPath ??= new List<DtStraightPath>();
polys.Clear();
straightPath.Clear();
@ -202,7 +201,7 @@ namespace DotRecast.Recast.Toolset.Tools
}
}
navQuery.FindStraightPath(startPt, epos, polys, polys.Count, ref straightPath, MAX_POLYS, straightPathOptions);
navQuery.FindStraightPath(startPt, epos, polys, polys.Count, straightPath, out straightPathCount, maxStraightPath, straightPathOptions);
return DtStatus.DT_SUCCESS;
}
@ -221,8 +220,9 @@ namespace DotRecast.Recast.Toolset.Tools
}
public DtStatus UpdateSlicedFindPath(DtNavMeshQuery navQuery, int maxIter, long endRef, RcVec3f startPos, RcVec3f endPos,
ref List<long> path, ref List<DtStraightPath> straightPath)
ref List<long> path, Span<DtStraightPath> straightPath, out int straightPathCount, int maxStraightPath)
{
straightPathCount = 0;
var status = navQuery.UpdateSlicedFindPath(maxIter, out _);
if (!status.Succeeded())
@ -232,7 +232,6 @@ namespace DotRecast.Recast.Toolset.Tools
navQuery.FinalizeSlicedFindPath(ref path);
straightPath?.Clear();
if (path != null)
{
// In case of partial path, make sure the end point is clamped to the last polygon.
@ -246,8 +245,7 @@ namespace DotRecast.Recast.Toolset.Tools
}
}
straightPath = new List<DtStraightPath>(MAX_POLYS);
navQuery.FindStraightPath(startPos, epos, path, path.Count, ref straightPath, MAX_POLYS, DtStraightPathOptions.DT_STRAIGHTPATH_ALL_CROSSINGS);
navQuery.FindStraightPath(startPos, epos, path, path.Count, straightPath, out straightPathCount, maxStraightPath, DtStraightPathOptions.DT_STRAIGHTPATH_ALL_CROSSINGS);
}
return DtStatus.DT_SUCCESS;
@ -255,13 +253,12 @@ namespace DotRecast.Recast.Toolset.Tools
public DtStatus Raycast(DtNavMeshQuery navQuery, long startRef, long endRef, RcVec3f startPos, RcVec3f endPos, IDtQueryFilter filter,
ref List<long> polys, ref List<DtStraightPath> straightPath, ref RcVec3f hitPos, ref RcVec3f hitNormal, ref bool hitResult)
ref List<long> polys, Span<DtStraightPath> straightPath, out int straightPathCount, int maxStraightPath, ref RcVec3f hitPos, ref RcVec3f hitNormal, ref bool hitResult)
{
straightPathCount = 0;
if (startRef == 0 || endRef == 0)
{
polys?.Clear();
straightPath?.Clear();
return DtStatus.DT_FAILURE;
}
@ -299,10 +296,8 @@ namespace DotRecast.Recast.Toolset.Tools
}
}
straightPath ??= new List<DtStraightPath>();
straightPath.Clear();
straightPath.Add(new DtStraightPath(startPos, 0, 0));
straightPath.Add(new DtStraightPath(hitPos, 0, 0));
straightPath[straightPathCount++] = new DtStraightPath(startPos, 0, 0);
straightPath[straightPathCount++] = new DtStraightPath(hitPos, 0, 0);
return status;
}

View File

@ -17,15 +17,13 @@ freely, subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution.
*/
using System;
using System.Collections.Generic;
using DotRecast.Core.Numerics;
using Moq;
using NUnit.Framework;
namespace DotRecast.Detour.Crowd.Test;
public class DtPathCorridorTest
{
private readonly DtPathCorridor corridor = new DtPathCorridor();
@ -41,63 +39,35 @@ public class DtPathCorridorTest
[Test]
public void ShouldKeepOriginalPathInFindCornersWhenNothingCanBePruned()
{
List<DtStraightPath> straightPath = new();
straightPath.Add(new DtStraightPath(new RcVec3f(11, 20, 30.00001f), 0, 0));
straightPath.Add(new DtStraightPath(new RcVec3f(12, 20, 30.00002f), 0, 0));
straightPath.Add(new DtStraightPath(new RcVec3f(11f, 21, 32f), 0, 0));
straightPath.Add(new DtStraightPath(new RcVec3f(11f, 21, 32f), 0, 0));
var mockQuery = new Mock<DtNavMeshQuery>(It.IsAny<DtNavMesh>());
mockQuery.Setup(q => q.FindStraightPath(
It.IsAny<RcVec3f>(),
It.IsAny<RcVec3f>(),
It.IsAny<List<long>>(),
It.IsAny<int>(),
ref It.Ref<List<DtStraightPath>>.IsAny,
It.IsAny<int>(),
It.IsAny<int>())
)
.Callback((RcVec3f startPos, RcVec3f endPos, List<long> path, int pathSize,
ref List<DtStraightPath> refStraightPath, int maxStraightPath, int options) =>
{
refStraightPath = straightPath;
})
.Returns(() => DtStatus.DT_SUCCESS);
var straightPath = new DtStraightPath[4];
straightPath[0] = new DtStraightPath(new RcVec3f(11, 20, 30.00001f), 0, 0);
straightPath[1] = new DtStraightPath(new RcVec3f(12, 20, 30.00002f), 0, 0);
straightPath[2] = new DtStraightPath(new RcVec3f(11f, 21, 32f), 0, 0);
straightPath[3] = new DtStraightPath(new RcVec3f(11f, 21, 32f), 0, 0);
var query = new DtNavMeshQueryMock(straightPath, DtStatus.DT_SUCCESS);
var path = new List<DtStraightPath>();
corridor.FindCorners(ref path, int.MaxValue, mockQuery.Object, filter);
Assert.That(path.Count, Is.EqualTo(4));
Assert.That(path, Is.EqualTo(straightPath));
Span<DtStraightPath> path = stackalloc DtStraightPath[8];
var npath = corridor.FindCorners(path, 8, query, filter);
Assert.That(npath, Is.EqualTo(4));
Assert.That(path.Slice(0, npath).ToArray(), Is.EqualTo(straightPath));
}
[Test]
public void ShouldPrunePathInFindCorners()
{
List<DtStraightPath> straightPath = new();
straightPath.Add(new DtStraightPath(new RcVec3f(10, 20, 30.00001f), 0, 0)); // too close
straightPath.Add(new DtStraightPath(new RcVec3f(10, 20, 30.00002f), 0, 0)); // too close
straightPath.Add(new DtStraightPath(new RcVec3f(11f, 21, 32f), 0, 0));
straightPath.Add(new DtStraightPath(new RcVec3f(12f, 22, 33f), DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION, 0)); // offmesh
straightPath.Add(new DtStraightPath(new RcVec3f(11f, 21, 32f), DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION, 0)); // offmesh
DtStraightPath[] straightPath = new DtStraightPath[5];
straightPath[0] = (new DtStraightPath(new RcVec3f(10, 20, 30.00001f), 0, 0)); // too close
straightPath[1] = (new DtStraightPath(new RcVec3f(10, 20, 30.00002f), 0, 0)); // too close
straightPath[2] = (new DtStraightPath(new RcVec3f(11f, 21, 32f), 0, 0));
straightPath[3] = (new DtStraightPath(new RcVec3f(12f, 22, 33f), DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION, 0)); // offmesh
straightPath[4] = (new DtStraightPath(new RcVec3f(11f, 21, 32f), DtStraightPathFlags.DT_STRAIGHTPATH_OFFMESH_CONNECTION, 0)); // offmesh
var mockQuery = new Mock<DtNavMeshQuery>(It.IsAny<DtNavMesh>());
mockQuery.Setup(q => q.FindStraightPath(
It.IsAny<RcVec3f>(),
It.IsAny<RcVec3f>(),
It.IsAny<List<long>>(),
It.IsAny<int>(),
ref It.Ref<List<DtStraightPath>>.IsAny,
It.IsAny<int>(),
It.IsAny<int>())
).Callback((RcVec3f startPos, RcVec3f endPos, List<long> path, int pathSize,
ref List<DtStraightPath> refStraightPath, int maxStraightPath, int options) =>
{
refStraightPath = straightPath;
})
.Returns(() => DtStatus.DT_SUCCESS);
var query = new DtNavMeshQueryMock(straightPath, DtStatus.DT_SUCCESS);
var path = new List<DtStraightPath>();
corridor.FindCorners(ref path, int.MaxValue, mockQuery.Object, filter);
Assert.That(path.Count, Is.EqualTo(2));
Assert.That(path, Is.EqualTo(new List<DtStraightPath> { straightPath[2], straightPath[3] }));
Span<DtStraightPath> path = stackalloc DtStraightPath[8];
int npath = corridor.FindCorners(path, 8, query, filter);
Assert.That(npath, Is.EqualTo(2));
Assert.That(path.Slice(0, npath).ToArray(), Is.EqualTo(new DtStraightPath[] { straightPath[2], straightPath[3] }));
}
}

View File

@ -16,13 +16,13 @@ freely, subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution.
*/
using System;
using System.Collections.Generic;
using DotRecast.Core.Numerics;
using NUnit.Framework;
namespace DotRecast.Detour.Test;
public class FindPathTest : AbstractDetourTest
{
private static readonly DtStatus[] STATUSES =
@ -184,6 +184,7 @@ public class FindPathTest : AbstractDetourTest
{
IDtQueryFilter filter = new DtQueryDefaultFilter();
var path = new List<long>();
Span<DtStraightPath> straightPath = stackalloc DtStraightPath[256];
for (int i = 0; i < STRAIGHT_PATHS.Length; i++)
{
// startRefs.Length; i++) {
@ -192,9 +193,8 @@ public class FindPathTest : AbstractDetourTest
var startPos = startPoss[i];
var endPos = endPoss[i];
var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.NoOption);
var straightPath = new List<DtStraightPath>();
query.FindStraightPath(startPos, endPos, path, path.Count, ref straightPath, int.MaxValue, 0);
Assert.That(straightPath.Count, Is.EqualTo(STRAIGHT_PATHS[i].Length));
query.FindStraightPath(startPos, endPos, path, path.Count, straightPath, out var nstraightPath, 256, 0);
Assert.That(nstraightPath, Is.EqualTo(STRAIGHT_PATHS[i].Length));
for (int j = 0; j < STRAIGHT_PATHS[i].Length; j++)
{
Assert.That(straightPath[j].refs, Is.EqualTo(STRAIGHT_PATHS[i][j].refs));

View File

@ -18,6 +18,7 @@ freely, subject to the following restrictions:
3. This notice may not be removed or altered from any source distribution.
*/
using System;
using System.Collections.Generic;
using System.IO;
using DotRecast.Core;
@ -29,7 +30,6 @@ using NUnit.Framework;
namespace DotRecast.Detour.TileCache.Test;
public class TileCacheFindPathTest : AbstractTileCacheTest
{
private readonly RcVec3f start = new RcVec3f(39.44734f, 9.998177f, -0.784811f);
@ -56,11 +56,11 @@ public class TileCacheFindPathTest : AbstractTileCacheTest
var path = new List<long>();
var status = query.FindPath(startRef, endRef, startPos, endPos, filter, ref path, DtFindPathOption.NoOption);
int maxStraightPath = 256;
const int maxStraightPath = 256;
int options = 0;
var pathStr = new List<DtStraightPath>();
query.FindStraightPath(startPos, endPos, path, path.Count, ref pathStr, maxStraightPath, options);
Assert.That(pathStr.Count, Is.EqualTo(8));
Span<DtStraightPath> pathStr = stackalloc DtStraightPath[maxStraightPath];
query.FindStraightPath(startPos, endPos, path, path.Count, pathStr, out var npathStr, maxStraightPath, options);
Assert.That(npathStr, Is.EqualTo(8));
}
}