diff --git a/src/DotRecast.Core/IRcRand.cs b/src/DotRecast.Core/IRcRand.cs index 499e14c..15e810a 100644 --- a/src/DotRecast.Core/IRcRand.cs +++ b/src/DotRecast.Core/IRcRand.cs @@ -3,5 +3,7 @@ public interface IRcRand { float Next(); + double NextDouble(); + int NextInt32(); } } \ No newline at end of file diff --git a/src/DotRecast.Core/RcRand.cs b/src/DotRecast.Core/RcRand.cs index 279590a..6111aff 100644 --- a/src/DotRecast.Core/RcRand.cs +++ b/src/DotRecast.Core/RcRand.cs @@ -6,9 +6,13 @@ namespace DotRecast.Core { private readonly Random _r; - public RcRand() + public RcRand() : this(new Random()) { - _r = new Random(); + } + + public RcRand(Random r) + { + _r = r; } public RcRand(long seed) @@ -21,6 +25,11 @@ namespace DotRecast.Core return (float)_r.NextDouble(); } + public double NextDouble() + { + return _r.NextDouble(); + } + public int NextInt32() { return _r.Next(); diff --git a/src/DotRecast.Detour.Dynamic/DtDynamicNavMesh.cs b/src/DotRecast.Detour.Dynamic/DtDynamicNavMesh.cs index a8a4aee..dc40c41 100644 --- a/src/DotRecast.Detour.Dynamic/DtDynamicNavMesh.cs +++ b/src/DotRecast.Detour.Dynamic/DtDynamicNavMesh.cs @@ -40,7 +40,7 @@ namespace DotRecast.Detour.Dynamic private readonly BlockingCollection updateQueue = new BlockingCollection(); private readonly RcAtomicLong currentColliderId = new RcAtomicLong(0); private DtNavMesh _navMesh; - private bool dirty = true; + private bool _dirty = true; public DtDynamicNavMesh(DtVoxelFile voxelFile) { @@ -105,29 +105,6 @@ namespace DotRecast.Detour.Dynamic updateQueue.Add(new DtDynamicTileColliderRemovalJob(colliderId, GetTilesByCollider(colliderId))); } - /** - * Perform full build of the nav mesh - */ - public void Build() - { - ProcessQueue(); - Rebuild(_tiles.Values); - } - - /** - * Perform incremental update of the nav mesh - */ - public bool Update() - { - return Rebuild(ProcessQueue()); - } - - private bool Rebuild(ICollection stream) - { - foreach (var dynamicTile in stream) - Rebuild(dynamicTile); - return UpdateNavMesh(); - } private HashSet ProcessQueue() { @@ -159,27 +136,49 @@ namespace DotRecast.Detour.Dynamic } } - /** - * Perform full build concurrently using the given {@link ExecutorService} - */ - public Task Build(TaskFactory executor) + // Perform full build of the navmesh + public void Build() + { + ProcessQueue(); + Rebuild(_tiles.Values); + } + + // Perform full build concurrently using the given {@link ExecutorService} + public bool Build(TaskFactory executor) { ProcessQueue(); return Rebuild(_tiles.Values, executor); } - /** - * Perform incremental update concurrently using the given {@link ExecutorService} - */ - public Task Update(TaskFactory executor) + + // Perform incremental update of the navmesh + public bool Update() + { + return Rebuild(ProcessQueue()); + } + + // Perform incremental update concurrently using the given {@link ExecutorService} + public bool Update(TaskFactory executor) { return Rebuild(ProcessQueue(), executor); } - private Task Rebuild(ICollection tiles, TaskFactory executor) + private bool Rebuild(ICollection tiles) { - var tasks = tiles.Select(tile => executor.StartNew(() => Rebuild(tile))).ToArray(); - return Task.WhenAll(tasks).ContinueWith(k => UpdateNavMesh()); + foreach (var tile in tiles) + Rebuild(tile); + + return UpdateNavMesh(); + } + + private bool Rebuild(ICollection tiles, TaskFactory executor) + { + var tasks = tiles + .Select(tile => executor.StartNew(() => Rebuild(tile))) + .ToArray(); + + Task.WaitAll(tasks); + return UpdateNavMesh(); } private ICollection GetTiles(float[] bounds) @@ -218,19 +217,19 @@ namespace DotRecast.Detour.Dynamic { DtNavMeshCreateParams option = new DtNavMeshCreateParams(); option.walkableHeight = config.walkableHeight; - dirty = dirty | tile.Build(builder, config, _context); + _dirty = _dirty | tile.Build(builder, config, _context); } private bool UpdateNavMesh() { - if (dirty) + if (_dirty) { DtNavMesh navMesh = new DtNavMesh(navMeshParams, MAX_VERTS_PER_POLY); foreach (var t in _tiles.Values) t.AddTo(navMesh); - this._navMesh = navMesh; - dirty = false; + _navMesh = navMesh; + _dirty = false; return true; } diff --git a/src/DotRecast.Recast.Demo/Tools/DynamicUpdateSampleTool.cs b/src/DotRecast.Recast.Demo/Tools/DynamicUpdateSampleTool.cs index 9121213..4d6c3d6 100644 --- a/src/DotRecast.Recast.Demo/Tools/DynamicUpdateSampleTool.cs +++ b/src/DotRecast.Recast.Demo/Tools/DynamicUpdateSampleTool.cs @@ -91,7 +91,7 @@ public class DynamicUpdateSampleTool : ISampleTool var bridgeGeom = DemoInputGeomProvider.LoadFile("bridge.obj"); var houseGeom = DemoInputGeomProvider.LoadFile("house.obj"); var convexGeom = DemoInputGeomProvider.LoadFile("convex.obj"); - _tool = new(Random.Shared, bridgeGeom, houseGeom, convexGeom); + _tool = new(new RcRand(Random.Shared), bridgeGeom, houseGeom, convexGeom); executor = Task.Factory; } @@ -406,7 +406,7 @@ public class DynamicUpdateSampleTool : ISampleTool long t = RcFrequency.Ticks; try { - bool updated = _tool.UpdateDynaMesh(executor); + bool updated = _tool.Update(executor); if (updated) { buildTime = (RcFrequency.Ticks - t) / TimeSpan.TicksPerMillisecond; @@ -450,7 +450,7 @@ public class DynamicUpdateSampleTool : ISampleTool long t = RcFrequency.Ticks; try { - var _ = dynaMesh.Build(executor).Result; + var _ = dynaMesh.Build(executor); } catch (Exception e) { diff --git a/src/DotRecast.Recast.Toolset/Tools/RcDynamicUpdateTool.cs b/src/DotRecast.Recast.Toolset/Tools/RcDynamicUpdateTool.cs index 6900279..83cc474 100644 --- a/src/DotRecast.Recast.Toolset/Tools/RcDynamicUpdateTool.cs +++ b/src/DotRecast.Recast.Toolset/Tools/RcDynamicUpdateTool.cs @@ -18,12 +18,12 @@ namespace DotRecast.Recast.Toolset.Tools private DtDynamicNavMesh dynaMesh; private readonly Dictionary colliderGizmos; - private readonly Random random; + private readonly IRcRand random; private readonly DemoInputGeomProvider bridgeGeom; private readonly DemoInputGeomProvider houseGeom; private readonly DemoInputGeomProvider convexGeom; - public RcDynamicUpdateTool(Random rand, DemoInputGeomProvider bridgeGeom, DemoInputGeomProvider houseGeom, DemoInputGeomProvider convexGeom) + public RcDynamicUpdateTool(IRcRand rand, DemoInputGeomProvider bridgeGeom, DemoInputGeomProvider houseGeom, DemoInputGeomProvider convexGeom) { this.colliderGizmos = new Dictionary(); this.random = rand; @@ -339,20 +339,14 @@ namespace DotRecast.Recast.Toolset.Tools return resultvector; } - public bool UpdateDynaMesh(TaskFactory executor) + public bool Update(TaskFactory executor) { if (dynaMesh == null) { return false; } - bool updated = dynaMesh.Update(executor).Result; - if (updated) - { - return false; - } - - return true; + return dynaMesh.Update(executor); } public bool Raycast(RcVec3f spos, RcVec3f epos, out float hitPos, out RcVec3f raycastHitPos) diff --git a/test/DotRecast.Detour.Dynamic.Test/DynamicNavMeshTest.cs b/test/DotRecast.Detour.Dynamic.Test/DynamicNavMeshTest.cs index 1215635..cbcaa04 100644 --- a/test/DotRecast.Detour.Dynamic.Test/DynamicNavMeshTest.cs +++ b/test/DotRecast.Detour.Dynamic.Test/DynamicNavMeshTest.cs @@ -10,7 +10,6 @@ using NUnit.Framework; namespace DotRecast.Detour.Dynamic.Test; - public class DynamicNavMeshTest { private static readonly RcVec3f START_POS = new RcVec3f(70.87453f, 0.0010070801f, 86.69021f); @@ -32,9 +31,7 @@ public class DynamicNavMeshTest // create dynamic navmesh DtDynamicNavMesh mesh = new DtDynamicNavMesh(f); // build navmesh asynchronously using multiple threads - Task future = mesh.Build(Task.Factory); - // wait for build to complete - bool _ = future.Result; + mesh.Build(Task.Factory); // create new query DtNavMeshQuery query = new DtNavMeshQuery(mesh.NavMesh()); @@ -54,9 +51,8 @@ public class DynamicNavMeshTest long colliderId = mesh.AddCollider(colldier); // update navmesh asynchronously - future = mesh.Update(Task.Factory); - // wait for update to complete - _ = future.Result; + mesh.Update(Task.Factory); + // create new query query = new DtNavMeshQuery(mesh.NavMesh()); @@ -70,9 +66,7 @@ public class DynamicNavMeshTest // remove obstacle mesh.RemoveCollider(colliderId); // update navmesh asynchronously - future = mesh.Update(Task.Factory); - // wait for update to complete - _ = future.Result; + mesh.Update(Task.Factory); // create new query query = new DtNavMeshQuery(mesh.NavMesh()); diff --git a/test/DotRecast.Detour.Dynamic.Test/VoxelQueryTest.cs b/test/DotRecast.Detour.Dynamic.Test/VoxelQueryTest.cs index fc32f0a..451de65 100644 --- a/test/DotRecast.Detour.Dynamic.Test/VoxelQueryTest.cs +++ b/test/DotRecast.Detour.Dynamic.Test/VoxelQueryTest.cs @@ -31,7 +31,6 @@ using NUnit.Framework; namespace DotRecast.Detour.Dynamic.Test; - public class VoxelQueryTest { private const int TILE_WIDTH = 100; @@ -101,12 +100,12 @@ public class VoxelQueryTest // load voxels from file DtVoxelFileReader reader = new DtVoxelFileReader(DtVoxelTileLZ4ForTestCompressor.Shared); DtVoxelFile f = reader.Read(br); + // create dynamic navmesh var mesh = new DtDynamicNavMesh(f); + // build navmesh asynchronously using multiple threads - Task future = mesh.Build(Task.Factory); - // wait for build to complete - var _ = future.Result; + mesh.Build(Task.Factory); return mesh; } } \ No newline at end of file