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 {}