2023-03-14 08:02:43 +03:00
|
|
|
/*
|
|
|
|
recast4j copyright (c) 2015-2019 Piotr Piastucki piotr@jtilia.org
|
|
|
|
|
|
|
|
This software is provided 'as-is', without any express or implied
|
|
|
|
warranty. In no event will the authors be held liable for any damages
|
|
|
|
arising from the use of this software.
|
|
|
|
Permission is granted to anyone to use this software for any purpose,
|
|
|
|
including commercial applications, and to alter it and redistribute it
|
|
|
|
freely, subject to the following restrictions:
|
|
|
|
1. The origin of this software must not be misrepresented; you must not
|
|
|
|
claim that you wrote the original software. If you use this software
|
|
|
|
in a product, an acknowledgment in the product documentation would be
|
|
|
|
appreciated but is not required.
|
|
|
|
2. Altered source versions must be plainly marked as such, and must not be
|
|
|
|
misrepresented as being the original software.
|
|
|
|
3. This notice may not be removed or altered from any source distribution.
|
|
|
|
*/
|
|
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.IO;
|
|
|
|
using System.Linq;
|
|
|
|
using DotRecast.Core;
|
|
|
|
using DotRecast.Detour.Extras.Unity.Astar;
|
|
|
|
using DotRecast.Detour.Io;
|
2023-04-23 08:13:10 +03:00
|
|
|
using DotRecast.Detour.QueryResults;
|
2023-03-14 08:02:43 +03:00
|
|
|
using NUnit.Framework;
|
|
|
|
|
|
|
|
namespace DotRecast.Detour.Extras.Test.Unity.Astar;
|
|
|
|
|
2023-04-25 17:22:44 +03:00
|
|
|
[Parallelizable]
|
2023-03-16 19:48:49 +03:00
|
|
|
public class UnityAStarPathfindingImporterTest
|
|
|
|
{
|
2023-03-14 08:02:43 +03:00
|
|
|
[Test]
|
2023-05-05 02:44:48 +03:00
|
|
|
public void Test_v4_0_6()
|
2023-03-16 19:48:49 +03:00
|
|
|
{
|
2023-06-08 15:38:02 +03:00
|
|
|
DtNavMesh mesh = LoadNavMesh("graph.zip");
|
2023-06-03 15:47:26 +03:00
|
|
|
RcVec3f startPos = RcVec3f.Of(8.200293f, 2.155071f, -26.176147f);
|
|
|
|
RcVec3f endPos = RcVec3f.Of(11.971109f, 0.000000f, 8.663261f);
|
2023-05-05 02:44:48 +03:00
|
|
|
Result<List<long>> path = FindPath(mesh, startPos, endPos);
|
2023-06-10 06:37:39 +03:00
|
|
|
Assert.That(path.status, Is.EqualTo(DtStatus.DT_SUCCSESS));
|
2023-03-14 08:02:43 +03:00
|
|
|
Assert.That(path.result.Count, Is.EqualTo(57));
|
2023-05-05 02:44:48 +03:00
|
|
|
SaveMesh(mesh, "v4_0_6");
|
2023-03-14 08:02:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
2023-05-05 02:44:48 +03:00
|
|
|
public void Test_v4_1_16()
|
2023-03-16 19:48:49 +03:00
|
|
|
{
|
2023-06-08 15:38:02 +03:00
|
|
|
DtNavMesh mesh = LoadNavMesh("graph_v4_1_16.zip");
|
2023-06-03 15:47:26 +03:00
|
|
|
RcVec3f startPos = RcVec3f.Of(22.93f, -2.37f, -5.11f);
|
|
|
|
RcVec3f endPos = RcVec3f.Of(16.81f, -2.37f, 25.52f);
|
2023-05-05 02:44:48 +03:00
|
|
|
Result<List<long>> path = FindPath(mesh, startPos, endPos);
|
2023-06-10 15:57:39 +03:00
|
|
|
Assert.That(path.status.Succeeded(), Is.True);
|
2023-03-14 08:02:43 +03:00
|
|
|
Assert.That(path.result.Count, Is.EqualTo(15));
|
2023-05-05 02:44:48 +03:00
|
|
|
SaveMesh(mesh, "v4_1_16");
|
2023-03-14 08:02:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
2023-05-05 02:44:48 +03:00
|
|
|
public void TestBoundsTree()
|
2023-03-16 19:48:49 +03:00
|
|
|
{
|
2023-06-08 15:38:02 +03:00
|
|
|
DtNavMesh mesh = LoadNavMesh("test_boundstree.zip");
|
2023-06-03 15:47:26 +03:00
|
|
|
RcVec3f position = RcVec3f.Of(387.52988f, 19.997f, 368.86282f);
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-05-31 16:13:47 +03:00
|
|
|
mesh.CalcTileLoc(position, out var tileX, out var tileY);
|
|
|
|
long tileRef = mesh.GetTileRefAt(tileX, tileY, 0);
|
2023-06-08 15:38:02 +03:00
|
|
|
DtMeshTile tile = mesh.GetTileByRef(tileRef);
|
|
|
|
DtMeshData data = tile.data;
|
|
|
|
DtBVNode[] bvNodes = data.bvTree;
|
2023-03-14 08:02:43 +03:00
|
|
|
data.bvTree = null; // set BV-Tree empty to get 'clear' search poly without BV
|
2023-06-11 07:28:05 +03:00
|
|
|
var clearResult = GetNearestPolys(mesh, position)[0]; // check poly to exists
|
2023-03-14 08:02:43 +03:00
|
|
|
|
|
|
|
// restore BV-Tree and try search again
|
|
|
|
// important aspect in that test: BV result must equals result without BV
|
|
|
|
// if poly not found or found other poly - tile bounds is wrong!
|
|
|
|
data.bvTree = bvNodes;
|
2023-06-11 07:28:05 +03:00
|
|
|
var bvResult = GetNearestPolys(mesh, position)[0];
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-06-11 07:28:05 +03:00
|
|
|
Assert.That(bvResult.refs, Is.EqualTo(clearResult.refs));
|
2023-03-14 08:02:43 +03:00
|
|
|
}
|
|
|
|
|
2023-06-08 15:38:02 +03:00
|
|
|
private DtNavMesh LoadNavMesh(string filename)
|
2023-03-16 19:48:49 +03:00
|
|
|
{
|
2023-03-14 08:02:43 +03:00
|
|
|
var filepath = Loader.ToRPath(filename);
|
2023-04-29 13:48:19 +03:00
|
|
|
using var fs = new FileStream(filepath, FileMode.Open, FileAccess.Read);
|
2023-03-16 19:48:49 +03:00
|
|
|
|
2023-03-14 08:02:43 +03:00
|
|
|
// Import the graphs
|
|
|
|
UnityAStarPathfindingImporter importer = new UnityAStarPathfindingImporter();
|
2023-03-16 19:48:49 +03:00
|
|
|
|
2023-06-08 15:38:02 +03:00
|
|
|
DtNavMesh[] meshes = importer.Load(fs);
|
2023-03-14 08:02:43 +03:00
|
|
|
return meshes[0];
|
|
|
|
}
|
|
|
|
|
2023-06-08 15:38:02 +03:00
|
|
|
private Result<List<long>> FindPath(DtNavMesh mesh, RcVec3f startPos, RcVec3f endPos)
|
2023-03-16 19:48:49 +03:00
|
|
|
{
|
2023-03-14 08:02:43 +03:00
|
|
|
// Perform a simple pathfinding
|
2023-06-08 15:38:02 +03:00
|
|
|
DtNavMeshQuery query = new DtNavMeshQuery(mesh);
|
|
|
|
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-06-11 07:28:05 +03:00
|
|
|
var polys = GetNearestPolys(mesh, startPos, endPos);
|
2023-06-22 18:46:51 +03:00
|
|
|
return query.FindPath(polys[0].refs, polys[1].refs, startPos, endPos, filter, DtFindPathOption.Zero);
|
2023-03-14 08:02:43 +03:00
|
|
|
}
|
|
|
|
|
2023-06-11 07:28:05 +03:00
|
|
|
private DtPolyPoint[] GetNearestPolys(DtNavMesh mesh, params RcVec3f[] positions)
|
2023-03-16 19:48:49 +03:00
|
|
|
{
|
2023-06-08 15:38:02 +03:00
|
|
|
DtNavMeshQuery query = new DtNavMeshQuery(mesh);
|
|
|
|
IDtQueryFilter filter = new DtQueryDefaultFilter();
|
2023-06-03 15:47:26 +03:00
|
|
|
RcVec3f extents = RcVec3f.Of(0.1f, 0.1f, 0.1f);
|
2023-03-14 08:02:43 +03:00
|
|
|
|
2023-06-11 07:28:05 +03:00
|
|
|
var results = new DtPolyPoint[positions.Length];
|
2023-03-16 19:48:49 +03:00
|
|
|
for (int i = 0; i < results.Length; i++)
|
|
|
|
{
|
2023-06-03 15:47:26 +03:00
|
|
|
RcVec3f position = positions[i];
|
2023-06-11 07:41:37 +03:00
|
|
|
var status = query.FindNearestPoly(position, extents, filter, out var nearestRef, out var nearestPt, out var _);
|
2023-06-11 07:28:05 +03:00
|
|
|
Assert.That(status.Succeeded(), Is.True);
|
2023-06-11 07:41:37 +03:00
|
|
|
Assert.That(nearestPt, Is.Not.EqualTo(RcVec3f.Zero), "Nearest start position is null!");
|
2023-06-11 07:28:05 +03:00
|
|
|
|
2023-06-11 07:41:37 +03:00
|
|
|
results[i] = new DtPolyPoint(nearestRef, nearestPt);
|
2023-03-14 08:02:43 +03:00
|
|
|
}
|
2023-03-16 19:48:49 +03:00
|
|
|
|
2023-03-14 08:02:43 +03:00
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
2023-06-08 15:38:02 +03:00
|
|
|
private void SaveMesh(DtNavMesh mesh, string filePostfix)
|
2023-03-16 19:48:49 +03:00
|
|
|
{
|
2023-03-14 08:02:43 +03:00
|
|
|
// Set the flag to RecastDemo work properly
|
2023-05-05 02:44:48 +03:00
|
|
|
for (int i = 0; i < mesh.GetTileCount(); i++)
|
2023-03-16 19:48:49 +03:00
|
|
|
{
|
2023-06-08 15:38:02 +03:00
|
|
|
foreach (DtPoly p in mesh.GetTile(i).data.polys)
|
2023-03-16 19:48:49 +03:00
|
|
|
{
|
2023-03-14 08:02:43 +03:00
|
|
|
p.flags = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Save the mesh as recast file,
|
2023-06-08 16:24:34 +03:00
|
|
|
DtMeshSetWriter writer = new DtMeshSetWriter();
|
2023-03-14 08:02:43 +03:00
|
|
|
string filename = $"all_tiles_navmesh_{filePostfix}.bin";
|
|
|
|
string filepath = Path.Combine("test-output", filename);
|
|
|
|
using var fs = new FileStream(filename, FileMode.Create);
|
|
|
|
using var os = new BinaryWriter(fs);
|
2023-05-10 16:44:51 +03:00
|
|
|
writer.Write(os, mesh, RcByteOrder.LITTLE_ENDIAN, true);
|
2023-03-14 08:02:43 +03:00
|
|
|
}
|
2023-05-31 16:13:47 +03:00
|
|
|
}
|