diff --git a/PluginAPI.h b/PluginAPI.h index f2ded5df..f3d7f2a2 100644 --- a/PluginAPI.h +++ b/PluginAPI.h @@ -49,6 +49,8 @@ struct NavigationOptions bool paused = false; // pathing is paused bool track = true; // if spawn is to be tracked FacingType facing = FacingType::Forward; // Forward = normal, Backward = move along path facing backward. + int searchRadius = 0; // the max search radius of the path + glm::vec3 searchOrigin; // the starting position / origin of the search // set a new default log level while the path is running. info is the default. spdlog::level::level_enum logLevel = spdlog::level::info; diff --git a/dependencies/recast/Detour/Include/DetourNavMeshQuery.h b/dependencies/recast/Detour/Include/DetourNavMeshQuery.h index 61541e83..67330901 100644 --- a/dependencies/recast/Detour/Include/DetourNavMeshQuery.h +++ b/dependencies/recast/Detour/Include/DetourNavMeshQuery.h @@ -28,7 +28,7 @@ // setting is to use non-virtual functions, the actual implementations of the functions // are declared as inline for maximum speed. -//#define DT_VIRTUAL_QUERYFILTER 1 +#define DT_VIRTUAL_QUERYFILTER 1 /// Defines polygon filtering and traversal costs for navigation mesh query operations. /// @ingroup detour diff --git a/plugin/MQ2Navigation.cpp b/plugin/MQ2Navigation.cpp index 992623fc..147bc321 100644 --- a/plugin/MQ2Navigation.cpp +++ b/plugin/MQ2Navigation.cpp @@ -1699,6 +1699,24 @@ void MQ2NavigationPlugin::ParseOptions(std::string_view line, int idx, Navigatio { args->tag = value; } + else if (key == "searchradius") + { + options.searchRadius = GetIntFromString(value, 0); + } + else if (key == "searchorigin") + { + std::vector parts = mq::split_view(value, ' ', false); + if (parts.size() == 3) + { + options.searchOrigin = { GetFloatFromString(parts[0], 0), GetFloatFromString(parts[1], 0), GetFloatFromString(parts[2], 0) }; + } + else if (parts.size() == 2) + { + options.searchOrigin = { GetFloatFromString(parts[0], 0), pLocalPlayer->FloorHeight, GetFloatFromString(parts[2], 0) }; + } + else + SPDLOG_ERROR("Invalid argument for searchorigin: {}", value); + } } catch (const std::exception& ex) { diff --git a/plugin/NavigationPath.cpp b/plugin/NavigationPath.cpp index 428f6258..d93e2668 100644 --- a/plugin/NavigationPath.cpp +++ b/plugin/NavigationPath.cpp @@ -181,7 +181,7 @@ void NavigationPath::SetNavMesh(const std::shared_ptr& navMesh, m_query.reset(); - m_filter = dtQueryFilter{}; + m_filter = NavPathFilter{}; m_filter.setIncludeFlags(+PolyFlags::All); m_filter.setExcludeFlags(+PolyFlags::Disabled); if (auto* mesh = g_mq2Nav->Get()) @@ -330,6 +330,11 @@ std::unique_ptr NavigationPath::RecomputePath( glm::vec3 spos; // TODO: Cache the last known valid starting position to detect when moving off the mesh + if (m_destinationInfo && m_destinationInfo->options.searchRadius > 0) + { + m_filter.SetSearchOrigin(m_destinationInfo->options.searchOrigin); + m_filter.SetSearchRadius(m_destinationInfo->options.searchRadius); + } m_query->findNearestPoly( glm::value_ptr(startPos), @@ -924,4 +929,24 @@ void NavigationLine::Update() } } +bool NavPathFilter::passFilter(const dtPolyRef ref, const dtMeshTile* tile, const dtPoly* poly) const +{ + if (m_searchRadius > 0) + { + glm::vec3 polyCenter = glm::vec3{ 0, 0, 0 }; + + for (int i = 0; i < poly->vertCount; ++i) + { + const float* v = &tile->verts[poly->verts[i] * 3]; + polyCenter += glm::vec3{ v[0], v[1], v[2] }; + } + + polyCenter /= poly->vertCount; + + if (distSqr(m_searchOrigin, polyCenter) > (m_searchRadius * m_searchRadius)) + return false; + } + return dtQueryFilter::passFilter(ref, tile, poly); +} + //---------------------------------------------------------------------------- diff --git a/plugin/NavigationPath.h b/plugin/NavigationPath.h index f7b450ed..e848fb77 100644 --- a/plugin/NavigationPath.h +++ b/plugin/NavigationPath.h @@ -57,6 +57,21 @@ struct StraightPath int alloc = 0; }; +class NavPathFilter : public dtQueryFilter +{ +private: + int m_searchRadius = 0; + glm::vec3 m_searchOrigin; + +public: + inline NavPathFilter() { }; + inline virtual ~NavPathFilter() override { }; + virtual bool passFilter(const dtPolyRef ref, const dtMeshTile* tile, const dtPoly* poly) const override; + void SetSearchRadius(int radius) { m_searchRadius = radius; } + //int GetSearchRadius() const { return m_searchRadius; } + void SetSearchOrigin(const glm::vec3& pos) { m_searchOrigin = pos; } +}; + class NavigationPath { friend class NavigationLine; @@ -176,7 +191,7 @@ class NavigationPath std::vector m_renderPath; bool m_followingLink = false; - dtQueryFilter m_filter; + NavPathFilter m_filter; glm::vec3 m_extents = { 5, 10, 5 }; // note: X, Z, Y mq::Signal<>::ScopedConnection m_navMeshConn; @@ -257,3 +272,4 @@ class NavigationLine : public Renderable }; extern NavigationLine::LineStyle gNavigationLineStyle; +