forked from bit/DotRecastNetSim
Compare commits
4 Commits
pr/accepta
...
main
Author | SHA1 | Date |
---|---|---|
ikpil | b81a5923a3 | |
ikpil | 3fbfb968d0 | |
ikpil | 3c4723c907 | |
ikpil | 7836b78bb4 |
|
@ -6,7 +6,7 @@ namespace DotRecast.Core.Buffers
|
||||||
{
|
{
|
||||||
public static class RcRentedArray
|
public static class RcRentedArray
|
||||||
{
|
{
|
||||||
public static RcRentedArray<T> RentDisposableArray<T>(int minimumLength)
|
public static RcRentedArray<T> Rent<T>(int minimumLength)
|
||||||
{
|
{
|
||||||
var array = ArrayPool<T>.Shared.Rent(minimumLength);
|
var array = ArrayPool<T>.Shared.Rent(minimumLength);
|
||||||
return new RcRentedArray<T>(ArrayPool<T>.Shared, array, minimumLength);
|
return new RcRentedArray<T>(ArrayPool<T>.Shared, array, minimumLength);
|
||||||
|
@ -17,44 +17,41 @@ namespace DotRecast.Core.Buffers
|
||||||
{
|
{
|
||||||
private ArrayPool<T> _owner;
|
private ArrayPool<T> _owner;
|
||||||
private T[] _array;
|
private T[] _array;
|
||||||
private readonly RcAtomicInteger _disposed;
|
|
||||||
|
|
||||||
public int Length { get; }
|
public int Length { get; }
|
||||||
|
public bool IsDisposed => null == _owner || null == _array;
|
||||||
|
|
||||||
internal RcRentedArray(ArrayPool<T> owner, T[] array, int length)
|
internal RcRentedArray(ArrayPool<T> owner, T[] array, int length)
|
||||||
{
|
{
|
||||||
_owner = owner;
|
_owner = owner;
|
||||||
_array = array;
|
_array = array;
|
||||||
Length = length;
|
Length = length;
|
||||||
_disposed = new RcAtomicInteger(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public T this[int index]
|
public ref T this[int index]
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
||||||
return _array[index];
|
return ref _array[index];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
public T[] AsArray()
|
||||||
set
|
{
|
||||||
{
|
return _array;
|
||||||
RcThrowHelper.ThrowExceptionIfIndexOutOfRange(index, Length);
|
|
||||||
_array[index] = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
if (1 != _disposed.IncrementAndGet())
|
if (null != _owner && null != _array)
|
||||||
return;
|
{
|
||||||
|
_owner.Return(_array, true);
|
||||||
_owner?.Return(_array, true);
|
_owner = null;
|
||||||
_array = null;
|
_array = null;
|
||||||
_owner = null;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -168,7 +168,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate temp buffer for merging paths.
|
// Allocate temp buffer for merging paths.
|
||||||
_maxPathResult = 256;
|
_maxPathResult = DtCrowdConst.MAX_PATH_RESULT;
|
||||||
_pathQ = new DtPathQueue(config);
|
_pathQ = new DtPathQueue(config);
|
||||||
_agents = new List<DtCrowdAgent>();
|
_agents = new List<DtCrowdAgent>();
|
||||||
|
|
||||||
|
|
|
@ -30,5 +30,6 @@
|
||||||
public const int MAX_ITERS_PER_UPDATE = 100;
|
public const int MAX_ITERS_PER_UPDATE = 100;
|
||||||
public const int MAX_PATHQUEUE_NODES = 4096;
|
public const int MAX_PATHQUEUE_NODES = 4096;
|
||||||
public const int MAX_COMMON_NODES = 512;
|
public const int MAX_COMMON_NODES = 512;
|
||||||
|
public const int MAX_PATH_RESULT = 256;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -215,7 +215,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
if (res.Count > 1 && t > 0.99f)
|
if (res.Count > 1 && t > 0.99f)
|
||||||
{
|
{
|
||||||
m_path = DtPathUtils.MergeCorridorStartShortcut(m_path, m_maxPath, res);
|
m_path = DtPathUtils.MergeCorridorStartShortcut(m_path, m_path.Count, m_maxPath, res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -241,13 +241,13 @@ namespace DotRecast.Detour.Crowd
|
||||||
}
|
}
|
||||||
|
|
||||||
var res = new List<long>();
|
var res = new List<long>();
|
||||||
navquery.InitSlicedFindPath(m_path[0], m_path[m_path.Count - 1], m_pos, m_target, filter, 0);
|
navquery.InitSlicedFindPath(m_path[0], m_path[^1], m_pos, m_target, filter, 0);
|
||||||
navquery.UpdateSlicedFindPath(maxIterations, out var _);
|
navquery.UpdateSlicedFindPath(maxIterations, out var _);
|
||||||
var status = navquery.FinalizeSlicedFindPathPartial(m_path, ref res);
|
var status = navquery.FinalizeSlicedFindPathPartial(m_path, ref res);
|
||||||
|
|
||||||
if (status.Succeeded() && res.Count > 0)
|
if (status.Succeeded() && res.Count > 0)
|
||||||
{
|
{
|
||||||
m_path = DtPathUtils.MergeCorridorStartShortcut(m_path, m_maxPath, res);
|
m_path = DtPathUtils.MergeCorridorStartShortcut(m_path, m_path.Count, m_maxPath, res);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,7 +316,7 @@ namespace DotRecast.Detour.Crowd
|
||||||
var status = navquery.MoveAlongSurface(m_path[0], m_pos, npos, filter, out var result, ref visited);
|
var status = navquery.MoveAlongSurface(m_path[0], m_pos, npos, filter, out var result, ref visited);
|
||||||
if (status.Succeeded())
|
if (status.Succeeded())
|
||||||
{
|
{
|
||||||
m_path = DtPathUtils.MergeCorridorStartMoved(m_path, m_maxPath, visited);
|
m_path = DtPathUtils.MergeCorridorStartMoved(m_path, m_path.Count, m_maxPath, visited);
|
||||||
|
|
||||||
// Adjust the position to stay on top of the navmesh.
|
// Adjust the position to stay on top of the navmesh.
|
||||||
m_pos = result;
|
m_pos = result;
|
||||||
|
@ -355,10 +355,10 @@ namespace DotRecast.Detour.Crowd
|
||||||
{
|
{
|
||||||
// Move along navmesh and update new position.
|
// Move along navmesh and update new position.
|
||||||
var visited = new List<long>();
|
var visited = new List<long>();
|
||||||
var status = navquery.MoveAlongSurface(m_path[m_path.Count - 1], m_target, npos, filter, out var result, ref visited);
|
var status = navquery.MoveAlongSurface(m_path[^1], m_target, npos, filter, out var result, ref visited);
|
||||||
if (status.Succeeded())
|
if (status.Succeeded())
|
||||||
{
|
{
|
||||||
m_path = DtPathUtils.MergeCorridorEndMoved(m_path, m_maxPath, visited);
|
m_path = DtPathUtils.MergeCorridorEndMoved(m_path, m_path.Count, m_maxPath, visited);
|
||||||
// TODO: should we do that?
|
// TODO: should we do that?
|
||||||
// Adjust the position to stay on top of the navmesh.
|
// Adjust the position to stay on top of the navmesh.
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -358,8 +358,8 @@ namespace DotRecast.Detour
|
||||||
var tbmax = tile.data.header.bmax;
|
var tbmax = tile.data.header.bmax;
|
||||||
float qfac = tile.data.header.bvQuantFactor;
|
float qfac = tile.data.header.bvQuantFactor;
|
||||||
// Calculate quantized box
|
// Calculate quantized box
|
||||||
Span<int> bmin = stackalloc int[3];
|
int[] bmin = new int[3];
|
||||||
Span<int> bmax = stackalloc int[3];
|
int[] bmax = new int[3];
|
||||||
// dtClamp query box to world box.
|
// dtClamp query box to world box.
|
||||||
float minx = Math.Clamp(qmin.X, tbmin.X, tbmax.X) - tbmin.X;
|
float minx = Math.Clamp(qmin.X, tbmin.X, tbmax.X) - tbmin.X;
|
||||||
float miny = Math.Clamp(qmin.Y, tbmin.Y, tbmax.Y) - tbmin.Y;
|
float miny = Math.Clamp(qmin.Y, tbmin.Y, tbmax.Y) - tbmin.Y;
|
||||||
|
|
|
@ -583,8 +583,8 @@ namespace DotRecast.Detour
|
||||||
var tbmax = tile.data.header.bmax;
|
var tbmax = tile.data.header.bmax;
|
||||||
float qfac = tile.data.header.bvQuantFactor;
|
float qfac = tile.data.header.bvQuantFactor;
|
||||||
// Calculate quantized box
|
// Calculate quantized box
|
||||||
Span<int> bmin = stackalloc int[3];
|
int[] bmin = new int[3];
|
||||||
Span<int> bmax = stackalloc int[3];
|
int[] bmax = new int[3];
|
||||||
// dtClamp query box to world box.
|
// dtClamp query box to world box.
|
||||||
float minx = Math.Clamp(qmin.X, tbmin.X, tbmax.X) - tbmin.X;
|
float minx = Math.Clamp(qmin.X, tbmin.X, tbmax.X) - tbmin.X;
|
||||||
float miny = Math.Clamp(qmin.Y, tbmin.Y, tbmax.Y) - tbmin.Y;
|
float miny = Math.Clamp(qmin.Y, tbmin.Y, tbmax.Y) - tbmin.Y;
|
||||||
|
@ -1824,9 +1824,6 @@ namespace DotRecast.Detour
|
||||||
|
|
||||||
float[] verts = new float[m_nav.GetMaxVertsPerPoly() * 3];
|
float[] verts = new float[m_nav.GetMaxVertsPerPoly() * 3];
|
||||||
|
|
||||||
const int MAX_NEIS = 8;
|
|
||||||
Span<long> neis = stackalloc long[MAX_NEIS];
|
|
||||||
|
|
||||||
while (0 < stack.Count)
|
while (0 < stack.Count)
|
||||||
{
|
{
|
||||||
// Pop front.
|
// Pop front.
|
||||||
|
@ -1857,7 +1854,9 @@ namespace DotRecast.Detour
|
||||||
for (int i = 0, j = curPoly.vertCount - 1; i < curPoly.vertCount; j = i++)
|
for (int i = 0, j = curPoly.vertCount - 1; i < curPoly.vertCount; j = i++)
|
||||||
{
|
{
|
||||||
// Find links to neighbours.
|
// Find links to neighbours.
|
||||||
|
int MAX_NEIS = 8;
|
||||||
int nneis = 0;
|
int nneis = 0;
|
||||||
|
long[] neis = new long[MAX_NEIS];
|
||||||
|
|
||||||
if ((curPoly.neis[j] & DtNavMesh.DT_EXT_LINK) != 0)
|
if ((curPoly.neis[j] & DtNavMesh.DT_EXT_LINK) != 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -141,7 +141,7 @@ namespace DotRecast.Detour
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<long> MergeCorridorStartMoved(List<long> path, int maxPath, List<long> visited)
|
public static List<long> MergeCorridorStartMoved(List<long> path, int npath, int maxPath, List<long> visited)
|
||||||
{
|
{
|
||||||
int furthestPath = -1;
|
int furthestPath = -1;
|
||||||
int furthestVisited = -1;
|
int furthestVisited = -1;
|
||||||
|
@ -186,7 +186,7 @@ namespace DotRecast.Detour
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<long> MergeCorridorEndMoved(List<long> path, int maxPath, List<long> visited)
|
public static List<long> MergeCorridorEndMoved(List<long> path, int npath, int maxPath, List<long> visited)
|
||||||
{
|
{
|
||||||
int furthestPath = -1;
|
int furthestPath = -1;
|
||||||
int furthestVisited = -1;
|
int furthestVisited = -1;
|
||||||
|
@ -223,7 +223,7 @@ namespace DotRecast.Detour
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<long> MergeCorridorStartShortcut(List<long> path, int maxPath, List<long> visited)
|
public static List<long> MergeCorridorStartShortcut(List<long> path, int npath, int maxPath, List<long> visited)
|
||||||
{
|
{
|
||||||
int furthestPath = -1;
|
int furthestPath = -1;
|
||||||
int furthestVisited = -1;
|
int furthestVisited = -1;
|
||||||
|
|
|
@ -64,7 +64,7 @@ namespace DotRecast.Detour
|
||||||
/// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
|
/// @param[in] bmax Maximum bounds of box B. [(x, y, z)]
|
||||||
/// @return True if the two AABB's overlap.
|
/// @return True if the two AABB's overlap.
|
||||||
/// @see dtOverlapBounds
|
/// @see dtOverlapBounds
|
||||||
public static bool OverlapQuantBounds(Span<int> amin, Span<int> amax, Span<int> bmin, Span<int> bmax)
|
public static bool OverlapQuantBounds(int[] amin, int[] amax, int[] bmin, int[] bmax)
|
||||||
{
|
{
|
||||||
bool overlap = true;
|
bool overlap = true;
|
||||||
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
overlap = (amin[0] > bmax[0] || amax[0] < bmin[0]) ? false : overlap;
|
||||||
|
|
|
@ -92,7 +92,7 @@ namespace DotRecast.Recast.Toolset.Tools
|
||||||
|
|
||||||
iterPos = result;
|
iterPos = result;
|
||||||
|
|
||||||
pathIterPolys = DtPathUtils.MergeCorridorStartMoved(pathIterPolys, MAX_POLYS, visited);
|
pathIterPolys = DtPathUtils.MergeCorridorStartMoved(pathIterPolys, pathIterPolys.Count, MAX_POLYS, visited);
|
||||||
pathIterPolys = DtPathUtils.FixupShortcuts(pathIterPolys, navQuery);
|
pathIterPolys = DtPathUtils.FixupShortcuts(pathIterPolys, navQuery);
|
||||||
|
|
||||||
var status = navQuery.GetPolyHeight(pathIterPolys[0], result, out var h);
|
var status = navQuery.GetPolyHeight(pathIterPolys[0], result, out var h);
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using DotRecast.Core.Buffers;
|
||||||
|
using DotRecast.Core.Collections;
|
||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace DotRecast.Core.Test;
|
||||||
|
|
||||||
|
public class RcArrayBenchmarkTests
|
||||||
|
{
|
||||||
|
private const int StepLength = 512;
|
||||||
|
private const int RandomLoop = 1000;
|
||||||
|
private readonly RcRand _rand = new RcRand();
|
||||||
|
|
||||||
|
private (string title, long ticks) Bench(string title, Action<int> source)
|
||||||
|
{
|
||||||
|
var begin = RcFrequency.Ticks;
|
||||||
|
for (int step = StepLength; step > 0; --step)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < RandomLoop; ++i)
|
||||||
|
{
|
||||||
|
source.Invoke(step);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var end = RcFrequency.Ticks - begin;
|
||||||
|
return (title, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void RoundForArray(int len)
|
||||||
|
{
|
||||||
|
var array = new int[len];
|
||||||
|
for (int ii = 0; ii < len; ++ii)
|
||||||
|
{
|
||||||
|
array[ii] = _rand.NextInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void RoundForPureRentArray(int len)
|
||||||
|
{
|
||||||
|
var array = ArrayPool<int>.Shared.Rent(len);
|
||||||
|
for (int ii = 0; ii < array.Length; ++ii)
|
||||||
|
{
|
||||||
|
array[ii] = _rand.NextInt32();
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayPool<int>.Shared.Return(array);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void RoundForRcRentedArray(int len)
|
||||||
|
{
|
||||||
|
using var rentedArray = RcRentedArray.Rent<int>(len);
|
||||||
|
var array = rentedArray.AsArray();
|
||||||
|
for (int i = 0; i < rentedArray.Length; ++i)
|
||||||
|
{
|
||||||
|
array[i] = _rand.NextInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void RoundForRcStackArray(int len)
|
||||||
|
{
|
||||||
|
var array = new RcStackArray512<int>();
|
||||||
|
for (int ii = 0; ii < len; ++ii)
|
||||||
|
{
|
||||||
|
array[ii] = _rand.NextInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RoundForStackalloc(int len)
|
||||||
|
{
|
||||||
|
Span<int> array = stackalloc int[len];
|
||||||
|
for (int ii = 0; ii < len; ++ii)
|
||||||
|
{
|
||||||
|
array[ii] = _rand.NextInt32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBenchmarkArrays()
|
||||||
|
{
|
||||||
|
var list = new List<(string title, long ticks)>();
|
||||||
|
list.Add(Bench("new int[len]", RoundForArray));
|
||||||
|
list.Add(Bench("ArrayPool<int>.Shared.Rent(len)", RoundForPureRentArray));
|
||||||
|
list.Add(Bench("RcRentedArray.Rent<int>(len)", RoundForRcRentedArray));
|
||||||
|
list.Add(Bench("new RcStackArray512<int>()", RoundForRcStackArray));
|
||||||
|
list.Add(Bench("stackalloc int[len]", RoundForStackalloc));
|
||||||
|
|
||||||
|
list.Sort((x, y) => x.ticks.CompareTo(y.ticks));
|
||||||
|
|
||||||
|
foreach (var t in list)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{t.title} {t.ticks / (double)TimeSpan.TicksPerMillisecond} ms");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,7 +31,7 @@ public class RcRentedArrayTest
|
||||||
{
|
{
|
||||||
int length = Math.Max(2, (int)(rand.Next() * 2048));
|
int length = Math.Max(2, (int)(rand.Next() * 2048));
|
||||||
var values = RandomValues(length);
|
var values = RandomValues(length);
|
||||||
using var array = RcRentedArray.RentDisposableArray<int>(length);
|
using var array = RcRentedArray.Rent<int>(length);
|
||||||
|
|
||||||
for (int i = 0; i < array.Length; ++i)
|
for (int i = 0; i < array.Length; ++i)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue