mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-05 15:55:45 +00:00
Add off mesh connections for doors without teleport
This commit is contained in:
parent
f8dbd5902f
commit
346e9e3141
@ -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));
|
||||
}
|
||||
|
||||
void setNodeRotation(const MWWorld::Ptr& ptr, MWRender::RenderingManager& rendering, bool inverseRotationOrder)
|
||||
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));
|
||||
}
|
||||
|
||||
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;
|
||||
|
112
components/detournavigator/offmeshconnectionsmanager.hpp
Normal file
112
components/detournavigator/offmeshconnectionsmanager.hpp
Normal file
@ -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…
Reference in New Issue
Block a user