From cf1d8544e3f4ab3d676f882dc73d13ce08430cc0 Mon Sep 17 00:00:00 2001 From: elsid Date: Tue, 17 Jan 2023 23:31:17 +0100 Subject: [PATCH] Check agent bounds on adding agent to navigator Do not add agent bounds which are not supported by recastnavigation with given settings and log such events. To avoid reaching navmesh tile generation to find out it can't be generated for such agent bounds. --- apps/openmw/mwworld/scene.cpp | 5 +- apps/openmw/mwworld/worldimp.cpp | 11 +- .../detournavigator/navigator.cpp | 107 ++++++++++-------- components/detournavigator/makenavmesh.cpp | 37 +++++- components/detournavigator/makenavmesh.hpp | 2 + components/detournavigator/navigator.hpp | 3 +- components/detournavigator/navigatorimpl.cpp | 9 +- components/detournavigator/navigatorimpl.hpp | 2 +- components/detournavigator/navigatorstub.hpp | 2 +- 9 files changed, 113 insertions(+), 65 deletions(-) diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 0c8b56ec30..879a865823 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -184,7 +185,9 @@ namespace } else if (physics.getActor(ptr)) { - navigator.addAgent(world.getPathfindingAgentBounds(ptr)); + const DetourNavigator::AgentBounds agentBounds = world.getPathfindingAgentBounds(ptr); + if (!navigator.addAgent(agentBounds)) + Log(Debug::Warning) << "Agent bounds are not supported by navigator: " << agentBounds; } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 34c39fed82..d5c785035a 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -40,6 +40,7 @@ #include #include +#include #include #include #include @@ -1269,7 +1270,11 @@ namespace MWWorld mWorldScene->updateObjectScale(ptr); if (mPhysics->getActor(ptr)) - mNavigator->addAgent(getPathfindingAgentBounds(ptr)); + { + const DetourNavigator::AgentBounds agentBounds = getPathfindingAgentBounds(ptr); + if (!mNavigator->addAgent(agentBounds)) + Log(Debug::Warning) << "Scaled agent bounds are not supported by navigator: " << agentBounds; + } else if (const auto object = mPhysics->getObject(ptr)) updateNavigatorObject(*object); } @@ -2435,7 +2440,9 @@ namespace MWWorld applyLoopingParticles(player); - mNavigator->addAgent(getPathfindingAgentBounds(getPlayerConstPtr())); + const DetourNavigator::AgentBounds agentBounds = getPathfindingAgentBounds(getPlayerConstPtr()); + if (!mNavigator->addAgent(agentBounds)) + Log(Debug::Warning) << "Player agent bounds are not supported by navigator: " << agentBounds; } World::RestPermitted World::canRest() const diff --git a/apps/openmw_test_suite/detournavigator/navigator.cpp b/apps/openmw_test_suite/detournavigator/navigator.cpp index f6de993a85..6c8ad0ab5f 100644 --- a/apps/openmw_test_suite/detournavigator/navigator.cpp +++ b/apps/openmw_test_suite/detournavigator/navigator.cpp @@ -135,7 +135,7 @@ namespace TEST_F(DetourNavigatorNavigatorTest, find_path_for_existing_agent_with_no_navmesh_should_throw_exception) { - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); EXPECT_EQ( findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), Status::StartPolygonNotFound); @@ -143,8 +143,8 @@ namespace TEST_F(DetourNavigatorNavigatorTest, add_agent_should_count_each_agent) { - mNavigator->addAgent(mAgentBounds); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->removeAgent(mAgentBounds); EXPECT_EQ( findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), @@ -163,7 +163,7 @@ namespace const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); auto updateGuard = mNavigator->makeUpdateGuard(); mNavigator->addHeightfield(mCellPosition, cellSize, surface, updateGuard.get()); mNavigator->update(mPlayerPosition, updateGuard.get()); @@ -220,7 +220,7 @@ namespace compound.shape().addChildShape( btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), new btBoxShape(btVector3(20, 20, 100))); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); mNavigator->update(mPlayerPosition, nullptr); mNavigator->wait(WaitConditionType::allJobsDone, &mListener); @@ -311,7 +311,7 @@ namespace compound.shape().addChildShape( btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), new btBoxShape(btVector3(20, 20, 100))); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); mNavigator->addObject( ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform, nullptr); @@ -409,7 +409,7 @@ namespace CollisionShapeInstance heightfield2(makeSquareHeightfieldTerrainShape(heightfieldData2)); heightfield2.shape().setLocalScaling(btVector3(128, 128, 1)); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addObject(ObjectId(&heightfield1.shape()), ObjectShapes(heightfield1.instance(), mObjectTransform), mTransform, nullptr); mNavigator->addObject(ObjectId(&heightfield2.shape()), ObjectShapes(heightfield2.instance(), mObjectTransform), @@ -469,7 +469,7 @@ namespace const HeightfieldSurface surface2 = makeSquareHeightfieldSurface(heightfieldData2); const int cellSize2 = mHeightfieldTileSize * (surface2.mSize - 1); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addHeightfield(mCellPosition, cellSize1, surface1, nullptr); mNavigator->update(mPlayerPosition, nullptr); mNavigator->wait(WaitConditionType::allJobsDone, &mListener); @@ -512,7 +512,7 @@ namespace osg::ref_ptr instance(new Resource::BulletShapeInstance(bulletShape)); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addObject( ObjectId(instance->mCollisionShape.get()), ObjectShapes(instance, mObjectTransform), mTransform, nullptr); mNavigator->update(mPlayerPosition, nullptr); @@ -561,7 +561,7 @@ namespace const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addWater(mCellPosition, cellSize, 300, nullptr); mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); mNavigator->update(mPlayerPosition, nullptr); @@ -605,7 +605,7 @@ namespace const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addWater(mCellPosition, cellSize, -25, nullptr); mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); mNavigator->update(mPlayerPosition, nullptr); @@ -648,7 +648,7 @@ namespace const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); mNavigator->addWater(mCellPosition, std::numeric_limits::max(), -25, nullptr); mNavigator->update(mPlayerPosition, nullptr); @@ -690,7 +690,7 @@ namespace const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addWater(mCellPosition, cellSize, -25, nullptr); mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); mNavigator->update(mPlayerPosition, nullptr); @@ -730,7 +730,7 @@ namespace CollisionShapeInstance heightfield(makeSquareHeightfieldTerrainShape(heightfieldData)); heightfield.shape().setLocalScaling(btVector3(128, 128, 1)); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addObject(ObjectId(&heightfield.shape()), ObjectShapes(heightfield.instance(), mObjectTransform), mTransform, nullptr); mNavigator->update(mPlayerPosition, nullptr); @@ -787,7 +787,7 @@ namespace const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); mNavigator->update(mPlayerPosition, nullptr); mNavigator->wait(WaitConditionType::allJobsDone, &mListener); @@ -843,7 +843,7 @@ namespace const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); mNavigator->update(mPlayerPosition, nullptr); mNavigator->wait(WaitConditionType::allJobsDone, &mListener); @@ -882,7 +882,7 @@ namespace std::generate_n( std::back_inserter(boxes), 100, [] { return std::make_unique(btVector3(20, 20, 100)); }); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); @@ -944,7 +944,7 @@ namespace std::generate_n( std::back_inserter(shapes), 100, [] { return std::make_unique(btVector3(64, 64, 64)); }); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); for (std::size_t i = 0; i < shapes.size(); ++i) { @@ -992,7 +992,7 @@ namespace const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); mNavigator->update(mPlayerPosition, nullptr); mNavigator->wait(WaitConditionType::allJobsDone, &mListener); @@ -1022,7 +1022,7 @@ namespace const btVector3 oscillatingBoxShapePosition(288, 288, 400); CollisionShapeInstance borderBox(std::make_unique(btVector3(50, 50, 50))); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); mNavigator->addObject(ObjectId(&oscillatingBox.shape()), ObjectShapes(oscillatingBox.instance(), mObjectTransform), @@ -1058,7 +1058,7 @@ namespace const HeightfieldPlane plane{ 100 }; const int cellSize = mHeightfieldTileSize * 4; - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addHeightfield(mCellPosition, cellSize, plane, nullptr); mNavigator->update(mPlayerPosition, nullptr); mNavigator->wait(WaitConditionType::requiredTilesPresent, &mListener); @@ -1109,7 +1109,7 @@ namespace compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(204, -204, 0)), new btBoxShape(btVector3(200, 200, 1000))); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); mNavigator->addObject( ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform, nullptr); @@ -1150,7 +1150,7 @@ namespace compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(204, -204, 0)), new btBoxShape(btVector3(100, 100, 1000))); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr); mNavigator->addObject( ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform, nullptr); @@ -1192,7 +1192,7 @@ namespace const int cellSize2 = 200; const float level2 = 2; - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addWater(mCellPosition, cellSize1, level1, nullptr); mNavigator->update(mPlayerPosition, nullptr); mNavigator->wait(WaitConditionType::allJobsDone, &mListener); @@ -1206,31 +1206,6 @@ namespace EXPECT_EQ(mNavigator->getNavMesh(mAgentBounds)->lockConst()->getVersion(), version); } - TEST_F(DetourNavigatorNavigatorTest, add_agent_with_zero_coordinate_should_not_have_nav_mesh) - { - constexpr std::array heightfieldData{ { - 0, 0, 0, 0, 0, // row 0 - 0, -25, -25, -25, -25, // row 1 - 0, -25, -100, -100, -100, // row 2 - 0, -25, -100, -100, -100, // row 3 - 0, -25, -100, -100, -100, // row 4 - } }; - const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData); - const int cellSize = mHeightfieldTileSize * (surface.mSize - 1); - - const AgentBounds agentBounds{ CollisionShapeType::RotatingBox, { 0, 1, 1 } }; - mNavigator->addAgent(agentBounds); - auto updateGuard = mNavigator->makeUpdateGuard(); - mNavigator->addHeightfield(mCellPosition, cellSize, surface, updateGuard.get()); - mNavigator->update(mPlayerPosition, updateGuard.get()); - updateGuard.reset(); - mNavigator->wait(WaitConditionType::requiredTilesPresent, &mListener); - - EXPECT_EQ( - findPath(*mNavigator, agentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut), - Status::NavMeshNotFound); - } - TEST_F(DetourNavigatorNavigatorTest, update_for_very_big_object_should_be_limited) { const float size = static_cast(2 * static_cast(std::numeric_limits::max()) - 1); @@ -1241,7 +1216,7 @@ namespace }; mNavigator->updateBounds(mPlayerPosition, nullptr); - mNavigator->addAgent(mAgentBounds); + ASSERT_TRUE(mNavigator->addAgent(mAgentBounds)); mNavigator->addObject(ObjectId(&bigBox.shape()), ObjectShapes(bigBox.instance(), objectTransform), btTransform::getIdentity(), nullptr); @@ -1275,4 +1250,36 @@ namespace navMesh->lockConst()->forEachUsedTile([&](const auto&...) { ++usedNavMeshTiles; }); EXPECT_EQ(usedNavMeshTiles, 509); } + + struct DetourNavigatorNavigatorNotSupportedAgentBoundsTest : TestWithParam + { + }; + + TEST_P(DetourNavigatorNavigatorNotSupportedAgentBoundsTest, on_add_agent) + { + const Settings settings = makeSettings(); + NavigatorImpl navigator(settings, nullptr); + EXPECT_FALSE(navigator.addAgent(GetParam())); + } + + const std::array notSupportedAgentBounds = { + AgentBounds{ .mShapeType = CollisionShapeType::Aabb, .mHalfExtents = osg::Vec3f(0, 0, 0) }, + AgentBounds{ .mShapeType = CollisionShapeType::RotatingBox, .mHalfExtents = osg::Vec3f(0, 0, 0) }, + AgentBounds{ .mShapeType = CollisionShapeType::Cylinder, .mHalfExtents = osg::Vec3f(0, 0, 0) }, + AgentBounds{ .mShapeType = CollisionShapeType::Aabb, .mHalfExtents = osg::Vec3f(0, 0, 11.34f) }, + AgentBounds{ .mShapeType = CollisionShapeType::RotatingBox, .mHalfExtents = osg::Vec3f(0, 11.34f, 11.34f) }, + AgentBounds{ .mShapeType = CollisionShapeType::Cylinder, .mHalfExtents = osg::Vec3f(0, 0, 11.34f) }, + AgentBounds{ .mShapeType = CollisionShapeType::Aabb, .mHalfExtents = osg::Vec3f(1, 1, 0) }, + AgentBounds{ .mShapeType = CollisionShapeType::RotatingBox, .mHalfExtents = osg::Vec3f(1, 1, 0) }, + AgentBounds{ .mShapeType = CollisionShapeType::Cylinder, .mHalfExtents = osg::Vec3f(1, 1, 0) }, + AgentBounds{ .mShapeType = CollisionShapeType::Aabb, .mHalfExtents = osg::Vec3f(1, 1, 11.33f) }, + AgentBounds{ .mShapeType = CollisionShapeType::RotatingBox, .mHalfExtents = osg::Vec3f(1, 1, 11.33f) }, + AgentBounds{ .mShapeType = CollisionShapeType::Cylinder, .mHalfExtents = osg::Vec3f(1, 1, 11.33f) }, + AgentBounds{ .mShapeType = CollisionShapeType::Aabb, .mHalfExtents = osg::Vec3f(2043.54f, 2043.54f, 11.34f) }, + AgentBounds{ .mShapeType = CollisionShapeType::RotatingBox, .mHalfExtents = osg::Vec3f(2890, 1, 11.34f) }, + AgentBounds{ .mShapeType = CollisionShapeType::Cylinder, .mHalfExtents = osg::Vec3f(2890, 2890, 11.34f) }, + }; + + INSTANTIATE_TEST_SUITE_P(NotSupportedAgentBounds, DetourNavigatorNavigatorNotSupportedAgentBoundsTest, + ValuesIn(notSupportedAgentBounds)); } diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index 0663eb7c25..8616f1a9a6 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -31,6 +31,8 @@ namespace DetourNavigator { namespace { + constexpr int walkableRadiusUpperLimit = 255; + struct Rectangle { TileBounds mBounds; @@ -114,6 +116,16 @@ namespace DetourNavigator return waterLevel - settings.mSwimHeightScale * agentHalfExtentsZ - agentHalfExtentsZ; } + int getWalkableHeight(const RecastSettings& settings, const AgentBounds& agentBounds) + { + return static_cast(std::ceil(getHeight(settings, agentBounds) / settings.mCellHeight)); + } + + int getWalkableRadius(const RecastSettings& settings, const AgentBounds& agentBounds) + { + return static_cast(std::ceil(getRadius(settings, agentBounds) / settings.mCellSize)); + } + struct RecastParams { float mSampleDist = 0; @@ -128,10 +140,9 @@ namespace DetourNavigator { RecastParams result; - result.mWalkableHeight - = static_cast(std::ceil(getHeight(settings, agentBounds) / settings.mCellHeight)); + result.mWalkableHeight = getWalkableHeight(settings, agentBounds); result.mWalkableClimb = static_cast(std::floor(getMaxClimb(settings) / settings.mCellHeight)); - result.mWalkableRadius = static_cast(std::ceil(getRadius(settings, agentBounds) / settings.mCellSize)); + result.mWalkableRadius = getWalkableRadius(settings, agentBounds); result.mMaxEdgeLen = static_cast(std::round(static_cast(settings.mMaxEdgeLen) / settings.mCellSize)); result.mSampleDist @@ -288,10 +299,15 @@ namespace DetourNavigator context, realTileBounds, recastMesh.getFlatHeightfields(), settings, params, solid); } + bool isValidWalkableHeight(int value) + { + return value >= 3; + } + [[nodiscard]] bool buildCompactHeightfield(RecastContext& context, const int walkableHeight, const int walkableClimb, rcHeightfield& solid, rcCompactHeightfield& compact) { - if (walkableHeight < 3) + if (!isValidWalkableHeight(walkableHeight)) { Log(Debug::Warning) << context.getPrefix() << "Invalid walkableHeight to build compact heightfield: " << walkableHeight; @@ -308,9 +324,14 @@ namespace DetourNavigator return rcBuildCompactHeightfield(&context, walkableHeight, walkableClimb, solid, compact); } + bool isValidWalkableRadius(int value) + { + return 0 < value && value < walkableRadiusUpperLimit; + } + [[nodiscard]] bool erodeWalkableArea(RecastContext& context, int walkableRadius, rcCompactHeightfield& compact) { - if (walkableRadius <= 0 || 255 <= walkableRadius) + if (!isValidWalkableRadius(walkableRadius)) { Log(Debug::Warning) << context.getPrefix() << "Invalid walkableRadius to erode walkable area: " << walkableRadius; @@ -614,4 +635,10 @@ namespace DetourNavigator return navMesh; } + + bool isSupportedAgentBounds(const RecastSettings& settings, const AgentBounds& agentBounds) + { + return isValidWalkableHeight(getWalkableHeight(settings, agentBounds)) + && isValidWalkableRadius(getWalkableRadius(settings, agentBounds)); + } } diff --git a/components/detournavigator/makenavmesh.hpp b/components/detournavigator/makenavmesh.hpp index 229e1e72a2..842ef2ab6a 100644 --- a/components/detournavigator/makenavmesh.hpp +++ b/components/detournavigator/makenavmesh.hpp @@ -50,6 +50,8 @@ namespace DetourNavigator const TilePosition& tile, const RecastSettings& settings); NavMeshPtr makeEmptyNavMesh(const Settings& settings); + + bool isSupportedAgentBounds(const RecastSettings& settings, const AgentBounds& agentBounds); } #endif diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index acec287953..a41e4acff9 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -77,8 +77,9 @@ namespace DetourNavigator * @brief addAgent should be called for each agent even if all of them has same half extents. * @param agentBounds allows to setup bounding cylinder for each agent, for each different half extents * there is different navmesh. + * @return true if agent is successfully added or false if agent bounds are not supported. */ - virtual void addAgent(const AgentBounds& agentBounds) = 0; + virtual bool addAgent(const AgentBounds& agentBounds) = 0; /** * @brief removeAgent should be called for each agent even if all of them has same half extents diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index 00ec06b3cb..18aaf9bda5 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -1,4 +1,5 @@ #include "navigatorimpl.hpp" +#include "makenavmesh.hpp" #include "settingsutils.hpp" #include "stats.hpp" @@ -15,13 +16,13 @@ namespace DetourNavigator { } - void NavigatorImpl::addAgent(const AgentBounds& agentBounds) + bool NavigatorImpl::addAgent(const AgentBounds& agentBounds) { - if (agentBounds.mHalfExtents.x() == 0.f || agentBounds.mHalfExtents.y() == 0.f - || agentBounds.mHalfExtents.z() == 0.f) - return; + if (!isSupportedAgentBounds(mSettings.mRecast, agentBounds)) + return false; ++mAgents[agentBounds]; mNavMeshManager.addAgent(agentBounds); + return true; } void NavigatorImpl::removeAgent(const AgentBounds& agentBounds) diff --git a/components/detournavigator/navigatorimpl.hpp b/components/detournavigator/navigatorimpl.hpp index a28985d466..e8eed8b2b1 100644 --- a/components/detournavigator/navigatorimpl.hpp +++ b/components/detournavigator/navigatorimpl.hpp @@ -23,7 +23,7 @@ namespace DetourNavigator return std::make_unique(*this); } - void addAgent(const AgentBounds& agentBounds) override; + bool addAgent(const AgentBounds& agentBounds) override; void removeAgent(const AgentBounds& agentBounds) override; diff --git a/components/detournavigator/navigatorstub.hpp b/components/detournavigator/navigatorstub.hpp index 79a6e2a5d1..bce7ef6c56 100644 --- a/components/detournavigator/navigatorstub.hpp +++ b/components/detournavigator/navigatorstub.hpp @@ -19,7 +19,7 @@ namespace DetourNavigator std::unique_ptr makeUpdateGuard() override { return nullptr; } - void addAgent(const AgentBounds& /*agentBounds*/) override {} + bool addAgent(const AgentBounds& /*agentBounds*/) override { return true; } void removeAgent(const AgentBounds& /*agentBounds*/) override {}