From 76cba14f80cb2abcd92a3d9a3c3e8519ff548862 Mon Sep 17 00:00:00 2001 From: Jannis Date: Wed, 10 Jan 2024 19:47:21 +0100 Subject: [PATCH] update recastnavigation parameters, add polygon class with bridsons poisson disk sampling --- .../AmeisenNavigation.Server.vcxproj | 4 +- .../AmeisenNavigation.Server.vcxproj.filters | 3 - .../src/Config/Config.hpp | 6 +- .../src/Enums/EMessageType.hpp | 9 - .../src/Logging/AmeisenLogger.hpp | 2 +- AmeisenNavigation.Server/src/Main.cpp | 92 +- AmeisenNavigation.Server/src/Main.hpp | 62 +- AmeisenNavigation.Tester/MainWindow.xaml.cs | 10 +- AmeisenNavigation.Tester/Vector3.cs | 37 +- AmeisenNavigation/AmeisenNavigation.vcxproj | 11 +- .../AmeisenNavigation.vcxproj.filters | 2 + AmeisenNavigation/src/AmeisenNavigation.cpp | 50 +- AmeisenNavigation/src/AmeisenNavigation.hpp | 104 +- .../src/Clients/AmeisenNavClient.hpp | 20 +- .../src/Clients/ClientVersion.hpp | 6 +- AmeisenNavigation/src/Helpers/Point.hpp | 8 + AmeisenNavigation/src/Helpers/Polygon.hpp | 139 + dep/AnTCP.Server/include/AnTcpServer.hpp | 8 +- recastnavigation/Detour/CMakeLists.txt | 40 + recastnavigation/Detour/Include/DetourCrowd.h | 524 ++-- .../Detour/Include/DetourLocalBoundary.h | 67 +- .../Detour/Include/DetourNavMesh.h | 24 +- .../Detour/Include/DetourObstacleAvoidance.h | 201 +- .../Detour/Include/DetourPathCorridor.h | 224 +- .../Detour/Include/DetourPathQueue.h | 86 +- .../Detour/Include/DetourProximityGrid.h | 82 +- .../Detour/Include/DetourTileCache.h | 256 ++ .../Detour/Include/DetourTileCacheBuilder.h | 156 ++ .../Detour/Source/DetourCrowd.cpp | 2445 +++++++++-------- .../Detour/Source/DetourLocalBoundary.cpp | 176 +- .../Detour/Source/DetourObstacleAvoidance.cpp | 963 +++---- .../Detour/Source/DetourPathCorridor.cpp | 825 +++--- .../Detour/Source/DetourPathQueue.cpp | 289 +- .../Detour/Source/DetourProximityGrid.cpp | 257 +- .../Detour/Source/DetourTileCache.cpp | 825 ++++++ .../Detour/Source/DetourTileCacheBuilder.cpp | 2257 +++++++++++++++ recastnavigation/recastnavigation.vcxproj | 8 +- 37 files changed, 7033 insertions(+), 3245 deletions(-) delete mode 100644 AmeisenNavigation.Server/src/Enums/EMessageType.hpp create mode 100644 AmeisenNavigation/src/Helpers/Point.hpp create mode 100644 AmeisenNavigation/src/Helpers/Polygon.hpp create mode 100644 recastnavigation/Detour/CMakeLists.txt create mode 100644 recastnavigation/Detour/Include/DetourTileCache.h create mode 100644 recastnavigation/Detour/Include/DetourTileCacheBuilder.h create mode 100644 recastnavigation/Detour/Source/DetourTileCache.cpp create mode 100644 recastnavigation/Detour/Source/DetourTileCacheBuilder.cpp diff --git a/AmeisenNavigation.Server/AmeisenNavigation.Server.vcxproj b/AmeisenNavigation.Server/AmeisenNavigation.Server.vcxproj index 607f8cb..df261e2 100644 --- a/AmeisenNavigation.Server/AmeisenNavigation.Server.vcxproj +++ b/AmeisenNavigation.Server/AmeisenNavigation.Server.vcxproj @@ -127,6 +127,9 @@ true stdcpplatest stdc17 + AnySuitable + Speed + true Console @@ -180,7 +183,6 @@ - diff --git a/AmeisenNavigation.Server/AmeisenNavigation.Server.vcxproj.filters b/AmeisenNavigation.Server/AmeisenNavigation.Server.vcxproj.filters index a5fff5b..d2de0e3 100644 --- a/AmeisenNavigation.Server/AmeisenNavigation.Server.vcxproj.filters +++ b/AmeisenNavigation.Server/AmeisenNavigation.Server.vcxproj.filters @@ -23,9 +23,6 @@ Headerdateien - - Headerdateien - Headerdateien diff --git a/AmeisenNavigation.Server/src/Config/Config.hpp b/AmeisenNavigation.Server/src/Config/Config.hpp index 90eac0f..3de0936 100644 --- a/AmeisenNavigation.Server/src/Config/Config.hpp +++ b/AmeisenNavigation.Server/src/Config/Config.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include #include @@ -16,7 +16,7 @@ constexpr auto CONFIG_CHAR_DELIMITER = '='; struct AmeisenNavConfig { private: - std::map Map + std::unordered_map Map { { "fCatmullRomSplineAlpha", &catmullRomSplineAlpha }, { "fRandomPathMaxDistance", &randomPathMaxDistance }, @@ -36,7 +36,7 @@ struct AmeisenNavConfig int maxPolyPath = 512; int maxSearchNodes = 65535; int port = 47110; - int clientVersion = static_cast(CLIENT_VERSION::V335A); + int clientVersion = static_cast(ClientVersion::TC335A); std::string ip = "127.0.0.1"; std::string mmapsPath = "C:\\shady stuff\\mmaps\\"; diff --git a/AmeisenNavigation.Server/src/Enums/EMessageType.hpp b/AmeisenNavigation.Server/src/Enums/EMessageType.hpp deleted file mode 100644 index ebb8ff4..0000000 --- a/AmeisenNavigation.Server/src/Enums/EMessageType.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -enum class EMessageType : char -{ - PATH, - MOVE_ALONG_SURFACE, - RANDOM_POINT, - RANDOM_POINT_AROUND, -}; \ No newline at end of file diff --git a/AmeisenNavigation.Server/src/Logging/AmeisenLogger.hpp b/AmeisenNavigation.Server/src/Logging/AmeisenLogger.hpp index df8c4b8..99704a8 100644 --- a/AmeisenNavigation.Server/src/Logging/AmeisenLogger.hpp +++ b/AmeisenNavigation.Server/src/Logging/AmeisenLogger.hpp @@ -33,7 +33,7 @@ template constexpr void Log(const std::string& tag, int color, int colorSecond, Args&& ...args) { #if defined WIN32 || defined WIN64 - static void* ConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); + void* ConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); #endif std::cout << std::setw(14) << tag; diff --git a/AmeisenNavigation.Server/src/Main.cpp b/AmeisenNavigation.Server/src/Main.cpp index 7566a07..d8c4811 100644 --- a/AmeisenNavigation.Server/src/Main.cpp +++ b/AmeisenNavigation.Server/src/Main.cpp @@ -91,12 +91,15 @@ int main(int argc, const char* argv[]) Server->SetOnClientDisconnected(OnClientDisconnect); Server->AddCallback(static_cast(MessageType::PATH), PathCallback); - Server->AddCallback(static_cast(MessageType::RANDOM_PATH), RandomPathCallback); - Server->AddCallback(static_cast(MessageType::RANDOM_POINT), RandomPointCallback); Server->AddCallback(static_cast(MessageType::RANDOM_POINT_AROUND), RandomPointAroundCallback); Server->AddCallback(static_cast(MessageType::MOVE_ALONG_SURFACE), MoveAlongSurfaceCallback); Server->AddCallback(static_cast(MessageType::CAST_RAY), CastRayCallback); + Server->AddCallback(static_cast(MessageType::RANDOM_PATH), RandomPathCallback); + Server->AddCallback(static_cast(MessageType::RANDOM_POINT), RandomPointCallback); + + Server->AddCallback(static_cast(MessageType::EXPLORE_POLY), CastRayCallback); + LogS("Starting server on: ", Config->ip, ":", std::to_string(Config->port)); Server->Run(); @@ -135,7 +138,7 @@ void OnClientConnect(ClientHandler* handler) noexcept LogI("Client Connected: ", handler->GetIpAddress(), ":", handler->GetPort()); ClientPathBuffers[handler->GetId()] = std::make_pair(new float[Config->maxPolyPath * 3], new float[Config->maxPolyPath * 3]); - Nav->NewClient(handler->GetId(), static_cast(Config->clientVersion)); + Nav->NewClient(handler->GetId(), static_cast(Config->clientVersion)); } void OnClientDisconnect(ClientHandler* handler) noexcept @@ -161,29 +164,10 @@ void RandomPathCallback(ClientHandler* handler, char type, const void* data, int GenericPathCallback(handler, type, data, size, PathType::RANDOM); } -void RandomPointCallback(ClientHandler* handler, char type, const void* data, int size) noexcept -{ - const int mapId = *reinterpret_cast(data); - float point[3]{}; - - Nav->GetRandomPoint(handler->GetId(), mapId, point); - handler->SendData(type, point, VEC3_SIZE); -} - -void RandomPointAroundCallback(ClientHandler* handler, char type, const void* data, int size) noexcept -{ - const RandomPointAroundData request = *reinterpret_cast(data); - float point[3]{}; - - Nav->GetRandomPointAround(handler->GetId(), request.mapId, request.start, request.radius, point); - handler->SendData(type, point, VEC3_SIZE); -} - void MoveAlongSurfaceCallback(ClientHandler* handler, char type, const void* data, int size) noexcept { const MoveRequestData request = *reinterpret_cast(data); float point[3]{}; - Nav->MoveAlongSurface(handler->GetId(), request.mapId, request.start, request.end, point); handler->SendData(type, point, VEC3_SIZE); } @@ -225,30 +209,56 @@ void GenericPathCallback(ClientHandler* handler, char type, const void* data, in if (pathGenerated) { - if ((request.flags & static_cast(PathRequestFlags::CATMULLROM)) && pathSize > 9) - { - int smoothedPathSize = 0; - float* smoothedPathBuffer = ClientPathBuffers[handler->GetId()].second; - Nav->SmoothPathCatmullRom(pathBuffer, pathSize, smoothedPathBuffer, &smoothedPathSize, Config->catmullRomSplinePoints, Config->catmullRomSplineAlpha); + HandlePathFlagsAndSendData(handler, request.flags, pathSize, pathBuffer, type); + } + else + { + float zero[3]{}; + handler->SendData(type, zero, VEC3_SIZE); + } +} - handler->SendData(type, smoothedPathBuffer, smoothedPathSize * sizeof(float)); - } - else if ((request.flags & static_cast(PathRequestFlags::CHAIKIN)) && pathSize > 6) - { - int smoothedPathSize = 0; - float* smoothedPathBuffer = ClientPathBuffers[handler->GetId()].second; - Nav->SmoothPathChaikinCurve(pathBuffer, pathSize, smoothedPathBuffer, &smoothedPathSize); +void RandomPointCallback(ClientHandler* handler, char type, const void* data, int size) noexcept +{ + const int mapId = *reinterpret_cast(data); + float point[3]{}; + Nav->GetRandomPoint(handler->GetId(), mapId, point); + handler->SendData(type, point, VEC3_SIZE); +} - handler->SendData(type, smoothedPathBuffer, smoothedPathSize * sizeof(float)); - } - else - { - handler->SendData(type, pathBuffer, pathSize * sizeof(float)); - } +void RandomPointAroundCallback(ClientHandler* handler, char type, const void* data, int size) noexcept +{ + const RandomPointAroundData request = *reinterpret_cast(data); + float point[3]{}; + Nav->GetRandomPointAround(handler->GetId(), request.mapId, request.start, request.radius, point); + handler->SendData(type, point, VEC3_SIZE); +} + +void ExplorePolyCallback(ClientHandler* handler, char type, const void* data, int size) noexcept +{ + const ExplorePolyData request = *reinterpret_cast(data); + + int pathSize = 0; + float* pathBuffer = ClientPathBuffers[handler->GetId()].first; + bool pathGenerated = Nav->GetExplorePolyPath + ( + handler->GetId(), + request.mapId, + request.firstPolyPoint, + request.polyPointCount, + pathBuffer, + &pathSize, + request.start, + request.viewDistance + ); + + if (pathGenerated) + { + HandlePathFlagsAndSendData(handler, request.flags, pathSize, pathBuffer, type); } else { float zero[3]{}; handler->SendData(type, zero, VEC3_SIZE); } -} \ No newline at end of file +} diff --git a/AmeisenNavigation.Server/src/Main.hpp b/AmeisenNavigation.Server/src/Main.hpp index bd5d276..7bc0844 100644 --- a/AmeisenNavigation.Server/src/Main.hpp +++ b/AmeisenNavigation.Server/src/Main.hpp @@ -11,18 +11,18 @@ #include #include -constexpr auto AMEISENNAV_VERSION = "1.8.2.0"; - +constexpr auto AMEISENNAV_VERSION = "1.8.3.0"; constexpr auto VEC3_SIZE = sizeof(float) * 3; enum class MessageType { - PATH, - MOVE_ALONG_SURFACE, - RANDOM_POINT, - RANDOM_POINT_AROUND, - CAST_RAY, - RANDOM_PATH, + PATH, // Generate a simple straight path + MOVE_ALONG_SURFACE, // Move an entity by small deltas using pathfinding (usefull to prevent falling off edges...) + RANDOM_POINT, // Get a random point on the mesh + RANDOM_POINT_AROUND, // Get a random point on the mesh in a circle + CAST_RAY, // Cast a movement ray to test for obstacles + RANDOM_PATH, // Generate a straight path where the nodes get offsetted by a random value + EXPLORE_POLY, // Generate a route to explore the polygon (W.I.P) }; enum class PathType @@ -34,8 +34,8 @@ enum class PathType enum class PathRequestFlags : int { NONE = 0, - CHAIKIN = 1, - CATMULLROM = 2, + SMOOTH_CHAIKIN = 1, + SMOOTH_CATMULLROM = 2, }; struct PathRequestData @@ -67,11 +67,21 @@ struct RandomPointAroundData float radius; }; +struct ExplorePolyData +{ + int mapId; + int flags; + float start[3]; + float viewDistance; + int polyPointCount; + float firstPolyPoint[3]; +}; + inline AnTcpServer* Server = nullptr; inline AmeisenNavigation* Nav = nullptr; inline AmeisenNavConfig* Config = nullptr; -inline std::unordered_map> ClientPathBuffers; +inline std::unordered_map> ClientPathBuffers; int __stdcall SigIntHandler(unsigned long signal); @@ -80,9 +90,33 @@ void OnClientDisconnect(ClientHandler* handler) noexcept; void PathCallback(ClientHandler* handler, char type, const void* data, int size) noexcept; void RandomPathCallback(ClientHandler* handler, char type, const void* data, int size) noexcept; -void RandomPointCallback(ClientHandler* handler, char type, const void* data, int size) noexcept; -void RandomPointAroundCallback(ClientHandler* handler, char type, const void* data, int size) noexcept; void MoveAlongSurfaceCallback(ClientHandler* handler, char type, const void* data, int size) noexcept; void CastRayCallback(ClientHandler* handler, char type, const void* data, int size) noexcept; - void GenericPathCallback(ClientHandler* handler, char type, const void* data, int size, PathType pathType) noexcept; + +void RandomPointCallback(ClientHandler* handler, char type, const void* data, int size) noexcept; +void RandomPointAroundCallback(ClientHandler* handler, char type, const void* data, int size) noexcept; + +void ExplorePolyCallback(ClientHandler* handler, char type, const void* data, int size) noexcept; + +inline void HandlePathFlagsAndSendData(ClientHandler* handler, int flags, int pathSize, float* pathBuffer, char type) noexcept +{ + if ((flags & static_cast(PathRequestFlags::SMOOTH_CATMULLROM)) && pathSize > 9) + { + int smoothedPathSize = 0; + float* smoothedPathBuffer = ClientPathBuffers[handler->GetId()].second; + Nav->SmoothPathCatmullRom(pathBuffer, pathSize, smoothedPathBuffer, &smoothedPathSize, Config->catmullRomSplinePoints, Config->catmullRomSplineAlpha); + handler->SendData(type, smoothedPathBuffer, smoothedPathSize * sizeof(float)); + } + else if ((flags & static_cast(PathRequestFlags::SMOOTH_CHAIKIN)) && pathSize > 6) + { + int smoothedPathSize = 0; + float* smoothedPathBuffer = ClientPathBuffers[handler->GetId()].second; + Nav->SmoothPathChaikinCurve(pathBuffer, pathSize, smoothedPathBuffer, &smoothedPathSize); + handler->SendData(type, smoothedPathBuffer, smoothedPathSize * sizeof(float)); + } + else + { + handler->SendData(type, pathBuffer, pathSize * sizeof(float)); + } +} diff --git a/AmeisenNavigation.Tester/MainWindow.xaml.cs b/AmeisenNavigation.Tester/MainWindow.xaml.cs index 41c0667..ebe1293 100644 --- a/AmeisenNavigation.Tester/MainWindow.xaml.cs +++ b/AmeisenNavigation.Tester/MainWindow.xaml.cs @@ -41,11 +41,11 @@ public IEnumerable GetPath(MessageType msgType, int mapId, Vector3 star { try { - return Client.IsConnected ? Client.Send((byte)msgType, (mapId, flags, start, end)).AsArray() : Array.Empty(); + return Client.IsConnected ? Client.Send((byte)msgType, (mapId, flags, start, end)).AsArray() : []; } catch { - return Array.Empty(); + return []; } } @@ -53,11 +53,11 @@ public Vector3 GetPoint(int mapId) { try { - return Client.IsConnected ? Client.Send((byte)MessageType.RANDOM_POINT, mapId).As() : new Vector3(); + return Client.IsConnected ? Client.Send((byte)MessageType.RANDOM_POINT, mapId).As() : new(); } catch { - return new Vector3(); + return new(); } } @@ -187,7 +187,7 @@ private void Window_Loaded(object sender, RoutedEventArgs e) TextBoxEndZ.Text = end.Z.ToString(); } - private bool TryLoadFloat(TextBox textBox, out float f) + private static bool TryLoadFloat(TextBox textBox, out float f) { bool result = float.TryParse(textBox.Text, out f); // mark textbox red diff --git a/AmeisenNavigation.Tester/Vector3.cs b/AmeisenNavigation.Tester/Vector3.cs index bcfd96a..218d222 100644 --- a/AmeisenNavigation.Tester/Vector3.cs +++ b/AmeisenNavigation.Tester/Vector3.cs @@ -4,47 +4,36 @@ namespace AmeisenNavigation.Tester { [StructLayout(LayoutKind.Sequential)] - public struct Vector3 + public struct Vector3(float x, float y, float z) { - public Vector3(float x, float y, float z) - { - X = x; - Y = y; - Z = z; - } - - public override string ToString() + public override readonly string ToString() => $"{X}, {Y}, {Z}"; - public float X { get; set; } + public float X { get; set; } = x; - public float Y { get; set; } + public float Y { get; set; } = y; - public float Z { get; set; } + public float Z { get; set; } = z; public static Vector3 FromArray(float[] array) => new() { X = array[0], Y = array[1], Z = array[2] }; public static bool operator !=(Vector3 left, Vector3 right) - { - return !(left == right); - } + => !(left == right); public static bool operator ==(Vector3 left, Vector3 right) - { - return left.Equals(right); - } + => left.Equals(right); - public override bool Equals(object obj) + public override readonly bool Equals(object obj) => obj.GetType() == typeof(Vector3) && ((Vector3)obj).X == X && ((Vector3)obj).Y == Y && ((Vector3)obj).Z == Z; - public double GetDistance(Vector3 b) + public readonly double GetDistance(Vector3 b) => MathF.Sqrt(((X - b.X) * (X - b.X)) + ((Y - b.Y) * (Y - b.Y)) + ((Z - b.Z) * (Z - b.Z))); - public double GetDistance2D(Vector3 b) + public readonly double GetDistance2D(Vector3 b) => MathF.Sqrt(MathF.Pow(X - b.X, 2) + MathF.Pow(Y - b.Y, 2)); - public override int GetHashCode() + public override readonly int GetHashCode() { unchecked { @@ -52,7 +41,7 @@ public override int GetHashCode() } } - public float[] ToArray() - => new float[3] { X, Y, Z }; + public readonly float[] ToArray() + => [X, Y, Z]; } } \ No newline at end of file diff --git a/AmeisenNavigation/AmeisenNavigation.vcxproj b/AmeisenNavigation/AmeisenNavigation.vcxproj index 64b6df0..e9e383d 100644 --- a/AmeisenNavigation/AmeisenNavigation.vcxproj +++ b/AmeisenNavigation/AmeisenNavigation.vcxproj @@ -121,7 +121,7 @@ Disabled true true - stdcpp17 + stdcpplatest $(SolutionDir)\recastnavigation\Detour\Include; Default @@ -144,9 +144,10 @@ Default Speed true - StreamingSIMDExtensions2 + NotSet + AnySuitable true @@ -162,12 +163,12 @@ true true true - stdcpp17 + stdcpplatest $(SolutionDir)\recastnavigation\Detour\Include; Default Speed true - StreamingSIMDExtensions2 + NotSet AnySuitable @@ -187,6 +188,8 @@ + + diff --git a/AmeisenNavigation/AmeisenNavigation.vcxproj.filters b/AmeisenNavigation/AmeisenNavigation.vcxproj.filters index 86f1ba0..0cecd3c 100644 --- a/AmeisenNavigation/AmeisenNavigation.vcxproj.filters +++ b/AmeisenNavigation/AmeisenNavigation.vcxproj.filters @@ -6,6 +6,8 @@ + + diff --git a/AmeisenNavigation/src/AmeisenNavigation.cpp b/AmeisenNavigation/src/AmeisenNavigation.cpp index bc83a31..7ffd0f8 100644 --- a/AmeisenNavigation/src/AmeisenNavigation.cpp +++ b/AmeisenNavigation/src/AmeisenNavigation.cpp @@ -1,24 +1,24 @@ #include "AmeisenNavigation.hpp" -void AmeisenNavigation::NewClient(int id, CLIENT_VERSION version) noexcept +void AmeisenNavigation::NewClient(size_t clientId, ClientVersion version) noexcept { - if (IsValidClient(id)) { return; } + if (IsValidClient(clientId)) { return; } - ANAV_DEBUG_ONLY(std::cout << ">> New Client: " << id << std::endl); - Clients[id] = new AmeisenNavClient(id, version, MaxPathNodes); + ANAV_DEBUG_ONLY(std::cout << ">> New Client: " << clientId << std::endl); + Clients[clientId] = new AmeisenNavClient(clientId, version, MaxPathNodes); } -void AmeisenNavigation::FreeClient(int id) noexcept +void AmeisenNavigation::FreeClient(size_t clientId) noexcept { - if (!IsValidClient(id)) { return; } + if (!IsValidClient(clientId)) { return; } - delete Clients[id]; - Clients[id] = nullptr; + delete Clients[clientId]; + Clients[clientId] = nullptr; - ANAV_DEBUG_ONLY(std::cout << ">> Freed Client: " << id << std::endl); + ANAV_DEBUG_ONLY(std::cout << ">> Freed Client: " << clientId << std::endl); } -bool AmeisenNavigation::GetPath(int clientId, int mapId, const float* startPosition, const float* endPosition, float* path, int* pathSize) noexcept +bool AmeisenNavigation::GetPath(size_t clientId, int mapId, const float* startPosition, const float* endPosition, float* path, int* pathSize) noexcept { if (!IsValidClient(clientId) || !InitQueryAndLoadMmaps(clientId, mapId)) { return false; } @@ -37,7 +37,7 @@ bool AmeisenNavigation::GetPath(int clientId, int mapId, const float* startPosit return false; } -bool AmeisenNavigation::GetRandomPath(int clientId, int mapId, const float* startPosition, const float* endPosition, float* path, int* pathSize, float maxRandomDistance) noexcept +bool AmeisenNavigation::GetRandomPath(size_t clientId, int mapId, const float* startPosition, const float* endPosition, float* path, int* pathSize, float maxRandomDistance) noexcept { if (!IsValidClient(clientId) || !InitQueryAndLoadMmaps(clientId, mapId)) { return false; } @@ -80,7 +80,7 @@ bool AmeisenNavigation::GetRandomPath(int clientId, int mapId, const float* star return false; } -bool AmeisenNavigation::MoveAlongSurface(int clientId, int mapId, const float* startPosition, const float* endPosition, float* positionToGoTo) noexcept +bool AmeisenNavigation::MoveAlongSurface(size_t clientId, int mapId, const float* startPosition, const float* endPosition, float* positionToGoTo) noexcept { if (!IsValidClient(clientId) || !InitQueryAndLoadMmaps(clientId, mapId)) { return false; } @@ -121,7 +121,7 @@ bool AmeisenNavigation::MoveAlongSurface(int clientId, int mapId, const float* s return false; } -bool AmeisenNavigation::GetRandomPoint(int clientId, int mapId, float* position) noexcept +bool AmeisenNavigation::GetRandomPoint(size_t clientId, int mapId, float* position) noexcept { if (!IsValidClient(clientId) || !InitQueryAndLoadMmaps(clientId, mapId)) { return false; } @@ -149,7 +149,7 @@ bool AmeisenNavigation::GetRandomPoint(int clientId, int mapId, float* position) return false; } -bool AmeisenNavigation::GetRandomPointAround(int clientId, int mapId, const float* startPosition, float radius, float* position) noexcept +bool AmeisenNavigation::GetRandomPointAround(size_t clientId, int mapId, const float* startPosition, float radius, float* position) noexcept { if (!IsValidClient(clientId) || !InitQueryAndLoadMmaps(clientId, mapId)) { return false; } @@ -183,7 +183,7 @@ bool AmeisenNavigation::GetRandomPointAround(int clientId, int mapId, const floa return false; } -bool AmeisenNavigation::CastMovementRay(int clientId, int mapId, const float* startPosition, const float* endPosition, dtRaycastHit* raycastHit) noexcept +bool AmeisenNavigation::CastMovementRay(size_t clientId, int mapId, const float* startPosition, const float* endPosition, dtRaycastHit* raycastHit) noexcept { if (!IsValidClient(clientId) || !InitQueryAndLoadMmaps(clientId, mapId)) { return false; } @@ -217,6 +217,22 @@ bool AmeisenNavigation::CastMovementRay(int clientId, int mapId, const float* st return false; } +bool AmeisenNavigation::GetExplorePolyPath(size_t clientId, int mapId, const float* polyPoints, int inputSize, float* output, int* outputSize, const float* startPosition, float viewDistance) noexcept +{ + if (!IsValidClient(clientId) || !InitQueryAndLoadMmaps(clientId, mapId)) { return false; } + + ANAV_DEBUG_ONLY(std::cout << ">> [" << clientId << "] GetExplorePolyPath (" << mapId << ") " << PRINT_VEC3(startPosition) << " -> " << PRINT_VEC3(inputSize) << " polys" << std::endl); + + float rdStart[3]; + dtVcopy(rdStart, startPosition); + WowToRDCoords(rdStart); + + + + ANAV_ERROR_MSG(std::cout << ">> [" << clientId << "] Failed to call ...: " << "" << std::endl); + return false; +} + void AmeisenNavigation::SmoothPathChaikinCurve(const float* input, int inputSize, float* output, int* outputSize) const noexcept { InsertVector3(output, *outputSize, input, 0); @@ -424,7 +440,7 @@ bool AmeisenNavigation::LoadMmaps(int mapId) noexcept return true; } -bool AmeisenNavigation::InitQueryAndLoadMmaps(int clientId, int mapId) noexcept +bool AmeisenNavigation::InitQueryAndLoadMmaps(size_t clientId, int mapId) noexcept { // we already have a query if (Clients[clientId]->GetNavmeshQuery(mapId)) { return true; } @@ -458,7 +474,7 @@ bool AmeisenNavigation::InitQueryAndLoadMmaps(int clientId, int mapId) noexcept return true; } -bool AmeisenNavigation::CalculateNormalPath(int clientId, int mapId, const float* startPosition, const float* endPosition, float* path, int* pathSize, dtPolyRef* visited) noexcept +bool AmeisenNavigation::CalculateNormalPath(size_t clientId, int mapId, const float* startPosition, const float* endPosition, float* path, int* pathSize, dtPolyRef* visited) noexcept { float rdStart[3]; dtVcopy(rdStart, startPosition); diff --git a/AmeisenNavigation/src/AmeisenNavigation.hpp b/AmeisenNavigation/src/AmeisenNavigation.hpp index 13c054f..f5f2584 100644 --- a/AmeisenNavigation/src/AmeisenNavigation.hpp +++ b/AmeisenNavigation/src/AmeisenNavigation.hpp @@ -15,6 +15,8 @@ #include "Clients/AmeisenNavClient.hpp" +#include "Helpers/Polygon.hpp" + #ifdef _DEBUG #define ANAV_DEBUG_ONLY(x) x #define ANAV_ERROR_MSG(x) x @@ -56,8 +58,8 @@ class AmeisenNavigation int MaxPathNodes; int MaxSearchNodes; - std::unordered_map> NavMeshMap; - std::unordered_map Clients; + std::unordered_map> NavMeshMap; + std::unordered_map Clients; public: /// @@ -105,13 +107,13 @@ class AmeisenNavigation /// /// Unique id for the client. /// Version of the client. - void NewClient(int id, CLIENT_VERSION version) noexcept; + void NewClient(size_t clientId, ClientVersion version) noexcept; /// /// Call this to free a client. /// /// Uinique id of the client. - void FreeClient(int id) noexcept; + void FreeClient(size_t clientId) noexcept; /// /// Try to find a path from start to end. @@ -123,7 +125,7 @@ class AmeisenNavigation /// Path buffer. /// The paths size. /// True when a path was found, false if not. - bool GetPath(int clientId, int mapId, const float* startPosition, const float* endPosition, float* path, int* pathSize) noexcept; + bool GetPath(size_t clientId, int mapId, const float* startPosition, const float* endPosition, float* path, int* pathSize) noexcept; /// /// Try to find a path from start to end but randomize the final positions by x meters. @@ -136,7 +138,7 @@ class AmeisenNavigation /// The paths size. /// Max distance to the original psoition. /// True when a path was found, false if not. - bool GetRandomPath(int clientId, int mapId, const float* startPosition, const float* endPosition, float* path, int* pathSize, float maxRandomDistance) noexcept; + bool GetRandomPath(size_t clientId, int mapId, const float* startPosition, const float* endPosition, float* path, int* pathSize, float maxRandomDistance) noexcept; /// /// Try to move towards a specific location. @@ -147,7 +149,7 @@ class AmeisenNavigation /// End position vector. /// Target position. /// True when a path was found, false if not. - bool MoveAlongSurface(int clientId, int mapId, const float* startPosition, const float* endPosition, float* positionToGoTo) noexcept; + bool MoveAlongSurface(size_t clientId, int mapId, const float* startPosition, const float* endPosition, float* positionToGoTo) noexcept; /// /// Get a random point anywhere on the map. @@ -156,7 +158,7 @@ class AmeisenNavigation /// The map id to search a path on. /// Random position. /// True when a point has been found, fals eif not. - bool GetRandomPoint(int clientId, int mapId, float* position) noexcept; + bool GetRandomPoint(size_t clientId, int mapId, float* position) noexcept; /// /// Get a random point within x meters of the start position. @@ -167,7 +169,7 @@ class AmeisenNavigation /// Max distance to search for a random position. /// Random position. /// True when a point has been found, fals eif not. - bool GetRandomPointAround(int clientId, int mapId, const float* startPosition, float radius, float* position) noexcept; + bool GetRandomPointAround(size_t clientId, int mapId, const float* startPosition, float radius, float* position) noexcept; /// /// Cast a movement ray along the mesh and see whether it collides with a wall or not. @@ -178,7 +180,21 @@ class AmeisenNavigation /// End position vector. /// Detour raycast result. /// True when the ray hited no wall, false if it did. - bool CastMovementRay(int clientId, int mapId, const float* startPosition, const float* endPosition, dtRaycastHit* raycastHit) noexcept; + bool CastMovementRay(size_t clientId, int mapId, const float* startPosition, const float* endPosition, dtRaycastHit* raycastHit) noexcept; + + /// + /// Create a path to explore a polygon. Path will cover the area of the polygon and be created using a TSP algorithm to ensure efficiency. + /// + /// Id of the client to run this on. + /// The map id to search a path on. + /// Input polygon points. + /// Input polygon point count. + /// Output path. + /// Output paths size. + /// From where to start exploring the polygon. + /// How far can the agent see, lower values will result in more path points. + /// True when a path was found, false if not. + bool GetExplorePolyPath(size_t clientId, int mapId, const float* polyPoints, int inputSize, float* output, int* outputSize, const float* startPosition, float viewDistance) noexcept; /// /// Smooth a path using the chaikin-curve algorithm. @@ -208,27 +224,10 @@ class AmeisenNavigation bool LoadMmaps(int mapId) noexcept; private: - /// - /// Try to find the nearest poly for a given position. - /// - /// Id of the client to run this on. - /// The map id to search a path on. - /// Current position. - /// Closest point on the found poly. - /// Reference to the found poly if found, else 0. - inline dtPolyRef GetNearestPoly(int clientId, int mapId, float* position, float* closestPointOnPoly) const noexcept - { - dtPolyRef polyRef; - float extents[3] = { 6.0f, 6.0f, 6.0f }; - const auto& client = Clients.at(clientId); - bool result = dtStatusSucceed(client->GetNavmeshQuery(mapId)->findNearestPoly(position, extents, &client->QueryFilter(), &polyRef, closestPointOnPoly)); - return result ? polyRef : 0; - } - /// /// Helper function to insert a vector3 into a float buffer. /// - inline void InsertVector3(float* target, int& index, const float* vec, int offset) const noexcept + constexpr void InsertVector3(float* target, int& index, const float* vec, int offset) const noexcept { target[index] = vec[offset + 0]; target[index + 1] = vec[offset + 1]; @@ -236,21 +235,10 @@ class AmeisenNavigation index += 3; } - /// - /// Helper function to scale two vectors and add them. - /// Used by the smoothing algorithms. - /// - inline void ScaleAndAddVector3(const float* vec0, float fac0, const float* vec1, float fac1, float* s0, float* s1, float* output) const noexcept - { - dtVscale(s0, vec0, fac0); - dtVscale(s1, vec1, fac1); - dtVadd(output, s0, s1); - } - /// /// Convert the recast and detour coordinates to wow coordinates. /// - inline void RDToWowCoords(float* pos) const noexcept + constexpr void RDToWowCoords(float* pos) const noexcept { float oz = pos[2]; pos[2] = pos[1]; @@ -261,7 +249,7 @@ class AmeisenNavigation /// /// Convert the wow coordinates to recast and detour coordinates. /// - inline void WowToRDCoords(float* pos) const noexcept + constexpr void WowToRDCoords(float* pos) const noexcept { float ox = pos[0]; pos[0] = pos[1]; @@ -269,6 +257,34 @@ class AmeisenNavigation pos[2] = ox; } + /// + /// Try to find the nearest poly for a given position. + /// + /// Id of the client to run this on. + /// The map id to search a path on. + /// Current position. + /// Closest point on the found poly. + /// Reference to the found poly if found, else 0. + inline dtPolyRef GetNearestPoly(size_t clientId, int mapId, float* position, float* closestPointOnPoly) const noexcept + { + dtPolyRef polyRef; + float extents[3] = { 6.0f, 6.0f, 6.0f }; + const auto& client = Clients.at(clientId); + bool result = dtStatusSucceed(client->GetNavmeshQuery(mapId)->findNearestPoly(position, extents, &client->QueryFilter(), &polyRef, closestPointOnPoly)); + return result ? polyRef : 0; + } + + /// + /// Helper function to scale two vectors and add them. + /// Used by the smoothing algorithms. + /// + inline void ScaleAndAddVector3(const float* vec0, float fac0, const float* vec1, float fac1, float* s0, float* s1, float* output) const noexcept + { + dtVscale(s0, vec0, fac0); + dtVscale(s1, vec1, fac1); + dtVadd(output, s0, s1); + } + /// /// Returns true when th mmaps are loaded for the given continent. /// @@ -277,17 +293,17 @@ class AmeisenNavigation /// /// Returns true when the given client id is valid. /// - inline bool IsValidClient(int clientId) noexcept { return Clients[clientId] != nullptr; } + inline bool IsValidClient(size_t clientId) noexcept { return Clients[clientId] != nullptr; } /// /// Initializes a NavMeshQuery for the given client. /// - bool InitQueryAndLoadMmaps(int clientId, int mapId) noexcept; + bool InitQueryAndLoadMmaps(size_t clientId, int mapId) noexcept; /// /// Used by the GetPath and GetRandomPath methods to generate a path. /// - bool CalculateNormalPath(int clientId, int mapId, const float* startPosition, const float* endPosition, float* path, int* pathSize, dtPolyRef* visited = nullptr) noexcept; + bool CalculateNormalPath(size_t clientId, int mapId, const float* startPosition, const float* endPosition, float* path, int* pathSize, dtPolyRef* visited = nullptr) noexcept; /// /// Used to detect the mmap file format. diff --git a/AmeisenNavigation/src/Clients/AmeisenNavClient.hpp b/AmeisenNavigation/src/Clients/AmeisenNavClient.hpp index 8c780f6..27ecd88 100644 --- a/AmeisenNavigation/src/Clients/AmeisenNavClient.hpp +++ b/AmeisenNavigation/src/Clients/AmeisenNavClient.hpp @@ -11,8 +11,8 @@ class AmeisenNavClient { - int Id; - CLIENT_VERSION CVersion; + size_t Id; + ClientVersion CVersion; dtQueryFilter Filter; std::unordered_map NavMeshQuery; size_t BufferSize; @@ -20,8 +20,7 @@ class AmeisenNavClient dtPolyRef* MiscPathBuffer; public: - - AmeisenNavClient(int id, CLIENT_VERSION version, size_t polypathBufferSize) + AmeisenNavClient(size_t id, ClientVersion version, size_t polypathBufferSize) : Id(id), CVersion(version), BufferSize(polypathBufferSize), @@ -32,12 +31,12 @@ class AmeisenNavClient { switch (version) { - case CLIENT_VERSION::V335A: + case ClientVersion::TC335A: Filter.setIncludeFlags(static_cast(NavArea335a::GROUND) | static_cast(NavArea335a::WATER)); Filter.setExcludeFlags(static_cast(NavArea335a::EMPTY) | static_cast(NavArea335a::GROUND_STEEP) | static_cast(NavArea335a::MAGMA_SLIME)); break; - case CLIENT_VERSION::V548: + case ClientVersion::SF548: Filter.setIncludeFlags(static_cast(NavArea548::GROUND) | static_cast(NavArea548::WATER)); Filter.setExcludeFlags(static_cast(NavArea548::EMPTY) | static_cast(NavArea548::MAGMA) | static_cast(NavArea548::SLIME)); break; @@ -65,11 +64,12 @@ class AmeisenNavClient AmeisenNavClient(const AmeisenNavClient&) = delete; AmeisenNavClient& operator=(const AmeisenNavClient&) = delete; - inline int GetId() noexcept { return Id; } - inline dtQueryFilter& QueryFilter() noexcept { return Filter; } + constexpr size_t GetId() const noexcept { return Id; } + constexpr dtQueryFilter& QueryFilter() noexcept { return Filter; } + constexpr dtPolyRef* GetPolyPathBuffer() noexcept { return PolyPathBuffer; } + constexpr dtPolyRef* GetMiscPathBuffer() noexcept { return MiscPathBuffer ? MiscPathBuffer : MiscPathBuffer = new dtPolyRef[BufferSize]; } + inline dtNavMeshQuery* GetNavmeshQuery(int mapId) noexcept { return NavMeshQuery[mapId]; } - inline dtPolyRef* GetPolyPathBuffer() noexcept { return PolyPathBuffer; } - inline dtPolyRef* GetMiscPathBuffer() noexcept { return MiscPathBuffer ? MiscPathBuffer : MiscPathBuffer = new dtPolyRef[BufferSize]; } inline void SetNavmeshQuery(int mapId, dtNavMeshQuery* query) noexcept { NavMeshQuery[mapId] = query; } }; \ No newline at end of file diff --git a/AmeisenNavigation/src/Clients/ClientVersion.hpp b/AmeisenNavigation/src/Clients/ClientVersion.hpp index c3c4109..148c592 100644 --- a/AmeisenNavigation/src/Clients/ClientVersion.hpp +++ b/AmeisenNavigation/src/Clients/ClientVersion.hpp @@ -1,7 +1,7 @@ #pragma once -enum class CLIENT_VERSION : char +enum class ClientVersion : char { - V335A, - V548, + TC335A, + SF548, }; diff --git a/AmeisenNavigation/src/Helpers/Point.hpp b/AmeisenNavigation/src/Helpers/Point.hpp new file mode 100644 index 0000000..2e639af --- /dev/null +++ b/AmeisenNavigation/src/Helpers/Point.hpp @@ -0,0 +1,8 @@ +#pragma once + +struct Point +{ + float x, y; + + Point(float x, float y) : x(x), y(y) {} +}; diff --git a/AmeisenNavigation/src/Helpers/Polygon.hpp b/AmeisenNavigation/src/Helpers/Polygon.hpp new file mode 100644 index 0000000..230abcb --- /dev/null +++ b/AmeisenNavigation/src/Helpers/Polygon.hpp @@ -0,0 +1,139 @@ +#pragma once + +#include +#include +#include +#include + +#include "Point.hpp" + +struct Polygon +{ + std::vector vertices; + + Polygon(const std::vector& vertices) : vertices(vertices) {} + + bool isInside(const Point& p) const noexcept + { + int n = vertices.size(); + int count = 0; + + for (int i = 0; i < n; ++i) + { + int next = (i + 1) % n; + + if (((vertices[i].y <= p.y && p.y < vertices[next].y) || (vertices[next].y <= p.y && p.y < vertices[i].y)) + && (p.x < (vertices[next].x - vertices[i].x) * (p.y - vertices[i].y) / (vertices[next].y - vertices[i].y) + vertices[i].x)) + { + count++; + } + } + + return count % 2 == 1; + } + + /// + /// Generate randomized nodes using the Bridson's Poisson Disk Sampling algorithm that cover the polygons area. + /// + /// Minimum distance between nodes + /// + /// + std::vector bridsonsPoissonDiskSampling(float minDistance, int numCandidates = 30) const noexcept + { + std::vector points; + std::vector activeList; + std::random_device rd; + std::mt19937 rng(rd()); + std::uniform_real_distribution distribution(0.0, 1.0); + + if (vertices.empty()) + { + return points; + } + + float maxX = std::numeric_limits::min(); + float maxY = std::numeric_limits::min(); + float minX = std::numeric_limits::max(); + float minY = std::numeric_limits::max(); + + for (const Point& vertex : vertices) + { + maxX = std::max(maxX, vertex.x); + maxY = std::max(maxY, vertex.y); + minX = std::min(minX, vertex.x); + minY = std::min(minY, vertex.y); + } + + Point initialPoint{ 0.0f, 0.0f }; + + do + { + initialPoint = { distribution(rng) * (maxX - minX) + minX, distribution(rng) * (maxY - minY) + minY }; + } while ((!isInside(initialPoint))); + + points.emplace_back(initialPoint); + activeList.emplace_back(initialPoint); + + const float cellSize = minDistance / std::sqrt(2); + const int gridSizeX = static_cast(std::ceil((maxX - minX) / cellSize)); + const int gridSizeY = static_cast(std::ceil((maxY - minY) / cellSize)); + + std::vector> grid(gridSizeX, std::vector(gridSizeY, false)); + + while (!activeList.empty()) + { + int randomIndex = std::uniform_int_distribution(0, activeList.size() - 1)(rng); + Point currentPoint = activeList[randomIndex]; + bool foundCandidate = false; + + for (int i = 0; i < numCandidates; ++i) + { + float angle = distribution(rng) * 2.0f * std::numbers::pi_v; + float distance = distribution(rng) * minDistance + minDistance; + float cosAngle = std::cos(angle); + float sinAngle = std::sin(angle); + + Point candidate{ currentPoint.x + distance * cosAngle, currentPoint.y + distance * sinAngle }; + + if (candidate.x >= minX && candidate.x <= maxX && candidate.y >= minY && candidate.y <= maxY) + { + int gridX = static_cast((candidate.x - minX) / cellSize); + int gridY = static_cast((candidate.y - minY) / cellSize); + + if (!grid[gridX][gridY] && isInside(candidate) && checkMinDistance(candidate, points, minDistance)) + { + points.emplace_back(candidate); + activeList.emplace_back(candidate); + grid[gridX][gridY] = true; + + foundCandidate = true; + break; + } + } + } + + if (!foundCandidate) + { + activeList.erase(activeList.begin() + randomIndex); + } + } + + return points; + } + +private: + static bool checkMinDistance(const Point& p, const std::vector& points, float minDistance) + { + for (const Point& existingPoint : points) + { + float dist = std::sqrt((p.x - existingPoint.x) * (p.x - existingPoint.x) + (p.y - existingPoint.y) * (p.y - existingPoint.y)); + + if (dist < minDistance) + { + return false; + } + } + + return true; + } +}; diff --git a/dep/AnTCP.Server/include/AnTcpServer.hpp b/dep/AnTCP.Server/include/AnTcpServer.hpp index ee879c7..b43942a 100644 --- a/dep/AnTCP.Server/include/AnTcpServer.hpp +++ b/dep/AnTCP.Server/include/AnTcpServer.hpp @@ -151,10 +151,10 @@ class ClientHandler /// True if data was sent, false if not. inline bool SendData(AnTcpMessageType type, const void* data, size_t size) const noexcept { - const int packetSize = size + static_cast(sizeof(AnTcpMessageType)); - return send(Socket, reinterpret_cast(&packetSize), sizeof(decltype(packetSize)), 0) != SOCKET_ERROR - && send(Socket, &type, sizeof(AnTcpMessageType), 0) != SOCKET_ERROR - && send(Socket, static_cast(data), size, 0) != SOCKET_ERROR; + const int packetSize = static_cast(size) + static_cast(sizeof(AnTcpMessageType)); + return send(Socket, reinterpret_cast(&packetSize), static_cast(sizeof(decltype(packetSize))), 0) != SOCKET_ERROR + && send(Socket, &type, static_cast(sizeof(AnTcpMessageType)), 0) != SOCKET_ERROR + && send(Socket, static_cast(data), static_cast(size), 0) != SOCKET_ERROR; } /// diff --git a/recastnavigation/Detour/CMakeLists.txt b/recastnavigation/Detour/CMakeLists.txt new file mode 100644 index 0000000..c8eb858 --- /dev/null +++ b/recastnavigation/Detour/CMakeLists.txt @@ -0,0 +1,40 @@ +file(GLOB SOURCES Source/*.cpp) +add_library(Detour ${SOURCES}) + +add_library(RecastNavigation::Detour ALIAS Detour) +set_target_properties(Detour PROPERTIES DEBUG_POSTFIX -d) + +set(Detour_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Include") + +if(RECASTNAVIGATION_DT_POLYREF64) + target_compile_definitions(Detour PUBLIC DT_POLYREF64) +endif() +if(RECASTNAVIGATION_DT_VIRTUAL_QUERYFILTER) + target_compile_definitions(Detour PUBLIC DT_VIRTUAL_QUERYFILTER) +endif() + +target_include_directories(Detour PUBLIC + "$" +) + +set_target_properties(Detour PROPERTIES + SOVERSION ${SOVERSION} + VERSION ${LIB_VERSION} + COMPILE_PDB_OUTPUT_DIRECTORY . + COMPILE_PDB_NAME "Detour-d" + ) + +install(TARGETS Detour + EXPORT recastnavigation-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT library + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ${CMAKE_INSTALL_INCLUDEDIR}/recastnavigation + ) + +file(GLOB INCLUDES Include/*.h) +install(FILES ${INCLUDES} DESTINATION + ${CMAKE_INSTALL_INCLUDEDIR}/recastnavigation) +if(MSVC) + install(FILES "$/Detour-d.pdb" CONFIGURATIONS "Debug" DESTINATION "lib" OPTIONAL) +endif() diff --git a/recastnavigation/Detour/Include/DetourCrowd.h b/recastnavigation/Detour/Include/DetourCrowd.h index 9b97f61..854546f 100644 --- a/recastnavigation/Detour/Include/DetourCrowd.h +++ b/recastnavigation/Detour/Include/DetourCrowd.h @@ -56,127 +56,127 @@ static const int DT_CROWD_MAX_QUERY_FILTER_TYPE = 16; /// @see dtCrowdAgent::neis, dtCrowd struct dtCrowdNeighbour { - int idx; ///< The index of the neighbor in the crowd. - float dist; ///< The distance between the current agent and the neighbor. + int idx; ///< The index of the neighbor in the crowd. + float dist; ///< The distance between the current agent and the neighbor. }; /// The type of navigation mesh polygon the agent is currently traversing. /// @ingroup crowd enum CrowdAgentState { - DT_CROWDAGENT_STATE_INVALID, ///< The agent is not in a valid state. - DT_CROWDAGENT_STATE_WALKING, ///< The agent is traversing a normal navigation mesh polygon. - DT_CROWDAGENT_STATE_OFFMESH, ///< The agent is traversing an off-mesh connection. + DT_CROWDAGENT_STATE_INVALID, ///< The agent is not in a valid state. + DT_CROWDAGENT_STATE_WALKING, ///< The agent is traversing a normal navigation mesh polygon. + DT_CROWDAGENT_STATE_OFFMESH ///< The agent is traversing an off-mesh connection. }; /// Configuration parameters for a crowd agent. /// @ingroup crowd struct dtCrowdAgentParams { - float radius; ///< Agent radius. [Limit: >= 0] - float height; ///< Agent height. [Limit: > 0] - float maxAcceleration; ///< Maximum allowed acceleration. [Limit: >= 0] - float maxSpeed; ///< Maximum allowed speed. [Limit: >= 0] + float radius; ///< Agent radius. [Limit: >= 0] + float height; ///< Agent height. [Limit: > 0] + float maxAcceleration; ///< Maximum allowed acceleration. [Limit: >= 0] + float maxSpeed; ///< Maximum allowed speed. [Limit: >= 0] - /// Defines how close a collision element must be before it is considered for steering behaviors. [Limits: > 0] - float collisionQueryRange; + /// Defines how close a collision element must be before it is considered for steering behaviors. [Limits: > 0] + float collisionQueryRange; - float pathOptimizationRange; ///< The path visibility optimization range. [Limit: > 0] + float pathOptimizationRange; ///< The path visibility optimization range. [Limit: > 0] - /// How aggresive the agent manager should be at avoiding collisions with this agent. [Limit: >= 0] - float separationWeight; + /// How aggresive the agent manager should be at avoiding collisions with this agent. [Limit: >= 0] + float separationWeight; - /// Flags that impact steering behavior. (See: #UpdateFlags) - unsigned char updateFlags; + /// Flags that impact steering behavior. (See: #UpdateFlags) + unsigned char updateFlags; - /// The index of the avoidance configuration to use for the agent. - /// [Limits: 0 <= value <= #DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS] - unsigned char obstacleAvoidanceType; + /// The index of the avoidance configuration to use for the agent. + /// [Limits: 0 <= value <= #DT_CROWD_MAX_OBSTAVOIDANCE_PARAMS] + unsigned char obstacleAvoidanceType; - /// The index of the query filter used by this agent. - unsigned char queryFilterType; + /// The index of the query filter used by this agent. + unsigned char queryFilterType; - /// User defined data attached to the agent. - void* userData; + /// User defined data attached to the agent. + void* userData; }; enum MoveRequestState { - DT_CROWDAGENT_TARGET_NONE = 0, - DT_CROWDAGENT_TARGET_FAILED, - DT_CROWDAGENT_TARGET_VALID, - DT_CROWDAGENT_TARGET_REQUESTING, - DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE, - DT_CROWDAGENT_TARGET_WAITING_FOR_PATH, - DT_CROWDAGENT_TARGET_VELOCITY, + DT_CROWDAGENT_TARGET_NONE = 0, + DT_CROWDAGENT_TARGET_FAILED, + DT_CROWDAGENT_TARGET_VALID, + DT_CROWDAGENT_TARGET_REQUESTING, + DT_CROWDAGENT_TARGET_WAITING_FOR_QUEUE, + DT_CROWDAGENT_TARGET_WAITING_FOR_PATH, + DT_CROWDAGENT_TARGET_VELOCITY }; /// Represents an agent managed by a #dtCrowd object. /// @ingroup crowd struct dtCrowdAgent { - /// True if the agent is active, false if the agent is in an unused slot in the agent pool. - bool active; - - /// The type of mesh polygon the agent is traversing. (See: #CrowdAgentState) - unsigned char state; - - /// True if the agent has valid path (targetState == DT_CROWDAGENT_TARGET_VALID) and the path does not lead to the requested position, else false. - bool partial; - - /// The path corridor the agent is using. - dtPathCorridor corridor; - - /// The local boundary data for the agent. - dtLocalBoundary boundary; - - /// Time since the agent's path corridor was optimized. - float topologyOptTime; - - /// The known neighbors of the agent. - dtCrowdNeighbour neis[DT_CROWDAGENT_MAX_NEIGHBOURS]; - - /// The number of neighbors. - int nneis; - - /// The desired speed. - float desiredSpeed; - - float npos[3]; ///< The current agent position. [(x, y, z)] - float disp[3]; ///< A temporary value used to accumulate agent displacement during iterative collision resolution. [(x, y, z)] - float dvel[3]; ///< The desired velocity of the agent. Based on the current path, calculated from scratch each frame. [(x, y, z)] - float nvel[3]; ///< The desired velocity adjusted by obstacle avoidance, calculated from scratch each frame. [(x, y, z)] - float vel[3]; ///< The actual velocity of the agent. The change from nvel -> vel is constrained by max acceleration. [(x, y, z)] - - /// The agent's configuration parameters. - dtCrowdAgentParams params; - - /// The local path corridor corners for the agent. (Staight path.) [(x, y, z) * #ncorners] - float cornerVerts[DT_CROWDAGENT_MAX_CORNERS * 3]; - - /// The local path corridor corner flags. (See: #dtStraightPathFlags) [(flags) * #ncorners] - unsigned char cornerFlags[DT_CROWDAGENT_MAX_CORNERS]; - - /// The reference id of the polygon being entered at the corner. [(polyRef) * #ncorners] - dtPolyRef cornerPolys[DT_CROWDAGENT_MAX_CORNERS]; - - /// The number of corners. - int ncorners; - - unsigned char targetState; ///< State of the movement request. - dtPolyRef targetRef; ///< Target polyref of the movement request. - float targetPos[3]; ///< Target position of the movement request (or velocity in case of DT_CROWDAGENT_TARGET_VELOCITY). - dtPathQueueRef targetPathqRef; ///< Path finder ref. - bool targetReplan; ///< Flag indicating that the current path is being replanned. - float targetReplanTime; ///