From 3fcd63ff3468d1cba1980bf8f83c00cb87494809 Mon Sep 17 00:00:00 2001 From: Antoine Pilote Date: Fri, 9 Aug 2024 19:12:42 -0400 Subject: [PATCH] Added FindPath to C# API for path finding --- Nuake/src/AI/NavManager.cpp | 4 +- Nuake/src/AI/NavMesh.cpp | 57 ++++++++++++++++++- Nuake/src/AI/NavMesh.h | 13 ++++- Nuake/src/Core/FileSystem.cpp | 2 +- .../Scene/Components/NavMeshVolumeComponent.h | 7 ++- .../src/Scripting/NetModules/SceneNetAPI.cpp | 37 +++++++++++- NuakeNet/src/Components.cs | 24 ++++++++ NuakeNet/src/Entity.cs | 6 +- premake5.lua | 22 ++++--- 9 files changed, 152 insertions(+), 20 deletions(-) diff --git a/Nuake/src/AI/NavManager.cpp b/Nuake/src/AI/NavManager.cpp index c3ce1ad5..c7d94aa9 100644 --- a/Nuake/src/AI/NavManager.cpp +++ b/Nuake/src/AI/NavManager.cpp @@ -231,9 +231,9 @@ namespace Nuake { //params.offMeshConUserID = m_geom->getOffMeshConnectionId(); //params.offMeshConCount = m_geom->getOffMeshConnectionCount(); - const float agentHeight = 0.1f; + const float agentHeight = 0.5f; const float agentRadius = 0.1f; - const float agentMaxClimb = 0.1f; + const float agentMaxClimb = 0.01f; params.walkableHeight = agentHeight; params.walkableRadius = agentRadius; params.walkableClimb = agentMaxClimb; diff --git a/Nuake/src/AI/NavMesh.cpp b/Nuake/src/AI/NavMesh.cpp index 559b9ce2..1eece31e 100644 --- a/Nuake/src/AI/NavMesh.cpp +++ b/Nuake/src/AI/NavMesh.cpp @@ -27,7 +27,7 @@ namespace Nuake { m_DetourNavQuery = navMeshQuery; } - int NavMesh::FindNearestPolygon(const Vector3& searchPosition, const Vector3& searchBox) + NavMesh::PolySearchResult NavMesh::FindNearestPolygon(const Vector3& searchPosition, const Vector3& searchBox) { float nearestPoint[3]; float searchPos[3] = { searchPosition.x, searchPosition.y, searchPosition.z }; @@ -38,7 +38,60 @@ namespace Nuake { dtPolyRef resultPoly = 0; dtStatus status = m_DetourNavQuery->findNearestPoly(searchPos, searchExtent, &filter, &resultPoly, nearestPoint); - return resultPoly; + + PolySearchResult result = + { + .PolyID = static_cast(resultPoly), + .PositionInPoly = { nearestPoint[0], nearestPoint[1], nearestPoint[2] } + }; + return result; + } + + std::vector NavMesh::FindStraightPath(const Vector3& start, const Vector3& end) + { + // Find start & end polygon + constexpr Vector3 SEARCH_BOX = { 0.6, 0.85, 0.6 }; + PolySearchResult startPoly = FindNearestPolygon(start, SEARCH_BOX); + PolySearchResult endPoly = FindNearestPolygon(end, SEARCH_BOX); + + // Find poly corridor + constexpr int MAX_PATH = 2048; + constexpr int MAX_POLYS = 256; + + dtQueryFilter filter; + filter.setIncludeFlags(1); + dtPolyRef resultPoly[MAX_POLYS]; + int resultPathCount = 0; + dtStatus result = m_DetourNavQuery->findPath(startPoly.PolyID, endPoly.PolyID, + &(startPoly.PositionInPoly.x), &(endPoly.PositionInPoly.x), + &filter, resultPoly, &resultPathCount, MAX_PATH); + + // Find straight path in corridor + float straightPath[MAX_POLYS * 3]; + unsigned char straightPathFlags[MAX_POLYS]; + dtPolyRef straightPathPolys[MAX_POLYS]; + int nstraightPath; + result = m_DetourNavQuery->findStraightPath(&(startPoly.PositionInPoly.x), &(endPoly.PositionInPoly.x), + resultPoly, resultPathCount, straightPath, straightPathFlags, + straightPathPolys, &nstraightPath, MAX_POLYS); + + // Convert path into points + std::vector pathWaypoints; + if (dtStatusFailed(result)) + { + Logger::Log("Failed to find straight path.", "navmesh", VERBOSE); + return pathWaypoints; + } + + pathWaypoints.reserve(nstraightPath); + for (int i = 0; i < nstraightPath; ++i) + { + float* v = &straightPath[i * 3]; + const Vector3 waypoint = { v[0], v[1], v[2] }; + pathWaypoints.push_back(waypoint); + } + + return pathWaypoints; } std::vector NavMesh::FindPath(int polyStart, int polyEnd, const Vector3& nearestPointStart, const Vector3& nearestPointEnd, const int maxPoly) diff --git a/Nuake/src/AI/NavMesh.h b/Nuake/src/AI/NavMesh.h index dcb9a4a1..6d2afbf0 100644 --- a/Nuake/src/AI/NavMesh.h +++ b/Nuake/src/AI/NavMesh.h @@ -6,7 +6,14 @@ namespace Nuake { - class NavMesh : ISerializable { + class NavMesh : ISerializable + { + private: + struct PolySearchResult + { + int PolyID; + Vector3 PositionInPoly; + }; public: NavMesh(dtNavMesh* navMesh, dtNavMeshQuery* navMeshQuery); @@ -14,7 +21,9 @@ namespace Nuake { ~NavMesh(); // Query - int FindNearestPolygon(const Vector3 & searchPosition, const Vector3 & searchBox); + PolySearchResult FindNearestPolygon(const Vector3 & searchPosition, const Vector3 & searchBox); + + std::vector FindStraightPath(const Vector3& start, const Vector3& end); std::vector FindPath(int polyStart, int polyEnd, const Vector3& nearestPointStart, const Vector3& nearestPointEnd, const int maxPoly); diff --git a/Nuake/src/Core/FileSystem.cpp b/Nuake/src/Core/FileSystem.cpp index 03448dd6..4ce2c6a3 100644 --- a/Nuake/src/Core/FileSystem.cpp +++ b/Nuake/src/Core/FileSystem.cpp @@ -288,7 +288,7 @@ namespace Nuake std::string FileSystem::GetConfigFolderPath() { std::string subFolderPath = OS::GetConfigFolderPath().append("/Nuake/"); - if (!DirectoryExists(subFolderPath)) + if (!DirectoryExists(subFolderPath, true)) { MakeDirectory(subFolderPath); } diff --git a/Nuake/src/Scene/Components/NavMeshVolumeComponent.h b/Nuake/src/Scene/Components/NavMeshVolumeComponent.h index 5fa6de23..f8625786 100644 --- a/Nuake/src/Scene/Components/NavMeshVolumeComponent.h +++ b/Nuake/src/Scene/Components/NavMeshVolumeComponent.h @@ -33,7 +33,12 @@ namespace Nuake BEGIN_SERIALIZE(); SERIALIZE_VEC3(VolumeSize); SERIALIZE_VAL(OnlyIncludeMapGeometry); - SERIALIZE_OBJECT(NavMeshData); + + if (NavMeshData != nullptr) + { + SERIALIZE_OBJECT(NavMeshData); + } + // Generation config END_SERIALIZE(); } diff --git a/Nuake/src/Scripting/NetModules/SceneNetAPI.cpp b/Nuake/src/Scripting/NetModules/SceneNetAPI.cpp index c1630328..7ced023c 100644 --- a/Nuake/src/Scripting/NetModules/SceneNetAPI.cpp +++ b/Nuake/src/Scripting/NetModules/SceneNetAPI.cpp @@ -24,6 +24,7 @@ #include "src/Scripting/ScriptingEngineNet.h" #include +#include namespace Nuake { @@ -109,7 +110,8 @@ namespace Nuake { PARTICLE_EMITTER, QUAKE_MAP, BSP_BRUSH, - SPRITE + SPRITE, + NAVMESH }; bool EntityHasComponent(int id, int componentType) @@ -145,6 +147,7 @@ namespace Nuake { case QUAKE_MAP: return entity.HasComponent(); case BSP_BRUSH: return entity.HasComponent(); case SPRITE: return entity.HasComponent(); + case NAVMESH: return entity.HasComponent(); default: return false; } @@ -296,6 +299,36 @@ namespace Nuake { } } + Coral::Array NavMeshComponentFindPath(int entityId, float startx, float starty, float startz, float endx, float endy, float endz) + { + Entity entity = Entity((entt::entity)(entityId), Engine::GetCurrentScene().get()); + if (entity.IsValid() && entity.HasComponent()) + { + auto& navMeshVolume = entity.GetComponent(); + if (navMeshVolume.NavMeshData && navMeshVolume.NavMeshData->IsValid()) + { + auto& navMesh = navMeshVolume.NavMeshData; + + const Vector3& startPosition = { startx, starty, startz }; + const Vector3& endPosition = { endx, endy, endz }; + auto waypoints = navMesh->FindStraightPath(startPosition, endPosition); + + // Convert Vector3 array into float array + Coral::Array returnResult = Coral::Array::New(waypoints.size() * 3); + for (int i = 0; i < waypoints.size(); i++) + { + returnResult[i * 3 + 0] = waypoints[i].x; + returnResult[i * 3 + 1] = waypoints[i].y; + returnResult[i * 3 + 2] = waypoints[i].z; + } + + return returnResult; + } + } + + return {}; + } + void Nuake::SceneNetAPI::RegisterMethods() { // Entity @@ -320,6 +353,8 @@ namespace Nuake { RegisterMethod("CharacterControllerComponent.IsOnGroundIcall", &IsOnGround); RegisterMethod("SkinnedModelComponent.PlayIcall", &Play); + + RegisterMethod("NavMeshVolumeComponent.FindPathIcall", &NavMeshComponentFindPath); } } diff --git a/NuakeNet/src/Components.cs b/NuakeNet/src/Components.cs index 36a7273d..291318ae 100644 --- a/NuakeNet/src/Components.cs +++ b/NuakeNet/src/Components.cs @@ -319,4 +319,28 @@ namespace Nuake.Net public string Sprite { get; set; } } + + public class NavMeshVolumeComponent : IComponent + { + internal static unsafe delegate*> FindPathIcall; + + public NavMeshVolumeComponent(int entityId) { EntityID = entityId; } + + public List FindStraightPath(Vector3 start, Vector3 end) + { + List pathWaypoints = []; + unsafe + { + NativeArray waypoints = FindPathIcall(EntityID, start.X, start.Y, start.Z, end.X, end.Y, end.Z); + for(int i = 0; i < waypoints.Length; i += 3) + { + Vector3 waypointPosition = new Vector3(waypoints[i], waypoints[i + 1], waypoints[i + 2]); + pathWaypoints.Add(waypointPosition); + } + + return pathWaypoints; + } + } + } + } diff --git a/NuakeNet/src/Entity.cs b/NuakeNet/src/Entity.cs index bd877068..a28b0e0c 100644 --- a/NuakeNet/src/Entity.cs +++ b/NuakeNet/src/Entity.cs @@ -45,7 +45,8 @@ namespace Nuake.Net PARTICLE_EMITTER, QUAKE_MAP, BSP_BRUSH, - SPRITE + SPRITE, + NAVMESH } public int ID { get; set; } @@ -101,7 +102,8 @@ namespace Nuake.Net { typeof(ParticleEmitterComponent), ComponentTypes.PARTICLE_EMITTER }, { typeof(QuakeMapComponent), ComponentTypes.QUAKE_MAP }, { typeof(BSPBrushComponent), ComponentTypes.BSP_BRUSH }, - { typeof(SpriteComponent), ComponentTypes.SPRITE } + { typeof(SpriteComponent), ComponentTypes.SPRITE }, + { typeof(NavMeshVolumeComponent), ComponentTypes.NAVMESH } }; public bool HasComponent() diff --git a/premake5.lua b/premake5.lua index 5a53d283..51a3ecb5 100644 --- a/premake5.lua +++ b/premake5.lua @@ -27,17 +27,21 @@ workspace "Nuake" outputdir = "%{cfg.buildcfg}-%{cfg.system}-%{cfg.architecture}" -include "Nuake/dependencies/glfw_p5.lua" -include "Nuake/dependencies/glad_p5.lua" -include "Nuake/dependencies/assimp_p5.lua" -include "Nuake/dependencies/freetype_p5.lua" -include "Nuake/dependencies/jolt_p5.lua" -include "Nuake/dependencies/soloud_p5.lua" -include "Nuake/dependencies/optick_p5.lua" -include "Nuake/dependencies/coral_p5.lua" -include "Nuake/dependencies/recastnavigation_p5.lua" +group "Dependencies" + include "Nuake/dependencies/glfw_p5.lua" + include "Nuake/dependencies/glad_p5.lua" + include "Nuake/dependencies/assimp_p5.lua" + include "Nuake/dependencies/freetype_p5.lua" + include "Nuake/dependencies/jolt_p5.lua" + include "Nuake/dependencies/soloud_p5.lua" + include "Nuake/dependencies/optick_p5.lua" + include "Nuake/dependencies/coral_p5.lua" + include "Nuake/dependencies/recastnavigation_p5.lua" +group "" + include "NuakeNet/premake5.lua" + project "Nuake" location "Nuake" kind "StaticLib"