mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-26 09:35:28 +00:00
Merge branch 'navmesh_agent_bounds' into 'master'
Support different agent collision shape type for pathfinding See merge request OpenMW/openmw!2030
This commit is contained in:
commit
1a478875f0
@ -13,7 +13,7 @@ namespace
|
||||
|
||||
struct Key
|
||||
{
|
||||
osg::Vec3f mAgentHalfExtents;
|
||||
AgentBounds mAgentBounds;
|
||||
TilePosition mTilePosition;
|
||||
RecastMesh mRecastMesh;
|
||||
};
|
||||
@ -137,6 +137,7 @@ namespace
|
||||
template <class Random>
|
||||
Key generateKey(std::size_t triangles, Random& random)
|
||||
{
|
||||
const CollisionShapeType agentShapeType = CollisionShapeType::Aabb;
|
||||
const osg::Vec3f agentHalfExtents = generateAgentHalfExtents(0.5, 1.5, random);
|
||||
const TilePosition tilePosition = generateVec2i(10000, random);
|
||||
const std::size_t generation = std::uniform_int_distribution<std::size_t>(0, 100)(random);
|
||||
@ -146,7 +147,7 @@ namespace
|
||||
generateWater(std::back_inserter(water), 1, random);
|
||||
RecastMesh recastMesh(generation, revision, std::move(mesh), std::move(water),
|
||||
{generateHeightfield(random)}, {generateFlatHeightfield(random)}, {});
|
||||
return Key {agentHalfExtents, tilePosition, std::move(recastMesh)};
|
||||
return Key {AgentBounds {agentShapeType, agentHalfExtents}, tilePosition, std::move(recastMesh)};
|
||||
}
|
||||
|
||||
constexpr std::size_t trianglesPerTile = 239;
|
||||
@ -165,7 +166,7 @@ namespace
|
||||
while (true)
|
||||
{
|
||||
Key key = generateKey(trianglesPerTile, random);
|
||||
cache.set(key.mAgentHalfExtents, key.mTilePosition, key.mRecastMesh,
|
||||
cache.set(key.mAgentBounds, key.mTilePosition, key.mRecastMesh,
|
||||
std::make_unique<PreparedNavMeshData>());
|
||||
*out++ = std::move(key);
|
||||
const std::size_t newSize = cache.getStats().mNavMeshCacheSize;
|
||||
@ -188,7 +189,7 @@ namespace
|
||||
while (state.KeepRunning())
|
||||
{
|
||||
const auto& key = keys[n++ % keys.size()];
|
||||
const auto result = cache.get(key.mAgentHalfExtents, key.mTilePosition, key.mRecastMesh);
|
||||
const auto result = cache.get(key.mAgentBounds, key.mTilePosition, key.mRecastMesh);
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
@ -216,7 +217,7 @@ namespace
|
||||
while (state.KeepRunning())
|
||||
{
|
||||
const auto& key = keys[n++ % keys.size()];
|
||||
const auto result = cache.set(key.mAgentHalfExtents, key.mTilePosition, key.mRecastMesh,
|
||||
const auto result = cache.set(key.mAgentBounds, key.mTilePosition, key.mRecastMesh,
|
||||
std::make_unique<PreparedNavMeshData>());
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <components/vfs/registerarchives.hpp>
|
||||
#include <components/esm3/readerscache.hpp>
|
||||
#include <components/platform/platform.hpp>
|
||||
#include <components/detournavigator/agentbounds.hpp>
|
||||
|
||||
#include <osg/Vec3f>
|
||||
|
||||
@ -173,7 +174,9 @@ namespace NavMeshTool
|
||||
Settings::Manager settings;
|
||||
settings.load(config);
|
||||
|
||||
const DetourNavigator::CollisionShapeType agentCollisionShape = DetourNavigator::defaultCollisionShapeType;
|
||||
const osg::Vec3f agentHalfExtents = Settings::Manager::getVector3("default actor pathfind half extents", "Game");
|
||||
const DetourNavigator::AgentBounds agentBounds {agentCollisionShape, agentHalfExtents};
|
||||
const std::uint64_t maxDbFileSize = static_cast<std::uint64_t>(Settings::Manager::getInt64("max navmeshdb file size", "Navigator"));
|
||||
const std::string dbPath = (config.getUserDataPath() / "navmesh.db").string();
|
||||
|
||||
@ -201,7 +204,7 @@ namespace NavMeshTool
|
||||
WorldspaceData cellsData = gatherWorldspaceData(navigatorSettings, readers, vfs, bulletShapeManager,
|
||||
esmData, processInteriorCells, writeBinaryLog);
|
||||
|
||||
const Status status = generateAllNavMeshTiles(agentHalfExtents, navigatorSettings, threadsNumber,
|
||||
const Status status = generateAllNavMeshTiles(agentBounds, navigatorSettings, threadsNumber,
|
||||
removeUnusedTiles, writeBinaryLog, cellsData, std::move(db));
|
||||
|
||||
switch (status)
|
||||
|
@ -32,6 +32,7 @@ namespace NavMeshTool
|
||||
{
|
||||
namespace
|
||||
{
|
||||
using DetourNavigator::AgentBounds;
|
||||
using DetourNavigator::GenerateNavMeshTile;
|
||||
using DetourNavigator::NavMeshDb;
|
||||
using DetourNavigator::NavMeshTileInfo;
|
||||
@ -250,7 +251,7 @@ namespace NavMeshTool
|
||||
};
|
||||
}
|
||||
|
||||
Status generateAllNavMeshTiles(const osg::Vec3f& agentHalfExtents, const Settings& settings,
|
||||
Status generateAllNavMeshTiles(const AgentBounds& agentBounds, const Settings& settings,
|
||||
std::size_t threadsNumber, bool removeUnusedTiles, bool writeBinaryLog, WorldspaceData& data,
|
||||
NavMeshDb&& db)
|
||||
{
|
||||
@ -291,7 +292,7 @@ namespace NavMeshTool
|
||||
input->mWorldspace,
|
||||
tilePosition,
|
||||
RecastMeshProvider(input->mTileCachedRecastMeshManager),
|
||||
agentHalfExtents,
|
||||
agentBounds,
|
||||
settings,
|
||||
navMeshTileConsumer
|
||||
));
|
||||
|
@ -9,6 +9,7 @@ namespace DetourNavigator
|
||||
{
|
||||
class NavMeshDb;
|
||||
struct Settings;
|
||||
struct AgentBounds;
|
||||
}
|
||||
|
||||
namespace NavMeshTool
|
||||
@ -22,7 +23,7 @@ namespace NavMeshTool
|
||||
NotEnoughSpace,
|
||||
};
|
||||
|
||||
Status generateAllNavMeshTiles(const osg::Vec3f& agentHalfExtents, const DetourNavigator::Settings& settings,
|
||||
Status generateAllNavMeshTiles(const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Settings& settings,
|
||||
std::size_t threadsNumber, bool removeUnusedTiles, bool writeBinaryLog, WorldspaceData& cellsData,
|
||||
DetourNavigator::NavMeshDb&& db);
|
||||
}
|
||||
|
@ -79,6 +79,7 @@ namespace MWMechanics
|
||||
namespace DetourNavigator
|
||||
{
|
||||
struct Navigator;
|
||||
struct AgentBounds;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
@ -644,14 +645,13 @@ namespace MWBase
|
||||
virtual DetourNavigator::Navigator* getNavigator() const = 0;
|
||||
|
||||
virtual void updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
|
||||
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end) const = 0;
|
||||
const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end) const = 0;
|
||||
|
||||
virtual void removeActorPath(const MWWorld::ConstPtr& actor) const = 0;
|
||||
|
||||
virtual void setNavMeshNumberToRender(const std::size_t value) = 0;
|
||||
|
||||
/// Return physical half extents of the given actor to be used in pathfinding
|
||||
virtual osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const = 0;
|
||||
virtual DetourNavigator::AgentBounds getPathfindingAgentBounds(const MWWorld::ConstPtr& actor) const = 0;
|
||||
|
||||
virtual bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const = 0;
|
||||
|
||||
|
@ -268,11 +268,11 @@ namespace MWMechanics
|
||||
{
|
||||
const MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
// Try to build path to the target.
|
||||
const auto halfExtents = world->getPathfindingHalfExtents(actor);
|
||||
const auto agentBounds = world->getPathfindingAgentBounds(actor);
|
||||
const auto navigatorFlags = getNavigatorFlags(actor);
|
||||
const auto areaCosts = getAreaCosts(actor);
|
||||
const auto pathGridGraph = getPathGridGraph(actor.getCell());
|
||||
mPathFinder.buildPath(actor, vActorPos, vTargetPos, actor.getCell(), pathGridGraph, halfExtents,
|
||||
mPathFinder.buildPath(actor, vActorPos, vTargetPos, actor.getCell(), pathGridGraph, agentBounds,
|
||||
navigatorFlags, areaCosts, storage.mAttackRange, PathType::Full);
|
||||
|
||||
if (!mPathFinder.isPathConstructed())
|
||||
@ -280,12 +280,12 @@ namespace MWMechanics
|
||||
// If there is no path, try to find a point on a line from the actor position to target projected
|
||||
// on navmesh to attack the target from there.
|
||||
const auto navigator = world->getNavigator();
|
||||
const auto hit = DetourNavigator::raycast(*navigator, halfExtents, vActorPos, vTargetPos, navigatorFlags);
|
||||
const auto hit = DetourNavigator::raycast(*navigator, agentBounds, vActorPos, vTargetPos, navigatorFlags);
|
||||
|
||||
if (hit.has_value() && (*hit - vTargetPos).length() <= rangeAttack)
|
||||
{
|
||||
// If the point is close enough, try to find a path to that point.
|
||||
mPathFinder.buildPath(actor, vActorPos, *hit, actor.getCell(), pathGridGraph, halfExtents,
|
||||
mPathFinder.buildPath(actor, vActorPos, *hit, actor.getCell(), pathGridGraph, agentBounds,
|
||||
navigatorFlags, areaCosts, storage.mAttackRange, PathType::Full);
|
||||
if (mPathFinder.isPathConstructed())
|
||||
{
|
||||
|
@ -113,6 +113,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f&
|
||||
|
||||
const osg::Vec3f position = actor.getRefData().getPosition().asVec3(); //position of the actor
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
const DetourNavigator::AgentBounds agentBounds = world->getPathfindingAgentBounds(actor);
|
||||
|
||||
/// Stops the actor when it gets too close to a unloaded cell
|
||||
//... At current time, this test is unnecessary. AI shuts down when actor is more than "actors processing range" setting value
|
||||
@ -122,7 +123,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f&
|
||||
{
|
||||
actor.getClass().getMovementSettings(actor).mPosition[0] = 0;
|
||||
actor.getClass().getMovementSettings(actor).mPosition[1] = 0;
|
||||
world->updateActorPath(actor, mPathFinder.getPath(), world->getPathfindingHalfExtents(actor), position, dest);
|
||||
world->updateActorPath(actor, mPathFinder.getPath(), agentBounds, position, dest);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -148,9 +149,8 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f&
|
||||
{
|
||||
if (wasShortcutting || doesPathNeedRecalc(dest, actor)) // if need to rebuild path
|
||||
{
|
||||
const auto pathfindingHalfExtents = world->getPathfindingHalfExtents(actor);
|
||||
mPathFinder.buildLimitedPath(actor, position, dest, actor.getCell(), getPathGridGraph(actor.getCell()),
|
||||
pathfindingHalfExtents, getNavigatorFlags(actor), getAreaCosts(actor), endTolerance, pathType);
|
||||
agentBounds, getNavigatorFlags(actor), getAreaCosts(actor), endTolerance, pathType);
|
||||
mRotateOnTheRunChecks = 3;
|
||||
|
||||
// give priority to go directly on target if there is minimal opportunity
|
||||
@ -178,13 +178,13 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f&
|
||||
}
|
||||
}
|
||||
|
||||
const osg::Vec3f halfExtents = world->getHalfExtents(actor);
|
||||
const float pointTolerance = getPointTolerance(actor.getClass().getMaxSpeed(actor), duration, halfExtents);
|
||||
const float pointTolerance = getPointTolerance(actor.getClass().getMaxSpeed(actor), duration,
|
||||
world->getHalfExtents(actor));
|
||||
|
||||
static const bool smoothMovement = Settings::Manager::getBool("smooth movement", "Game");
|
||||
mPathFinder.update(position, pointTolerance, DEFAULT_TOLERANCE,
|
||||
/*shortenIfAlmostStraight=*/smoothMovement, actorCanMoveByZ,
|
||||
halfExtents, getNavigatorFlags(actor));
|
||||
agentBounds, getNavigatorFlags(actor));
|
||||
|
||||
if (isDestReached || mPathFinder.checkPathCompleted()) // if path is finished
|
||||
{
|
||||
@ -197,7 +197,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const osg::Vec3f&
|
||||
else if (mPathFinder.getPath().empty())
|
||||
return false;
|
||||
|
||||
world->updateActorPath(actor, mPathFinder.getPath(), world->getPathfindingHalfExtents(actor), position, dest);
|
||||
world->updateActorPath(actor, mPathFinder.getPath(), agentBounds, position, dest);
|
||||
|
||||
if (mRotateOnTheRunChecks == 0
|
||||
|| isReachableRotatingOnTheRun(actor, *mPathFinder.getPath().begin())) // to prevent circling around a path point
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include <components/esm3/aisequence.hpp>
|
||||
#include <components/detournavigator/agentbounds.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/mechanicsmanager.hpp"
|
||||
|
@ -71,7 +71,7 @@ namespace MWMechanics
|
||||
const auto position = actor.getRefData().getPosition().asVec3();
|
||||
const bool isWaterCreature = actor.getClass().isPureWaterCreature(actor);
|
||||
const bool isFlyingCreature = actor.getClass().isPureFlyingCreature(actor);
|
||||
const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor);
|
||||
const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingAgentBounds(actor).mHalfExtents;
|
||||
osg::Vec3f direction = destination - position;
|
||||
direction.normalize();
|
||||
const auto visibleDestination = (
|
||||
@ -210,10 +210,10 @@ namespace MWMechanics
|
||||
}
|
||||
else
|
||||
{
|
||||
const osg::Vec3f halfExtents = MWBase::Environment::get().getWorld()->getPathfindingHalfExtents(actor);
|
||||
const auto agentBounds = MWBase::Environment::get().getWorld()->getPathfindingAgentBounds(actor);
|
||||
constexpr float endTolerance = 0;
|
||||
mPathFinder.buildPath(actor, pos.asVec3(), mDestination, actor.getCell(),
|
||||
getPathGridGraph(actor.getCell()), halfExtents, getNavigatorFlags(actor), getAreaCosts(actor),
|
||||
getPathGridGraph(actor.getCell()), agentBounds, getNavigatorFlags(actor), getAreaCosts(actor),
|
||||
endTolerance, PathType::Full);
|
||||
}
|
||||
|
||||
@ -345,7 +345,7 @@ namespace MWMechanics
|
||||
const bool isWaterCreature = actor.getClass().isPureWaterCreature(actor);
|
||||
const bool isFlyingCreature = actor.getClass().isPureFlyingCreature(actor);
|
||||
const auto world = MWBase::Environment::get().getWorld();
|
||||
const auto halfExtents = world->getPathfindingHalfExtents(actor);
|
||||
const auto agentBounds = world->getPathfindingAgentBounds(actor);
|
||||
const auto navigator = world->getNavigator();
|
||||
const auto navigatorFlags = getNavigatorFlags(actor);
|
||||
const auto areaCosts = getAreaCosts(actor);
|
||||
@ -358,7 +358,7 @@ namespace MWMechanics
|
||||
if (!isWaterCreature && !isFlyingCreature)
|
||||
{
|
||||
// findRandomPointAroundCircle uses wanderDistance as limit for random and not as exact distance
|
||||
if (const auto destination = DetourNavigator::findRandomPointAroundCircle(*navigator, halfExtents,
|
||||
if (const auto destination = DetourNavigator::findRandomPointAroundCircle(*navigator, agentBounds,
|
||||
mInitialActorPosition, wanderDistance, navigatorFlags, []() {
|
||||
auto& prng = MWBase::Environment::get().getWorld()->getPrng();
|
||||
return Misc::Rng::rollProbability(prng);
|
||||
@ -385,7 +385,7 @@ namespace MWMechanics
|
||||
if (isWaterCreature || isFlyingCreature)
|
||||
mPathFinder.buildStraightPath(mDestination);
|
||||
else
|
||||
mPathFinder.buildPathByNavMesh(actor, currentPosition, mDestination, halfExtents, navigatorFlags,
|
||||
mPathFinder.buildPathByNavMesh(actor, currentPosition, mDestination, agentBounds, navigatorFlags,
|
||||
areaCosts, endTolerance, PathType::Full);
|
||||
|
||||
if (mPathFinder.isPathConstructed())
|
||||
@ -532,8 +532,8 @@ namespace MWMechanics
|
||||
{
|
||||
if (mUsePathgrid)
|
||||
{
|
||||
const auto halfExtents = MWBase::Environment::get().getWorld()->getHalfExtents(actor);
|
||||
mPathFinder.buildPathByNavMeshToNextPoint(actor, halfExtents, getNavigatorFlags(actor),
|
||||
const auto agentBounds = MWBase::Environment::get().getWorld()->getPathfindingAgentBounds(actor);
|
||||
mPathFinder.buildPathByNavMeshToNextPoint(actor, agentBounds, getNavigatorFlags(actor),
|
||||
getAreaCosts(actor));
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <array>
|
||||
|
||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||
#include <components/detournavigator/agentbounds.hpp>
|
||||
|
||||
#include "../mwworld/class.hpp"
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
@ -80,7 +81,7 @@ namespace MWMechanics
|
||||
std::vector<MWWorld::Ptr>* occupyingActors)
|
||||
{
|
||||
const auto world = MWBase::Environment::get().getWorld();
|
||||
const osg::Vec3f halfExtents = world->getPathfindingHalfExtents(actor);
|
||||
const osg::Vec3f halfExtents = world->getPathfindingAgentBounds(actor).mHalfExtents;
|
||||
const auto maxHalfExtent = std::max(halfExtents.x(), std::max(halfExtents.y(), halfExtents.z()));
|
||||
if (ignorePlayer)
|
||||
{
|
||||
|
@ -109,12 +109,12 @@ namespace
|
||||
struct IsValidShortcut
|
||||
{
|
||||
const DetourNavigator::Navigator* mNavigator;
|
||||
const osg::Vec3f mHalfExtents;
|
||||
const DetourNavigator::AgentBounds mAgentBounds;
|
||||
const DetourNavigator::Flags mFlags;
|
||||
|
||||
bool operator()(const osg::Vec3f& start, const osg::Vec3f& end) const
|
||||
{
|
||||
const auto position = DetourNavigator::raycast(*mNavigator, mHalfExtents, start, end, mFlags);
|
||||
const auto position = DetourNavigator::raycast(*mNavigator, mAgentBounds, start, end, mFlags);
|
||||
return position.has_value() && std::abs((position.value() - start).length2() - (end - start).length2()) <= 1;
|
||||
}
|
||||
};
|
||||
@ -307,8 +307,8 @@ namespace MWMechanics
|
||||
}
|
||||
|
||||
void PathFinder::update(const osg::Vec3f& position, float pointTolerance, float destinationTolerance,
|
||||
bool shortenIfAlmostStraight, bool canMoveByZ, const osg::Vec3f& halfExtents,
|
||||
const DetourNavigator::Flags flags)
|
||||
bool shortenIfAlmostStraight, bool canMoveByZ, const DetourNavigator::AgentBounds& agentBounds,
|
||||
const DetourNavigator::Flags flags)
|
||||
{
|
||||
if (mPath.empty())
|
||||
return;
|
||||
@ -318,7 +318,7 @@ namespace MWMechanics
|
||||
|
||||
const IsValidShortcut isValidShortcut {
|
||||
MWBase::Environment::get().getWorld()->getNavigator(),
|
||||
halfExtents, flags
|
||||
agentBounds, flags
|
||||
};
|
||||
|
||||
if (shortenIfAlmostStraight)
|
||||
@ -375,13 +375,13 @@ namespace MWMechanics
|
||||
}
|
||||
|
||||
void PathFinder::buildPathByNavMesh(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint,
|
||||
const osg::Vec3f& endPoint, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags,
|
||||
const osg::Vec3f& endPoint, const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Flags flags,
|
||||
const DetourNavigator::AreaCosts& areaCosts, float endTolerance, PathType pathType)
|
||||
{
|
||||
mPath.clear();
|
||||
|
||||
// If it's not possible to build path over navmesh due to disabled navmesh generation fallback to straight path
|
||||
DetourNavigator::Status status = buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents, flags,
|
||||
DetourNavigator::Status status = buildPathByNavigatorImpl(actor, startPoint, endPoint, agentBounds, flags,
|
||||
areaCosts, endTolerance, pathType, std::back_inserter(mPath));
|
||||
|
||||
if (status != DetourNavigator::Status::Success)
|
||||
@ -394,7 +394,7 @@ namespace MWMechanics
|
||||
}
|
||||
|
||||
void PathFinder::buildPath(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, const osg::Vec3f& endPoint,
|
||||
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const osg::Vec3f& halfExtents,
|
||||
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const DetourNavigator::AgentBounds& agentBounds,
|
||||
const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts, float endTolerance,
|
||||
PathType pathType)
|
||||
{
|
||||
@ -405,7 +405,7 @@ namespace MWMechanics
|
||||
|
||||
if (!actor.getClass().isPureWaterCreature(actor) && !actor.getClass().isPureFlyingCreature(actor))
|
||||
{
|
||||
status = buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents, flags, areaCosts,
|
||||
status = buildPathByNavigatorImpl(actor, startPoint, endPoint, agentBounds, flags, areaCosts,
|
||||
endTolerance, pathType, std::back_inserter(mPath));
|
||||
if (status != DetourNavigator::Status::Success)
|
||||
mPath.clear();
|
||||
@ -413,7 +413,7 @@ namespace MWMechanics
|
||||
|
||||
if (status != DetourNavigator::Status::NavMeshNotFound && mPath.empty() && (flags & DetourNavigator::Flag_usePathgrid) == 0)
|
||||
{
|
||||
status = buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents,
|
||||
status = buildPathByNavigatorImpl(actor, startPoint, endPoint, agentBounds,
|
||||
flags | DetourNavigator::Flag_usePathgrid, areaCosts, endTolerance, pathType, std::back_inserter(mPath));
|
||||
if (status != DetourNavigator::Status::Success)
|
||||
mPath.clear();
|
||||
@ -429,14 +429,14 @@ namespace MWMechanics
|
||||
}
|
||||
|
||||
DetourNavigator::Status PathFinder::buildPathByNavigatorImpl(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint,
|
||||
const osg::Vec3f& endPoint, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags,
|
||||
const osg::Vec3f& endPoint, const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Flags flags,
|
||||
const DetourNavigator::AreaCosts& areaCosts, float endTolerance, PathType pathType,
|
||||
std::back_insert_iterator<std::deque<osg::Vec3f>> out)
|
||||
{
|
||||
const auto world = MWBase::Environment::get().getWorld();
|
||||
const auto stepSize = getPathStepSize(actor);
|
||||
const auto navigator = world->getNavigator();
|
||||
const auto status = DetourNavigator::findPath(*navigator, halfExtents, stepSize,
|
||||
const auto status = DetourNavigator::findPath(*navigator, agentBounds, stepSize,
|
||||
startPoint, endPoint, flags, areaCosts, endTolerance, out);
|
||||
|
||||
if (pathType == PathType::Partial && status == DetourNavigator::Status::PartialPath)
|
||||
@ -453,8 +453,9 @@ namespace MWMechanics
|
||||
return status;
|
||||
}
|
||||
|
||||
void PathFinder::buildPathByNavMeshToNextPoint(const MWWorld::ConstPtr& actor, const osg::Vec3f& halfExtents,
|
||||
const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts)
|
||||
void PathFinder::buildPathByNavMeshToNextPoint(const MWWorld::ConstPtr& actor,
|
||||
const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Flags flags,
|
||||
const DetourNavigator::AreaCosts& areaCosts)
|
||||
{
|
||||
if (mPath.empty())
|
||||
return;
|
||||
@ -469,7 +470,7 @@ namespace MWMechanics
|
||||
std::deque<osg::Vec3f> prePath;
|
||||
auto prePathInserter = std::back_inserter(prePath);
|
||||
const float endTolerance = 0;
|
||||
const auto status = DetourNavigator::findPath(*navigator, halfExtents, stepSize,
|
||||
const auto status = DetourNavigator::findPath(*navigator, agentBounds, stepSize,
|
||||
startPoint, mPath.front(), flags, areaCosts, endTolerance, prePathInserter);
|
||||
|
||||
if (status == DetourNavigator::Status::NavMeshNotFound)
|
||||
@ -494,9 +495,9 @@ namespace MWMechanics
|
||||
}
|
||||
|
||||
void PathFinder::buildLimitedPath(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, const osg::Vec3f& endPoint,
|
||||
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const osg::Vec3f& halfExtents,
|
||||
const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts, float endTolerance,
|
||||
PathType pathType)
|
||||
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph,
|
||||
const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Flags flags,
|
||||
const DetourNavigator::AreaCosts& areaCosts, float endTolerance, PathType pathType)
|
||||
{
|
||||
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
|
||||
const auto maxDistance = std::min(
|
||||
@ -506,9 +507,9 @@ namespace MWMechanics
|
||||
const auto startToEnd = endPoint - startPoint;
|
||||
const auto distance = startToEnd.length();
|
||||
if (distance <= maxDistance)
|
||||
return buildPath(actor, startPoint, endPoint, cell, pathgridGraph, halfExtents, flags, areaCosts,
|
||||
return buildPath(actor, startPoint, endPoint, cell, pathgridGraph, agentBounds, flags, areaCosts,
|
||||
endTolerance, pathType);
|
||||
const auto end = startPoint + startToEnd * maxDistance / distance;
|
||||
buildPath(actor, startPoint, end, cell, pathgridGraph, halfExtents, flags, areaCosts, endTolerance, pathType);
|
||||
buildPath(actor, startPoint, end, cell, pathgridGraph, agentBounds, flags, areaCosts, endTolerance, pathType);
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,11 @@ namespace MWWorld
|
||||
class Ptr;
|
||||
}
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
struct AgentBounds;
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
class PathgridGraph;
|
||||
@ -98,25 +103,26 @@ namespace MWMechanics
|
||||
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph);
|
||||
|
||||
void buildPathByNavMesh(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint,
|
||||
const osg::Vec3f& endPoint, const osg::Vec3f& halfExtents, const DetourNavigator::Flags flags,
|
||||
const DetourNavigator::AreaCosts& areaCosts, float endTolerance, PathType pathType);
|
||||
|
||||
void buildPath(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, const osg::Vec3f& endPoint,
|
||||
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const osg::Vec3f& halfExtents,
|
||||
const osg::Vec3f& endPoint, const DetourNavigator::AgentBounds& agentBounds,
|
||||
const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts, float endTolerance,
|
||||
PathType pathType);
|
||||
|
||||
void buildPathByNavMeshToNextPoint(const MWWorld::ConstPtr& actor, const osg::Vec3f& halfExtents,
|
||||
void buildPath(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, const osg::Vec3f& endPoint,
|
||||
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph,
|
||||
const DetourNavigator::AgentBounds& agentBounds, const DetourNavigator::Flags flags,
|
||||
const DetourNavigator::AreaCosts& areaCosts, float endTolerance, PathType pathType);
|
||||
|
||||
void buildPathByNavMeshToNextPoint(const MWWorld::ConstPtr& actor, const DetourNavigator::AgentBounds& agentBounds,
|
||||
const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts);
|
||||
|
||||
void buildLimitedPath(const MWWorld::ConstPtr& actor, const osg::Vec3f& startPoint, const osg::Vec3f& endPoint,
|
||||
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const osg::Vec3f& halfExtents,
|
||||
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph, const DetourNavigator::AgentBounds& agentBounds,
|
||||
const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts, float endTolerance,
|
||||
PathType pathType);
|
||||
|
||||
/// Remove front point if exist and within tolerance
|
||||
void update(const osg::Vec3f& position, float pointTolerance, float destinationTolerance,
|
||||
bool shortenIfAlmostStraight, bool canMoveByZ, const osg::Vec3f& halfExtents,
|
||||
bool shortenIfAlmostStraight, bool canMoveByZ, const DetourNavigator::AgentBounds& agentBounds,
|
||||
const DetourNavigator::Flags flags);
|
||||
|
||||
bool checkPathCompleted() const
|
||||
@ -219,7 +225,7 @@ namespace MWMechanics
|
||||
const PathgridGraph& pathgridGraph, std::back_insert_iterator<std::deque<osg::Vec3f>> out);
|
||||
|
||||
[[nodiscard]] DetourNavigator::Status buildPathByNavigatorImpl(const MWWorld::ConstPtr& actor,
|
||||
const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, const osg::Vec3f& halfExtents,
|
||||
const osg::Vec3f& startPoint, const osg::Vec3f& endPoint, const DetourNavigator::AgentBounds& agentBounds,
|
||||
const DetourNavigator::Flags flags, const DetourNavigator::AreaCosts& areaCosts, float endTolerance, PathType pathType,
|
||||
std::back_insert_iterator<std::deque<osg::Vec3f>> out);
|
||||
};
|
||||
|
@ -57,7 +57,18 @@ Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, Physic
|
||||
}
|
||||
|
||||
mShape = std::make_unique<btBoxShape>(Misc::Convert::toBullet(mOriginalHalfExtents));
|
||||
mRotationallyInvariant = (mMeshTranslation.x() == 0.0 && mMeshTranslation.y() == 0.0) && std::fabs(mOriginalHalfExtents.x() - mOriginalHalfExtents.y()) < 2.2;
|
||||
|
||||
if ((mMeshTranslation.x() == 0.0 && mMeshTranslation.y() == 0.0)
|
||||
&& std::fabs(mOriginalHalfExtents.x() - mOriginalHalfExtents.y()) < 2.2)
|
||||
{
|
||||
mRotationallyInvariant = true;
|
||||
mCollisionShapeType = DetourNavigator::CollisionShapeType::Aabb;
|
||||
}
|
||||
else
|
||||
{
|
||||
mRotationallyInvariant = false;
|
||||
mCollisionShapeType = DetourNavigator::CollisionShapeType::RotatingBox;
|
||||
}
|
||||
|
||||
mConvexShape = static_cast<btConvexShape*>(mShape.get());
|
||||
mConvexShape->setMargin(0.001); // make sure bullet isn't using the huge default convex shape margin of 0.04
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
#include "ptrholder.hpp"
|
||||
|
||||
#include <components/detournavigator/collisionshapetype.hpp>
|
||||
|
||||
#include <LinearMath/btTransform.h>
|
||||
#include <osg/Vec3f>
|
||||
#include <osg/Quat>
|
||||
@ -156,6 +158,8 @@ namespace MWPhysics
|
||||
|
||||
void setActive(bool value) { mActive = value; }
|
||||
|
||||
DetourNavigator::CollisionShapeType getCollisionShapeType() const { return mCollisionShapeType; }
|
||||
|
||||
private:
|
||||
MWWorld::Ptr mStandingOnPtr;
|
||||
/// Removes then re-adds the collision object to the dynamics world
|
||||
@ -171,6 +175,8 @@ namespace MWPhysics
|
||||
|
||||
bool mRotationallyInvariant;
|
||||
|
||||
DetourNavigator::CollisionShapeType mCollisionShapeType;
|
||||
|
||||
std::unique_ptr<btCollisionShape> mShape;
|
||||
btConvexShape* mConvexShape;
|
||||
|
||||
|
@ -38,7 +38,7 @@ namespace MWRender
|
||||
}
|
||||
|
||||
void ActorsPaths::update(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
|
||||
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end,
|
||||
const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end,
|
||||
const DetourNavigator::Settings& settings)
|
||||
{
|
||||
if (!mEnabled)
|
||||
@ -48,7 +48,7 @@ namespace MWRender
|
||||
if (group != mGroups.end())
|
||||
mRootNode->removeChild(group->second.mNode);
|
||||
|
||||
auto newGroup = SceneUtil::createAgentPathGroup(path, halfExtents, start, end, settings.mRecast);
|
||||
auto newGroup = SceneUtil::createAgentPathGroup(path, agentBounds, start, end, settings.mRecast);
|
||||
if (newGroup)
|
||||
{
|
||||
MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(newGroup, "debug");
|
||||
|
@ -17,6 +17,7 @@ namespace osg
|
||||
namespace DetourNavigator
|
||||
{
|
||||
struct Settings;
|
||||
struct AgentBounds;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
@ -30,7 +31,7 @@ namespace MWRender
|
||||
bool toggle();
|
||||
|
||||
void update(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
|
||||
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end,
|
||||
const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end,
|
||||
const DetourNavigator::Settings& settings);
|
||||
|
||||
void remove(const MWWorld::ConstPtr& actor);
|
||||
|
@ -1518,9 +1518,9 @@ namespace MWRender
|
||||
}
|
||||
|
||||
void RenderingManager::updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
|
||||
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end) const
|
||||
const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end) const
|
||||
{
|
||||
mActorsPaths->update(actor, path, halfExtents, start, end, mNavigator.getSettings());
|
||||
mActorsPaths->update(actor, path, agentBounds, start, end, mNavigator.getSettings());
|
||||
}
|
||||
|
||||
void RenderingManager::removeActorPath(const MWWorld::ConstPtr& actor) const
|
||||
|
@ -66,6 +66,7 @@ namespace DetourNavigator
|
||||
{
|
||||
struct Navigator;
|
||||
struct Settings;
|
||||
struct AgentBounds;
|
||||
}
|
||||
|
||||
namespace MWWorld
|
||||
@ -236,7 +237,7 @@ namespace MWRender
|
||||
bool toggleBorders();
|
||||
|
||||
void updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
|
||||
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end) const;
|
||||
const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end) const;
|
||||
|
||||
void removeActorPath(const MWWorld::ConstPtr& actor) const;
|
||||
|
||||
|
@ -187,7 +187,7 @@ namespace
|
||||
}
|
||||
else if (physics.getActor(ptr))
|
||||
{
|
||||
navigator.addAgent(world.getPathfindingHalfExtents(ptr));
|
||||
navigator.addAgent(world.getPathfindingAgentBounds(ptr));
|
||||
}
|
||||
}
|
||||
|
||||
@ -332,7 +332,7 @@ namespace MWWorld
|
||||
}
|
||||
else if (mPhysics->getActor(ptr))
|
||||
{
|
||||
mNavigator.removeAgent(mWorld.getPathfindingHalfExtents(ptr));
|
||||
mNavigator.removeAgent(mWorld.getPathfindingAgentBounds(ptr));
|
||||
mRendering.removeActorPath(ptr);
|
||||
mPhysics->remove(ptr);
|
||||
}
|
||||
@ -940,7 +940,7 @@ namespace MWWorld
|
||||
}
|
||||
else if (mPhysics->getActor(ptr))
|
||||
{
|
||||
mNavigator.removeAgent(mWorld.getPathfindingHalfExtents(ptr));
|
||||
mNavigator.removeAgent(mWorld.getPathfindingAgentBounds(ptr));
|
||||
}
|
||||
mPhysics->remove(ptr);
|
||||
mRendering.removeObject (ptr);
|
||||
|
@ -1275,7 +1275,7 @@ namespace MWWorld
|
||||
if (!force && scale == ptr.getCellRef().getScale())
|
||||
return;
|
||||
if (mPhysics->getActor(ptr))
|
||||
mNavigator->removeAgent(getPathfindingHalfExtents(ptr));
|
||||
mNavigator->removeAgent(getPathfindingAgentBounds(ptr));
|
||||
|
||||
ptr.getCellRef().setScale(scale);
|
||||
mRendering->pagingBlacklistObject(mStore.find(ptr.getCellRef().getRefId()), ptr);
|
||||
@ -1285,7 +1285,7 @@ namespace MWWorld
|
||||
mWorldScene->updateObjectScale(ptr);
|
||||
|
||||
if (mPhysics->getActor(ptr))
|
||||
mNavigator->addAgent(getPathfindingHalfExtents(ptr));
|
||||
mNavigator->addAgent(getPathfindingAgentBounds(ptr));
|
||||
else if (const auto object = mPhysics->getObject(ptr))
|
||||
updateNavigatorObject(*object);
|
||||
}
|
||||
@ -2416,7 +2416,7 @@ namespace MWWorld
|
||||
{
|
||||
// Remove the old CharacterController
|
||||
MWBase::Environment::get().getMechanicsManager()->remove(getPlayerPtr(), true);
|
||||
mNavigator->removeAgent(getPathfindingHalfExtents(getPlayerConstPtr()));
|
||||
mNavigator->removeAgent(getPathfindingAgentBounds(getPlayerConstPtr()));
|
||||
mPhysics->remove(getPlayerPtr());
|
||||
mRendering->removePlayer(getPlayerPtr());
|
||||
MWBase::Environment::get().getLuaManager()->objectRemovedFromScene(getPlayerPtr());
|
||||
@ -2453,7 +2453,7 @@ namespace MWWorld
|
||||
|
||||
applyLoopingParticles(player);
|
||||
|
||||
mNavigator->addAgent(getPathfindingHalfExtents(getPlayerConstPtr()));
|
||||
mNavigator->addAgent(getPathfindingAgentBounds(getPlayerConstPtr()));
|
||||
}
|
||||
|
||||
World::RestPermitted World::canRest () const
|
||||
@ -3898,9 +3898,9 @@ namespace MWWorld
|
||||
}
|
||||
|
||||
void World::updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
|
||||
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end) const
|
||||
const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end) const
|
||||
{
|
||||
mRendering->updateActorPath(actor, path, halfExtents, start, end);
|
||||
mRendering->updateActorPath(actor, path, agentBounds, start, end);
|
||||
}
|
||||
|
||||
void World::removeActorPath(const MWWorld::ConstPtr& actor) const
|
||||
@ -3913,12 +3913,13 @@ namespace MWWorld
|
||||
mRendering->setNavMeshNumber(value);
|
||||
}
|
||||
|
||||
osg::Vec3f World::getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const
|
||||
DetourNavigator::AgentBounds World::getPathfindingAgentBounds(const MWWorld::ConstPtr& actor) const
|
||||
{
|
||||
if (actor.isInCell() && actor.getCell()->isExterior())
|
||||
return mDefaultHalfExtents; // Using default half extents for better performance
|
||||
const MWPhysics::Actor* physicsActor = mPhysics->getActor(actor);
|
||||
if (physicsActor == nullptr || (actor.isInCell() && actor.getCell()->isExterior()))
|
||||
return DetourNavigator::AgentBounds {DetourNavigator::defaultCollisionShapeType, mDefaultHalfExtents};
|
||||
else
|
||||
return getHalfExtents(actor);
|
||||
return DetourNavigator::AgentBounds {physicsActor->getCollisionShapeType(), physicsActor->getHalfExtents()};
|
||||
}
|
||||
|
||||
bool World::hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const
|
||||
|
@ -727,14 +727,13 @@ namespace MWWorld
|
||||
DetourNavigator::Navigator* getNavigator() const override;
|
||||
|
||||
void updateActorPath(const MWWorld::ConstPtr& actor, const std::deque<osg::Vec3f>& path,
|
||||
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end) const override;
|
||||
const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end) const override;
|
||||
|
||||
void removeActorPath(const MWWorld::ConstPtr& actor) const override;
|
||||
|
||||
void setNavMeshNumberToRender(const std::size_t value) override;
|
||||
|
||||
/// Return physical half extents of the given actor to be used in pathfinding
|
||||
osg::Vec3f getPathfindingHalfExtents(const MWWorld::ConstPtr& actor) const override;
|
||||
DetourNavigator::AgentBounds getPathfindingAgentBounds(const MWWorld::ConstPtr& actor) const override;
|
||||
|
||||
bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const override;
|
||||
|
||||
|
@ -50,7 +50,7 @@ namespace
|
||||
Settings mSettings = makeSettings();
|
||||
TileCachedRecastMeshManager mRecastMeshManager {mSettings.mRecast};
|
||||
OffMeshConnectionsManager mOffMeshConnectionsManager {mSettings.mRecast};
|
||||
const osg::Vec3f mAgentHalfExtents {29, 29, 66};
|
||||
const AgentBounds mAgentBounds {CollisionShapeType::Aabb, {29, 29, 66}};
|
||||
const TilePosition mPlayerTile {0, 0};
|
||||
const std::string mWorldspace = "sys::default";
|
||||
const btBoxShape mBox {btVector3(100, 100, 20)};
|
||||
@ -76,7 +76,7 @@ namespace
|
||||
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr);
|
||||
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
||||
const std::map<TilePosition, ChangeType> changedTiles {{TilePosition {0, 0}, ChangeType::add}};
|
||||
updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||
EXPECT_NE(navMeshCacheItem->lockConst()->getImpl().getTileRefAt(0, 0, 0), 0);
|
||||
}
|
||||
@ -88,14 +88,14 @@ namespace
|
||||
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr);
|
||||
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
||||
const std::map<TilePosition, ChangeType> changedTiles {{TilePosition {0, 0}, ChangeType::add}};
|
||||
updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||
{
|
||||
const auto stats = updater.getStats();
|
||||
ASSERT_EQ(stats.mCache.mGetCount, 1);
|
||||
ASSERT_EQ(stats.mCache.mHitCount, 0);
|
||||
}
|
||||
updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||
{
|
||||
const auto stats = updater.getStats();
|
||||
@ -111,14 +111,14 @@ namespace
|
||||
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr);
|
||||
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
||||
const std::map<TilePosition, ChangeType> changedTiles {{TilePosition {0, 0}, ChangeType::update}};
|
||||
updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||
{
|
||||
const auto stats = updater.getStats();
|
||||
ASSERT_EQ(stats.mCache.mGetCount, 1);
|
||||
ASSERT_EQ(stats.mCache.mHitCount, 0);
|
||||
}
|
||||
updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||
{
|
||||
const auto stats = updater.getStats();
|
||||
@ -138,7 +138,7 @@ namespace
|
||||
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
||||
const TilePosition tilePosition {0, 0};
|
||||
const std::map<TilePosition, ChangeType> changedTiles {{tilePosition, ChangeType::add}};
|
||||
updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||
updater.stop();
|
||||
const auto recastMesh = mRecastMeshManager.getMesh(mWorldspace, tilePosition);
|
||||
@ -146,10 +146,11 @@ namespace
|
||||
ShapeId nextShapeId {1};
|
||||
const std::vector<DbRefGeometryObject> objects = makeDbRefGeometryObjects(recastMesh->getMeshSources(),
|
||||
[&] (const MeshSource& v) { return resolveMeshSource(*dbPtr, v, nextShapeId); });
|
||||
const auto tile = dbPtr->findTile(mWorldspace, tilePosition, serialize(mSettings.mRecast, *recastMesh, objects));
|
||||
const auto tile = dbPtr->findTile(mWorldspace, tilePosition,
|
||||
serialize(mSettings.mRecast, mAgentBounds, *recastMesh, objects));
|
||||
ASSERT_TRUE(tile.has_value());
|
||||
EXPECT_EQ(tile->mTileId, 1);
|
||||
EXPECT_EQ(tile->mVersion, mSettings.mNavMeshVersion);
|
||||
EXPECT_EQ(tile->mVersion, navMeshVersion);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorAsyncNavMeshUpdaterTest, post_when_writing_to_db_disabled_should_not_write_tiles)
|
||||
@ -164,7 +165,7 @@ namespace
|
||||
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
||||
const TilePosition tilePosition {0, 0};
|
||||
const std::map<TilePosition, ChangeType> changedTiles {{tilePosition, ChangeType::add}};
|
||||
updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||
updater.stop();
|
||||
const auto recastMesh = mRecastMeshManager.getMesh(mWorldspace, tilePosition);
|
||||
@ -172,7 +173,8 @@ namespace
|
||||
ShapeId nextShapeId {1};
|
||||
const std::vector<DbRefGeometryObject> objects = makeDbRefGeometryObjects(recastMesh->getMeshSources(),
|
||||
[&] (const MeshSource& v) { return resolveMeshSource(*dbPtr, v, nextShapeId); });
|
||||
const auto tile = dbPtr->findTile(mWorldspace, tilePosition, serialize(mSettings.mRecast, *recastMesh, objects));
|
||||
const auto tile = dbPtr->findTile(mWorldspace, tilePosition,
|
||||
serialize(mSettings.mRecast, mAgentBounds, *recastMesh, objects));
|
||||
ASSERT_FALSE(tile.has_value());
|
||||
}
|
||||
|
||||
@ -188,7 +190,7 @@ namespace
|
||||
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
||||
const TilePosition tilePosition {0, 0};
|
||||
const std::map<TilePosition, ChangeType> changedTiles {{tilePosition, ChangeType::add}};
|
||||
updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||
updater.stop();
|
||||
const auto recastMesh = mRecastMeshManager.getMesh(mWorldspace, tilePosition);
|
||||
@ -207,7 +209,7 @@ namespace
|
||||
std::make_unique<NavMeshDb>(":memory:", std::numeric_limits<std::uint64_t>::max()));
|
||||
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
||||
const std::map<TilePosition, ChangeType> changedTiles {{TilePosition {0, 0}, ChangeType::add}};
|
||||
updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||
{
|
||||
const auto stats = updater.getStats();
|
||||
@ -217,7 +219,7 @@ namespace
|
||||
ASSERT_EQ(stats.mDb->mGetTileCount, 1);
|
||||
ASSERT_EQ(stats.mDbGetTileHits, 0);
|
||||
}
|
||||
updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||
{
|
||||
const auto stats = updater.getStats();
|
||||
@ -236,12 +238,12 @@ namespace
|
||||
AsyncNavMeshUpdater updater(mSettings, mRecastMeshManager, mOffMeshConnectionsManager, nullptr);
|
||||
const auto navMeshCacheItem = std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), 1);
|
||||
const std::map<TilePosition, ChangeType> changedTilesAdd {{TilePosition {0, 0}, ChangeType::add}};
|
||||
updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTilesAdd);
|
||||
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTilesAdd);
|
||||
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||
ASSERT_NE(navMeshCacheItem->lockConst()->getImpl().getTileRefAt(0, 0, 0), 0);
|
||||
const std::map<TilePosition, ChangeType> changedTilesRemove {{TilePosition {0, 0}, ChangeType::remove}};
|
||||
const TilePosition playerTile(100, 100);
|
||||
updater.post(mAgentHalfExtents, navMeshCacheItem, playerTile, mWorldspace, changedTilesRemove);
|
||||
updater.post(mAgentBounds, navMeshCacheItem, playerTile, mWorldspace, changedTilesRemove);
|
||||
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||
EXPECT_EQ(navMeshCacheItem->lockConst()->getImpl().getTileRefAt(0, 0, 0), 0);
|
||||
}
|
||||
@ -261,7 +263,7 @@ namespace
|
||||
for (int x = -5; x <= 5; ++x)
|
||||
for (int y = -5; y <= 5; ++y)
|
||||
changedTiles.emplace(TilePosition {x, y}, ChangeType::add);
|
||||
updater.post(mAgentHalfExtents, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.post(mAgentBounds, navMeshCacheItem, mPlayerTile, mWorldspace, changedTiles);
|
||||
updater.wait(mListener, WaitConditionType::allJobsDone);
|
||||
updater.stop();
|
||||
const std::set<TilePosition> present {
|
||||
@ -276,7 +278,6 @@ namespace
|
||||
TilePosition(0, 2),
|
||||
TilePosition(1, -1),
|
||||
TilePosition(1, 0),
|
||||
TilePosition(1, 1),
|
||||
};
|
||||
for (int x = -5; x <= 5; ++x)
|
||||
for (int y = -5; y <= 5; ++y)
|
||||
@ -288,7 +289,8 @@ namespace
|
||||
[&] (const MeshSource& v) { return resolveMeshSource(*dbPtr, v); });
|
||||
if (!objects.has_value())
|
||||
continue;
|
||||
EXPECT_EQ(dbPtr->findTile(mWorldspace, tilePosition, serialize(mSettings.mRecast, *recastMesh, *objects)).has_value(),
|
||||
EXPECT_EQ(dbPtr->findTile(mWorldspace, tilePosition,
|
||||
serialize(mSettings.mRecast, mAgentBounds, *recastMesh, *objects)).has_value(),
|
||||
present.find(tilePosition) != present.end())
|
||||
<< tilePosition.x() << " " << tilePosition.y() << " present=" << (present.find(tilePosition) != present.end());
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ namespace
|
||||
std::unique_ptr<Navigator> mNavigator;
|
||||
const osg::Vec3f mPlayerPosition;
|
||||
const std::string mWorldspace;
|
||||
const osg::Vec3f mAgentHalfExtents;
|
||||
const AgentBounds mAgentBounds {CollisionShapeType::Aabb, {29, 29, 66}};
|
||||
osg::Vec3f mStart;
|
||||
osg::Vec3f mEnd;
|
||||
std::deque<osg::Vec3f> mPath;
|
||||
@ -59,7 +59,6 @@ namespace
|
||||
DetourNavigatorNavigatorTest()
|
||||
: mPlayerPosition(256, 256, 0)
|
||||
, mWorldspace("sys::default")
|
||||
, mAgentHalfExtents(29, 29, 66)
|
||||
, mStart(52, 460, 1)
|
||||
, mEnd(460, 52, 1)
|
||||
, mOut(mPath)
|
||||
@ -122,24 +121,24 @@ namespace
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, find_path_for_empty_should_return_empty)
|
||||
{
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
Status::NavMeshNotFound);
|
||||
EXPECT_EQ(mPath, std::deque<osg::Vec3f>());
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, find_path_for_existing_agent_with_no_navmesh_should_throw_exception)
|
||||
{
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
Status::StartPolygonNotFound);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, add_agent_should_count_each_agent)
|
||||
{
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->removeAgent(mAgentHalfExtents);
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
mNavigator->removeAgent(mAgentBounds);
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
Status::StartPolygonNotFound);
|
||||
}
|
||||
|
||||
@ -155,12 +154,12 @@ namespace
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::requiredTilesPresent);
|
||||
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
Status::Success);
|
||||
|
||||
EXPECT_THAT(mPath, ElementsAre(
|
||||
@ -204,12 +203,12 @@ namespace
|
||||
CollisionShapeInstance compound(std::make_unique<btCompoundShape>());
|
||||
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), new btBoxShape(btVector3(20, 20, 100)));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
Status::Success);
|
||||
|
||||
EXPECT_THAT(mPath, ElementsAre(
|
||||
@ -243,7 +242,7 @@ namespace
|
||||
|
||||
mPath.clear();
|
||||
mOut = std::back_inserter(mPath);
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
Status::Success);
|
||||
|
||||
EXPECT_THAT(mPath, ElementsAre(
|
||||
@ -288,13 +287,13 @@ namespace
|
||||
CollisionShapeInstance compound(std::make_unique<btCompoundShape>());
|
||||
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(0, 0, 0)), new btBoxShape(btVector3(20, 20, 100)));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
Status::Success);
|
||||
|
||||
EXPECT_THAT(mPath, ElementsAre(
|
||||
@ -331,7 +330,7 @@ namespace
|
||||
|
||||
mPath.clear();
|
||||
mOut = std::back_inserter(mPath);
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
Status::Success);
|
||||
|
||||
EXPECT_THAT(mPath, ElementsAre(
|
||||
@ -382,13 +381,13 @@ namespace
|
||||
CollisionShapeInstance heightfield2(makeSquareHeightfieldTerrainShape(heightfieldData2));
|
||||
heightfield2.shape().setLocalScaling(btVector3(128, 128, 1));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
mNavigator->addObject(ObjectId(&heightfield1.shape()), ObjectShapes(heightfield1.instance(), mObjectTransform), mTransform);
|
||||
mNavigator->addObject(ObjectId(&heightfield2.shape()), ObjectShapes(heightfield2.instance(), mObjectTransform), mTransform);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
Status::Success);
|
||||
|
||||
EXPECT_THAT(mPath, ElementsAre(
|
||||
@ -439,7 +438,7 @@ namespace
|
||||
const HeightfieldSurface surface2 = makeSquareHeightfieldSurface(heightfieldData2);
|
||||
const int cellSize2 = mHeightfieldTileSize * (surface2.mSize - 1);
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
EXPECT_TRUE(mNavigator->addHeightfield(mCellPosition, cellSize1, surface1));
|
||||
EXPECT_FALSE(mNavigator->addHeightfield(mCellPosition, cellSize2, surface2));
|
||||
}
|
||||
@ -472,12 +471,12 @@ namespace
|
||||
|
||||
osg::ref_ptr<const Resource::BulletShapeInstance> instance(new Resource::BulletShapeInstance(bulletShape));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
mNavigator->addObject(ObjectId(instance->mCollisionShape.get()), ObjectShapes(instance, mObjectTransform), mTransform);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
Status::Success);
|
||||
|
||||
EXPECT_THAT(mPath, ElementsAre(
|
||||
@ -519,7 +518,7 @@ namespace
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
mNavigator->addWater(mCellPosition, cellSize, 300);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
@ -530,7 +529,7 @@ namespace
|
||||
mEnd.x() = 256;
|
||||
mEnd.z() = 300;
|
||||
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_swim, mAreaCosts, mEndTolerance, mOut),
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_swim, mAreaCosts, mEndTolerance, mOut),
|
||||
Status::Success);
|
||||
|
||||
EXPECT_THAT(mPath, ElementsAre(
|
||||
@ -567,7 +566,7 @@ namespace
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
mNavigator->addWater(mCellPosition, cellSize, -25);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
@ -576,7 +575,7 @@ namespace
|
||||
mStart.x() = 256;
|
||||
mEnd.x() = 256;
|
||||
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_swim | Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_swim | Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
Status::Success);
|
||||
|
||||
EXPECT_THAT(mPath, ElementsAre(
|
||||
@ -613,7 +612,7 @@ namespace
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->addWater(mCellPosition, std::numeric_limits<int>::max(), -25);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
@ -622,7 +621,7 @@ namespace
|
||||
mStart.x() = 256;
|
||||
mEnd.x() = 256;
|
||||
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_swim | Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_swim | Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
Status::Success);
|
||||
|
||||
EXPECT_THAT(mPath, ElementsAre(
|
||||
@ -659,7 +658,7 @@ namespace
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
mNavigator->addWater(mCellPosition, cellSize, -25);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
@ -668,7 +667,7 @@ namespace
|
||||
mStart.x() = 256;
|
||||
mEnd.x() = 256;
|
||||
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
Status::Success);
|
||||
|
||||
EXPECT_THAT(mPath, ElementsAre(
|
||||
@ -703,7 +702,7 @@ namespace
|
||||
CollisionShapeInstance heightfield(makeSquareHeightfieldTerrainShape(heightfieldData));
|
||||
heightfield.shape().setLocalScaling(btVector3(128, 128, 1));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
mNavigator->addObject(ObjectId(&heightfield.shape()), ObjectShapes(heightfield.instance(), mObjectTransform), mTransform);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
@ -716,7 +715,7 @@ namespace
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
Status::Success);
|
||||
|
||||
EXPECT_THAT(mPath, ElementsAre(
|
||||
@ -757,7 +756,7 @@ namespace
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
@ -770,7 +769,7 @@ namespace
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
Status::Success);
|
||||
|
||||
EXPECT_THAT(mPath, ElementsAre(
|
||||
@ -812,14 +811,14 @@ namespace
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
Misc::Rng::init(42);
|
||||
|
||||
const auto result = findRandomPointAroundCircle(*mNavigator, mAgentHalfExtents, mStart, 100.0, Flag_walk,
|
||||
const auto result = findRandomPointAroundCircle(*mNavigator, mAgentBounds, mStart, 100.0, Flag_walk,
|
||||
[]() { return Misc::Rng::rollClosedProbability(); });
|
||||
|
||||
ASSERT_THAT(result, Optional(Vec3fEq(70.35845947265625, 335.592041015625, -2.6667339801788330078125)))
|
||||
@ -849,7 +848,7 @@ namespace
|
||||
std::vector<CollisionShapeInstance<btBoxShape>> boxes;
|
||||
std::generate_n(std::back_inserter(boxes), 100, [] { return std::make_unique<btBoxShape>(btVector3(20, 20, 100)); });
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
|
||||
@ -870,7 +869,7 @@ namespace
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
Status::Success);
|
||||
|
||||
EXPECT_THAT(mPath, ElementsAre(
|
||||
@ -905,7 +904,7 @@ namespace
|
||||
std::vector<CollisionShapeInstance<btBoxShape>> shapes;
|
||||
std::generate_n(std::back_inserter(shapes), 100, [] { return std::make_unique<btBoxShape>(btVector3(64, 64, 64)); });
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
|
||||
for (std::size_t i = 0; i < shapes.size(); ++i)
|
||||
{
|
||||
@ -950,14 +949,14 @@ namespace
|
||||
const HeightfieldSurface surface = makeSquareHeightfieldSurface(heightfieldData);
|
||||
const int cellSize = mHeightfieldTileSize * (surface.mSize - 1);
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
const osg::Vec3f start(57, 460, 1);
|
||||
const osg::Vec3f end(460, 57, 1);
|
||||
const auto result = raycast(*mNavigator, mAgentHalfExtents, start, end, Flag_walk);
|
||||
const auto result = raycast(*mNavigator, mAgentBounds, start, end, Flag_walk);
|
||||
|
||||
ASSERT_THAT(result, Optional(Vec3fEq(end.x(), end.y(), 1.95257937908172607421875)))
|
||||
<< (result ? *result : osg::Vec3f());
|
||||
@ -979,7 +978,7 @@ namespace
|
||||
const btVector3 oscillatingBoxShapePosition(288, 288, 400);
|
||||
CollisionShapeInstance borderBox(std::make_unique<btBoxShape>(btVector3(50, 50, 50)));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->addObject(ObjectId(&oscillatingBox.shape()), ObjectShapes(oscillatingBox.instance(), mObjectTransform),
|
||||
btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition));
|
||||
@ -1013,12 +1012,12 @@ namespace
|
||||
const HeightfieldPlane plane {100};
|
||||
const int cellSize = mHeightfieldTileSize * 4;
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, plane);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::requiredTilesPresent);
|
||||
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
Status::Success);
|
||||
|
||||
EXPECT_THAT(mPath, ElementsAre(
|
||||
@ -1063,13 +1062,13 @@ namespace
|
||||
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(204, -204, 0)),
|
||||
new btBoxShape(btVector3(200, 200, 1000)));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mEndTolerance, mOut),
|
||||
Status::PartialPath);
|
||||
|
||||
EXPECT_THAT(mPath, ElementsAre(
|
||||
@ -1102,7 +1101,7 @@ namespace
|
||||
compound.shape().addChildShape(btTransform(btMatrix3x3::getIdentity(), btVector3(204, -204, 0)),
|
||||
new btBoxShape(btVector3(100, 100, 1000)));
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize, surface);
|
||||
mNavigator->addObject(ObjectId(&compound.shape()), ObjectShapes(compound.instance(), mObjectTransform), mTransform);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
@ -1110,7 +1109,7 @@ namespace
|
||||
|
||||
const float endTolerance = 1000.0f;
|
||||
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, endTolerance, mOut),
|
||||
EXPECT_EQ(findPath(*mNavigator, mAgentBounds, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, endTolerance, mOut),
|
||||
Status::Success);
|
||||
|
||||
EXPECT_THAT(mPath, ElementsAre(
|
||||
@ -1142,7 +1141,7 @@ namespace
|
||||
const int cellSize2 = 200;
|
||||
const float level2 = 2;
|
||||
|
||||
mNavigator->addAgent(mAgentHalfExtents);
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
EXPECT_TRUE(mNavigator->addWater(mCellPosition, cellSize1, level1));
|
||||
EXPECT_FALSE(mNavigator->addWater(mCellPosition, cellSize2, level2));
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ namespace
|
||||
|
||||
struct DetourNavigatorNavMeshTilesCacheTest : Test
|
||||
{
|
||||
const osg::Vec3f mAgentHalfExtents {1, 2, 3};
|
||||
const AgentBounds mAgentBounds {CollisionShapeType::Aabb, {1, 2, 3}};
|
||||
const TilePosition mTilePosition {0, 0};
|
||||
const std::size_t mGeneration = 0;
|
||||
const std::size_t mRevision = 0;
|
||||
@ -117,7 +117,7 @@ namespace
|
||||
const std::size_t maxSize = 0;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh));
|
||||
EXPECT_FALSE(cache.get(mAgentBounds, mTilePosition, mRecastMesh));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_for_not_enought_cache_size_should_return_empty_value)
|
||||
@ -125,7 +125,7 @@ namespace
|
||||
const std::size_t maxSize = 0;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
|
||||
EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)));
|
||||
EXPECT_FALSE(cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData)));
|
||||
EXPECT_NE(mPreparedNavMeshData, nullptr);
|
||||
}
|
||||
|
||||
@ -136,7 +136,7 @@ namespace
|
||||
const auto copy = clone(*mPreparedNavMeshData);
|
||||
ASSERT_EQ(*mPreparedNavMeshData, *copy);
|
||||
|
||||
const auto result = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
const auto result = cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
ASSERT_TRUE(result);
|
||||
EXPECT_EQ(result.get(), *copy);
|
||||
}
|
||||
@ -148,9 +148,9 @@ namespace
|
||||
auto copy = clone(*mPreparedNavMeshData);
|
||||
const auto sameCopy = clone(*mPreparedNavMeshData);
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
EXPECT_EQ(mPreparedNavMeshData, nullptr);
|
||||
const auto result = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(copy));
|
||||
const auto result = cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(copy));
|
||||
ASSERT_TRUE(result);
|
||||
EXPECT_EQ(result.get(), *sameCopy);
|
||||
}
|
||||
@ -161,8 +161,8 @@ namespace
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
const auto copy = clone(*mPreparedNavMeshData);
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
const auto result = cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh);
|
||||
cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
const auto result = cache.get(mAgentBounds, mTilePosition, mRecastMesh);
|
||||
ASSERT_TRUE(result);
|
||||
EXPECT_EQ(result.get(), *copy);
|
||||
}
|
||||
@ -171,10 +171,10 @@ namespace
|
||||
{
|
||||
const std::size_t maxSize = 1;
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
const osg::Vec3f unexsistentAgentHalfExtents {1, 1, 1};
|
||||
const AgentBounds absentAgentBounds {CollisionShapeType::Aabb, {1, 1, 1}};
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
EXPECT_FALSE(cache.get(unexsistentAgentHalfExtents, mTilePosition, mRecastMesh));
|
||||
cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
EXPECT_FALSE(cache.get(absentAgentBounds, mTilePosition, mRecastMesh));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, get_for_cache_miss_by_tile_position_should_return_empty_value)
|
||||
@ -183,8 +183,8 @@ namespace
|
||||
NavMeshTilesCache cache(maxSize);
|
||||
const TilePosition unexistentTilePosition {1, 1};
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
EXPECT_FALSE(cache.get(mAgentHalfExtents, unexistentTilePosition, mRecastMesh));
|
||||
cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
EXPECT_FALSE(cache.get(mAgentBounds, unexistentTilePosition, mRecastMesh));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, get_for_cache_miss_by_recast_mesh_should_return_empty_value)
|
||||
@ -194,8 +194,8 @@ namespace
|
||||
const std::vector<CellWater> water(1, CellWater {osg::Vec2i(), Water {1, 0.0f}});
|
||||
const RecastMesh unexistentRecastMesh(mGeneration, mRevision, mMesh, water, mHeightfields, mFlatHeightfields, mSources);
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, unexistentRecastMesh));
|
||||
cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
EXPECT_FALSE(cache.get(mAgentBounds, mTilePosition, unexistentRecastMesh));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_replace_unused_value)
|
||||
@ -208,12 +208,12 @@ namespace
|
||||
auto anotherPreparedNavMeshData = makePeparedNavMeshData(3);
|
||||
const auto copy = clone(*anotherPreparedNavMeshData);
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
const auto result = cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh,
|
||||
cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
const auto result = cache.set(mAgentBounds, mTilePosition, anotherRecastMesh,
|
||||
std::move(anotherPreparedNavMeshData));
|
||||
ASSERT_TRUE(result);
|
||||
EXPECT_EQ(result.get(), *copy);
|
||||
EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh));
|
||||
EXPECT_FALSE(cache.get(mAgentBounds, mTilePosition, mRecastMesh));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_not_replace_used_value)
|
||||
@ -225,9 +225,9 @@ namespace
|
||||
const RecastMesh anotherRecastMesh(mGeneration, mRevision, mMesh, water, mHeightfields, mFlatHeightfields, mSources);
|
||||
auto anotherPreparedNavMeshData = makePeparedNavMeshData(3);
|
||||
|
||||
const auto value = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh,
|
||||
const auto value = cache.set(mAgentBounds, mTilePosition, mRecastMesh,
|
||||
std::move(mPreparedNavMeshData));
|
||||
EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh,
|
||||
EXPECT_FALSE(cache.set(mAgentBounds, mTilePosition, anotherRecastMesh,
|
||||
std::move(anotherPreparedNavMeshData)));
|
||||
}
|
||||
|
||||
@ -247,17 +247,17 @@ namespace
|
||||
mHeightfields, mFlatHeightfields, mSources);
|
||||
auto mostRecentlySetData = makePeparedNavMeshData(3);
|
||||
|
||||
ASSERT_TRUE(cache.set(mAgentHalfExtents, mTilePosition, leastRecentlySetRecastMesh,
|
||||
ASSERT_TRUE(cache.set(mAgentBounds, mTilePosition, leastRecentlySetRecastMesh,
|
||||
std::move(leastRecentlySetData)));
|
||||
ASSERT_TRUE(cache.set(mAgentHalfExtents, mTilePosition, mostRecentlySetRecastMesh,
|
||||
ASSERT_TRUE(cache.set(mAgentBounds, mTilePosition, mostRecentlySetRecastMesh,
|
||||
std::move(mostRecentlySetData)));
|
||||
|
||||
const auto result = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh,
|
||||
const auto result = cache.set(mAgentBounds, mTilePosition, mRecastMesh,
|
||||
std::move(mPreparedNavMeshData));
|
||||
EXPECT_EQ(result.get(), *copy);
|
||||
|
||||
EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, leastRecentlySetRecastMesh));
|
||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mostRecentlySetRecastMesh));
|
||||
EXPECT_FALSE(cache.get(mAgentBounds, mTilePosition, leastRecentlySetRecastMesh));
|
||||
EXPECT_TRUE(cache.get(mAgentBounds, mTilePosition, mostRecentlySetRecastMesh));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_replace_unused_least_recently_used_value)
|
||||
@ -277,28 +277,28 @@ namespace
|
||||
auto mostRecentlyUsedData = makePeparedNavMeshData(3);
|
||||
const auto mostRecentlyUsedCopy = clone(*mostRecentlyUsedData);
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, leastRecentlyUsedRecastMesh, std::move(leastRecentlyUsedData));
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mostRecentlyUsedRecastMesh, std::move(mostRecentlyUsedData));
|
||||
cache.set(mAgentBounds, mTilePosition, leastRecentlyUsedRecastMesh, std::move(leastRecentlyUsedData));
|
||||
cache.set(mAgentBounds, mTilePosition, mostRecentlyUsedRecastMesh, std::move(mostRecentlyUsedData));
|
||||
|
||||
{
|
||||
const auto value = cache.get(mAgentHalfExtents, mTilePosition, leastRecentlyUsedRecastMesh);
|
||||
const auto value = cache.get(mAgentBounds, mTilePosition, leastRecentlyUsedRecastMesh);
|
||||
ASSERT_TRUE(value);
|
||||
ASSERT_EQ(value.get(), *leastRecentlyUsedCopy);
|
||||
}
|
||||
|
||||
{
|
||||
const auto value = cache.get(mAgentHalfExtents, mTilePosition, mostRecentlyUsedRecastMesh);
|
||||
const auto value = cache.get(mAgentBounds, mTilePosition, mostRecentlyUsedRecastMesh);
|
||||
ASSERT_TRUE(value);
|
||||
ASSERT_EQ(value.get(), *mostRecentlyUsedCopy);
|
||||
}
|
||||
|
||||
const auto copy = clone(*mPreparedNavMeshData);
|
||||
const auto result = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh,
|
||||
const auto result = cache.set(mAgentBounds, mTilePosition, mRecastMesh,
|
||||
std::move(mPreparedNavMeshData));
|
||||
EXPECT_EQ(result.get(), *copy);
|
||||
|
||||
EXPECT_FALSE(cache.get(mAgentHalfExtents, mTilePosition, leastRecentlyUsedRecastMesh));
|
||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mostRecentlyUsedRecastMesh));
|
||||
EXPECT_FALSE(cache.get(mAgentBounds, mTilePosition, leastRecentlyUsedRecastMesh));
|
||||
EXPECT_TRUE(cache.get(mAgentBounds, mTilePosition, mostRecentlyUsedRecastMesh));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_not_replace_unused_least_recently_used_value_when_item_does_not_not_fit_cache_max_size)
|
||||
@ -311,9 +311,9 @@ namespace
|
||||
mHeightfields, mFlatHeightfields, mSources);
|
||||
auto tooLargeData = makePeparedNavMeshData(10);
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, tooLargeRecastMesh, std::move(tooLargeData)));
|
||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh));
|
||||
cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
EXPECT_FALSE(cache.set(mAgentBounds, mTilePosition, tooLargeRecastMesh, std::move(tooLargeData)));
|
||||
EXPECT_TRUE(cache.get(mAgentBounds, mTilePosition, mRecastMesh));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, set_should_not_replace_unused_least_recently_used_value_when_item_does_not_not_fit_size_of_unused_items)
|
||||
@ -331,15 +331,15 @@ namespace
|
||||
mHeightfields, mFlatHeightfields, mSources);
|
||||
auto tooLargeData = makePeparedNavMeshData(10);
|
||||
|
||||
const auto value = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh,
|
||||
const auto value = cache.set(mAgentBounds, mTilePosition, mRecastMesh,
|
||||
std::move(mPreparedNavMeshData));
|
||||
ASSERT_TRUE(value);
|
||||
ASSERT_TRUE(cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh,
|
||||
ASSERT_TRUE(cache.set(mAgentBounds, mTilePosition, anotherRecastMesh,
|
||||
std::move(anotherData)));
|
||||
EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, tooLargeRecastMesh,
|
||||
EXPECT_FALSE(cache.set(mAgentBounds, mTilePosition, tooLargeRecastMesh,
|
||||
std::move(tooLargeData)));
|
||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh));
|
||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, anotherRecastMesh));
|
||||
EXPECT_TRUE(cache.get(mAgentBounds, mTilePosition, mRecastMesh));
|
||||
EXPECT_TRUE(cache.get(mAgentBounds, mTilePosition, anotherRecastMesh));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, release_used_after_set_then_used_by_get_item_should_left_this_item_available)
|
||||
@ -351,14 +351,14 @@ namespace
|
||||
const RecastMesh anotherRecastMesh(mGeneration, mRevision, mMesh, water, mHeightfields, mFlatHeightfields, mSources);
|
||||
auto anotherData = makePeparedNavMeshData(3);
|
||||
|
||||
const auto firstCopy = cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
const auto firstCopy = cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
ASSERT_TRUE(firstCopy);
|
||||
{
|
||||
const auto secondCopy = cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh);
|
||||
const auto secondCopy = cache.get(mAgentBounds, mTilePosition, mRecastMesh);
|
||||
ASSERT_TRUE(secondCopy);
|
||||
}
|
||||
EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh, std::move(anotherData)));
|
||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh));
|
||||
EXPECT_FALSE(cache.set(mAgentBounds, mTilePosition, anotherRecastMesh, std::move(anotherData)));
|
||||
EXPECT_TRUE(cache.get(mAgentBounds, mTilePosition, mRecastMesh));
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavMeshTilesCacheTest, release_twice_used_item_should_left_this_item_available)
|
||||
@ -370,14 +370,14 @@ namespace
|
||||
const RecastMesh anotherRecastMesh(mGeneration, mRevision, mMesh, water, mHeightfields, mFlatHeightfields, mSources);
|
||||
auto anotherData = makePeparedNavMeshData(3);
|
||||
|
||||
cache.set(mAgentHalfExtents, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
const auto firstCopy = cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh);
|
||||
cache.set(mAgentBounds, mTilePosition, mRecastMesh, std::move(mPreparedNavMeshData));
|
||||
const auto firstCopy = cache.get(mAgentBounds, mTilePosition, mRecastMesh);
|
||||
ASSERT_TRUE(firstCopy);
|
||||
{
|
||||
const auto secondCopy = cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh);
|
||||
const auto secondCopy = cache.get(mAgentBounds, mTilePosition, mRecastMesh);
|
||||
ASSERT_TRUE(secondCopy);
|
||||
}
|
||||
EXPECT_FALSE(cache.set(mAgentHalfExtents, mTilePosition, anotherRecastMesh, std::move(anotherData)));
|
||||
EXPECT_TRUE(cache.get(mAgentHalfExtents, mTilePosition, mRecastMesh));
|
||||
EXPECT_FALSE(cache.set(mAgentBounds, mTilePosition, anotherRecastMesh, std::move(anotherData)));
|
||||
EXPECT_TRUE(cache.get(mAgentBounds, mTilePosition, mRecastMesh));
|
||||
}
|
||||
}
|
||||
|
34
components/detournavigator/agentbounds.hpp
Normal file
34
components/detournavigator/agentbounds.hpp
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_AGENTBOUNDS_H
|
||||
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_AGENTBOUNDS_H
|
||||
|
||||
#include "collisionshapetype.hpp"
|
||||
|
||||
#include <osg/Vec3f>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
struct AgentBounds
|
||||
{
|
||||
CollisionShapeType mShapeType;
|
||||
osg::Vec3f mHalfExtents;
|
||||
};
|
||||
|
||||
inline auto tie(const AgentBounds& value)
|
||||
{
|
||||
return std::tie(value.mShapeType, value.mHalfExtents);
|
||||
}
|
||||
|
||||
inline bool operator==(const AgentBounds& lhs, const AgentBounds& rhs)
|
||||
{
|
||||
return tie(lhs) == tie(rhs);
|
||||
}
|
||||
|
||||
inline bool operator<(const AgentBounds& lhs, const AgentBounds& rhs)
|
||||
{
|
||||
return tie(lhs) < tie(rhs);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -32,12 +32,12 @@ namespace DetourNavigator
|
||||
}
|
||||
|
||||
int getMinDistanceTo(const TilePosition& position, int maxDistance,
|
||||
const std::set<std::tuple<osg::Vec3f, TilePosition>>& pushedTiles,
|
||||
const std::set<std::tuple<osg::Vec3f, TilePosition>>& presentTiles)
|
||||
const std::set<std::tuple<AgentBounds, TilePosition>>& pushedTiles,
|
||||
const std::set<std::tuple<AgentBounds, TilePosition>>& presentTiles)
|
||||
{
|
||||
int result = maxDistance;
|
||||
for (const auto& [halfExtents, tile] : pushedTiles)
|
||||
if (presentTiles.find(std::tie(halfExtents, tile)) == presentTiles.end())
|
||||
for (const auto& [agentBounds, tile] : pushedTiles)
|
||||
if (presentTiles.find(std::tie(agentBounds, tile)) == presentTiles.end())
|
||||
result = std::min(result, getManhattanDistance(position, tile));
|
||||
return result;
|
||||
}
|
||||
@ -84,14 +84,14 @@ namespace DetourNavigator
|
||||
|
||||
auto getAgentAndTile(const Job& job) noexcept
|
||||
{
|
||||
return std::make_tuple(job.mAgentHalfExtents, job.mChangedTile);
|
||||
return std::make_tuple(job.mAgentBounds, job.mChangedTile);
|
||||
}
|
||||
|
||||
std::unique_ptr<DbWorker> makeDbWorker(AsyncNavMeshUpdater& updater, std::unique_ptr<NavMeshDb>&& db, const Settings& settings)
|
||||
{
|
||||
if (db == nullptr)
|
||||
return nullptr;
|
||||
return std::make_unique<DbWorker>(updater, std::move(db), TileVersion(settings.mNavMeshVersion),
|
||||
return std::make_unique<DbWorker>(updater, std::move(db), TileVersion(navMeshVersion),
|
||||
settings.mRecast, settings.mWriteToNavMeshDb);
|
||||
}
|
||||
|
||||
@ -112,11 +112,11 @@ namespace DetourNavigator
|
||||
}
|
||||
}
|
||||
|
||||
Job::Job(const osg::Vec3f& agentHalfExtents, std::weak_ptr<GuardedNavMeshCacheItem> navMeshCacheItem,
|
||||
Job::Job(const AgentBounds& agentBounds, std::weak_ptr<GuardedNavMeshCacheItem> navMeshCacheItem,
|
||||
std::string_view worldspace, const TilePosition& changedTile, ChangeType changeType, int distanceToPlayer,
|
||||
std::chrono::steady_clock::time_point processTime)
|
||||
: mId(getNextJobId())
|
||||
, mAgentHalfExtents(agentHalfExtents)
|
||||
, mAgentBounds(agentBounds)
|
||||
, mNavMeshCacheItem(std::move(navMeshCacheItem))
|
||||
, mWorldspace(worldspace)
|
||||
, mChangedTile(changedTile)
|
||||
@ -145,7 +145,7 @@ namespace DetourNavigator
|
||||
stop();
|
||||
}
|
||||
|
||||
void AsyncNavMeshUpdater::post(const osg::Vec3f& agentHalfExtents, const SharedNavMeshCacheItem& navMeshCacheItem,
|
||||
void AsyncNavMeshUpdater::post(const AgentBounds& agentBounds, const SharedNavMeshCacheItem& navMeshCacheItem,
|
||||
const TilePosition& playerTile, std::string_view worldspace,
|
||||
const std::map<TilePosition, ChangeType>& changedTiles)
|
||||
{
|
||||
@ -169,16 +169,16 @@ namespace DetourNavigator
|
||||
|
||||
for (const auto& [changedTile, changeType] : changedTiles)
|
||||
{
|
||||
if (mPushed.emplace(agentHalfExtents, changedTile).second)
|
||||
if (mPushed.emplace(agentBounds, changedTile).second)
|
||||
{
|
||||
const auto processTime = changeType == ChangeType::update
|
||||
? mLastUpdates[std::tie(agentHalfExtents, changedTile)] + mSettings.get().mMinUpdateInterval
|
||||
? mLastUpdates[std::tie(agentBounds, changedTile)] + mSettings.get().mMinUpdateInterval
|
||||
: std::chrono::steady_clock::time_point();
|
||||
|
||||
const JobIt it = mJobs.emplace(mJobs.end(), agentHalfExtents, navMeshCacheItem, worldspace,
|
||||
const JobIt it = mJobs.emplace(mJobs.end(), agentBounds, navMeshCacheItem, worldspace,
|
||||
changedTile, changeType, getManhattanDistance(changedTile, playerTile), processTime);
|
||||
|
||||
Log(Debug::Debug) << "Post job " << it->mId << " for agent=(" << it->mAgentHalfExtents << ")"
|
||||
Log(Debug::Debug) << "Post job " << it->mId << " for agent=(" << it->mAgentBounds << ")"
|
||||
<< " changedTile=(" << it->mChangedTile << ")";
|
||||
|
||||
if (playerTileChanged)
|
||||
@ -342,7 +342,7 @@ namespace DetourNavigator
|
||||
switch (status)
|
||||
{
|
||||
case JobStatus::Done:
|
||||
unlockTile(job->mAgentHalfExtents, job->mChangedTile);
|
||||
unlockTile(job->mAgentBounds, job->mChangedTile);
|
||||
if (job->mGeneratedNavMeshData != nullptr)
|
||||
mDbWorker->enqueueJob(job);
|
||||
else
|
||||
@ -419,7 +419,7 @@ namespace DetourNavigator
|
||||
return JobStatus::Done;
|
||||
}
|
||||
|
||||
NavMeshTilesCache::Value cachedNavMeshData = mNavMeshTilesCache.get(job.mAgentHalfExtents, job.mChangedTile, *recastMesh);
|
||||
NavMeshTilesCache::Value cachedNavMeshData = mNavMeshTilesCache.get(job.mAgentBounds, job.mChangedTile, *recastMesh);
|
||||
std::unique_ptr<PreparedNavMeshData> preparedNavMeshData;
|
||||
const PreparedNavMeshData* preparedNavMeshDataPtr = nullptr;
|
||||
|
||||
@ -435,7 +435,7 @@ namespace DetourNavigator
|
||||
return JobStatus::MemoryCacheMiss;
|
||||
}
|
||||
|
||||
preparedNavMeshData = prepareNavMeshTileData(*recastMesh, job.mChangedTile, job.mAgentHalfExtents, mSettings.get().mRecast);
|
||||
preparedNavMeshData = prepareNavMeshTileData(*recastMesh, job.mChangedTile, job.mAgentBounds, mSettings.get().mRecast);
|
||||
|
||||
if (preparedNavMeshData == nullptr)
|
||||
{
|
||||
@ -450,7 +450,7 @@ namespace DetourNavigator
|
||||
}
|
||||
else
|
||||
{
|
||||
cachedNavMeshData = mNavMeshTilesCache.set(job.mAgentHalfExtents, job.mChangedTile,
|
||||
cachedNavMeshData = mNavMeshTilesCache.set(job.mAgentBounds, job.mChangedTile,
|
||||
*recastMesh, std::move(preparedNavMeshData));
|
||||
preparedNavMeshDataPtr = cachedNavMeshData ? &cachedNavMeshData.get() : preparedNavMeshData.get();
|
||||
}
|
||||
@ -459,7 +459,7 @@ namespace DetourNavigator
|
||||
const auto offMeshConnections = mOffMeshConnectionsManager.get().get(job.mChangedTile);
|
||||
|
||||
const UpdateNavMeshStatus status = navMeshCacheItem.lock()->updateTile(job.mChangedTile, std::move(cachedNavMeshData),
|
||||
makeNavMeshTileData(*preparedNavMeshDataPtr, offMeshConnections, job.mAgentHalfExtents, job.mChangedTile, mSettings.get().mRecast));
|
||||
makeNavMeshTileData(*preparedNavMeshDataPtr, offMeshConnections, job.mAgentBounds, job.mChangedTile, mSettings.get().mRecast));
|
||||
|
||||
return handleUpdateNavMeshStatus(status, job, navMeshCacheItem, *recastMesh);
|
||||
}
|
||||
@ -471,7 +471,7 @@ namespace DetourNavigator
|
||||
std::unique_ptr<PreparedNavMeshData> preparedNavMeshData;
|
||||
bool generatedNavMeshData = false;
|
||||
|
||||
if (job.mCachedTileData.has_value() && job.mCachedTileData->mVersion == mSettings.get().mNavMeshVersion)
|
||||
if (job.mCachedTileData.has_value() && job.mCachedTileData->mVersion == navMeshVersion)
|
||||
{
|
||||
preparedNavMeshData = std::make_unique<PreparedNavMeshData>();
|
||||
if (deserialize(job.mCachedTileData->mData, *preparedNavMeshData))
|
||||
@ -482,7 +482,7 @@ namespace DetourNavigator
|
||||
|
||||
if (preparedNavMeshData == nullptr)
|
||||
{
|
||||
preparedNavMeshData = prepareNavMeshTileData(*job.mRecastMesh, job.mChangedTile, job.mAgentHalfExtents, mSettings.get().mRecast);
|
||||
preparedNavMeshData = prepareNavMeshTileData(*job.mRecastMesh, job.mChangedTile, job.mAgentBounds, mSettings.get().mRecast);
|
||||
generatedNavMeshData = true;
|
||||
}
|
||||
|
||||
@ -493,14 +493,14 @@ namespace DetourNavigator
|
||||
return JobStatus::Done;
|
||||
}
|
||||
|
||||
auto cachedNavMeshData = mNavMeshTilesCache.set(job.mAgentHalfExtents, job.mChangedTile, *job.mRecastMesh,
|
||||
auto cachedNavMeshData = mNavMeshTilesCache.set(job.mAgentBounds, job.mChangedTile, *job.mRecastMesh,
|
||||
std::move(preparedNavMeshData));
|
||||
|
||||
const auto offMeshConnections = mOffMeshConnectionsManager.get().get(job.mChangedTile);
|
||||
|
||||
const PreparedNavMeshData* preparedNavMeshDataPtr = cachedNavMeshData ? &cachedNavMeshData.get() : preparedNavMeshData.get();
|
||||
const UpdateNavMeshStatus status = navMeshCacheItem.lock()->updateTile(job.mChangedTile, std::move(cachedNavMeshData),
|
||||
makeNavMeshTileData(*preparedNavMeshDataPtr, offMeshConnections, job.mAgentHalfExtents, job.mChangedTile, mSettings.get().mRecast));
|
||||
makeNavMeshTileData(*preparedNavMeshDataPtr, offMeshConnections, job.mAgentBounds, job.mChangedTile, mSettings.get().mRecast));
|
||||
|
||||
const JobStatus result = handleUpdateNavMeshStatus(status, job, navMeshCacheItem, *job.mRecastMesh);
|
||||
|
||||
@ -522,12 +522,12 @@ namespace DetourNavigator
|
||||
if (status == UpdateNavMeshStatus::removed || status == UpdateNavMeshStatus::lost)
|
||||
{
|
||||
const std::scoped_lock lock(mMutex);
|
||||
mPresentTiles.erase(std::make_tuple(job.mAgentHalfExtents, job.mChangedTile));
|
||||
mPresentTiles.erase(std::make_tuple(job.mAgentBounds, job.mChangedTile));
|
||||
}
|
||||
else if (isSuccess(status) && status != UpdateNavMeshStatus::ignored)
|
||||
{
|
||||
const std::scoped_lock lock(mMutex);
|
||||
mPresentTiles.insert(std::make_tuple(job.mAgentHalfExtents, job.mChangedTile));
|
||||
mPresentTiles.insert(std::make_tuple(job.mAgentBounds, job.mChangedTile));
|
||||
}
|
||||
|
||||
writeDebugFiles(job, &recastMesh);
|
||||
@ -564,7 +564,7 @@ namespace DetourNavigator
|
||||
if (job->mRecastMesh != nullptr)
|
||||
return job;
|
||||
|
||||
if (!lockTile(job->mAgentHalfExtents, job->mChangedTile))
|
||||
if (!lockTile(job->mAgentBounds, job->mChangedTile))
|
||||
{
|
||||
Log(Debug::Debug) << "Failed to lock tile by " << job->mId;
|
||||
++job->mTryNumber;
|
||||
@ -604,14 +604,14 @@ namespace DetourNavigator
|
||||
|
||||
void AsyncNavMeshUpdater::repost(JobIt job)
|
||||
{
|
||||
unlockTile(job->mAgentHalfExtents, job->mChangedTile);
|
||||
unlockTile(job->mAgentBounds, job->mChangedTile);
|
||||
|
||||
if (mShouldStop || job->mTryNumber > 2)
|
||||
return;
|
||||
|
||||
const std::lock_guard<std::mutex> lock(mMutex);
|
||||
|
||||
if (mPushed.emplace(job->mAgentHalfExtents, job->mChangedTile).second)
|
||||
if (mPushed.emplace(job->mAgentBounds, job->mChangedTile).second)
|
||||
{
|
||||
++job->mTryNumber;
|
||||
insertPrioritizedJob(job, mWaiting);
|
||||
@ -622,17 +622,17 @@ namespace DetourNavigator
|
||||
mJobs.erase(job);
|
||||
}
|
||||
|
||||
bool AsyncNavMeshUpdater::lockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile)
|
||||
bool AsyncNavMeshUpdater::lockTile(const AgentBounds& agentBounds, const TilePosition& changedTile)
|
||||
{
|
||||
Log(Debug::Debug) << "Locking tile agent=(" << agentHalfExtents << ") changedTile=(" << changedTile << ")";
|
||||
return mProcessingTiles.lock()->emplace(agentHalfExtents, changedTile).second;
|
||||
Log(Debug::Debug) << "Locking tile agent=" << agentBounds << " changedTile=(" << changedTile << ")";
|
||||
return mProcessingTiles.lock()->emplace(agentBounds, changedTile).second;
|
||||
}
|
||||
|
||||
void AsyncNavMeshUpdater::unlockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile)
|
||||
void AsyncNavMeshUpdater::unlockTile(const AgentBounds& agentBounds, const TilePosition& changedTile)
|
||||
{
|
||||
auto locked = mProcessingTiles.lock();
|
||||
locked->erase(std::tie(agentHalfExtents, changedTile));
|
||||
Log(Debug::Debug) << "Unlocked tile agent=(" << agentHalfExtents << ") changedTile=(" << changedTile << ")";
|
||||
locked->erase(std::tie(agentBounds, changedTile));
|
||||
Log(Debug::Debug) << "Unlocked tile agent=" << agentBounds << " changedTile=(" << changedTile << ")";
|
||||
if (locked->empty())
|
||||
mProcessed.notify_all();
|
||||
}
|
||||
@ -819,7 +819,7 @@ namespace DetourNavigator
|
||||
{
|
||||
const auto objects = makeDbRefGeometryObjects(job->mRecastMesh->getMeshSources(),
|
||||
[&] (const MeshSource& v) { return resolveMeshSource(*mDb, v, mNextShapeId); });
|
||||
job->mInput = serialize(mRecastSettings, *job->mRecastMesh, objects);
|
||||
job->mInput = serialize(mRecastSettings, job->mAgentBounds, *job->mRecastMesh, objects);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -827,7 +827,7 @@ namespace DetourNavigator
|
||||
[&] (const MeshSource& v) { return resolveMeshSource(*mDb, v); });
|
||||
if (!objects.has_value())
|
||||
return;
|
||||
job->mInput = serialize(mRecastSettings, *job->mRecastMesh, *objects);
|
||||
job->mInput = serialize(mRecastSettings, job->mAgentBounds, *job->mRecastMesh, *objects);
|
||||
}
|
||||
}
|
||||
|
||||
@ -850,7 +850,7 @@ namespace DetourNavigator
|
||||
Log(Debug::Debug) << "Serializing input for job " << job->mId;
|
||||
const std::vector<DbRefGeometryObject> objects = makeDbRefGeometryObjects(job->mRecastMesh->getMeshSources(),
|
||||
[&] (const MeshSource& v) { return resolveMeshSource(*mDb, v, mNextShapeId); });
|
||||
job->mInput = serialize(mRecastSettings, *job->mRecastMesh, objects);
|
||||
job->mInput = serialize(mRecastSettings, job->mAgentBounds, *job->mRecastMesh, objects);
|
||||
}
|
||||
|
||||
if (const auto& cachedTileData = job->mCachedTileData)
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "waitconditiontype.hpp"
|
||||
#include "navmeshdb.hpp"
|
||||
#include "changetype.hpp"
|
||||
#include "agentbounds.hpp"
|
||||
|
||||
#include <osg/Vec3f>
|
||||
|
||||
@ -42,7 +43,7 @@ namespace DetourNavigator
|
||||
struct Job
|
||||
{
|
||||
const std::size_t mId;
|
||||
const osg::Vec3f mAgentHalfExtents;
|
||||
const AgentBounds mAgentBounds;
|
||||
const std::weak_ptr<GuardedNavMeshCacheItem> mNavMeshCacheItem;
|
||||
const std::string mWorldspace;
|
||||
const TilePosition mChangedTile;
|
||||
@ -57,7 +58,7 @@ namespace DetourNavigator
|
||||
std::optional<TileData> mCachedTileData;
|
||||
std::unique_ptr<PreparedNavMeshData> mGeneratedNavMeshData;
|
||||
|
||||
Job(const osg::Vec3f& agentHalfExtents, std::weak_ptr<GuardedNavMeshCacheItem> navMeshCacheItem,
|
||||
Job(const AgentBounds& agentBounds, std::weak_ptr<GuardedNavMeshCacheItem> navMeshCacheItem,
|
||||
std::string_view worldspace, const TilePosition& changedTile, ChangeType changeType, int distanceToPlayer,
|
||||
std::chrono::steady_clock::time_point processTime);
|
||||
};
|
||||
@ -166,7 +167,7 @@ namespace DetourNavigator
|
||||
OffMeshConnectionsManager& offMeshConnectionsManager, std::unique_ptr<NavMeshDb>&& db);
|
||||
~AsyncNavMeshUpdater();
|
||||
|
||||
void post(const osg::Vec3f& agentHalfExtents, const SharedNavMeshCacheItem& navMeshCacheItem,
|
||||
void post(const AgentBounds& agentBounds, const SharedNavMeshCacheItem& navMeshCacheItem,
|
||||
const TilePosition& playerTile, std::string_view worldspace,
|
||||
const std::map<TilePosition, ChangeType>& changedTiles);
|
||||
|
||||
@ -191,12 +192,12 @@ namespace DetourNavigator
|
||||
std::condition_variable mProcessed;
|
||||
std::list<Job> mJobs;
|
||||
std::deque<JobIt> mWaiting;
|
||||
std::set<std::tuple<osg::Vec3f, TilePosition>> mPushed;
|
||||
std::set<std::tuple<AgentBounds, TilePosition>> mPushed;
|
||||
Misc::ScopeGuarded<TilePosition> mPlayerTile;
|
||||
NavMeshTilesCache mNavMeshTilesCache;
|
||||
Misc::ScopeGuarded<std::set<std::tuple<osg::Vec3f, TilePosition>>> mProcessingTiles;
|
||||
std::map<std::tuple<osg::Vec3f, TilePosition>, std::chrono::steady_clock::time_point> mLastUpdates;
|
||||
std::set<std::tuple<osg::Vec3f, TilePosition>> mPresentTiles;
|
||||
Misc::ScopeGuarded<std::set<std::tuple<AgentBounds, TilePosition>>> mProcessingTiles;
|
||||
std::map<std::tuple<AgentBounds, TilePosition>, std::chrono::steady_clock::time_point> mLastUpdates;
|
||||
std::set<std::tuple<AgentBounds, TilePosition>> mPresentTiles;
|
||||
std::vector<std::thread> mThreads;
|
||||
std::unique_ptr<DbWorker> mDbWorker;
|
||||
std::atomic_size_t mDbGetTileHits {0};
|
||||
@ -220,9 +221,9 @@ namespace DetourNavigator
|
||||
|
||||
void repost(JobIt job);
|
||||
|
||||
bool lockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile);
|
||||
bool lockTile(const AgentBounds& agentBounds, const TilePosition& changedTile);
|
||||
|
||||
void unlockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile);
|
||||
void unlockTile(const AgentBounds& agentBounds, const TilePosition& changedTile);
|
||||
|
||||
inline std::size_t getTotalJobs() const;
|
||||
|
||||
|
17
components/detournavigator/collisionshapetype.hpp
Normal file
17
components/detournavigator/collisionshapetype.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_COLLISIONSHAPETYPE_H
|
||||
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_COLLISIONSHAPETYPE_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
enum class CollisionShapeType : std::uint8_t
|
||||
{
|
||||
Aabb = 0,
|
||||
RotatingBox = 1,
|
||||
};
|
||||
|
||||
inline constexpr CollisionShapeType defaultCollisionShapeType = CollisionShapeType::Aabb;
|
||||
}
|
||||
|
||||
#endif
|
@ -4,6 +4,7 @@
|
||||
#include "tilebounds.hpp"
|
||||
#include "status.hpp"
|
||||
#include "recastmesh.hpp"
|
||||
#include "agentbounds.hpp"
|
||||
|
||||
#include <osg/io_utils>
|
||||
|
||||
@ -69,6 +70,21 @@ namespace DetourNavigator
|
||||
return s << ", .mOriginalSize=" << v.mOriginalSize << "}";
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& s, CollisionShapeType v)
|
||||
{
|
||||
switch (v)
|
||||
{
|
||||
case CollisionShapeType::Aabb: return s << "AgentShapeType::Aabb";
|
||||
case CollisionShapeType::RotatingBox: return s << "AgentShapeType::RotatingBox";
|
||||
}
|
||||
return s << "AgentShapeType::" << static_cast<std::underlying_type_t<CollisionShapeType>>(v);
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& s, const AgentBounds& v)
|
||||
{
|
||||
return s << "AgentBounds {" << v.mShapeType << ", " << v.mHalfExtents << "}";
|
||||
}
|
||||
|
||||
class RecastMesh;
|
||||
struct RecastSettings;
|
||||
|
||||
|
@ -38,12 +38,12 @@ namespace DetourNavigator
|
||||
}
|
||||
|
||||
GenerateNavMeshTile::GenerateNavMeshTile(std::string worldspace, const TilePosition& tilePosition,
|
||||
RecastMeshProvider recastMeshProvider, const osg::Vec3f& agentHalfExtents,
|
||||
RecastMeshProvider recastMeshProvider, const AgentBounds& agentBounds,
|
||||
const DetourNavigator::Settings& settings, std::weak_ptr<NavMeshTileConsumer> consumer)
|
||||
: mWorldspace(std::move(worldspace))
|
||||
, mTilePosition(tilePosition)
|
||||
, mRecastMeshProvider(recastMeshProvider)
|
||||
, mAgentHalfExtents(agentHalfExtents)
|
||||
, mAgentBounds(agentBounds)
|
||||
, mSettings(settings)
|
||||
, mConsumer(std::move(consumer)) {}
|
||||
|
||||
@ -70,25 +70,25 @@ namespace DetourNavigator
|
||||
|
||||
const std::vector<DbRefGeometryObject> objects = makeDbRefGeometryObjects(recastMesh->getMeshSources(),
|
||||
[&] (const MeshSource& v) { return consumer->resolveMeshSource(v); });
|
||||
std::vector<std::byte> input = serialize(mSettings.mRecast, *recastMesh, objects);
|
||||
std::vector<std::byte> input = serialize(mSettings.mRecast, mAgentBounds, *recastMesh, objects);
|
||||
const std::optional<NavMeshTileInfo> info = consumer->find(mWorldspace, mTilePosition, input);
|
||||
|
||||
if (info.has_value() && info->mVersion == mSettings.mNavMeshVersion)
|
||||
if (info.has_value() && info->mVersion == navMeshVersion)
|
||||
{
|
||||
consumer->identity(mWorldspace, mTilePosition, info->mTileId);
|
||||
ignore.mConsumer = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto data = prepareNavMeshTileData(*recastMesh, mTilePosition, mAgentHalfExtents, mSettings.mRecast);
|
||||
const auto data = prepareNavMeshTileData(*recastMesh, mTilePosition, mAgentBounds, mSettings.mRecast);
|
||||
|
||||
if (data == nullptr)
|
||||
return;
|
||||
|
||||
if (info.has_value())
|
||||
consumer->update(mWorldspace, mTilePosition, info->mTileId, mSettings.mNavMeshVersion, *data);
|
||||
consumer->update(mWorldspace, mTilePosition, info->mTileId, navMeshVersion, *data);
|
||||
else
|
||||
consumer->insert(mWorldspace, mTilePosition, mSettings.mNavMeshVersion, input, *data);
|
||||
consumer->insert(mWorldspace, mTilePosition, navMeshVersion, input, *data);
|
||||
|
||||
ignore.mConsumer = nullptr;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "recastmeshprovider.hpp"
|
||||
#include "tileposition.hpp"
|
||||
#include "agentbounds.hpp"
|
||||
|
||||
#include <components/sceneutil/workqueue.hpp>
|
||||
|
||||
@ -57,7 +58,7 @@ namespace DetourNavigator
|
||||
{
|
||||
public:
|
||||
GenerateNavMeshTile(std::string worldspace, const TilePosition& tilePosition,
|
||||
RecastMeshProvider recastMeshProvider, const osg::Vec3f& agentHalfExtents, const Settings& settings,
|
||||
RecastMeshProvider recastMeshProvider, const AgentBounds& agentBounds, const Settings& settings,
|
||||
std::weak_ptr<NavMeshTileConsumer> consumer);
|
||||
|
||||
void doWork() final;
|
||||
@ -66,7 +67,7 @@ namespace DetourNavigator
|
||||
const std::string mWorldspace;
|
||||
const TilePosition mTilePosition;
|
||||
const RecastMeshProvider mRecastMeshProvider;
|
||||
const osg::Vec3f mAgentHalfExtents;
|
||||
const AgentBounds mAgentBounds;
|
||||
const Settings& mSettings;
|
||||
std::weak_ptr<NavMeshTileConsumer> mConsumer;
|
||||
|
||||
|
@ -101,9 +101,9 @@ namespace
|
||||
return result;
|
||||
}
|
||||
|
||||
float getHeight(const RecastSettings& settings,const osg::Vec3f& agentHalfExtents)
|
||||
float getHeight(const RecastSettings& settings,const AgentBounds& agentBounds)
|
||||
{
|
||||
return getAgentHeight(agentHalfExtents) * settings.mRecastScaleFactor;
|
||||
return getAgentHeight(agentBounds) * settings.mRecastScaleFactor;
|
||||
}
|
||||
|
||||
float getMaxClimb(const RecastSettings& settings)
|
||||
@ -111,14 +111,14 @@ namespace
|
||||
return settings.mMaxClimb * settings.mRecastScaleFactor;
|
||||
}
|
||||
|
||||
float getRadius(const RecastSettings& settings, const osg::Vec3f& agentHalfExtents)
|
||||
float getRadius(const RecastSettings& settings, const AgentBounds& agentBounds)
|
||||
{
|
||||
return getAgentRadius(agentHalfExtents) * settings.mRecastScaleFactor;
|
||||
return getAgentRadius(agentBounds) * settings.mRecastScaleFactor;
|
||||
}
|
||||
|
||||
float getSwimLevel(const RecastSettings& settings, const float waterLevel, const float agentHalfExtentsZ)
|
||||
{
|
||||
return waterLevel - settings.mSwimHeightScale * agentHalfExtentsZ - agentHalfExtentsZ;;
|
||||
return waterLevel - settings.mSwimHeightScale * agentHalfExtentsZ - agentHalfExtentsZ;
|
||||
}
|
||||
|
||||
struct RecastParams
|
||||
@ -131,13 +131,13 @@ namespace
|
||||
int mWalkableRadius = 0;
|
||||
};
|
||||
|
||||
RecastParams makeRecastParams(const RecastSettings& settings, const osg::Vec3f& agentHalfExtents)
|
||||
RecastParams makeRecastParams(const RecastSettings& settings, const AgentBounds& agentBounds)
|
||||
{
|
||||
RecastParams result;
|
||||
|
||||
result.mWalkableHeight = static_cast<int>(std::ceil(getHeight(settings, agentHalfExtents) / settings.mCellHeight));
|
||||
result.mWalkableHeight = static_cast<int>(std::ceil(getHeight(settings, agentBounds) / settings.mCellHeight));
|
||||
result.mWalkableClimb = static_cast<int>(std::floor(getMaxClimb(settings) / settings.mCellHeight));
|
||||
result.mWalkableRadius = static_cast<int>(std::ceil(getRadius(settings, agentHalfExtents) / settings.mCellSize));
|
||||
result.mWalkableRadius = static_cast<int>(std::ceil(getRadius(settings, agentBounds) / settings.mCellSize));
|
||||
result.mMaxEdgeLen = static_cast<int>(std::round(static_cast<float>(settings.mMaxEdgeLen) / settings.mCellSize));
|
||||
result.mSampleDist = settings.mDetailSampleDist < 0.9f ? 0 : settings.mCellSize * settings.mDetailSampleDist;
|
||||
result.mSampleMaxError = settings.mCellHeight * settings.mDetailSampleMaxError;
|
||||
@ -227,7 +227,7 @@ namespace
|
||||
);
|
||||
}
|
||||
|
||||
bool rasterizeTriangles(rcContext& context, const osg::Vec3f& agentHalfExtents, const std::vector<CellWater>& water,
|
||||
bool rasterizeTriangles(rcContext& context, float agentHalfExtentsZ, const std::vector<CellWater>& water,
|
||||
const RecastSettings& settings, const RecastParams& params, const TileBounds& realTileBounds, rcHeightfield& solid)
|
||||
{
|
||||
for (const CellWater& cellWater : water)
|
||||
@ -237,7 +237,7 @@ namespace
|
||||
{
|
||||
const Rectangle rectangle {
|
||||
toNavMeshCoordinates(settings, *intersection),
|
||||
toNavMeshCoordinates(settings, getSwimLevel(settings, cellWater.mWater.mLevel, agentHalfExtents.z()))
|
||||
toNavMeshCoordinates(settings, getSwimLevel(settings, cellWater.mWater.mLevel, agentHalfExtentsZ))
|
||||
};
|
||||
if (!rasterizeTriangles(context, rectangle, AreaType_water, params, solid))
|
||||
return false;
|
||||
@ -277,12 +277,12 @@ namespace
|
||||
return true;
|
||||
}
|
||||
|
||||
bool rasterizeTriangles(rcContext& context, const TilePosition& tilePosition, const osg::Vec3f& agentHalfExtents,
|
||||
bool rasterizeTriangles(rcContext& context, const TilePosition& tilePosition, float agentHalfExtentsZ,
|
||||
const RecastMesh& recastMesh, const RecastSettings& settings, const RecastParams& params, rcHeightfield& solid)
|
||||
{
|
||||
const TileBounds realTileBounds = makeRealTileBoundsWithBorder(settings, tilePosition);
|
||||
return rasterizeTriangles(context, recastMesh.getMesh(), settings, params, solid)
|
||||
&& rasterizeTriangles(context, agentHalfExtents, recastMesh.getWater(), settings, params, realTileBounds, solid)
|
||||
&& rasterizeTriangles(context, agentHalfExtentsZ, recastMesh.getWater(), settings, params, realTileBounds, solid)
|
||||
&& rasterizeTriangles(context, recastMesh.getHeightfields(), settings, params, solid)
|
||||
&& rasterizeTriangles(context, realTileBounds, recastMesh.getFlatHeightfields(), settings, params, solid);
|
||||
}
|
||||
@ -389,7 +389,7 @@ namespace
|
||||
return power;
|
||||
}
|
||||
|
||||
std::pair<float, float> getBoundsByZ(const RecastMesh& recastMesh, const osg::Vec3f& agentHalfExtents, const RecastSettings& settings)
|
||||
std::pair<float, float> getBoundsByZ(const RecastMesh& recastMesh, float agentHalfExtentsZ, const RecastSettings& settings)
|
||||
{
|
||||
float minZ = 0;
|
||||
float maxZ = 0;
|
||||
@ -403,7 +403,7 @@ namespace
|
||||
|
||||
for (const CellWater& water : recastMesh.getWater())
|
||||
{
|
||||
const float swimLevel = getSwimLevel(settings, water.mWater.mLevel, agentHalfExtents.z());
|
||||
const float swimLevel = getSwimLevel(settings, water.mWater.mLevel, agentHalfExtentsZ);
|
||||
minZ = std::min(minZ, swimLevel);
|
||||
maxZ = std::max(maxZ, swimLevel);
|
||||
}
|
||||
@ -431,19 +431,19 @@ namespace
|
||||
namespace DetourNavigator
|
||||
{
|
||||
std::unique_ptr<PreparedNavMeshData> prepareNavMeshTileData(const RecastMesh& recastMesh,
|
||||
const TilePosition& tilePosition, const osg::Vec3f& agentHalfExtents, const RecastSettings& settings)
|
||||
const TilePosition& tilePosition, const AgentBounds& agentBounds, const RecastSettings& settings)
|
||||
{
|
||||
rcContext context;
|
||||
|
||||
const auto [minZ, maxZ] = getBoundsByZ(recastMesh, agentHalfExtents, settings);
|
||||
const auto [minZ, maxZ] = getBoundsByZ(recastMesh, agentBounds.mHalfExtents.z(), settings);
|
||||
|
||||
rcHeightfield solid;
|
||||
initHeightfield(context, tilePosition, toNavMeshCoordinates(settings, minZ),
|
||||
toNavMeshCoordinates(settings, maxZ), settings, solid);
|
||||
|
||||
const RecastParams params = makeRecastParams(settings, agentHalfExtents);
|
||||
const RecastParams params = makeRecastParams(settings, agentBounds);
|
||||
|
||||
if (!rasterizeTriangles(context, tilePosition, agentHalfExtents, recastMesh, settings, params, solid))
|
||||
if (!rasterizeTriangles(context, tilePosition, agentBounds.mHalfExtents.z(), recastMesh, settings, params, solid))
|
||||
return nullptr;
|
||||
|
||||
rcFilterLowHangingWalkableObstacles(&context, params.mWalkableClimb, solid);
|
||||
@ -462,11 +462,11 @@ namespace DetourNavigator
|
||||
}
|
||||
|
||||
NavMeshData makeNavMeshTileData(const PreparedNavMeshData& data,
|
||||
const std::vector<OffMeshConnection>& offMeshConnections, const osg::Vec3f& agentHalfExtents,
|
||||
const std::vector<OffMeshConnection>& offMeshConnections, const AgentBounds& agentBounds,
|
||||
const TilePosition& tile, const RecastSettings& settings)
|
||||
{
|
||||
const auto offMeshConVerts = getOffMeshVerts(offMeshConnections);
|
||||
const std::vector<float> offMeshConRad(offMeshConnections.size(), getRadius(settings, agentHalfExtents));
|
||||
const std::vector<float> offMeshConRad(offMeshConnections.size(), getRadius(settings, agentBounds));
|
||||
const std::vector<unsigned char> offMeshConDir(offMeshConnections.size(), 0);
|
||||
const std::vector<unsigned char> offMeshConAreas = getOffMeshConAreas(offMeshConnections);
|
||||
const std::vector<unsigned short> offMeshConFlags = getOffMeshFlags(offMeshConnections);
|
||||
@ -491,8 +491,8 @@ namespace DetourNavigator
|
||||
params.offMeshConFlags = offMeshConFlags.data();
|
||||
params.offMeshConUserID = nullptr;
|
||||
params.offMeshConCount = static_cast<int>(offMeshConnections.size());
|
||||
params.walkableHeight = getHeight(settings, agentHalfExtents);
|
||||
params.walkableRadius = getRadius(settings, agentHalfExtents);
|
||||
params.walkableHeight = getHeight(settings, agentBounds);
|
||||
params.walkableRadius = getRadius(settings, agentBounds);
|
||||
params.walkableClimb = getMaxClimb(settings);
|
||||
rcVcopy(params.bmin, data.mPolyMesh.bmin);
|
||||
rcVcopy(params.bmax, data.mPolyMesh.bmax);
|
||||
|
@ -51,10 +51,10 @@ namespace DetourNavigator
|
||||
}
|
||||
|
||||
std::unique_ptr<PreparedNavMeshData> prepareNavMeshTileData(const RecastMesh& recastMesh,
|
||||
const TilePosition& tilePosition, const osg::Vec3f& agentHalfExtents, const RecastSettings& settings);
|
||||
const TilePosition& tilePosition, const AgentBounds& agentBounds, const RecastSettings& settings);
|
||||
|
||||
NavMeshData makeNavMeshTileData(const PreparedNavMeshData& data,
|
||||
const std::vector<OffMeshConnection>& offMeshConnections, const osg::Vec3f& agentHalfExtents,
|
||||
const std::vector<OffMeshConnection>& offMeshConnections, const AgentBounds& agentBounds,
|
||||
const TilePosition& tile, const RecastSettings& settings);
|
||||
|
||||
NavMeshPtr makeEmptyNavMesh(const Settings& settings);
|
||||
|
@ -26,6 +26,7 @@ namespace Loading
|
||||
namespace DetourNavigator
|
||||
{
|
||||
struct Settings;
|
||||
struct AgentBounds;
|
||||
|
||||
struct ObjectShapes
|
||||
{
|
||||
@ -66,16 +67,16 @@ namespace DetourNavigator
|
||||
|
||||
/**
|
||||
* @brief addAgent should be called for each agent even if all of them has same half extents.
|
||||
* @param agentHalfExtents 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.
|
||||
*/
|
||||
virtual void addAgent(const osg::Vec3f& agentHalfExtents) = 0;
|
||||
virtual void addAgent(const AgentBounds& agentBounds) = 0;
|
||||
|
||||
/**
|
||||
* @brief removeAgent should be called for each agent even if all of them has same half extents
|
||||
* @param agentHalfExtents allows determine which agent to remove
|
||||
* @param agentBounds allows determine which agent to remove
|
||||
*/
|
||||
virtual void removeAgent(const osg::Vec3f& agentHalfExtents) = 0;
|
||||
virtual void removeAgent(const AgentBounds& agentBounds) = 0;
|
||||
|
||||
/**
|
||||
* @brief setWorldspace should be called before adding object from new worldspace
|
||||
@ -185,13 +186,13 @@ namespace DetourNavigator
|
||||
* @brief getNavMesh returns navmesh for specific agent half extents
|
||||
* @return navmesh
|
||||
*/
|
||||
virtual SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& agentHalfExtents) const = 0;
|
||||
virtual SharedNavMeshCacheItem getNavMesh(const AgentBounds& agentBounds) const = 0;
|
||||
|
||||
/**
|
||||
* @brief getNavMeshes returns all current navmeshes
|
||||
* @return map of agent half extents to navmesh
|
||||
*/
|
||||
virtual std::map<osg::Vec3f, SharedNavMeshCacheItem> getNavMeshes() const = 0;
|
||||
virtual std::map<AgentBounds, SharedNavMeshCacheItem> getNavMeshes() const = 0;
|
||||
|
||||
virtual const Settings& getSettings() const = 0;
|
||||
|
||||
|
@ -16,17 +16,17 @@ namespace DetourNavigator
|
||||
{
|
||||
}
|
||||
|
||||
void NavigatorImpl::addAgent(const osg::Vec3f& agentHalfExtents)
|
||||
void NavigatorImpl::addAgent(const AgentBounds& agentBounds)
|
||||
{
|
||||
if(agentHalfExtents.length2() <= 0)
|
||||
if(agentBounds.mHalfExtents.length2() <= 0)
|
||||
return;
|
||||
++mAgents[agentHalfExtents];
|
||||
mNavMeshManager.addAgent(agentHalfExtents);
|
||||
++mAgents[agentBounds];
|
||||
mNavMeshManager.addAgent(agentBounds);
|
||||
}
|
||||
|
||||
void NavigatorImpl::removeAgent(const osg::Vec3f& agentHalfExtents)
|
||||
void NavigatorImpl::removeAgent(const AgentBounds& agentBounds)
|
||||
{
|
||||
const auto it = mAgents.find(agentHalfExtents);
|
||||
const auto it = mAgents.find(agentBounds);
|
||||
if (it == mAgents.end())
|
||||
return;
|
||||
if (it->second > 0)
|
||||
@ -178,12 +178,12 @@ namespace DetourNavigator
|
||||
mNavMeshManager.wait(listener, waitConditionType);
|
||||
}
|
||||
|
||||
SharedNavMeshCacheItem NavigatorImpl::getNavMesh(const osg::Vec3f& agentHalfExtents) const
|
||||
SharedNavMeshCacheItem NavigatorImpl::getNavMesh(const AgentBounds& agentBounds) const
|
||||
{
|
||||
return mNavMeshManager.getNavMesh(agentHalfExtents);
|
||||
return mNavMeshManager.getNavMesh(agentBounds);
|
||||
}
|
||||
|
||||
std::map<osg::Vec3f, SharedNavMeshCacheItem> NavigatorImpl::getNavMeshes() const
|
||||
std::map<AgentBounds, SharedNavMeshCacheItem> NavigatorImpl::getNavMeshes() const
|
||||
{
|
||||
return mNavMeshManager.getNavMeshes();
|
||||
}
|
||||
|
@ -18,9 +18,9 @@ namespace DetourNavigator
|
||||
*/
|
||||
explicit NavigatorImpl(const Settings& settings, std::unique_ptr<NavMeshDb>&& db);
|
||||
|
||||
void addAgent(const osg::Vec3f& agentHalfExtents) override;
|
||||
void addAgent(const AgentBounds& agentBounds) override;
|
||||
|
||||
void removeAgent(const osg::Vec3f& agentHalfExtents) override;
|
||||
void removeAgent(const AgentBounds& agentBounds) override;
|
||||
|
||||
void setWorldspace(std::string_view worldspace) override;
|
||||
|
||||
@ -56,9 +56,9 @@ namespace DetourNavigator
|
||||
|
||||
void wait(Loading::Listener& listener, WaitConditionType waitConditionType) override;
|
||||
|
||||
SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& agentHalfExtents) const override;
|
||||
SharedNavMeshCacheItem getNavMesh(const AgentBounds& agentBounds) const override;
|
||||
|
||||
std::map<osg::Vec3f, SharedNavMeshCacheItem> getNavMeshes() const override;
|
||||
std::map<AgentBounds, SharedNavMeshCacheItem> getNavMeshes() const override;
|
||||
|
||||
const Settings& getSettings() const override;
|
||||
|
||||
@ -73,7 +73,7 @@ namespace DetourNavigator
|
||||
NavMeshManager mNavMeshManager;
|
||||
bool mUpdatesEnabled;
|
||||
std::optional<TilePosition> mLastPlayerPosition;
|
||||
std::map<osg::Vec3f, std::size_t> mAgents;
|
||||
std::map<AgentBounds, std::size_t> mAgents;
|
||||
std::unordered_map<ObjectId, ObjectId> mAvoidIds;
|
||||
std::unordered_map<ObjectId, ObjectId> mWaterIds;
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_NAVIGATORSTUB_H
|
||||
|
||||
#include "navigator.hpp"
|
||||
#include "settings.hpp"
|
||||
|
||||
namespace Loading
|
||||
{
|
||||
@ -15,9 +16,9 @@ namespace DetourNavigator
|
||||
public:
|
||||
NavigatorStub() = default;
|
||||
|
||||
void addAgent(const osg::Vec3f& /*agentHalfExtents*/) override {}
|
||||
void addAgent(const AgentBounds& /*agentBounds*/) override {}
|
||||
|
||||
void removeAgent(const osg::Vec3f& /*agentHalfExtents*/) override {}
|
||||
void removeAgent(const AgentBounds& /*agentBounds*/) override {}
|
||||
|
||||
void setWorldspace(std::string_view /*worldspace*/) override {}
|
||||
|
||||
@ -80,14 +81,14 @@ namespace DetourNavigator
|
||||
|
||||
void wait(Loading::Listener& /*listener*/, WaitConditionType /*waitConditionType*/) override {}
|
||||
|
||||
SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& /*agentHalfExtents*/) const override
|
||||
SharedNavMeshCacheItem getNavMesh(const AgentBounds& /*agentBounds*/) const override
|
||||
{
|
||||
return mEmptyNavMeshCacheItem;
|
||||
}
|
||||
|
||||
std::map<osg::Vec3f, SharedNavMeshCacheItem> getNavMeshes() const override
|
||||
std::map<AgentBounds, SharedNavMeshCacheItem> getNavMeshes() const override
|
||||
{
|
||||
return std::map<osg::Vec3f, SharedNavMeshCacheItem>();
|
||||
return {};
|
||||
}
|
||||
|
||||
const Settings& getSettings() const override
|
||||
|
@ -5,30 +5,30 @@
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
std::optional<osg::Vec3f> findRandomPointAroundCircle(const Navigator& navigator, const osg::Vec3f& agentHalfExtents,
|
||||
std::optional<osg::Vec3f> findRandomPointAroundCircle(const Navigator& navigator, const AgentBounds& agentBounds,
|
||||
const osg::Vec3f& start, const float maxRadius, const Flags includeFlags, float(*prng)())
|
||||
{
|
||||
const auto navMesh = navigator.getNavMesh(agentHalfExtents);
|
||||
const auto navMesh = navigator.getNavMesh(agentBounds);
|
||||
if (!navMesh)
|
||||
return std::nullopt;
|
||||
const auto& settings = navigator.getSettings();
|
||||
const auto result = DetourNavigator::findRandomPointAroundCircle(navMesh->lockConst()->getImpl(),
|
||||
toNavMeshCoordinates(settings.mRecast, agentHalfExtents), toNavMeshCoordinates(settings.mRecast, start),
|
||||
toNavMeshCoordinates(settings.mRecast, agentBounds.mHalfExtents), toNavMeshCoordinates(settings.mRecast, start),
|
||||
toNavMeshCoordinates(settings.mRecast, maxRadius), includeFlags, settings.mDetour, prng);
|
||||
if (!result)
|
||||
return std::nullopt;
|
||||
return std::optional<osg::Vec3f>(fromNavMeshCoordinates(settings.mRecast, *result));
|
||||
}
|
||||
|
||||
std::optional<osg::Vec3f> raycast(const Navigator& navigator, const osg::Vec3f& agentHalfExtents, const osg::Vec3f& start,
|
||||
std::optional<osg::Vec3f> raycast(const Navigator& navigator, const AgentBounds& agentBounds, const osg::Vec3f& start,
|
||||
const osg::Vec3f& end, const Flags includeFlags)
|
||||
{
|
||||
const auto navMesh = navigator.getNavMesh(agentHalfExtents);
|
||||
const auto navMesh = navigator.getNavMesh(agentBounds);
|
||||
if (navMesh == nullptr)
|
||||
return std::nullopt;
|
||||
const auto& settings = navigator.getSettings();
|
||||
const auto result = DetourNavigator::raycast(navMesh->lockConst()->getImpl(),
|
||||
toNavMeshCoordinates(settings.mRecast, agentHalfExtents), toNavMeshCoordinates(settings.mRecast, start),
|
||||
toNavMeshCoordinates(settings.mRecast, agentBounds.mHalfExtents), toNavMeshCoordinates(settings.mRecast, start),
|
||||
toNavMeshCoordinates(settings.mRecast, end), includeFlags, settings.mDetour);
|
||||
if (!result)
|
||||
return std::nullopt;
|
||||
|
@ -12,7 +12,7 @@ namespace DetourNavigator
|
||||
{
|
||||
/**
|
||||
* @brief findPath fills output iterator with points of scene surfaces to be used for actor to walk through.
|
||||
* @param agentHalfExtents allows to find navmesh for given actor.
|
||||
* @param agentBounds allows to find navmesh for given actor.
|
||||
* @param start path from given point.
|
||||
* @param end path at given point.
|
||||
* @param includeFlags setup allowed surfaces for actor to walk.
|
||||
@ -22,8 +22,8 @@ namespace DetourNavigator
|
||||
* Equal to out if no path is found.
|
||||
*/
|
||||
template <class OutputIterator>
|
||||
inline Status findPath(const Navigator& navigator, const osg::Vec3f& agentHalfExtents, const float stepSize, const osg::Vec3f& start,
|
||||
const osg::Vec3f& end, const Flags includeFlags, const DetourNavigator::AreaCosts& areaCosts,
|
||||
inline Status findPath(const Navigator& navigator, const AgentBounds& agentBounds, const float stepSize,
|
||||
const osg::Vec3f& start, const osg::Vec3f& end, const Flags includeFlags, const AreaCosts& areaCosts,
|
||||
float endTolerance, OutputIterator& out)
|
||||
{
|
||||
static_assert(
|
||||
@ -33,35 +33,35 @@ namespace DetourNavigator
|
||||
>::value,
|
||||
"out is not an OutputIterator"
|
||||
);
|
||||
const auto navMesh = navigator.getNavMesh(agentHalfExtents);
|
||||
const auto navMesh = navigator.getNavMesh(agentBounds);
|
||||
if (navMesh == nullptr)
|
||||
return Status::NavMeshNotFound;
|
||||
const auto settings = navigator.getSettings();
|
||||
return findSmoothPath(navMesh->lockConst()->getImpl(), toNavMeshCoordinates(settings.mRecast, agentHalfExtents),
|
||||
return findSmoothPath(navMesh->lockConst()->getImpl(), toNavMeshCoordinates(settings.mRecast, agentBounds.mHalfExtents),
|
||||
toNavMeshCoordinates(settings.mRecast, stepSize), toNavMeshCoordinates(settings.mRecast, start),
|
||||
toNavMeshCoordinates(settings.mRecast, end), includeFlags, areaCosts, settings, endTolerance, out);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief findRandomPointAroundCircle returns random location on navmesh within the reach of specified location.
|
||||
* @param agentHalfExtents allows to find navmesh for given actor.
|
||||
* @param agentBounds allows to find navmesh for given actor.
|
||||
* @param start path from given point.
|
||||
* @param maxRadius limit maximum distance from start.
|
||||
* @param includeFlags setup allowed surfaces for actor to walk.
|
||||
* @return not empty optional with position if point is found and empty optional if point is not found.
|
||||
*/
|
||||
std::optional<osg::Vec3f> findRandomPointAroundCircle(const Navigator& navigator, const osg::Vec3f& agentHalfExtents,
|
||||
std::optional<osg::Vec3f> findRandomPointAroundCircle(const Navigator& navigator, const AgentBounds& agentBounds,
|
||||
const osg::Vec3f& start, const float maxRadius, const Flags includeFlags, float(*prng)());
|
||||
|
||||
/**
|
||||
* @brief raycast finds farest navmesh point from start on a line from start to end that has path from start.
|
||||
* @param agentHalfExtents allows to find navmesh for given actor.
|
||||
* @param agentBounds allows to find navmesh for given actor.
|
||||
* @param start of the line
|
||||
* @param end of the line
|
||||
* @param includeFlags setup allowed surfaces for actor to walk.
|
||||
* @return not empty optional with position if point is found and empty optional if point is not found.
|
||||
*/
|
||||
std::optional<osg::Vec3f> raycast(const Navigator& navigator, const osg::Vec3f& agentHalfExtents, const osg::Vec3f& start,
|
||||
std::optional<osg::Vec3f> raycast(const Navigator& navigator, const AgentBounds& agentBounds, const osg::Vec3f& start,
|
||||
const osg::Vec3f& end, const Flags includeFlags);
|
||||
}
|
||||
|
||||
|
@ -151,27 +151,27 @@ namespace DetourNavigator
|
||||
return true;
|
||||
}
|
||||
|
||||
void NavMeshManager::addAgent(const osg::Vec3f& agentHalfExtents)
|
||||
void NavMeshManager::addAgent(const AgentBounds& agentBounds)
|
||||
{
|
||||
auto cached = mCache.find(agentHalfExtents);
|
||||
auto cached = mCache.find(agentBounds);
|
||||
if (cached != mCache.end())
|
||||
return;
|
||||
mCache.insert(std::make_pair(agentHalfExtents,
|
||||
mCache.insert(std::make_pair(agentBounds,
|
||||
std::make_shared<GuardedNavMeshCacheItem>(makeEmptyNavMesh(mSettings), ++mGenerationCounter)));
|
||||
Log(Debug::Debug) << "cache add for agent=" << agentHalfExtents;
|
||||
Log(Debug::Debug) << "cache add for agent=" << agentBounds;
|
||||
}
|
||||
|
||||
bool NavMeshManager::reset(const osg::Vec3f& agentHalfExtents)
|
||||
bool NavMeshManager::reset(const AgentBounds& agentBounds)
|
||||
{
|
||||
const auto it = mCache.find(agentHalfExtents);
|
||||
const auto it = mCache.find(agentBounds);
|
||||
if (it == mCache.end())
|
||||
return true;
|
||||
if (!resetIfUnique(it->second))
|
||||
return false;
|
||||
mCache.erase(agentHalfExtents);
|
||||
mChangedTiles.erase(agentHalfExtents);
|
||||
mPlayerTile.erase(agentHalfExtents);
|
||||
mLastRecastMeshManagerRevision.erase(agentHalfExtents);
|
||||
mCache.erase(agentBounds);
|
||||
mChangedTiles.erase(agentBounds);
|
||||
mPlayerTile.erase(agentBounds);
|
||||
mLastRecastMeshManagerRevision.erase(agentBounds);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -195,28 +195,28 @@ namespace DetourNavigator
|
||||
addChangedTile(tile, ChangeType::update);
|
||||
}
|
||||
|
||||
void NavMeshManager::update(const osg::Vec3f& playerPosition, const osg::Vec3f& agentHalfExtents)
|
||||
void NavMeshManager::update(const osg::Vec3f& playerPosition, const AgentBounds& agentBounds)
|
||||
{
|
||||
const auto playerTile = getTilePosition(mSettings.mRecast, toNavMeshCoordinates(mSettings.mRecast, playerPosition));
|
||||
auto& lastRevision = mLastRecastMeshManagerRevision[agentHalfExtents];
|
||||
auto lastPlayerTile = mPlayerTile.find(agentHalfExtents);
|
||||
auto& lastRevision = mLastRecastMeshManagerRevision[agentBounds];
|
||||
auto lastPlayerTile = mPlayerTile.find(agentBounds);
|
||||
if (lastRevision == mRecastMeshManager.getRevision() && lastPlayerTile != mPlayerTile.end()
|
||||
&& lastPlayerTile->second == playerTile)
|
||||
return;
|
||||
lastRevision = mRecastMeshManager.getRevision();
|
||||
if (lastPlayerTile == mPlayerTile.end())
|
||||
lastPlayerTile = mPlayerTile.insert(std::make_pair(agentHalfExtents, playerTile)).first;
|
||||
lastPlayerTile = mPlayerTile.insert(std::make_pair(agentBounds, playerTile)).first;
|
||||
else
|
||||
lastPlayerTile->second = playerTile;
|
||||
std::map<TilePosition, ChangeType> tilesToPost;
|
||||
const auto cached = getCached(agentHalfExtents);
|
||||
const auto cached = getCached(agentBounds);
|
||||
if (!cached)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << "Agent with half extents is not found: " << agentHalfExtents;
|
||||
stream << "Agent with half extents is not found: " << agentBounds;
|
||||
throw InvalidArgument(stream.str());
|
||||
}
|
||||
const auto changedTiles = mChangedTiles.find(agentHalfExtents);
|
||||
const auto changedTiles = mChangedTiles.find(agentBounds);
|
||||
{
|
||||
const auto locked = cached->lockConst();
|
||||
const auto& navMesh = locked->getImpl();
|
||||
@ -247,10 +247,10 @@ namespace DetourNavigator
|
||||
recastMeshManager.reportNavMeshChange(recastMeshManager.getVersion(), Version {0, 0});
|
||||
});
|
||||
}
|
||||
mAsyncNavMeshUpdater.post(agentHalfExtents, cached, playerTile, mRecastMeshManager.getWorldspace(), tilesToPost);
|
||||
mAsyncNavMeshUpdater.post(agentBounds, cached, playerTile, mRecastMeshManager.getWorldspace(), tilesToPost);
|
||||
if (changedTiles != mChangedTiles.end())
|
||||
changedTiles->second.clear();
|
||||
Log(Debug::Debug) << "Cache update posted for agent=" << agentHalfExtents <<
|
||||
Log(Debug::Debug) << "Cache update posted for agent=" << agentBounds <<
|
||||
" playerTile=" << lastPlayerTile->second <<
|
||||
" recastMeshManagerRevision=" << lastRevision;
|
||||
}
|
||||
@ -260,12 +260,12 @@ namespace DetourNavigator
|
||||
mAsyncNavMeshUpdater.wait(listener, waitConditionType);
|
||||
}
|
||||
|
||||
SharedNavMeshCacheItem NavMeshManager::getNavMesh(const osg::Vec3f& agentHalfExtents) const
|
||||
SharedNavMeshCacheItem NavMeshManager::getNavMesh(const AgentBounds& agentBounds) const
|
||||
{
|
||||
return getCached(agentHalfExtents);
|
||||
return getCached(agentBounds);
|
||||
}
|
||||
|
||||
std::map<osg::Vec3f, SharedNavMeshCacheItem> NavMeshManager::getNavMeshes() const
|
||||
std::map<AgentBounds, SharedNavMeshCacheItem> NavMeshManager::getNavMeshes() const
|
||||
{
|
||||
return mCache;
|
||||
}
|
||||
@ -319,9 +319,9 @@ namespace DetourNavigator
|
||||
}
|
||||
}
|
||||
|
||||
SharedNavMeshCacheItem NavMeshManager::getCached(const osg::Vec3f& agentHalfExtents) const
|
||||
SharedNavMeshCacheItem NavMeshManager::getCached(const AgentBounds& agentBounds) const
|
||||
{
|
||||
const auto cached = mCache.find(agentHalfExtents);
|
||||
const auto cached = mCache.find(agentBounds);
|
||||
if (cached != mCache.end())
|
||||
return cached->second;
|
||||
return SharedNavMeshCacheItem();
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include "recastmeshtiles.hpp"
|
||||
#include "waitconditiontype.hpp"
|
||||
#include "heightfieldshape.hpp"
|
||||
|
||||
#include "agentbounds.hpp"
|
||||
|
||||
#include <osg/Vec3f>
|
||||
|
||||
@ -35,7 +35,7 @@ namespace DetourNavigator
|
||||
|
||||
bool removeObject(const ObjectId id);
|
||||
|
||||
void addAgent(const osg::Vec3f& agentHalfExtents);
|
||||
void addAgent(const AgentBounds& agentBounds);
|
||||
|
||||
bool addWater(const osg::Vec2i& cellPosition, int cellSize, float level);
|
||||
|
||||
@ -45,19 +45,19 @@ namespace DetourNavigator
|
||||
|
||||
bool removeHeightfield(const osg::Vec2i& cellPosition);
|
||||
|
||||
bool reset(const osg::Vec3f& agentHalfExtents);
|
||||
bool reset(const AgentBounds& agentBounds);
|
||||
|
||||
void addOffMeshConnection(const ObjectId id, const osg::Vec3f& start, const osg::Vec3f& end, const AreaType areaType);
|
||||
|
||||
void removeOffMeshConnections(const ObjectId id);
|
||||
|
||||
void update(const osg::Vec3f& playerPosition, const osg::Vec3f& agentHalfExtents);
|
||||
void update(const osg::Vec3f& playerPosition, const AgentBounds& agentBounds);
|
||||
|
||||
void wait(Loading::Listener& listener, WaitConditionType waitConditionType);
|
||||
|
||||
SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& agentHalfExtents) const;
|
||||
SharedNavMeshCacheItem getNavMesh(const AgentBounds& agentBounds) const;
|
||||
|
||||
std::map<osg::Vec3f, SharedNavMeshCacheItem> getNavMeshes() const;
|
||||
std::map<AgentBounds, SharedNavMeshCacheItem> getNavMeshes() const;
|
||||
|
||||
void reportStats(unsigned int frameNumber, osg::Stats& stats) const;
|
||||
|
||||
@ -69,11 +69,11 @@ namespace DetourNavigator
|
||||
TileCachedRecastMeshManager mRecastMeshManager;
|
||||
OffMeshConnectionsManager mOffMeshConnectionsManager;
|
||||
AsyncNavMeshUpdater mAsyncNavMeshUpdater;
|
||||
std::map<osg::Vec3f, SharedNavMeshCacheItem> mCache;
|
||||
std::map<osg::Vec3f, std::map<TilePosition, ChangeType>> mChangedTiles;
|
||||
std::map<AgentBounds, SharedNavMeshCacheItem> mCache;
|
||||
std::map<AgentBounds, std::map<TilePosition, ChangeType>> mChangedTiles;
|
||||
std::size_t mGenerationCounter = 0;
|
||||
std::map<osg::Vec3f, TilePosition> mPlayerTile;
|
||||
std::map<osg::Vec3f, std::size_t> mLastRecastMeshManagerRevision;
|
||||
std::map<AgentBounds, TilePosition> mPlayerTile;
|
||||
std::map<AgentBounds, std::size_t> mLastRecastMeshManagerRevision;
|
||||
|
||||
void addChangedTiles(const btCollisionShape& shape, const btTransform& transform, const ChangeType changeType);
|
||||
|
||||
@ -81,7 +81,7 @@ namespace DetourNavigator
|
||||
|
||||
void addChangedTile(const TilePosition& tilePosition, const ChangeType changeType);
|
||||
|
||||
SharedNavMeshCacheItem getCached(const osg::Vec3f& agentHalfExtents) const;
|
||||
SharedNavMeshCacheItem getCached(const AgentBounds& agentBounds) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -10,14 +10,14 @@ namespace DetourNavigator
|
||||
: mMaxNavMeshDataSize(maxNavMeshDataSize), mUsedNavMeshDataSize(0), mFreeNavMeshDataSize(0),
|
||||
mHitCount(0), mGetCount(0) {}
|
||||
|
||||
NavMeshTilesCache::Value NavMeshTilesCache::get(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile,
|
||||
NavMeshTilesCache::Value NavMeshTilesCache::get(const AgentBounds& agentBounds, const TilePosition& changedTile,
|
||||
const RecastMesh& recastMesh)
|
||||
{
|
||||
const std::lock_guard<std::mutex> lock(mMutex);
|
||||
|
||||
++mGetCount;
|
||||
|
||||
const auto tile = mValues.find(std::make_tuple(agentHalfExtents, changedTile, recastMesh));
|
||||
const auto tile = mValues.find(std::make_tuple(agentBounds, changedTile, recastMesh));
|
||||
if (tile == mValues.end())
|
||||
return Value();
|
||||
|
||||
@ -28,7 +28,7 @@ namespace DetourNavigator
|
||||
return Value(*this, tile->second);
|
||||
}
|
||||
|
||||
NavMeshTilesCache::Value NavMeshTilesCache::set(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile,
|
||||
NavMeshTilesCache::Value NavMeshTilesCache::set(const AgentBounds& agentBounds, const TilePosition& changedTile,
|
||||
const RecastMesh& recastMesh, std::unique_ptr<PreparedNavMeshData>&& value)
|
||||
{
|
||||
const auto itemSize = sizeof(RecastMesh) + getSize(recastMesh)
|
||||
@ -45,8 +45,8 @@ namespace DetourNavigator
|
||||
RecastMeshData key {recastMesh.getMesh(), recastMesh.getWater(),
|
||||
recastMesh.getHeightfields(), recastMesh.getFlatHeightfields()};
|
||||
|
||||
const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentHalfExtents, changedTile, std::move(key), itemSize);
|
||||
const auto emplaced = mValues.emplace(std::make_tuple(agentHalfExtents, changedTile, std::cref(iterator->mRecastMeshData)), iterator);
|
||||
const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentBounds, changedTile, std::move(key), itemSize);
|
||||
const auto emplaced = mValues.emplace(std::make_tuple(agentBounds, changedTile, std::cref(iterator->mRecastMeshData)), iterator);
|
||||
|
||||
if (!emplaced.second)
|
||||
{
|
||||
@ -92,7 +92,7 @@ namespace DetourNavigator
|
||||
{
|
||||
const auto& item = mFreeItems.back();
|
||||
|
||||
const auto value = mValues.find(std::make_tuple(item.mAgentHalfExtents, item.mChangedTile, std::cref(item.mRecastMeshData)));
|
||||
const auto value = mValues.find(std::make_tuple(item.mAgentBounds, item.mChangedTile, std::cref(item.mRecastMeshData)));
|
||||
if (value == mValues.end())
|
||||
return;
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "preparednavmeshdata.hpp"
|
||||
#include "recastmesh.hpp"
|
||||
#include "tileposition.hpp"
|
||||
#include "agentbounds.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <map>
|
||||
@ -52,16 +53,16 @@ namespace DetourNavigator
|
||||
struct Item
|
||||
{
|
||||
std::atomic<std::int64_t> mUseCount;
|
||||
osg::Vec3f mAgentHalfExtents;
|
||||
AgentBounds mAgentBounds;
|
||||
TilePosition mChangedTile;
|
||||
RecastMeshData mRecastMeshData;
|
||||
std::unique_ptr<PreparedNavMeshData> mPreparedNavMeshData;
|
||||
std::size_t mSize;
|
||||
|
||||
Item(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile,
|
||||
Item(const AgentBounds& agentBounds, const TilePosition& changedTile,
|
||||
RecastMeshData&& recastMeshData, std::size_t size)
|
||||
: mUseCount(0)
|
||||
, mAgentHalfExtents(agentHalfExtents)
|
||||
, mAgentBounds(agentBounds)
|
||||
, mChangedTile(changedTile)
|
||||
, mRecastMeshData(std::move(recastMeshData))
|
||||
, mSize(size)
|
||||
@ -136,10 +137,10 @@ namespace DetourNavigator
|
||||
|
||||
NavMeshTilesCache(const std::size_t maxNavMeshDataSize);
|
||||
|
||||
Value get(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile,
|
||||
Value get(const AgentBounds& agentBounds, const TilePosition& changedTile,
|
||||
const RecastMesh& recastMesh);
|
||||
|
||||
Value set(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile,
|
||||
Value set(const AgentBounds& agentBounds, const TilePosition& changedTile,
|
||||
const RecastMesh& recastMesh, std::unique_ptr<PreparedNavMeshData>&& value);
|
||||
|
||||
Stats getStats() const;
|
||||
@ -153,7 +154,7 @@ namespace DetourNavigator
|
||||
std::size_t mGetCount;
|
||||
std::list<Item> mBusyItems;
|
||||
std::list<Item> mFreeItems;
|
||||
std::map<std::tuple<osg::Vec3f, TilePosition, std::reference_wrapper<const RecastMeshData>>, ItemIterator, std::less<>> mValues;
|
||||
std::map<std::tuple<AgentBounds, TilePosition, std::reference_wrapper<const RecastMeshData>>, ItemIterator, std::less<>> mValues;
|
||||
|
||||
void removeLeastRecentlyUsed();
|
||||
|
||||
|
@ -1,20 +1,32 @@
|
||||
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTPARAMS_H
|
||||
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_RECASTPARAMS_H
|
||||
|
||||
#include "agentbounds.hpp"
|
||||
|
||||
#include <osg/Vec3f>
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
inline float getAgentHeight(const osg::Vec3f& agentHalfExtents)
|
||||
inline float getAgentHeight(const AgentBounds& agentBounds)
|
||||
{
|
||||
return 2.0f * agentHalfExtents.z();
|
||||
return 2.0f * agentBounds.mHalfExtents.z();
|
||||
}
|
||||
|
||||
inline float getAgentRadius(const osg::Vec3f& agentHalfExtents)
|
||||
inline float getAgentRadius(const AgentBounds& agentBounds)
|
||||
{
|
||||
return std::max(agentHalfExtents.x(), agentHalfExtents.y()) * std::sqrt(2);
|
||||
switch (agentBounds.mShapeType)
|
||||
{
|
||||
case CollisionShapeType::Aabb:
|
||||
return std::max(agentBounds.mHalfExtents.x(), agentBounds.mHalfExtents.y()) * std::sqrt(2);
|
||||
case CollisionShapeType::RotatingBox:
|
||||
return agentBounds.mHalfExtents.x();
|
||||
}
|
||||
assert(false && "Unsupported agent shape type");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "recast.hpp"
|
||||
#include "recastmesh.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "agentbounds.hpp"
|
||||
|
||||
#include <components/serialization/binaryreader.hpp>
|
||||
#include <components/serialization/binarywriter.hpp>
|
||||
@ -136,12 +137,13 @@ namespace
|
||||
}
|
||||
|
||||
template <class Visitor>
|
||||
void operator()(Visitor&& visitor, const RecastSettings& settings, const RecastMesh& recastMesh,
|
||||
const std::vector<DbRefGeometryObject>& dbRefGeometryObjects) const
|
||||
void operator()(Visitor&& visitor, const RecastSettings& settings, const AgentBounds& agentBounds,
|
||||
const RecastMesh& recastMesh, const std::vector<DbRefGeometryObject>& dbRefGeometryObjects) const
|
||||
{
|
||||
visitor(*this, DetourNavigator::recastMeshMagic);
|
||||
visitor(*this, DetourNavigator::recastMeshVersion);
|
||||
visitor(*this, settings);
|
||||
visitor(*this, agentBounds);
|
||||
visitor(*this, recastMesh);
|
||||
visitor(*this, dbRefGeometryObjects);
|
||||
}
|
||||
@ -228,21 +230,28 @@ namespace
|
||||
visitor(*this, value.mPolyMesh);
|
||||
visitor(*this, value.mPolyMeshDetail);
|
||||
}
|
||||
|
||||
template <class Visitor>
|
||||
void operator()(Visitor&& visitor, const AgentBounds& value) const
|
||||
{
|
||||
visitor(*this, value.mShapeType);
|
||||
visitor(*this, value.mHalfExtents);
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace DetourNavigator
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
std::vector<std::byte> serialize(const RecastSettings& settings, const RecastMesh& recastMesh,
|
||||
const std::vector<DbRefGeometryObject>& dbRefGeometryObjects)
|
||||
std::vector<std::byte> serialize(const RecastSettings& settings, const AgentBounds& agentBounds,
|
||||
const RecastMesh& recastMesh, const std::vector<DbRefGeometryObject>& dbRefGeometryObjects)
|
||||
{
|
||||
constexpr Format<Serialization::Mode::Write> format;
|
||||
Serialization::SizeAccumulator sizeAccumulator;
|
||||
format(sizeAccumulator, settings, recastMesh, dbRefGeometryObjects);
|
||||
format(sizeAccumulator, settings, agentBounds, recastMesh, dbRefGeometryObjects);
|
||||
std::vector<std::byte> result(sizeAccumulator.value());
|
||||
format(Serialization::BinaryWriter(result.data(), result.data() + result.size()),
|
||||
settings, recastMesh, dbRefGeometryObjects);
|
||||
settings, agentBounds, recastMesh, dbRefGeometryObjects);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -11,15 +11,16 @@ namespace DetourNavigator
|
||||
struct DbRefGeometryObject;
|
||||
struct PreparedNavMeshData;
|
||||
struct RecastSettings;
|
||||
struct AgentBounds;
|
||||
|
||||
constexpr char recastMeshMagic[] = {'r', 'c', 's', 't'};
|
||||
constexpr std::uint32_t recastMeshVersion = 1;
|
||||
constexpr std::uint32_t recastMeshVersion = 2;
|
||||
|
||||
constexpr char preparedNavMeshDataMagic[] = {'p', 'n', 'a', 'v'};
|
||||
constexpr std::uint32_t preparedNavMeshDataVersion = 1;
|
||||
|
||||
std::vector<std::byte> serialize(const RecastSettings& settings, const RecastMesh& value,
|
||||
const std::vector<DbRefGeometryObject>& dbRefGeometryObjects);
|
||||
std::vector<std::byte> serialize(const RecastSettings& settings, const AgentBounds& agentBounds,
|
||||
const RecastMesh& recastMesh, const std::vector<DbRefGeometryObject>& dbRefGeometryObjects);
|
||||
|
||||
std::vector<std::byte> serialize(const PreparedNavMeshData& value);
|
||||
|
||||
|
@ -61,7 +61,6 @@ namespace DetourNavigator
|
||||
result.mEnableRecastMeshFileNameRevision = ::Settings::Manager::getBool("enable recast mesh file name revision", "Navigator");
|
||||
result.mEnableNavMeshFileNameRevision = ::Settings::Manager::getBool("enable nav mesh file name revision", "Navigator");
|
||||
result.mMinUpdateInterval = std::chrono::milliseconds(::Settings::Manager::getInt("min update interval ms", "Navigator"));
|
||||
result.mNavMeshVersion = ::Settings::Manager::getInt("nav mesh version", "Navigator");
|
||||
result.mEnableNavMeshDiskCache = ::Settings::Manager::getBool("enable nav mesh disk cache", "Navigator");
|
||||
result.mWriteToNavMeshDb = ::Settings::Manager::getBool("write to navmeshdb", "Navigator");
|
||||
result.mMaxDbFileSize = static_cast<std::uint64_t>(::Settings::Manager::getInt64("max navmeshdb file size", "Navigator"));
|
||||
|
@ -50,10 +50,11 @@ namespace DetourNavigator
|
||||
std::string mRecastMeshPathPrefix;
|
||||
std::string mNavMeshPathPrefix;
|
||||
std::chrono::milliseconds mMinUpdateInterval;
|
||||
std::int64_t mNavMeshVersion = 0;
|
||||
std::uint64_t mMaxDbFileSize = 0;
|
||||
};
|
||||
|
||||
inline constexpr std::int64_t navMeshVersion = 2;
|
||||
|
||||
RecastSettings makeRecastSettingsFromSettingsManager();
|
||||
|
||||
DetourSettings makeDetourSettingsFromSettingsManager();
|
||||
|
@ -37,7 +37,7 @@ namespace
|
||||
namespace SceneUtil
|
||||
{
|
||||
osg::ref_ptr<osg::Group> createAgentPathGroup(const std::deque<osg::Vec3f>& path,
|
||||
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end,
|
||||
const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end,
|
||||
const DetourNavigator::RecastSettings& settings)
|
||||
{
|
||||
using namespace DetourNavigator;
|
||||
@ -46,8 +46,8 @@ namespace SceneUtil
|
||||
|
||||
DebugDraw debugDraw(*group, DebugDraw::makeStateSet(), osg::Vec3f(0, 0, 0), 1);
|
||||
|
||||
const auto agentRadius = DetourNavigator::getAgentRadius(halfExtents);
|
||||
const auto agentHeight = DetourNavigator::getAgentHeight(halfExtents);
|
||||
const auto agentRadius = DetourNavigator::getAgentRadius(agentBounds);
|
||||
const auto agentHeight = DetourNavigator::getAgentHeight(agentBounds);
|
||||
const auto agentClimb = settings.mMaxClimb;
|
||||
const auto startColor = duRGBA(128, 25, 0, 192);
|
||||
const auto endColor = duRGBA(51, 102, 0, 129);
|
||||
|
@ -14,12 +14,13 @@ namespace osg
|
||||
namespace DetourNavigator
|
||||
{
|
||||
struct RecastSettings;
|
||||
struct AgentBounds;
|
||||
}
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
osg::ref_ptr<osg::Group> createAgentPathGroup(const std::deque<osg::Vec3f>& path,
|
||||
const osg::Vec3f& halfExtents, const osg::Vec3f& start, const osg::Vec3f& end,
|
||||
const DetourNavigator::AgentBounds& agentBounds, const osg::Vec3f& start, const osg::Vec3f& end,
|
||||
const DetourNavigator::RecastSettings& settings);
|
||||
}
|
||||
|
||||
|
@ -943,10 +943,6 @@ min update interval ms = 250
|
||||
# Distance is measured in the number of tiles and can be only an integer value.
|
||||
wait until min distance to player = 5
|
||||
|
||||
# Version of navigation mesh generation algorithm.
|
||||
# Should be increased each time there is a difference between output of makeNavMeshTileData function for the same input.
|
||||
nav mesh version = 1
|
||||
|
||||
# Use navigation mesh cache stored on disk (true, false)
|
||||
enable nav mesh disk cache = true
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user