mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-03 07:39:41 +00:00
Support different agent collision shape type for pathfinding
Actors may have different collision shapes. Currently there are axis-aligned bounding boxes and rotating bounding boxes. With AABB it's required to use bounding cylinder for navmesh agent to avoid providing paths where actor can't pass. But for rotating bounding boxes cylinder with diameter equal to the front face width should be used to not reduce of available paths. For example rats have rotating bounding box as collision shape because of the difference between front and side faces width. * Add agent bounds to navmesh tile db cache key. This is required to distinguish tiles for agents with different bounds. * Increase navmesh version because navmesh tile db cache key and data has changed. * Move navmesh version to the code to avoid misconfiguration by users. * Fix all places where wrong half extents were used for pathfinding.
This commit is contained in:
parent
15c7ed774c
commit
1a12c453d6
51 changed files with 515 additions and 389 deletions
|
@ -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…
Reference in a new issue