Add off mesh connections for doors without teleport

pull/1633/head
elsid 6 years ago
parent f8dbd5902f
commit 346e9e3141
No known key found for this signature in database
GPG Key ID: B845CB9FEE18AB40

@ -414,5 +414,8 @@ DetourNavigator::Flags MWMechanics::AiPackage::getNavigatorFlags(const MWWorld::
if (actorClass.canWalk(actor))
result |= DetourNavigator::Flag_walk;
if (actorClass.isBipedal(actor) && getTypeId() != TypeIdWander)
result |= DetourNavigator::Flag_openDoor;
return result;
}

@ -29,6 +29,7 @@
#include "../mwphysics/actor.hpp"
#include "../mwphysics/object.hpp"
#include "../mwphysics/heightfield.hpp"
#include "../mwphysics/convert.hpp"
#include "player.hpp"
#include "localscripts.hpp"
@ -40,25 +41,45 @@
namespace
{
osg::Quat makeActorOsgQuat(const ESM::Position& position)
{
return osg::Quat(position.rot[2], osg::Vec3(0, 0, -1));
}
osg::Quat makeInversedOrderObjectOsgQuat(const ESM::Position& position)
{
const float xr = position.rot[0];
const float yr = position.rot[1];
const float zr = position.rot[2];
return osg::Quat(xr, osg::Vec3(-1, 0, 0))
* osg::Quat(yr, osg::Vec3(0, -1, 0))
* osg::Quat(zr, osg::Vec3(0, 0, -1));
}
void setNodeRotation(const MWWorld::Ptr& ptr, MWRender::RenderingManager& rendering, bool inverseRotationOrder)
osg::Quat makeObjectOsgQuat(const ESM::Position& position)
{
const float xr = position.rot[0];
const float yr = position.rot[1];
const float zr = position.rot[2];
return osg::Quat(zr, osg::Vec3(0, 0, -1))
* osg::Quat(yr, osg::Vec3(0, -1, 0))
* osg::Quat(xr, osg::Vec3(-1, 0, 0));
}
void setNodeRotation(const MWWorld::Ptr& ptr, MWRender::RenderingManager& rendering, const bool inverseRotationOrder)
{
if (!ptr.getRefData().getBaseNode())
return;
osg::Quat worldRotQuat(ptr.getRefData().getPosition().rot[2], osg::Vec3(0,0,-1));
if (!ptr.getClass().isActor())
{
float xr = ptr.getRefData().getPosition().rot[0];
float yr = ptr.getRefData().getPosition().rot[1];
if (!inverseRotationOrder)
worldRotQuat = worldRotQuat * osg::Quat(yr, osg::Vec3(0,-1,0)) *
osg::Quat(xr, osg::Vec3(-1,0,0));
else
worldRotQuat = osg::Quat(xr, osg::Vec3(-1,0,0)) * osg::Quat(yr, osg::Vec3(0,-1,0)) * worldRotQuat;
}
rendering.rotateObject(ptr, worldRotQuat);
rendering.rotateObject(ptr,
ptr.getClass().isActor()
? makeActorOsgQuat(ptr.getRefData().getPosition())
: (inverseRotationOrder
? makeInversedOrderObjectOsgQuat(ptr.getRefData().getPosition())
: makeObjectOsgQuat(ptr.getRefData().getPosition()))
);
}
void addObject(const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics,
@ -84,23 +105,6 @@ namespace
ptr.getClass().insertObject (ptr, model, physics);
if (const auto object = physics.getObject(ptr))
{
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
const DetourNavigator::ObjectShapes shapes {
*object->getShapeInstance()->getCollisionShape(),
object->getShapeInstance()->getAvoidCollisionShape()
};
navigator->addObject(reinterpret_cast<std::size_t>(object), shapes,
object->getCollisionObject()->getWorldTransform());
}
else if (const auto actor = physics.getActor(ptr))
{
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
const auto playerHalfExtents = physics.getHalfExtents(MWBase::Environment::get().getWorld()->getPlayerPtr());
navigator->addAgent(playerHalfExtents);
}
if (useAnim)
MWBase::Environment::get().getMechanicsManager()->add(ptr);
@ -111,6 +115,71 @@ namespace
MWBase::Environment::get().getWorld()->applyLoopingParticles(ptr);
}
void addObject(const MWWorld::Ptr& ptr, const MWPhysics::PhysicsSystem& physics, DetourNavigator::Navigator& navigator)
{
if (const auto object = physics.getObject(ptr))
{
if (ptr.getClass().isDoor() && !ptr.getCellRef().getTeleport())
{
const auto shape = object->getShapeInstance()->getCollisionShape();
btVector3 aabbMin;
btVector3 aabbMax;
shape->getAabb(btTransform::getIdentity(), aabbMin, aabbMax);
const auto center = (aabbMax + aabbMin) * 0.5f;
const auto distanceFromDoor = MWBase::Environment::get().getWorld()->getMaxActivationDistance() * 0.5f;
const auto toPoint = aabbMax.x() - aabbMin.x() < aabbMax.y() - aabbMin.y()
? btVector3(distanceFromDoor, 0, 0)
: btVector3(0, distanceFromDoor, 0);
const auto& transform = object->getCollisionObject()->getWorldTransform();
const btTransform closedDoorTransform(
MWPhysics::toBullet(makeObjectOsgQuat(ptr.getCellRef().getPosition())),
transform.getOrigin()
);
const auto start = DetourNavigator::makeOsgVec3f(closedDoorTransform(center + toPoint));
const auto startPoint = physics.castRay(start, start - osg::Vec3f(0, 0, 1000), ptr, {},
MWPhysics::CollisionType_World | MWPhysics::CollisionType_HeightMap | MWPhysics::CollisionType_Water);
const auto connectionStart = startPoint.mHit ? startPoint.mHitPos : start;
const auto end = DetourNavigator::makeOsgVec3f(closedDoorTransform(center - toPoint));
const auto endPoint = physics.castRay(end, end - osg::Vec3f(0, 0, 1000), ptr, {},
MWPhysics::CollisionType_World | MWPhysics::CollisionType_HeightMap | MWPhysics::CollisionType_Water);
const auto connectionEnd = endPoint.mHit ? endPoint.mHitPos : end;
navigator.addObject(
reinterpret_cast<std::size_t>(object),
DetourNavigator::DoorShapes(
*shape,
object->getShapeInstance()->getAvoidCollisionShape(),
connectionStart,
connectionEnd
),
transform
);
}
else
{
navigator.addObject(
reinterpret_cast<std::size_t>(object),
DetourNavigator::ObjectShapes {
*object->getShapeInstance()->getCollisionShape(),
object->getShapeInstance()->getAvoidCollisionShape()
},
object->getCollisionObject()->getWorldTransform()
);
}
}
else if (const auto actor = physics.getActor(ptr))
{
const auto playerHalfExtents = physics.getHalfExtents(MWBase::Environment::get().getWorld()->getPlayerPtr());
navigator.addAgent(playerHalfExtents);
}
}
void updateObjectRotation (const MWWorld::Ptr& ptr, MWPhysics::PhysicsSystem& physics,
MWRender::RenderingManager& rendering, bool inverseRotationOrder)
{
@ -137,24 +206,19 @@ namespace
MWWorld::CellStore& mCell;
bool mRescale;
Loading::Listener& mLoadingListener;
MWPhysics::PhysicsSystem& mPhysics;
MWRender::RenderingManager& mRendering;
std::vector<MWWorld::Ptr> mToInsert;
InsertVisitor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener,
MWPhysics::PhysicsSystem& physics, MWRender::RenderingManager& rendering);
InsertVisitor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener);
bool operator() (const MWWorld::Ptr& ptr);
void insert();
template <class AddObject>
void insert(AddObject&& addObject);
};
InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, bool rescale,
Loading::Listener& loadingListener, MWPhysics::PhysicsSystem& physics,
MWRender::RenderingManager& rendering)
: mCell (cell), mRescale (rescale), mLoadingListener (loadingListener),
mPhysics (physics),
mRendering (rendering)
InsertVisitor::InsertVisitor (MWWorld::CellStore& cell, bool rescale, Loading::Listener& loadingListener)
: mCell (cell), mRescale (rescale), mLoadingListener (loadingListener)
{}
bool InsertVisitor::operator() (const MWWorld::Ptr& ptr)
@ -165,7 +229,8 @@ namespace
return true;
}
void InsertVisitor::insert()
template <class AddObject>
void InsertVisitor::insert(AddObject&& addObject)
{
for (std::vector<MWWorld::Ptr>::iterator it = mToInsert.begin(); it != mToInsert.end(); ++it)
{
@ -182,7 +247,7 @@ namespace
{
try
{
addObject(ptr, mPhysics, mRendering);
addObject(ptr);
}
catch (const std::exception& e)
{
@ -577,8 +642,9 @@ namespace MWWorld
mLastPlayerPos = pos.asVec3();
}
Scene::Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics)
: mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering)
Scene::Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics,
DetourNavigator::Navigator& navigator)
: mCurrentCell (0), mCellChanged (false), mPhysics(physics), mRendering(rendering), mNavigator(navigator)
, mPreloadTimer(0.f)
, mHalfGridSize(Settings::Manager::getInt("exterior cell load distance", "Cells"))
, mCellLoadingThreshold(1024.f)
@ -706,9 +772,10 @@ namespace MWWorld
void Scene::insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener)
{
InsertVisitor insertVisitor (cell, rescale, *loadingListener, *mPhysics, mRendering);
InsertVisitor insertVisitor (cell, rescale, *loadingListener);
cell.forEach (insertVisitor);
insertVisitor.insert();
insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mRendering); });
insertVisitor.insert([&] (const MWWorld::Ptr& ptr) { addObject(ptr, *mPhysics, mNavigator); });
// do adjustPosition (snapping actors to ground) after objects are loaded, so we don't depend on the loading order
AdjustPositionVisitor adjustPosVisitor;
@ -720,6 +787,7 @@ namespace MWWorld
try
{
addObject(ptr, *mPhysics, mRendering);
addObject(ptr, *mPhysics, mNavigator);
MWBase::Environment::get().getWorld()->scaleObject(ptr, ptr.getCellRef().getScale());
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
const auto player = MWBase::Environment::get().getWorld()->getPlayerPtr();

@ -30,6 +30,7 @@ namespace Loading
namespace DetourNavigator
{
class Navigator;
class Water;
}
@ -63,6 +64,7 @@ namespace MWWorld
bool mCellChanged;
MWPhysics::PhysicsSystem *mPhysics;
MWRender::RenderingManager& mRendering;
DetourNavigator::Navigator& mNavigator;
std::unique_ptr<CellPreloader> mPreloader;
float mPreloadTimer;
int mHalfGridSize;
@ -91,7 +93,8 @@ namespace MWWorld
public:
Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics);
Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics,
DetourNavigator::Navigator& navigator);
~Scene();

@ -235,7 +235,7 @@ namespace MWWorld
mWeatherManager.reset(new MWWorld::WeatherManager(*mRendering, mFallback, mStore));
mWorldScene.reset(new Scene(*mRendering.get(), mPhysics.get()));
mWorldScene.reset(new Scene(*mRendering.get(), mPhysics.get(), *mNavigator));
}
void World::fillGlobalVariables()

@ -46,9 +46,11 @@ namespace DetourNavigator
return stream << "unknown";
}
AsyncNavMeshUpdater::AsyncNavMeshUpdater(const Settings& settings, TileCachedRecastMeshManager& recastMeshManager)
AsyncNavMeshUpdater::AsyncNavMeshUpdater(const Settings& settings, TileCachedRecastMeshManager& recastMeshManager,
OffMeshConnectionsManager& offMeshConnectionsManager)
: mSettings(settings)
, mRecastMeshManager(recastMeshManager)
, mOffMeshConnectionsManager(offMeshConnectionsManager)
, mShouldStop()
, mThread([&] { process(); })
{
@ -124,9 +126,10 @@ namespace DetourNavigator
const auto recastMesh = mRecastMeshManager.get().getMesh(job.mChangedTile);
const auto playerTile = getPlayerTile();
const auto offMeshConnections = mOffMeshConnectionsManager.get().get(job.mChangedTile);
const auto status = updateNavMesh(job.mAgentHalfExtents, recastMesh.get(), job.mChangedTile, playerTile,
mSettings, *job.mNavMeshCacheItem);
offMeshConnections, mSettings, *job.mNavMeshCacheItem);
const auto finish = std::chrono::steady_clock::now();

@ -2,6 +2,7 @@
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_ASYNCNAVMESHUPDATER_H
#include "navmeshcacheitem.hpp"
#include "offmeshconnectionsmanager.hpp"
#include "tilecachedrecastmeshmanager.hpp"
#include "tileposition.hpp"
@ -32,7 +33,8 @@ namespace DetourNavigator
class AsyncNavMeshUpdater
{
public:
AsyncNavMeshUpdater(const Settings& settings, TileCachedRecastMeshManager& recastMeshManager);
AsyncNavMeshUpdater(const Settings& settings, TileCachedRecastMeshManager& recastMeshManager,
OffMeshConnectionsManager& offMeshConnectionsManager);
~AsyncNavMeshUpdater();
void post(const osg::Vec3f& agentHalfExtents, const std::shared_ptr<NavMeshCacheItem>& mNavMeshCacheItem,
@ -58,6 +60,7 @@ namespace DetourNavigator
std::reference_wrapper<const Settings> mSettings;
std::reference_wrapper<TileCachedRecastMeshManager> mRecastMeshManager;
std::reference_wrapper<OffMeshConnectionsManager> mOffMeshConnectionsManager;
std::atomic_bool mShouldStop;
std::mutex mMutex;
std::condition_variable mHasJob;

@ -10,6 +10,7 @@ namespace DetourNavigator
Flag_none = 0,
Flag_walk = 1 << 0,
Flag_swim = 1 << 1,
Flag_openDoor = 1 << 2,
};
}

@ -100,9 +100,31 @@ namespace
}
}
std::vector<float> getOffMeshVerts(const std::vector<OffMeshConnection>& connections)
{
std::vector<float> result;
result.reserve(connections.size() * 6);
const auto add = [&] (const osg::Vec3f& v)
{
result.push_back(v.x());
result.push_back(v.y());
result.push_back(v.z());
};
for (const auto& v : connections)
{
add(v.mStart);
add(v.mEnd);
}
return result;
}
NavMeshData makeNavMeshTileData(const osg::Vec3f& agentHalfExtents, const RecastMesh& recastMesh,
const int tileX, const int tileY, const osg::Vec3f& boundsMin, const osg::Vec3f& boundsMax,
const Settings& settings)
const std::vector<OffMeshConnection>& offMeshConnections, const int tileX, const int tileY,
const osg::Vec3f& boundsMin, const osg::Vec3f& boundsMax, const Settings& settings)
{
rcContext context;
rcConfig config;
@ -280,6 +302,12 @@ namespace
polyMesh.flags[i] = Flag_swim;
}
const auto offMeshConVerts = getOffMeshVerts(offMeshConnections);
const std::vector<float> offMeshConRad(offMeshConnections.size(), getRadius(settings, agentHalfExtents));
const std::vector<unsigned char> offMeshConDir(offMeshConnections.size(), DT_OFFMESH_CON_BIDIR);
const std::vector<unsigned char> offMeshConAreas(offMeshConnections.size(), AreaType_ground);
const std::vector<unsigned short> offMeshConFlags(offMeshConnections.size(), Flag_openDoor);
dtNavMeshCreateParams params;
params.verts = polyMesh.verts;
params.vertCount = polyMesh.nverts;
@ -293,13 +321,13 @@ namespace
params.detailVertsCount = polyMeshDetail.nverts;
params.detailTris = polyMeshDetail.tris;
params.detailTriCount = polyMeshDetail.ntris;
params.offMeshConVerts = nullptr;
params.offMeshConRad = nullptr;
params.offMeshConDir = nullptr;
params.offMeshConAreas = nullptr;
params.offMeshConFlags = nullptr;
params.offMeshConVerts = offMeshConVerts.data();
params.offMeshConRad = offMeshConRad.data();
params.offMeshConDir = offMeshConDir.data();
params.offMeshConAreas = offMeshConAreas.data();
params.offMeshConFlags = offMeshConFlags.data();
params.offMeshConUserID = nullptr;
params.offMeshConCount = 0;
params.offMeshConCount = static_cast<int>(offMeshConnections.size());
params.walkableHeight = getHeight(settings, agentHalfExtents);
params.walkableRadius = getRadius(settings, agentHalfExtents);
params.walkableClimb = getMaxClimb(settings);
@ -358,7 +386,8 @@ namespace DetourNavigator
}
UpdateNavMeshStatus updateNavMesh(const osg::Vec3f& agentHalfExtents, const RecastMesh* recastMesh,
const TilePosition& changedTile, const TilePosition& playerTile, const Settings& settings,
const TilePosition& changedTile, const TilePosition& playerTile,
const std::vector<OffMeshConnection>& offMeshConnections, const Settings& settings,
NavMeshCacheItem& navMeshCacheItem)
{
log("update NavMesh with mutiple tiles:",
@ -419,7 +448,7 @@ namespace DetourNavigator
const osg::Vec3f tileBorderMin(tileBounds.mMin.x(), boundsMin.y() - 1, tileBounds.mMin.y());
const osg::Vec3f tileBorderMax(tileBounds.mMax.x(), boundsMax.y() + 1, tileBounds.mMax.y());
auto navMeshData = makeNavMeshTileData(agentHalfExtents, *recastMesh, x, y,
auto navMeshData = makeNavMeshTileData(agentHalfExtents, *recastMesh, offMeshConnections, x, y,
tileBorderMin, tileBorderMax, settings);
if (!navMeshData.mValue)

@ -1,6 +1,7 @@
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_MAKENAVMESH_H
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_MAKENAVMESH_H
#include "offmeshconnectionsmanager.hpp"
#include "settings.hpp"
#include "navmeshcacheitem.hpp"
#include "tileposition.hpp"
@ -47,7 +48,8 @@ namespace DetourNavigator
NavMeshPtr makeEmptyNavMesh(const Settings& settings);
UpdateNavMeshStatus updateNavMesh(const osg::Vec3f& agentHalfExtents, const RecastMesh* recastMesh,
const TilePosition& changedTile, const TilePosition& playerTile, const Settings& settings,
const TilePosition& changedTile, const TilePosition& playerTile,
const std::vector<OffMeshConnection>& offMeshConnections, const Settings& settings,
NavMeshCacheItem& navMeshCacheItem);
}

@ -47,6 +47,20 @@ namespace DetourNavigator
return result;
}
bool Navigator::addObject(std::size_t id, const DoorShapes& shapes, const btTransform& transform)
{
if (addObject(id, static_cast<const ObjectShapes&>(shapes), transform))
{
mNavMeshManager.addOffMeshConnection(
id,
toNavMeshCoordinates(mSettings, shapes.mConnectionStart),
toNavMeshCoordinates(mSettings, shapes.mConnectionEnd)
);
return true;
}
return false;
}
bool Navigator::updateObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform)
{
return mNavMeshManager.updateObject(id, shape, transform, AreaType_ground);
@ -67,6 +81,11 @@ namespace DetourNavigator
return result;
}
bool Navigator::updateObject(std::size_t id, const DoorShapes& shapes, const btTransform& transform)
{
return updateObject(id, static_cast<const ObjectShapes&>(shapes), transform);
}
bool Navigator::removeObject(std::size_t id)
{
bool result = mNavMeshManager.removeObject(id);
@ -76,6 +95,7 @@ namespace DetourNavigator
const auto water = mWaterIds.find(id);
if (water != mWaterIds.end())
result = mNavMeshManager.removeObject(water->second) || result;
mNavMeshManager.removeOffMeshConnection(id);
return result;
}

@ -19,6 +19,19 @@ namespace DetourNavigator
{}
};
struct DoorShapes : ObjectShapes
{
osg::Vec3f mConnectionStart;
osg::Vec3f mConnectionEnd;
DoorShapes(const btCollisionShape& shape, const btCollisionShape* avoid,
const osg::Vec3f& connectionStart,const osg::Vec3f& connectionEnd)
: ObjectShapes(shape, avoid)
, mConnectionStart(connectionStart)
, mConnectionEnd(connectionEnd)
{}
};
class Navigator
{
public:
@ -32,10 +45,14 @@ namespace DetourNavigator
bool addObject(std::size_t id, const ObjectShapes& shapes, const btTransform& transform);
bool addObject(std::size_t id, const DoorShapes& shapes, const btTransform& transform);
bool updateObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform);
bool updateObject(std::size_t id, const ObjectShapes& shapes, const btTransform& transform);
bool updateObject(std::size_t id, const DoorShapes& shapes, const btTransform& transform);
bool removeObject(std::size_t id);
bool addWater(const osg::Vec2i& cellPosition, const int cellSize, const btScalar level,

@ -28,7 +28,8 @@ namespace DetourNavigator
NavMeshManager::NavMeshManager(const Settings& settings)
: mSettings(settings)
, mRecastMeshManager(settings)
, mAsyncNavMeshUpdater(settings, mRecastMeshManager)
, mOffMeshConnectionsManager(settings)
, mAsyncNavMeshUpdater(settings, mRecastMeshManager, mOffMeshConnectionsManager)
{}
bool NavMeshManager::addObject(std::size_t id, const btCollisionShape& shape, const btTransform& transform,
@ -90,6 +91,34 @@ namespace DetourNavigator
mCache.erase(agentHalfExtents);
}
void NavMeshManager::addOffMeshConnection(std::size_t id, const osg::Vec3f& start, const osg::Vec3f& end)
{
if (!mOffMeshConnectionsManager.add(id, OffMeshConnection {start, end}))
return;
const auto startTilePosition = getTilePosition(mSettings, start);
const auto endTilePosition = getTilePosition(mSettings, end);
addChangedTile(startTilePosition, ChangeType::add);
if (startTilePosition != endTilePosition)
addChangedTile(endTilePosition, ChangeType::add);
}
void NavMeshManager::removeOffMeshConnection(std::size_t id)
{
if (const auto connection = mOffMeshConnectionsManager.remove(id))
{
const auto startTilePosition = getTilePosition(mSettings, connection->mStart);
const auto endTilePosition = getTilePosition(mSettings, connection->mEnd);
addChangedTile(startTilePosition, ChangeType::remove);
if (startTilePosition != endTilePosition)
addChangedTile(endTilePosition, ChangeType::remove);
}
}
void NavMeshManager::update(osg::Vec3f playerPosition, const osg::Vec3f& agentHalfExtents)
{
const auto playerTile = getTilePosition(mSettings, toNavMeshCoordinates(mSettings, playerPosition));

@ -3,6 +3,7 @@
#include "asyncnavmeshupdater.hpp"
#include "cachedrecastmeshmanager.hpp"
#include "offmeshconnectionsmanager.hpp"
#include "sharednavmesh.hpp"
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
@ -37,6 +38,10 @@ namespace DetourNavigator
void reset(const osg::Vec3f& agentHalfExtents);
void addOffMeshConnection(std::size_t id, const osg::Vec3f& start, const osg::Vec3f& end);
void removeOffMeshConnection(std::size_t id);
void update(osg::Vec3f playerPosition, const osg::Vec3f& agentHalfExtents);
void wait();
@ -48,6 +53,7 @@ namespace DetourNavigator
private:
const Settings& mSettings;
TileCachedRecastMeshManager mRecastMeshManager;
OffMeshConnectionsManager mOffMeshConnectionsManager;
std::map<osg::Vec3f, std::shared_ptr<NavMeshCacheItem>> mCache;
std::map<osg::Vec3f, std::map<TilePosition, ChangeType>> mChangedTiles;
AsyncNavMeshUpdater mAsyncNavMeshUpdater;

@ -0,0 +1,112 @@
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_OFFMESHCONNECTIONSMANAGER_H
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_OFFMESHCONNECTIONSMANAGER_H
#include "settings.hpp"
#include "settingsutils.hpp"
#include "tileposition.hpp"
#include <osg/Vec3f>
#include <boost/optional.hpp>
#include <map>
#include <mutex>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace DetourNavigator
{
struct OffMeshConnection
{
osg::Vec3f mStart;
osg::Vec3f mEnd;
};
class OffMeshConnectionsManager
{
public:
OffMeshConnectionsManager(const Settings& settings)
: mSettings(settings)
{}
bool add(const std::size_t id, const OffMeshConnection& value)
{
const std::lock_guard<std::mutex> lock(mMutex);
if (!mValuesById.insert(std::make_pair(id, value)).second)
return false;
const auto startTilePosition = getTilePosition(mSettings, value.mStart);
const auto endTilePosition = getTilePosition(mSettings, value.mEnd);
mValuesByTilePosition[startTilePosition].insert(id);
if (startTilePosition != endTilePosition)
mValuesByTilePosition[endTilePosition].insert(id);
return true;
}
boost::optional<OffMeshConnection> remove(const std::size_t id)
{
const std::lock_guard<std::mutex> lock(mMutex);
const auto itById = mValuesById.find(id);
if (itById == mValuesById.end())
return boost::none;
const auto result = itById->second;
mValuesById.erase(itById);
const auto startTilePosition = getTilePosition(mSettings, result.mStart);
const auto endTilePosition = getTilePosition(mSettings, result.mEnd);
removeByTilePosition(startTilePosition, id);
if (startTilePosition != endTilePosition)
removeByTilePosition(endTilePosition, id);
return result;
}
std::vector<OffMeshConnection> get(const TilePosition& tilePosition)
{
std::vector<OffMeshConnection> result;
const std::lock_guard<std::mutex> lock(mMutex);
const auto itByTilePosition = mValuesByTilePosition.find(tilePosition);
if (itByTilePosition == mValuesByTilePosition.end())
return result;
std::for_each(itByTilePosition->second.begin(), itByTilePosition->second.end(),
[&] (const std::size_t v)
{
const auto itById = mValuesById.find(v);
if (itById != mValuesById.end())
result.push_back(itById->second);
});
return result;
}
private:
const Settings& mSettings;
std::mutex mMutex;
std::unordered_map<std::size_t, OffMeshConnection> mValuesById;
std::map<TilePosition, std::unordered_set<std::size_t>> mValuesByTilePosition;
void removeByTilePosition(const TilePosition& tilePosition, const std::size_t id)
{
const auto it = mValuesByTilePosition.find(tilePosition);
if (it != mValuesByTilePosition.end())
it->second.erase(id);
}
};
}
#endif
Loading…
Cancel
Save