mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-16 18:59:57 +00:00
Do single navigator update per frame
Primarily for crossing cell border case. Each Navigator::update call has a cost. Doing it multiple times per frame increased frame duration on cell loading. Call Navigator::wait only when cell has changed but do not use Scene::hasCellChanged because it doesn't always indicates it.
This commit is contained in:
parent
8125d51a0f
commit
e1bed86d7e
16 changed files with 140 additions and 215 deletions
|
@ -7,8 +7,6 @@
|
|||
#include <components/esm3/esmwriter.hpp>
|
||||
#include <components/esm3/stolenitems.hpp>
|
||||
|
||||
#include <components/detournavigator/navigator.hpp>
|
||||
|
||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
@ -813,12 +811,6 @@ namespace MWMechanics
|
|||
bool MechanicsManager::toggleAI()
|
||||
{
|
||||
mAI = !mAI;
|
||||
|
||||
MWBase::World* world = MWBase::Environment::get().getWorld();
|
||||
world->getNavigator()->setUpdatesEnabled(mAI);
|
||||
if (mAI)
|
||||
world->getNavigator()->update(world->getPlayerPtr().getRefData().getPosition().asVec3());
|
||||
|
||||
return mAI;
|
||||
}
|
||||
|
||||
|
|
|
@ -365,8 +365,6 @@ namespace MWWorld
|
|||
if (const auto pathgrid = mWorld.getStore().get<ESM::Pathgrid>().search(*cell->getCell()))
|
||||
mNavigator.removePathgrid(*pathgrid);
|
||||
|
||||
mNavigator.update(mWorld.getPlayerPtr().getRefData().getPosition().asVec3());
|
||||
|
||||
MWBase::Environment::get().getMechanicsManager()->drop (cell);
|
||||
|
||||
mRendering.removeCell(cell);
|
||||
|
@ -514,12 +512,7 @@ namespace MWWorld
|
|||
|
||||
void Scene::playerMoved(const osg::Vec3f &pos)
|
||||
{
|
||||
if (mCurrentCell == nullptr)
|
||||
return;
|
||||
|
||||
mNavigator.updatePlayerPosition(pos);
|
||||
|
||||
if (!mCurrentCell->isExterior())
|
||||
if (!mCurrentCell || !mCurrentCell->isExterior())
|
||||
return;
|
||||
|
||||
osg::Vec2i newCell = getNewGridCenter(pos, &mCurrentGridCenter);
|
||||
|
@ -619,7 +612,7 @@ namespace MWWorld
|
|||
if (changeEvent)
|
||||
mCellChanged = true;
|
||||
|
||||
mNavigator.wait(*loadingListener, DetourNavigator::WaitConditionType::requiredTilesPresent);
|
||||
mCellLoaded = true;
|
||||
}
|
||||
|
||||
void Scene::addPostponedPhysicsObjects()
|
||||
|
@ -868,13 +861,13 @@ namespace MWWorld
|
|||
if (changeEvent)
|
||||
mCellChanged = true;
|
||||
|
||||
mCellLoaded = true;
|
||||
|
||||
if (useFading)
|
||||
MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5);
|
||||
|
||||
MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell);
|
||||
|
||||
mNavigator.wait(*loadingListener, DetourNavigator::WaitConditionType::requiredTilesPresent);
|
||||
|
||||
MWBase::Environment::get().getWorld()->getPostProcessor()->setExteriorFlag(cell->getCell()->mData.mFlags & ESM::Cell::QuasiEx);
|
||||
}
|
||||
|
||||
|
@ -921,11 +914,6 @@ namespace MWWorld
|
|||
addObject(ptr, mWorld, mPagedRefs, *mPhysics, mRendering);
|
||||
addObject(ptr, mWorld, *mPhysics, mNavigator);
|
||||
mWorld.scaleObject(ptr, ptr.getCellRef().getScale());
|
||||
if (mCurrentCell != nullptr)
|
||||
{
|
||||
const auto player = mWorld.getPlayerPtr();
|
||||
mNavigator.update(player.getRefData().getPosition().asVec3());
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
|
@ -945,11 +933,6 @@ namespace MWWorld
|
|||
if (const auto object = mPhysics->getObject(ptr))
|
||||
{
|
||||
mNavigator.removeObject(DetourNavigator::ObjectId(object));
|
||||
if (mCurrentCell != nullptr)
|
||||
{
|
||||
const auto player = mWorld.getPlayerPtr();
|
||||
mNavigator.update(player.getRefData().getPosition().asVec3());
|
||||
}
|
||||
}
|
||||
else if (mPhysics->getActor(ptr))
|
||||
{
|
||||
|
|
|
@ -85,6 +85,7 @@ namespace MWWorld
|
|||
CellStore* mCurrentCell; // the cell the player is in
|
||||
CellStoreCollection mActiveCells;
|
||||
bool mCellChanged;
|
||||
bool mCellLoaded = false;
|
||||
MWWorld::World& mWorld;
|
||||
MWPhysics::PhysicsSystem *mPhysics;
|
||||
MWRender::RenderingManager& mRendering;
|
||||
|
@ -152,6 +153,10 @@ namespace MWWorld
|
|||
bool hasCellChanged() const;
|
||||
///< Has the set of active cells changed, since the last frame?
|
||||
|
||||
bool hasCellLoaded() const { return mCellLoaded; }
|
||||
|
||||
void resetCellLoaded() { mCellLoaded = false; }
|
||||
|
||||
void changeToInteriorCell (const std::string& cellName, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent=true);
|
||||
///< Move to interior cell.
|
||||
/// @param changeEvent Set cellChanged flag?
|
||||
|
|
|
@ -154,7 +154,6 @@ namespace MWWorld
|
|||
mUserDataPath(userDataPath),
|
||||
mDefaultHalfExtents(Settings::Manager::getVector3("default actor pathfind half extents", "Game")),
|
||||
mDefaultActorCollisionShapeType(DetourNavigator::toCollisionShapeType(Settings::Manager::getInt("actor collision shape type", "Game"))),
|
||||
mShouldUpdateNavigator(false),
|
||||
mActivationDistanceOverride (activationDistanceOverride),
|
||||
mStartCell(startCell), mDistanceToFacedObject(-1.f), mTeleportEnabled(true),
|
||||
mLevitationEnabled(true), mGoToJail(false), mDaysInPrison(0),
|
||||
|
@ -1536,12 +1535,7 @@ namespace MWWorld
|
|||
if (const auto object = mPhysics->getObject(door.first))
|
||||
updateNavigatorObject(*object);
|
||||
|
||||
auto player = getPlayerPtr();
|
||||
if (mShouldUpdateNavigator && player.getCell() != nullptr)
|
||||
{
|
||||
mNavigator->update(player.getRefData().getPosition().asVec3());
|
||||
mShouldUpdateNavigator = false;
|
||||
}
|
||||
mNavigator->update(getPlayerPtr().getRefData().getPosition().asVec3());
|
||||
}
|
||||
|
||||
void World::updateNavigatorObject(const MWPhysics::Object& object)
|
||||
|
@ -1549,8 +1543,7 @@ namespace MWWorld
|
|||
const MWWorld::Ptr ptr = object.getPtr();
|
||||
const DetourNavigator::ObjectShapes shapes(object.getShapeInstance(),
|
||||
DetourNavigator::ObjectTransform {ptr.getRefData().getPosition(), ptr.getCellRef().getScale()});
|
||||
mShouldUpdateNavigator = mNavigator->updateObject(DetourNavigator::ObjectId(&object), shapes, object.getTransform())
|
||||
|| mShouldUpdateNavigator;
|
||||
mNavigator->updateObject(DetourNavigator::ObjectId(&object), shapes, object.getTransform());
|
||||
}
|
||||
|
||||
const MWPhysics::RayCastingInterface* World::getRayCasting() const
|
||||
|
@ -1821,10 +1814,7 @@ namespace MWWorld
|
|||
|
||||
updateWeather(duration, paused);
|
||||
|
||||
if (!paused)
|
||||
{
|
||||
updateNavigator();
|
||||
}
|
||||
updateNavigator();
|
||||
|
||||
mPlayer->update();
|
||||
|
||||
|
@ -1842,6 +1832,13 @@ namespace MWWorld
|
|||
mSpellPreloadTimer = 0.1f;
|
||||
preloadSpells();
|
||||
}
|
||||
|
||||
if (mWorldScene->hasCellLoaded())
|
||||
{
|
||||
mNavigator->wait(*MWBase::Environment::get().getWindowManager()->getLoadingScreen(),
|
||||
DetourNavigator::WaitConditionType::requiredTilesPresent);
|
||||
mWorldScene->resetCellLoaded();
|
||||
}
|
||||
}
|
||||
|
||||
void World::updatePhysics (float duration, bool paused, osg::Timer_t frameStart, unsigned int frameNumber, osg::Stats& stats)
|
||||
|
|
|
@ -113,7 +113,6 @@ namespace MWWorld
|
|||
|
||||
osg::Vec3f mDefaultHalfExtents;
|
||||
DetourNavigator::CollisionShapeType mDefaultActorCollisionShapeType;
|
||||
bool mShouldUpdateNavigator;
|
||||
|
||||
int mActivationDistanceOverride;
|
||||
|
||||
|
|
|
@ -439,8 +439,17 @@ namespace
|
|||
const int cellSize2 = mHeightfieldTileSize * (surface2.mSize - 1);
|
||||
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
EXPECT_TRUE(mNavigator->addHeightfield(mCellPosition, cellSize1, surface1));
|
||||
EXPECT_FALSE(mNavigator->addHeightfield(mCellPosition, cellSize2, surface2));
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize1, surface1);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
const Version version = mNavigator->getNavMesh(mAgentBounds)->lockConst()->getVersion();
|
||||
|
||||
mNavigator->addHeightfield(mCellPosition, cellSize2, surface2);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
EXPECT_EQ(mNavigator->getNavMesh(mAgentBounds)->lockConst()->getVersion(), version);
|
||||
}
|
||||
|
||||
TEST_F(DetourNavigatorNavigatorTest, path_should_be_around_avoid_shape)
|
||||
|
@ -1142,7 +1151,16 @@ namespace
|
|||
const float level2 = 2;
|
||||
|
||||
mNavigator->addAgent(mAgentBounds);
|
||||
EXPECT_TRUE(mNavigator->addWater(mCellPosition, cellSize1, level1));
|
||||
EXPECT_FALSE(mNavigator->addWater(mCellPosition, cellSize2, level2));
|
||||
mNavigator->addWater(mCellPosition, cellSize1, level1);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
const Version version = mNavigator->getNavMesh(mAgentBounds)->lockConst()->getVersion();
|
||||
|
||||
mNavigator->addWater(mCellPosition, cellSize2, level2);
|
||||
mNavigator->update(mPlayerPosition);
|
||||
mNavigator->wait(mListener, WaitConditionType::allJobsDone);
|
||||
|
||||
EXPECT_EQ(mNavigator->getNavMesh(mAgentBounds)->lockConst()->getVersion(), version);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -216,27 +216,13 @@ namespace DetourNavigator
|
|||
|
||||
void AsyncNavMeshUpdater::wait(Loading::Listener& listener, WaitConditionType waitConditionType)
|
||||
{
|
||||
if (mSettings.get().mWaitUntilMinDistanceToPlayer == 0)
|
||||
return;
|
||||
listener.setLabel("#{Navigation:BuildingNavigationMesh}");
|
||||
const std::size_t initialJobsLeft = getTotalJobs();
|
||||
std::size_t maxProgress = initialJobsLeft + mThreads.size();
|
||||
listener.setProgressRange(maxProgress);
|
||||
switch (waitConditionType)
|
||||
{
|
||||
case WaitConditionType::requiredTilesPresent:
|
||||
{
|
||||
const int minDistanceToPlayer = waitUntilJobsDoneForNotPresentTiles(initialJobsLeft, maxProgress, listener);
|
||||
if (minDistanceToPlayer < mSettings.get().mWaitUntilMinDistanceToPlayer)
|
||||
{
|
||||
mProcessingTiles.wait(mProcessed, [] (const auto& v) { return v.empty(); });
|
||||
listener.setProgress(maxProgress);
|
||||
}
|
||||
waitUntilJobsDoneForNotPresentTiles(listener);
|
||||
break;
|
||||
}
|
||||
case WaitConditionType::allJobsDone:
|
||||
waitUntilAllJobsDone();
|
||||
listener.setProgress(maxProgress);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -255,8 +241,10 @@ namespace DetourNavigator
|
|||
thread.join();
|
||||
}
|
||||
|
||||
int AsyncNavMeshUpdater::waitUntilJobsDoneForNotPresentTiles(const std::size_t initialJobsLeft, std::size_t& maxProgress, Loading::Listener& listener)
|
||||
void AsyncNavMeshUpdater::waitUntilJobsDoneForNotPresentTiles(Loading::Listener& listener)
|
||||
{
|
||||
const std::size_t initialJobsLeft = getTotalJobs();
|
||||
std::size_t maxProgress = initialJobsLeft + mThreads.size();
|
||||
std::size_t prevJobsLeft = initialJobsLeft;
|
||||
std::size_t jobsDone = 0;
|
||||
std::size_t jobsLeft = 0;
|
||||
|
@ -275,7 +263,13 @@ namespace DetourNavigator
|
|||
return minDistanceToPlayer >= maxDistanceToPlayer;
|
||||
};
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
while (!mDone.wait_for(lock, std::chrono::milliseconds(250), isDone))
|
||||
if (getMinDistanceTo(playerPosition, maxDistanceToPlayer, mPushed, mPresentTiles) >= maxDistanceToPlayer
|
||||
|| (mJobs.empty() && mProcessingTiles.lockConst()->empty()))
|
||||
return;
|
||||
Loading::ScopedLoad load(&listener);
|
||||
listener.setLabel("#{Navigation:BuildingNavigationMesh}");
|
||||
listener.setProgressRange(maxProgress);
|
||||
while (!mDone.wait_for(lock, std::chrono::milliseconds(20), isDone))
|
||||
{
|
||||
if (maxProgress < jobsLeft)
|
||||
{
|
||||
|
@ -291,14 +285,19 @@ namespace DetourNavigator
|
|||
listener.increaseProgress(newJobsDone);
|
||||
}
|
||||
}
|
||||
return minDistanceToPlayer;
|
||||
lock.unlock();
|
||||
if (minDistanceToPlayer < maxDistanceToPlayer)
|
||||
{
|
||||
mProcessingTiles.wait(mProcessed, [] (const auto& v) { return v.empty(); });
|
||||
listener.setProgress(maxProgress);
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncNavMeshUpdater::waitUntilAllJobsDone()
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
mDone.wait(lock, [this] { return mJobs.size() == 0; });
|
||||
mDone.wait(lock, [this] { return mJobs.empty(); });
|
||||
}
|
||||
mProcessingTiles.wait(mProcessed, [] (const auto& v) { return v.empty(); });
|
||||
}
|
||||
|
|
|
@ -223,9 +223,9 @@ namespace DetourNavigator
|
|||
|
||||
void cleanupLastUpdates();
|
||||
|
||||
int waitUntilJobsDoneForNotPresentTiles(const std::size_t initialJobsLeft, std::size_t& maxJobsLeft, Loading::Listener& listener);
|
||||
inline void waitUntilJobsDoneForNotPresentTiles(Loading::Listener& listener);
|
||||
|
||||
void waitUntilAllJobsDone();
|
||||
inline void waitUntilAllJobsDone();
|
||||
};
|
||||
|
||||
void reportStats(const AsyncNavMeshUpdater::Stats& stats, unsigned int frameNumber, osg::Stats& out);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "recastmesh.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "settingsutils.hpp"
|
||||
#include "version.hpp"
|
||||
|
||||
#include <components/bullethelpers/operators.hpp>
|
||||
|
||||
|
@ -191,6 +192,11 @@ namespace DetourNavigator
|
|||
return stream << "ChangeType::" << static_cast<int>(value);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const Version& value)
|
||||
{
|
||||
return stream << "Version {" << value.mGeneration << ", " << value.mRevision << "}";
|
||||
}
|
||||
|
||||
void writeToFile(const RecastMesh& recastMesh, const std::string& pathPrefix,
|
||||
const std::string& revision, const RecastSettings& settings)
|
||||
{
|
||||
|
|
|
@ -18,6 +18,8 @@ class dtNavMesh;
|
|||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
struct Version;
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const TileBounds& value);
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, Status value);
|
||||
|
@ -54,6 +56,8 @@ namespace DetourNavigator
|
|||
|
||||
std::ostream& operator<<(std::ostream& stream, ChangeType value);
|
||||
|
||||
std::ostream& operator<<(std::ostream& stream, const Version& value);
|
||||
|
||||
class RecastMesh;
|
||||
struct RecastSettings;
|
||||
|
||||
|
|
|
@ -100,65 +100,56 @@ namespace DetourNavigator
|
|||
* @param id is used to distinguish different objects
|
||||
* @param shape members must live until object is updated by another shape removed from Navigator
|
||||
* @param transform allows to setup objects geometry according to its world state
|
||||
* @return true if object is added, false if there is already object with given id
|
||||
*/
|
||||
virtual bool addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) = 0;
|
||||
virtual void addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) = 0;
|
||||
|
||||
/**
|
||||
* @brief addObject is used to add doors.
|
||||
* @param id is used to distinguish different objects.
|
||||
* @param shape members must live until object is updated by another shape or removed from Navigator.
|
||||
* @param transform allows to setup objects geometry according to its world state.
|
||||
* @return true if object is added, false if there is already object with given id.
|
||||
*/
|
||||
virtual bool addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) = 0;
|
||||
virtual void addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) = 0;
|
||||
|
||||
/**
|
||||
* @brief updateObject replace object geometry by given data.
|
||||
* @param id is used to find object.
|
||||
* @param shape members must live until object is updated by another shape removed from Navigator.
|
||||
* @param transform allows to setup objects geometry according to its world state.
|
||||
* @return true if object is updated, false if there is no object with given id.
|
||||
*/
|
||||
virtual bool updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) = 0;
|
||||
virtual void updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) = 0;
|
||||
|
||||
/**
|
||||
* @brief updateObject replace object geometry by given data.
|
||||
* @param id is used to find object.
|
||||
* @param shape members must live until object is updated by another shape removed from Navigator.
|
||||
* @param transform allows to setup objects geometry according to its world state.
|
||||
* @return true if object is updated, false if there is no object with given id.
|
||||
*/
|
||||
virtual bool updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) = 0;
|
||||
virtual void updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) = 0;
|
||||
|
||||
/**
|
||||
* @brief removeObject to make it no more available at the scene.
|
||||
* @param id is used to find object.
|
||||
* @return true if object is removed, false if there is no object with given id.
|
||||
*/
|
||||
virtual bool removeObject(const ObjectId id) = 0;
|
||||
virtual void removeObject(const ObjectId id) = 0;
|
||||
|
||||
/**
|
||||
* @brief addWater is used to set water level at given world cell.
|
||||
* @param cellPosition allows to distinguish cells if there is many in current world.
|
||||
* @param cellSize set cell borders. std::numeric_limits<int>::max() disables cell borders.
|
||||
* @param shift set global shift of cell center.
|
||||
* @return true if there was no water at given cell if cellSize != std::numeric_limits<int>::max() or there is
|
||||
* at least single object is added to the scene, false if there is already water for given cell or there is no
|
||||
* any other objects.
|
||||
*/
|
||||
virtual bool addWater(const osg::Vec2i& cellPosition, int cellSize, float level) = 0;
|
||||
virtual void addWater(const osg::Vec2i& cellPosition, int cellSize, float level) = 0;
|
||||
|
||||
/**
|
||||
* @brief removeWater to make it no more available at the scene.
|
||||
* @param cellPosition allows to find cell.
|
||||
* @return true if there was water at given cell.
|
||||
*/
|
||||
virtual bool removeWater(const osg::Vec2i& cellPosition) = 0;
|
||||
virtual void removeWater(const osg::Vec2i& cellPosition) = 0;
|
||||
|
||||
virtual bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape) = 0;
|
||||
virtual void addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape) = 0;
|
||||
|
||||
virtual bool removeHeightfield(const osg::Vec2i& cellPosition) = 0;
|
||||
virtual void removeHeightfield(const osg::Vec2i& cellPosition) = 0;
|
||||
|
||||
virtual void addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) = 0;
|
||||
|
||||
|
@ -170,17 +161,6 @@ namespace DetourNavigator
|
|||
*/
|
||||
virtual void update(const osg::Vec3f& playerPosition) = 0;
|
||||
|
||||
/**
|
||||
* @brief updatePlayerPosition starts background navmesh update using current scene state only when player position has been changed.
|
||||
* @param playerPosition setup initial point to order build tiles of navmesh.
|
||||
*/
|
||||
virtual void updatePlayerPosition(const osg::Vec3f& playerPosition) = 0;
|
||||
|
||||
/**
|
||||
* @brief disable navigator updates
|
||||
*/
|
||||
virtual void setUpdatesEnabled(bool enabled) = 0;
|
||||
|
||||
/**
|
||||
* @brief wait locks thread until tiles are updated from last update call based on passed condition type.
|
||||
* @param waitConditionType defines when waiting will stop
|
||||
|
|
|
@ -11,7 +11,6 @@ namespace DetourNavigator
|
|||
NavigatorImpl::NavigatorImpl(const Settings& settings, std::unique_ptr<NavMeshDb>&& db)
|
||||
: mSettings(settings)
|
||||
, mNavMeshManager(mSettings, std::move(db))
|
||||
, mUpdatesEnabled(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -42,7 +41,12 @@ namespace DetourNavigator
|
|||
mNavMeshManager.updateBounds(playerPosition);
|
||||
}
|
||||
|
||||
bool NavigatorImpl::addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform)
|
||||
void NavigatorImpl::addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform)
|
||||
{
|
||||
addObjectImpl(id, shapes, transform);
|
||||
}
|
||||
|
||||
bool NavigatorImpl::addObjectImpl(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform)
|
||||
{
|
||||
const CollisionShape collisionShape(shapes.mShapeInstance, *shapes.mShapeInstance->mCollisionShape, shapes.mTransform);
|
||||
bool result = mNavMeshManager.addObject(id, collisionShape, transform, AreaType_ground);
|
||||
|
@ -59,72 +63,65 @@ namespace DetourNavigator
|
|||
return result;
|
||||
}
|
||||
|
||||
bool NavigatorImpl::addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform)
|
||||
void NavigatorImpl::addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform)
|
||||
{
|
||||
if (addObject(id, static_cast<const ObjectShapes&>(shapes), transform))
|
||||
if (addObjectImpl(id, static_cast<const ObjectShapes&>(shapes), transform))
|
||||
{
|
||||
const osg::Vec3f start = toNavMeshCoordinates(mSettings.mRecast, shapes.mConnectionStart);
|
||||
const osg::Vec3f end = toNavMeshCoordinates(mSettings.mRecast, shapes.mConnectionEnd);
|
||||
mNavMeshManager.addOffMeshConnection(id, start, end, AreaType_door);
|
||||
mNavMeshManager.addOffMeshConnection(id, end, start, AreaType_door);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool NavigatorImpl::updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform)
|
||||
void NavigatorImpl::updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform)
|
||||
{
|
||||
const CollisionShape collisionShape(shapes.mShapeInstance, *shapes.mShapeInstance->mCollisionShape, shapes.mTransform);
|
||||
bool result = mNavMeshManager.updateObject(id, collisionShape, transform, AreaType_ground);
|
||||
mNavMeshManager.updateObject(id, collisionShape, transform, AreaType_ground);
|
||||
if (const btCollisionShape* const avoidShape = shapes.mShapeInstance->mAvoidCollisionShape.get())
|
||||
{
|
||||
const ObjectId avoidId(avoidShape);
|
||||
const CollisionShape avoidCollisionShape(shapes.mShapeInstance, *avoidShape, shapes.mTransform);
|
||||
if (mNavMeshManager.updateObject(avoidId, avoidCollisionShape, transform, AreaType_null))
|
||||
{
|
||||
updateAvoidShapeId(id, avoidId);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NavigatorImpl::updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform)
|
||||
void NavigatorImpl::updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform)
|
||||
{
|
||||
return updateObject(id, static_cast<const ObjectShapes&>(shapes), transform);
|
||||
}
|
||||
|
||||
bool NavigatorImpl::removeObject(const ObjectId id)
|
||||
void NavigatorImpl::removeObject(const ObjectId id)
|
||||
{
|
||||
bool result = mNavMeshManager.removeObject(id);
|
||||
mNavMeshManager.removeObject(id);
|
||||
const auto avoid = mAvoidIds.find(id);
|
||||
if (avoid != mAvoidIds.end())
|
||||
result = mNavMeshManager.removeObject(avoid->second) || result;
|
||||
mNavMeshManager.removeObject(avoid->second);
|
||||
const auto water = mWaterIds.find(id);
|
||||
if (water != mWaterIds.end())
|
||||
result = mNavMeshManager.removeObject(water->second) || result;
|
||||
mNavMeshManager.removeObject(water->second);
|
||||
mNavMeshManager.removeOffMeshConnections(id);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool NavigatorImpl::addWater(const osg::Vec2i& cellPosition, int cellSize, float level)
|
||||
void NavigatorImpl::addWater(const osg::Vec2i& cellPosition, int cellSize, float level)
|
||||
{
|
||||
return mNavMeshManager.addWater(cellPosition, cellSize, level);
|
||||
mNavMeshManager.addWater(cellPosition, cellSize, level);
|
||||
}
|
||||
|
||||
bool NavigatorImpl::removeWater(const osg::Vec2i& cellPosition)
|
||||
void NavigatorImpl::removeWater(const osg::Vec2i& cellPosition)
|
||||
{
|
||||
return mNavMeshManager.removeWater(cellPosition);
|
||||
mNavMeshManager.removeWater(cellPosition);
|
||||
}
|
||||
|
||||
bool NavigatorImpl::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape)
|
||||
void NavigatorImpl::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape)
|
||||
{
|
||||
return mNavMeshManager.addHeightfield(cellPosition, cellSize, shape);
|
||||
mNavMeshManager.addHeightfield(cellPosition, cellSize, shape);
|
||||
}
|
||||
|
||||
bool NavigatorImpl::removeHeightfield(const osg::Vec2i& cellPosition)
|
||||
void NavigatorImpl::removeHeightfield(const osg::Vec2i& cellPosition)
|
||||
{
|
||||
return mNavMeshManager.removeHeightfield(cellPosition);
|
||||
mNavMeshManager.removeHeightfield(cellPosition);
|
||||
}
|
||||
|
||||
void NavigatorImpl::addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid)
|
||||
|
@ -150,31 +147,15 @@ namespace DetourNavigator
|
|||
|
||||
void NavigatorImpl::update(const osg::Vec3f& playerPosition)
|
||||
{
|
||||
if (!mUpdatesEnabled)
|
||||
return;
|
||||
removeUnusedNavMeshes();
|
||||
for (const auto& v : mAgents)
|
||||
mNavMeshManager.update(playerPosition, v.first);
|
||||
}
|
||||
|
||||
void NavigatorImpl::updatePlayerPosition(const osg::Vec3f& playerPosition)
|
||||
{
|
||||
const TilePosition tilePosition = getTilePosition(mSettings.mRecast, toNavMeshCoordinates(mSettings.mRecast, playerPosition));
|
||||
if (mLastPlayerPosition.has_value() && *mLastPlayerPosition == tilePosition)
|
||||
return;
|
||||
mNavMeshManager.updateBounds(playerPosition);
|
||||
update(playerPosition);
|
||||
mLastPlayerPosition = tilePosition;
|
||||
}
|
||||
|
||||
void NavigatorImpl::setUpdatesEnabled(bool enabled)
|
||||
{
|
||||
mUpdatesEnabled = enabled;
|
||||
}
|
||||
|
||||
void NavigatorImpl::wait(Loading::Listener& listener, WaitConditionType waitConditionType)
|
||||
{
|
||||
mNavMeshManager.wait(listener, waitConditionType);
|
||||
if (mSettings.mWaitUntilMinDistanceToPlayer > 0)
|
||||
mNavMeshManager.wait(listener, waitConditionType);
|
||||
}
|
||||
|
||||
SharedNavMeshCacheItem NavigatorImpl::getNavMesh(const AgentBounds& agentBounds) const
|
||||
|
|
|
@ -26,23 +26,23 @@ namespace DetourNavigator
|
|||
|
||||
void updateBounds(const osg::Vec3f& playerPosition) override;
|
||||
|
||||
bool addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) override;
|
||||
void addObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) override;
|
||||
|
||||
bool addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) override;
|
||||
void addObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) override;
|
||||
|
||||
bool updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) override;
|
||||
void updateObject(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform) override;
|
||||
|
||||
bool updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) override;
|
||||
void updateObject(const ObjectId id, const DoorShapes& shapes, const btTransform& transform) override;
|
||||
|
||||
bool removeObject(const ObjectId id) override;
|
||||
void removeObject(const ObjectId id) override;
|
||||
|
||||
bool addWater(const osg::Vec2i& cellPosition, int cellSize, float level) override;
|
||||
void addWater(const osg::Vec2i& cellPosition, int cellSize, float level) override;
|
||||
|
||||
bool removeWater(const osg::Vec2i& cellPosition) override;
|
||||
void removeWater(const osg::Vec2i& cellPosition) override;
|
||||
|
||||
bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape) override;
|
||||
void addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape) override;
|
||||
|
||||
bool removeHeightfield(const osg::Vec2i& cellPosition) override;
|
||||
void removeHeightfield(const osg::Vec2i& cellPosition) override;
|
||||
|
||||
void addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) override;
|
||||
|
||||
|
@ -50,10 +50,6 @@ namespace DetourNavigator
|
|||
|
||||
void update(const osg::Vec3f& playerPosition) override;
|
||||
|
||||
void updatePlayerPosition(const osg::Vec3f& playerPosition) override;
|
||||
|
||||
void setUpdatesEnabled(bool enabled) override;
|
||||
|
||||
void wait(Loading::Listener& listener, WaitConditionType waitConditionType) override;
|
||||
|
||||
SharedNavMeshCacheItem getNavMesh(const AgentBounds& agentBounds) const override;
|
||||
|
@ -71,12 +67,12 @@ namespace DetourNavigator
|
|||
private:
|
||||
Settings mSettings;
|
||||
NavMeshManager mNavMeshManager;
|
||||
bool mUpdatesEnabled;
|
||||
std::optional<TilePosition> mLastPlayerPosition;
|
||||
std::map<AgentBounds, std::size_t> mAgents;
|
||||
std::unordered_map<ObjectId, ObjectId> mAvoidIds;
|
||||
std::unordered_map<ObjectId, ObjectId> mWaterIds;
|
||||
|
||||
inline bool addObjectImpl(const ObjectId id, const ObjectShapes& shapes, const btTransform& transform);
|
||||
void updateAvoidShapeId(const ObjectId id, const ObjectId avoidId);
|
||||
void updateWaterShapeId(const ObjectId id, const ObjectId waterId);
|
||||
void updateId(const ObjectId id, const ObjectId waterId, std::unordered_map<ObjectId, ObjectId>& ids);
|
||||
|
|
|
@ -22,50 +22,24 @@ namespace DetourNavigator
|
|||
|
||||
void setWorldspace(std::string_view /*worldspace*/) override {}
|
||||
|
||||
bool addObject(const ObjectId /*id*/, const ObjectShapes& /*shapes*/, const btTransform& /*transform*/) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void addObject(const ObjectId /*id*/, const ObjectShapes& /*shapes*/, const btTransform& /*transform*/) override {}
|
||||
|
||||
bool addObject(const ObjectId /*id*/, const DoorShapes& /*shapes*/, const btTransform& /*transform*/) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void addObject(const ObjectId /*id*/, const DoorShapes& /*shapes*/, const btTransform& /*transform*/) override {}
|
||||
|
||||
bool updateObject(const ObjectId /*id*/, const ObjectShapes& /*shapes*/, const btTransform& /*transform*/) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void updateObject(const ObjectId /*id*/, const ObjectShapes& /*shapes*/, const btTransform& /*transform*/) override {}
|
||||
|
||||
bool updateObject(const ObjectId /*id*/, const DoorShapes& /*shapes*/, const btTransform& /*transform*/) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void updateObject(const ObjectId /*id*/, const DoorShapes& /*shapes*/, const btTransform& /*transform*/) override {}
|
||||
|
||||
bool removeObject(const ObjectId /*id*/) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void removeObject(const ObjectId /*id*/) override {}
|
||||
|
||||
bool addWater(const osg::Vec2i& /*cellPosition*/, int /*cellSize*/, float /*level*/) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void addWater(const osg::Vec2i& /*cellPosition*/, int /*cellSize*/, float /*level*/) override {}
|
||||
|
||||
bool removeWater(const osg::Vec2i& /*cellPosition*/) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void removeWater(const osg::Vec2i& /*cellPosition*/) override {}
|
||||
|
||||
bool addHeightfield(const osg::Vec2i& /*cellPosition*/, int /*cellSize*/, const HeightfieldShape& /*height*/) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void addHeightfield(const osg::Vec2i& /*cellPosition*/, int /*cellSize*/, const HeightfieldShape& /*height*/)
|
||||
override {}
|
||||
|
||||
bool removeHeightfield(const osg::Vec2i& /*cellPosition*/) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
void removeHeightfield(const osg::Vec2i& /*cellPosition*/) override {}
|
||||
|
||||
void addPathgrid(const ESM::Cell& /*cell*/, const ESM::Pathgrid& /*pathgrid*/) override {}
|
||||
|
||||
|
@ -75,10 +49,6 @@ namespace DetourNavigator
|
|||
|
||||
void updateBounds(const osg::Vec3f& /*playerPosition*/) override {}
|
||||
|
||||
void updatePlayerPosition(const osg::Vec3f& /*playerPosition*/) override {};
|
||||
|
||||
void setUpdatesEnabled(bool /*enabled*/) override {}
|
||||
|
||||
void wait(Loading::Listener& /*listener*/, WaitConditionType /*waitConditionType*/) override {}
|
||||
|
||||
SharedNavMeshCacheItem getNavMesh(const AgentBounds& /*agentBounds*/) const override
|
||||
|
|
|
@ -107,51 +107,46 @@ namespace DetourNavigator
|
|||
[&] (const TilePosition& tile, ChangeType changeType) { addChangedTile(tile, changeType); });
|
||||
}
|
||||
|
||||
bool NavMeshManager::removeObject(const ObjectId id)
|
||||
void NavMeshManager::removeObject(const ObjectId id)
|
||||
{
|
||||
const auto object = mRecastMeshManager.removeObject(id);
|
||||
if (!object)
|
||||
return false;
|
||||
return;
|
||||
addChangedTiles(object->mShape, object->mTransform, ChangeType::remove);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NavMeshManager::addWater(const osg::Vec2i& cellPosition, int cellSize, float level)
|
||||
void NavMeshManager::addWater(const osg::Vec2i& cellPosition, int cellSize, float level)
|
||||
{
|
||||
if (!mRecastMeshManager.addWater(cellPosition, cellSize, level))
|
||||
return false;
|
||||
return;
|
||||
const btVector3 shift = Misc::Convert::toBullet(getWaterShift3d(cellPosition, cellSize, level));
|
||||
addChangedTiles(cellSize, shift, ChangeType::add);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NavMeshManager::removeWater(const osg::Vec2i& cellPosition)
|
||||
void NavMeshManager::removeWater(const osg::Vec2i& cellPosition)
|
||||
{
|
||||
const auto water = mRecastMeshManager.removeWater(cellPosition);
|
||||
if (!water)
|
||||
return false;
|
||||
return;
|
||||
const btVector3 shift = Misc::Convert::toBullet(getWaterShift3d(cellPosition, water->mCellSize, water->mLevel));
|
||||
addChangedTiles(water->mCellSize, shift, ChangeType::remove);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NavMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape)
|
||||
void NavMeshManager::addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape)
|
||||
{
|
||||
if (!mRecastMeshManager.addHeightfield(cellPosition, cellSize, shape))
|
||||
return false;
|
||||
return;
|
||||
const btVector3 shift = getHeightfieldShift(shape, cellPosition, cellSize);
|
||||
addChangedTiles(cellSize, shift, ChangeType::add);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NavMeshManager::removeHeightfield(const osg::Vec2i& cellPosition)
|
||||
void NavMeshManager::removeHeightfield(const osg::Vec2i& cellPosition)
|
||||
{
|
||||
const auto heightfield = mRecastMeshManager.removeHeightfield(cellPosition);
|
||||
if (!heightfield)
|
||||
return false;
|
||||
return;
|
||||
const btVector3 shift = getHeightfieldShift(heightfield->mShape, cellPosition, heightfield->mCellSize);
|
||||
addChangedTiles(heightfield->mCellSize, shift, ChangeType::remove);
|
||||
return true;
|
||||
}
|
||||
|
||||
void NavMeshManager::addAgent(const AgentBounds& agentBounds)
|
||||
|
|
|
@ -32,17 +32,17 @@ namespace DetourNavigator
|
|||
bool updateObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform,
|
||||
const AreaType areaType);
|
||||
|
||||
bool removeObject(const ObjectId id);
|
||||
void removeObject(const ObjectId id);
|
||||
|
||||
void addAgent(const AgentBounds& agentBounds);
|
||||
|
||||
bool addWater(const osg::Vec2i& cellPosition, int cellSize, float level);
|
||||
void addWater(const osg::Vec2i& cellPosition, int cellSize, float level);
|
||||
|
||||
bool removeWater(const osg::Vec2i& cellPosition);
|
||||
void removeWater(const osg::Vec2i& cellPosition);
|
||||
|
||||
bool addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape);
|
||||
void addHeightfield(const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape);
|
||||
|
||||
bool removeHeightfield(const osg::Vec2i& cellPosition);
|
||||
void removeHeightfield(const osg::Vec2i& cellPosition);
|
||||
|
||||
bool reset(const AgentBounds& agentBounds);
|
||||
|
||||
|
|
Loading…
Reference in a new issue