mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-01 07:09:41 +00:00
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.
This commit is contained in:
parent
a7e37509de
commit
cf1d8544e3
9 changed files with 113 additions and 65 deletions
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <components/debug/debuglog.hpp>
|
#include <components/debug/debuglog.hpp>
|
||||||
#include <components/detournavigator/agentbounds.hpp>
|
#include <components/detournavigator/agentbounds.hpp>
|
||||||
|
#include <components/detournavigator/debug.hpp>
|
||||||
#include <components/detournavigator/heightfieldshape.hpp>
|
#include <components/detournavigator/heightfieldshape.hpp>
|
||||||
#include <components/detournavigator/navigator.hpp>
|
#include <components/detournavigator/navigator.hpp>
|
||||||
#include <components/detournavigator/navigatorimpl.hpp>
|
#include <components/detournavigator/navigatorimpl.hpp>
|
||||||
|
@ -184,7 +185,9 @@ namespace
|
||||||
}
|
}
|
||||||
else if (physics.getActor(ptr))
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include <components/sceneutil/workqueue.hpp>
|
#include <components/sceneutil/workqueue.hpp>
|
||||||
|
|
||||||
#include <components/detournavigator/agentbounds.hpp>
|
#include <components/detournavigator/agentbounds.hpp>
|
||||||
|
#include <components/detournavigator/debug.hpp>
|
||||||
#include <components/detournavigator/navigator.hpp>
|
#include <components/detournavigator/navigator.hpp>
|
||||||
#include <components/detournavigator/navigatorimpl.hpp>
|
#include <components/detournavigator/navigatorimpl.hpp>
|
||||||
#include <components/detournavigator/settings.hpp>
|
#include <components/detournavigator/settings.hpp>
|
||||||
|
@ -1269,7 +1270,11 @@ namespace MWWorld
|
||||||
mWorldScene->updateObjectScale(ptr);
|
mWorldScene->updateObjectScale(ptr);
|
||||||
|
|
||||||
if (mPhysics->getActor(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))
|
else if (const auto object = mPhysics->getObject(ptr))
|
||||||
updateNavigatorObject(*object);
|
updateNavigatorObject(*object);
|
||||||
}
|
}
|
||||||
|
@ -2435,7 +2440,9 @@ namespace MWWorld
|
||||||
|
|
||||||
applyLoopingParticles(player);
|
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
|
World::RestPermitted World::canRest() const
|
||||||
|
|
|
@ -135,7 +135,7 @@ namespace
|
||||||
|
|
||||||
TEST_F(DetourNavigatorNavigatorTest, find_path_for_existing_agent_with_no_navmesh_should_throw_exception)
|
TEST_F(DetourNavigatorNavigatorTest, find_path_for_existing_agent_with_no_navmesh_should_throw_exception)
|
||||||
{
|
{
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||||
Status::StartPolygonNotFound);
|
Status::StartPolygonNotFound);
|
||||||
|
@ -143,8 +143,8 @@ namespace
|
||||||
|
|
||||||
TEST_F(DetourNavigatorNavigatorTest, add_agent_should_count_each_agent)
|
TEST_F(DetourNavigatorNavigatorTest, add_agent_should_count_each_agent)
|
||||||
{
|
{
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
mNavigator->removeAgent(mAgentBounds);
|
mNavigator->removeAgent(mAgentBounds);
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||||
|
@ -163,7 +163,7 @@ namespace
|
||||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
auto updateGuard = mNavigator->makeUpdateGuard();
|
auto updateGuard = mNavigator->makeUpdateGuard();
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface, updateGuard.get());
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface, updateGuard.get());
|
||||||
mNavigator->update(mPlayerPosition, updateGuard.get());
|
mNavigator->update(mPlayerPosition, updateGuard.get());
|
||||||
|
@ -220,7 +220,7 @@ namespace
|
||||||
compound.shape().addChildShape(
|
compound.shape().addChildShape(
|
||||||
btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), new btBoxShape(btVector3(20, 20, 100)));
|
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->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
||||||
mNavigator->update(mPlayerPosition, nullptr);
|
mNavigator->update(mPlayerPosition, nullptr);
|
||||||
mNavigator->wait(WaitConditionType::allJobsDone, &mListener);
|
mNavigator->wait(WaitConditionType::allJobsDone, &mListener);
|
||||||
|
@ -311,7 +311,7 @@ namespace
|
||||||
compound.shape().addChildShape(
|
compound.shape().addChildShape(
|
||||||
btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), new btBoxShape(btVector3(20, 20, 100)));
|
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->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
||||||
mNavigator->addObject(
|
mNavigator->addObject(
|
||||||
ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform, nullptr);
|
ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform, nullptr);
|
||||||
|
@ -409,7 +409,7 @@ namespace
|
||||||
CollisionShapeInstance heightfield2(makeSquareHeightfieldTerrainShape(heightfieldData2));
|
CollisionShapeInstance heightfield2(makeSquareHeightfieldTerrainShape(heightfieldData2));
|
||||||
heightfield2.shape().setLocalScaling(btVector3(128, 128, 1));
|
heightfield2.shape().setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
mNavigator->addObject(ObjectId(&heightfield1.shape()), ObjectShapes(heightfield1.instance(), mObjectTransform),
|
mNavigator->addObject(ObjectId(&heightfield1.shape()), ObjectShapes(heightfield1.instance(), mObjectTransform),
|
||||||
mTransform, nullptr);
|
mTransform, nullptr);
|
||||||
mNavigator->addObject(ObjectId(&heightfield2.shape()), ObjectShapes(heightfield2.instance(), mObjectTransform),
|
mNavigator->addObject(ObjectId(&heightfield2.shape()), ObjectShapes(heightfield2.instance(), mObjectTransform),
|
||||||
|
@ -469,7 +469,7 @@ namespace
|
||||||
const HeightfieldSurface surface2 = makeSquareHeightfieldSurface(heightfieldData2);
|
const HeightfieldSurface surface2 = makeSquareHeightfieldSurface(heightfieldData2);
|
||||||
const int cellSize2 = mHeightfieldTileSize * (surface2.mSize - 1);
|
const int cellSize2 = mHeightfieldTileSize * (surface2.mSize - 1);
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize1, surface1, nullptr);
|
mNavigator->addHeightfield(mCellPosition, cellSize1, surface1, nullptr);
|
||||||
mNavigator->update(mPlayerPosition, nullptr);
|
mNavigator->update(mPlayerPosition, nullptr);
|
||||||
mNavigator->wait(WaitConditionType::allJobsDone, &mListener);
|
mNavigator->wait(WaitConditionType::allJobsDone, &mListener);
|
||||||
|
@ -512,7 +512,7 @@ namespace
|
||||||
|
|
||||||
osg::ref_ptr<const Resource::BulletShapeInstance> instance(new Resource::BulletShapeInstance(bulletShape));
|
osg::ref_ptr<const Resource::BulletShapeInstance> instance(new Resource::BulletShapeInstance(bulletShape));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
mNavigator->addObject(
|
mNavigator->addObject(
|
||||||
ObjectId(instance->mCollisionShape.get()), ObjectShapes(instance, mObjectTransform), mTransform, nullptr);
|
ObjectId(instance->mCollisionShape.get()), ObjectShapes(instance, mObjectTransform), mTransform, nullptr);
|
||||||
mNavigator->update(mPlayerPosition, nullptr);
|
mNavigator->update(mPlayerPosition, nullptr);
|
||||||
|
@ -561,7 +561,7 @@ namespace
|
||||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
mNavigator->addWater(mCellPosition, cellSize, 300, nullptr);
|
mNavigator->addWater(mCellPosition, cellSize, 300, nullptr);
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
||||||
mNavigator->update(mPlayerPosition, nullptr);
|
mNavigator->update(mPlayerPosition, nullptr);
|
||||||
|
@ -605,7 +605,7 @@ namespace
|
||||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
mNavigator->addWater(mCellPosition, cellSize, -25, nullptr);
|
mNavigator->addWater(mCellPosition, cellSize, -25, nullptr);
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
||||||
mNavigator->update(mPlayerPosition, nullptr);
|
mNavigator->update(mPlayerPosition, nullptr);
|
||||||
|
@ -648,7 +648,7 @@ namespace
|
||||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
||||||
mNavigator->addWater(mCellPosition, std::numeric_limits<int>::max(), -25, nullptr);
|
mNavigator->addWater(mCellPosition, std::numeric_limits<int>::max(), -25, nullptr);
|
||||||
mNavigator->update(mPlayerPosition, nullptr);
|
mNavigator->update(mPlayerPosition, nullptr);
|
||||||
|
@ -690,7 +690,7 @@ namespace
|
||||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
mNavigator->addWater(mCellPosition, cellSize, -25, nullptr);
|
mNavigator->addWater(mCellPosition, cellSize, -25, nullptr);
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
||||||
mNavigator->update(mPlayerPosition, nullptr);
|
mNavigator->update(mPlayerPosition, nullptr);
|
||||||
|
@ -730,7 +730,7 @@ namespace
|
||||||
CollisionShapeInstance heightfield(makeSquareHeightfieldTerrainShape(heightfieldData));
|
CollisionShapeInstance heightfield(makeSquareHeightfieldTerrainShape(heightfieldData));
|
||||||
heightfield.shape().setLocalScaling(btVector3(128, 128, 1));
|
heightfield.shape().setLocalScaling(btVector3(128, 128, 1));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
mNavigator->addObject(ObjectId(&heightfield.shape()), ObjectShapes(heightfield.instance(), mObjectTransform),
|
mNavigator->addObject(ObjectId(&heightfield.shape()), ObjectShapes(heightfield.instance(), mObjectTransform),
|
||||||
mTransform, nullptr);
|
mTransform, nullptr);
|
||||||
mNavigator->update(mPlayerPosition, nullptr);
|
mNavigator->update(mPlayerPosition, nullptr);
|
||||||
|
@ -787,7 +787,7 @@ namespace
|
||||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
||||||
mNavigator->update(mPlayerPosition, nullptr);
|
mNavigator->update(mPlayerPosition, nullptr);
|
||||||
mNavigator->wait(WaitConditionType::allJobsDone, &mListener);
|
mNavigator->wait(WaitConditionType::allJobsDone, &mListener);
|
||||||
|
@ -843,7 +843,7 @@ namespace
|
||||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
||||||
mNavigator->update(mPlayerPosition, nullptr);
|
mNavigator->update(mPlayerPosition, nullptr);
|
||||||
mNavigator->wait(WaitConditionType::allJobsDone, &mListener);
|
mNavigator->wait(WaitConditionType::allJobsDone, &mListener);
|
||||||
|
@ -882,7 +882,7 @@ namespace
|
||||||
std::generate_n(
|
std::generate_n(
|
||||||
std::back_inserter(boxes), 100, [] { return std::make_unique<btBoxShape>(btVector3(20, 20, 100)); });
|
std::back_inserter(boxes), 100, [] { return std::make_unique<btBoxShape>(btVector3(20, 20, 100)); });
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
|
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
||||||
|
|
||||||
|
@ -944,7 +944,7 @@ namespace
|
||||||
std::generate_n(
|
std::generate_n(
|
||||||
std::back_inserter(shapes), 100, [] { return std::make_unique<btBoxShape>(btVector3(64, 64, 64)); });
|
std::back_inserter(shapes), 100, [] { return std::make_unique<btBoxShape>(btVector3(64, 64, 64)); });
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
|
|
||||||
for (std::size_t i = 0; i < shapes.size(); ++i)
|
for (std::size_t i = 0; i < shapes.size(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -992,7 +992,7 @@ namespace
|
||||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
||||||
mNavigator->update(mPlayerPosition, nullptr);
|
mNavigator->update(mPlayerPosition, nullptr);
|
||||||
mNavigator->wait(WaitConditionType::allJobsDone, &mListener);
|
mNavigator->wait(WaitConditionType::allJobsDone, &mListener);
|
||||||
|
@ -1022,7 +1022,7 @@ namespace
|
||||||
const btVector3 oscillatingBoxShapePosition(288, 288, 400);
|
const btVector3 oscillatingBoxShapePosition(288, 288, 400);
|
||||||
CollisionShapeInstance borderBox(std::make_unique<btBoxShape>(btVector3(50, 50, 50)));
|
CollisionShapeInstance borderBox(std::make_unique<btBoxShape>(btVector3(50, 50, 50)));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
||||||
mNavigator->addObject(ObjectId(&oscillatingBox.shape()),
|
mNavigator->addObject(ObjectId(&oscillatingBox.shape()),
|
||||||
ObjectShapes(oscillatingBox.instance(), mObjectTransform),
|
ObjectShapes(oscillatingBox.instance(), mObjectTransform),
|
||||||
|
@ -1058,7 +1058,7 @@ namespace
|
||||||
const HeightfieldPlane plane{ 100 };
|
const HeightfieldPlane plane{ 100 };
|
||||||
const int cellSize = mHeightfieldTileSize * 4;
|
const int cellSize = mHeightfieldTileSize * 4;
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, plane, nullptr);
|
mNavigator->addHeightfield(mCellPosition, cellSize, plane, nullptr);
|
||||||
mNavigator->update(mPlayerPosition, nullptr);
|
mNavigator->update(mPlayerPosition, nullptr);
|
||||||
mNavigator->wait(WaitConditionType::requiredTilesPresent, &mListener);
|
mNavigator->wait(WaitConditionType::requiredTilesPresent, &mListener);
|
||||||
|
@ -1109,7 +1109,7 @@ namespace
|
||||||
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(204, -204, 0)),
|
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(204, -204, 0)),
|
||||||
new btBoxShape(btVector3(200, 200, 1000)));
|
new btBoxShape(btVector3(200, 200, 1000)));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
||||||
mNavigator->addObject(
|
mNavigator->addObject(
|
||||||
ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform, nullptr);
|
ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform, nullptr);
|
||||||
|
@ -1150,7 +1150,7 @@ namespace
|
||||||
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(204, -204, 0)),
|
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(204, -204, 0)),
|
||||||
new btBoxShape(btVector3(100, 100, 1000)));
|
new btBoxShape(btVector3(100, 100, 1000)));
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
mNavigator->addHeightfield(mCellPosition, cellSize, surface, nullptr);
|
||||||
mNavigator->addObject(
|
mNavigator->addObject(
|
||||||
ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform, nullptr);
|
ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform, nullptr);
|
||||||
|
@ -1192,7 +1192,7 @@ namespace
|
||||||
const int cellSize2 = 200;
|
const int cellSize2 = 200;
|
||||||
const float level2 = 2;
|
const float level2 = 2;
|
||||||
|
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
mNavigator->addWater(mCellPosition, cellSize1, level1, nullptr);
|
mNavigator->addWater(mCellPosition, cellSize1, level1, nullptr);
|
||||||
mNavigator->update(mPlayerPosition, nullptr);
|
mNavigator->update(mPlayerPosition, nullptr);
|
||||||
mNavigator->wait(WaitConditionType::allJobsDone, &mListener);
|
mNavigator->wait(WaitConditionType::allJobsDone, &mListener);
|
||||||
|
@ -1206,31 +1206,6 @@ namespace
|
||||||
EXPECT_EQ(mNavigator->getNavMesh(mAgentBounds)->lockConst()->getVersion(), version);
|
EXPECT_EQ(mNavigator->getNavMesh(mAgentBounds)->lockConst()->getVersion(), version);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DetourNavigatorNavigatorTest, add_agent_with_zero_coordinate_should_not_have_nav_mesh)
|
|
||||||
{
|
|
||||||
constexpr std::array<float, 5 * 5> 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)
|
TEST_F(DetourNavigatorNavigatorTest, update_for_very_big_object_should_be_limited)
|
||||||
{
|
{
|
||||||
const float size = static_cast<float>(2 * static_cast<std::int64_t>(std::numeric_limits<int>::max()) - 1);
|
const float size = static_cast<float>(2 * static_cast<std::int64_t>(std::numeric_limits<int>::max()) - 1);
|
||||||
|
@ -1241,7 +1216,7 @@ namespace
|
||||||
};
|
};
|
||||||
|
|
||||||
mNavigator->updateBounds(mPlayerPosition, nullptr);
|
mNavigator->updateBounds(mPlayerPosition, nullptr);
|
||||||
mNavigator->addAgent(mAgentBounds);
|
ASSERT_TRUE(mNavigator->addAgent(mAgentBounds));
|
||||||
mNavigator->addObject(ObjectId(&bigBox.shape()), ObjectShapes(bigBox.instance(), objectTransform),
|
mNavigator->addObject(ObjectId(&bigBox.shape()), ObjectShapes(bigBox.instance(), objectTransform),
|
||||||
btTransform::getIdentity(), nullptr);
|
btTransform::getIdentity(), nullptr);
|
||||||
|
|
||||||
|
@ -1275,4 +1250,36 @@ namespace
|
||||||
navMesh->lockConst()->forEachUsedTile([&](const auto&...) { ++usedNavMeshTiles; });
|
navMesh->lockConst()->forEachUsedTile([&](const auto&...) { ++usedNavMeshTiles; });
|
||||||
EXPECT_EQ(usedNavMeshTiles, 509);
|
EXPECT_EQ(usedNavMeshTiles, 509);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DetourNavigatorNavigatorNotSupportedAgentBoundsTest : TestWithParam<AgentBounds>
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,8 @@ namespace DetourNavigator
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
constexpr int walkableRadiusUpperLimit = 255;
|
||||||
|
|
||||||
struct Rectangle
|
struct Rectangle
|
||||||
{
|
{
|
||||||
TileBounds mBounds;
|
TileBounds mBounds;
|
||||||
|
@ -114,6 +116,16 @@ namespace DetourNavigator
|
||||||
return waterLevel - settings.mSwimHeightScale * agentHalfExtentsZ - agentHalfExtentsZ;
|
return waterLevel - settings.mSwimHeightScale * agentHalfExtentsZ - agentHalfExtentsZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getWalkableHeight(const RecastSettings& settings, const AgentBounds& agentBounds)
|
||||||
|
{
|
||||||
|
return static_cast<int>(std::ceil(getHeight(settings, agentBounds) / settings.mCellHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
int getWalkableRadius(const RecastSettings& settings, const AgentBounds& agentBounds)
|
||||||
|
{
|
||||||
|
return static_cast<int>(std::ceil(getRadius(settings, agentBounds) / settings.mCellSize));
|
||||||
|
}
|
||||||
|
|
||||||
struct RecastParams
|
struct RecastParams
|
||||||
{
|
{
|
||||||
float mSampleDist = 0;
|
float mSampleDist = 0;
|
||||||
|
@ -128,10 +140,9 @@ namespace DetourNavigator
|
||||||
{
|
{
|
||||||
RecastParams result;
|
RecastParams result;
|
||||||
|
|
||||||
result.mWalkableHeight
|
result.mWalkableHeight = getWalkableHeight(settings, agentBounds);
|
||||||
= static_cast<int>(std::ceil(getHeight(settings, agentBounds) / settings.mCellHeight));
|
|
||||||
result.mWalkableClimb = static_cast<int>(std::floor(getMaxClimb(settings) / settings.mCellHeight));
|
result.mWalkableClimb = static_cast<int>(std::floor(getMaxClimb(settings) / settings.mCellHeight));
|
||||||
result.mWalkableRadius = static_cast<int>(std::ceil(getRadius(settings, agentBounds) / settings.mCellSize));
|
result.mWalkableRadius = getWalkableRadius(settings, agentBounds);
|
||||||
result.mMaxEdgeLen
|
result.mMaxEdgeLen
|
||||||
= static_cast<int>(std::round(static_cast<float>(settings.mMaxEdgeLen) / settings.mCellSize));
|
= static_cast<int>(std::round(static_cast<float>(settings.mMaxEdgeLen) / settings.mCellSize));
|
||||||
result.mSampleDist
|
result.mSampleDist
|
||||||
|
@ -288,10 +299,15 @@ namespace DetourNavigator
|
||||||
context, realTileBounds, recastMesh.getFlatHeightfields(), settings, params, solid);
|
context, realTileBounds, recastMesh.getFlatHeightfields(), settings, params, solid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isValidWalkableHeight(int value)
|
||||||
|
{
|
||||||
|
return value >= 3;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool buildCompactHeightfield(RecastContext& context, const int walkableHeight,
|
[[nodiscard]] bool buildCompactHeightfield(RecastContext& context, const int walkableHeight,
|
||||||
const int walkableClimb, rcHeightfield& solid, rcCompactHeightfield& compact)
|
const int walkableClimb, rcHeightfield& solid, rcCompactHeightfield& compact)
|
||||||
{
|
{
|
||||||
if (walkableHeight < 3)
|
if (!isValidWalkableHeight(walkableHeight))
|
||||||
{
|
{
|
||||||
Log(Debug::Warning) << context.getPrefix()
|
Log(Debug::Warning) << context.getPrefix()
|
||||||
<< "Invalid walkableHeight to build compact heightfield: " << walkableHeight;
|
<< "Invalid walkableHeight to build compact heightfield: " << walkableHeight;
|
||||||
|
@ -308,9 +324,14 @@ namespace DetourNavigator
|
||||||
return rcBuildCompactHeightfield(&context, walkableHeight, walkableClimb, solid, compact);
|
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)
|
[[nodiscard]] bool erodeWalkableArea(RecastContext& context, int walkableRadius, rcCompactHeightfield& compact)
|
||||||
{
|
{
|
||||||
if (walkableRadius <= 0 || 255 <= walkableRadius)
|
if (!isValidWalkableRadius(walkableRadius))
|
||||||
{
|
{
|
||||||
Log(Debug::Warning) << context.getPrefix()
|
Log(Debug::Warning) << context.getPrefix()
|
||||||
<< "Invalid walkableRadius to erode walkable area: " << walkableRadius;
|
<< "Invalid walkableRadius to erode walkable area: " << walkableRadius;
|
||||||
|
@ -614,4 +635,10 @@ namespace DetourNavigator
|
||||||
|
|
||||||
return navMesh;
|
return navMesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isSupportedAgentBounds(const RecastSettings& settings, const AgentBounds& agentBounds)
|
||||||
|
{
|
||||||
|
return isValidWalkableHeight(getWalkableHeight(settings, agentBounds))
|
||||||
|
&& isValidWalkableRadius(getWalkableRadius(settings, agentBounds));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,8 @@ namespace DetourNavigator
|
||||||
const TilePosition& tile, const RecastSettings& settings);
|
const TilePosition& tile, const RecastSettings& settings);
|
||||||
|
|
||||||
NavMeshPtr makeEmptyNavMesh(const Settings& settings);
|
NavMeshPtr makeEmptyNavMesh(const Settings& settings);
|
||||||
|
|
||||||
|
bool isSupportedAgentBounds(const RecastSettings& settings, const AgentBounds& agentBounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -77,8 +77,9 @@ namespace DetourNavigator
|
||||||
* @brief addAgent should be called for each agent even if all of them has same half extents.
|
* @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
|
* @param agentBounds allows to setup bounding cylinder for each agent, for each different half extents
|
||||||
* there is different navmesh.
|
* 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
|
* @brief removeAgent should be called for each agent even if all of them has same half extents
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "navigatorimpl.hpp"
|
#include "navigatorimpl.hpp"
|
||||||
|
#include "makenavmesh.hpp"
|
||||||
#include "settingsutils.hpp"
|
#include "settingsutils.hpp"
|
||||||
#include "stats.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
|
if (!isSupportedAgentBounds(mSettings.mRecast, agentBounds))
|
||||||
|| agentBounds.mHalfExtents.z() == 0.f)
|
return false;
|
||||||
return;
|
|
||||||
++mAgents[agentBounds];
|
++mAgents[agentBounds];
|
||||||
mNavMeshManager.addAgent(agentBounds);
|
mNavMeshManager.addAgent(agentBounds);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NavigatorImpl::removeAgent(const AgentBounds& agentBounds)
|
void NavigatorImpl::removeAgent(const AgentBounds& agentBounds)
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace DetourNavigator
|
||||||
return std::make_unique<const UpdateGuard>(*this);
|
return std::make_unique<const UpdateGuard>(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addAgent(const AgentBounds& agentBounds) override;
|
bool addAgent(const AgentBounds& agentBounds) override;
|
||||||
|
|
||||||
void removeAgent(const AgentBounds& agentBounds) override;
|
void removeAgent(const AgentBounds& agentBounds) override;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace DetourNavigator
|
||||||
|
|
||||||
std::unique_ptr<const UpdateGuard> makeUpdateGuard() override { return nullptr; }
|
std::unique_ptr<const UpdateGuard> makeUpdateGuard() override { return nullptr; }
|
||||||
|
|
||||||
void addAgent(const AgentBounds& /*agentBounds*/) override {}
|
bool addAgent(const AgentBounds& /*agentBounds*/) override { return true; }
|
||||||
|
|
||||||
void removeAgent(const AgentBounds& /*agentBounds*/) override {}
|
void removeAgent(const AgentBounds& /*agentBounds*/) override {}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue