1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-29 04:06:40 +00:00

Merge branch 'navmesh_wait' into 'master'

Wait until navmesh is generated within given distance around player (#5500)

Closes #5500

See merge request OpenMW/openmw!819
This commit is contained in:
psi29a 2021-05-13 16:56:39 +00:00
commit fd89582e0c
16 changed files with 147 additions and 37 deletions

View file

@ -143,6 +143,7 @@
Feature #5456: Basic collada animation support Feature #5456: Basic collada animation support
Feature #5457: Realistic diagonal movement Feature #5457: Realistic diagonal movement
Feature #5486: Fixes trainers to choose their training skills based on their base skill points Feature #5486: Fixes trainers to choose their training skills based on their base skill points
Feature #5500: Prepare enough navmesh tiles before scene loading ends
Feature #5511: Add in game option to toggle HRTF support in OpenMW Feature #5511: Add in game option to toggle HRTF support in OpenMW
Feature #5519: Code Patch tab in launcher Feature #5519: Code Patch tab in launcher
Feature #5524: Resume failed script execution after reload Feature #5524: Resume failed script execution after reload

View file

@ -618,6 +618,8 @@ namespace MWWorld
if (changeEvent) if (changeEvent)
mCellChanged = true; mCellChanged = true;
mNavigator.wait(*loadingListener);
} }
void Scene::testExteriorCells() void Scene::testExteriorCells()
@ -845,6 +847,8 @@ namespace MWWorld
MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5); MWBase::Environment::get().getWindowManager()->fadeScreenIn(0.5);
MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell); MWBase::Environment::get().getWindowManager()->changeCell(mCurrentCell);
mNavigator.wait(*loadingListener);
} }
void Scene::changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos, bool changeEvent) void Scene::changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos, bool changeEvent)

View file

@ -3,6 +3,7 @@
#include <components/detournavigator/navigatorimpl.hpp> #include <components/detournavigator/navigatorimpl.hpp>
#include <components/detournavigator/exceptions.hpp> #include <components/detournavigator/exceptions.hpp>
#include <components/misc/rng.hpp> #include <components/misc/rng.hpp>
#include <components/loadinglistener/loadinglistener.hpp>
#include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h> #include <BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h>
#include <BulletCollision/CollisionShapes/btBoxShape.h> #include <BulletCollision/CollisionShapes/btBoxShape.h>
@ -35,6 +36,7 @@ namespace
std::back_insert_iterator<std::deque<osg::Vec3f>> mOut; std::back_insert_iterator<std::deque<osg::Vec3f>> mOut;
float mStepSize; float mStepSize;
AreaCosts mAreaCosts; AreaCosts mAreaCosts;
Loading::Listener mListener;
DetourNavigatorNavigatorTest() DetourNavigatorNavigatorTest()
: mPlayerPosition(0, 0, 0) : mPlayerPosition(0, 0, 0)
@ -64,6 +66,7 @@ namespace
mSettings.mRegionMergeSize = 20; mSettings.mRegionMergeSize = 20;
mSettings.mRegionMinSize = 8; mSettings.mRegionMinSize = 8;
mSettings.mTileSize = 64; mSettings.mTileSize = 64;
mSettings.mWaitUntilMinDistanceToPlayer = std::numeric_limits<int>::max();
mSettings.mAsyncNavMeshUpdaterThreads = 1; mSettings.mAsyncNavMeshUpdaterThreads = 1;
mSettings.mMaxNavMeshTilesCacheSize = 1024 * 1024; mSettings.mMaxNavMeshTilesCacheSize = 1024 * 1024;
mSettings.mMaxPolygonPathSize = 1024; mSettings.mMaxPolygonPathSize = 1024;
@ -124,7 +127,7 @@ namespace
mNavigator->addAgent(mAgentHalfExtents); mNavigator->addAgent(mAgentHalfExtents);
mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity());
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success);
@ -174,7 +177,7 @@ namespace
mNavigator->addAgent(mAgentHalfExtents); mNavigator->addAgent(mAgentHalfExtents);
mNavigator->addObject(ObjectId(&heightfieldShape), heightfieldShape, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&heightfieldShape), heightfieldShape, btTransform::getIdentity());
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success);
@ -206,7 +209,7 @@ namespace
mNavigator->addObject(ObjectId(&compoundShape), compoundShape, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&compoundShape), compoundShape, btTransform::getIdentity());
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
mPath.clear(); mPath.clear();
mOut = std::back_inserter(mPath); mOut = std::back_inserter(mPath);
@ -259,7 +262,7 @@ namespace
mNavigator->addObject(ObjectId(&heightfieldShape), heightfieldShape, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&heightfieldShape), heightfieldShape, btTransform::getIdentity());
mNavigator->addObject(ObjectId(&compoundShape), compoundShape, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&compoundShape), compoundShape, btTransform::getIdentity());
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success);
@ -293,7 +296,7 @@ namespace
mNavigator->updateObject(ObjectId(&compoundShape), compoundShape, btTransform::getIdentity()); mNavigator->updateObject(ObjectId(&compoundShape), compoundShape, btTransform::getIdentity());
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
mPath.clear(); mPath.clear();
mOut = std::back_inserter(mPath); mOut = std::back_inserter(mPath);
@ -352,7 +355,7 @@ namespace
mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity());
mNavigator->addObject(ObjectId(&shape2), shape2, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape2), shape2, btTransform::getIdentity());
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success);
@ -408,7 +411,7 @@ namespace
mNavigator->addAgent(mAgentHalfExtents); mNavigator->addAgent(mAgentHalfExtents);
mNavigator->addObject(ObjectId(&shape), ObjectShapes {shape, &shapeAvoid}, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape), ObjectShapes {shape, &shapeAvoid}, btTransform::getIdentity());
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success);
@ -456,7 +459,7 @@ namespace
mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, 300, btTransform::getIdentity()); mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, 300, btTransform::getIdentity());
mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity());
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
mStart.x() = 0; mStart.x() = 0;
mStart.z() = 300; mStart.z() = 300;
@ -504,7 +507,7 @@ namespace
mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, -25, btTransform::getIdentity()); mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, -25, btTransform::getIdentity());
mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity());
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
mStart.x() = 0; mStart.x() = 0;
mEnd.x() = 0; mEnd.x() = 0;
@ -551,7 +554,7 @@ namespace
mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity());
mNavigator->addWater(osg::Vec2i(0, 0), std::numeric_limits<int>::max(), -25, btTransform::getIdentity()); mNavigator->addWater(osg::Vec2i(0, 0), std::numeric_limits<int>::max(), -25, btTransform::getIdentity());
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
mStart.x() = 0; mStart.x() = 0;
mEnd.x() = 0; mEnd.x() = 0;
@ -598,7 +601,7 @@ namespace
mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, -25, btTransform::getIdentity()); mNavigator->addWater(osg::Vec2i(0, 0), 128 * 4, -25, btTransform::getIdentity());
mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity());
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
mStart.x() = 0; mStart.x() = 0;
mEnd.x() = 0; mEnd.x() = 0;
@ -642,15 +645,15 @@ namespace
mNavigator->addAgent(mAgentHalfExtents); mNavigator->addAgent(mAgentHalfExtents);
mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity());
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
mNavigator->removeObject(ObjectId(&shape)); mNavigator->removeObject(ObjectId(&shape));
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity());
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success);
@ -696,7 +699,7 @@ namespace
mNavigator->addAgent(mAgentHalfExtents); mNavigator->addAgent(mAgentHalfExtents);
mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity());
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
Misc::Rng::init(42); Misc::Rng::init(42);
@ -745,7 +748,7 @@ namespace
} }
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success); EXPECT_EQ(mNavigator->findPath(mAgentHalfExtents, mStepSize, mStart, mEnd, Flag_walk, mAreaCosts, mOut), Status::Success);
@ -788,7 +791,7 @@ namespace
mNavigator->addObject(ObjectId(&shapes[i]), shapes[i], transform); mNavigator->addObject(ObjectId(&shapes[i]), shapes[i], transform);
} }
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
const auto start = std::chrono::steady_clock::now(); const auto start = std::chrono::steady_clock::now();
for (std::size_t i = 0; i < shapes.size(); ++i) for (std::size_t i = 0; i < shapes.size(); ++i)
@ -797,7 +800,7 @@ namespace
mNavigator->updateObject(ObjectId(&shapes[i]), shapes[i], transform); mNavigator->updateObject(ObjectId(&shapes[i]), shapes[i], transform);
} }
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
for (std::size_t i = 0; i < shapes.size(); ++i) for (std::size_t i = 0; i < shapes.size(); ++i)
{ {
@ -805,7 +808,7 @@ namespace
mNavigator->updateObject(ObjectId(&shapes[i]), shapes[i], transform); mNavigator->updateObject(ObjectId(&shapes[i]), shapes[i], transform);
} }
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
const auto duration = std::chrono::steady_clock::now() - start; const auto duration = std::chrono::steady_clock::now() - start;
@ -828,7 +831,7 @@ namespace
mNavigator->addAgent(mAgentHalfExtents); mNavigator->addAgent(mAgentHalfExtents);
mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity()); mNavigator->addObject(ObjectId(&shape), shape, btTransform::getIdentity());
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
const auto result = mNavigator->raycast(mAgentHalfExtents, mStart, mEnd, Flag_walk); const auto result = mNavigator->raycast(mAgentHalfExtents, mStart, mEnd, Flag_walk);
@ -859,7 +862,7 @@ namespace
mNavigator->addObject(ObjectId(&boderBoxShape), boderBoxShape, mNavigator->addObject(ObjectId(&boderBoxShape), boderBoxShape,
btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition + btVector3(0, 0, 200))); btTransform(btMatrix3x3::getIdentity(), oscillatingBoxShapePosition + btVector3(0, 0, 200)));
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
const auto navMeshes = mNavigator->getNavMeshes(); const auto navMeshes = mNavigator->getNavMeshes();
ASSERT_EQ(navMeshes.size(), 1); ASSERT_EQ(navMeshes.size(), 1);
@ -875,7 +878,7 @@ namespace
oscillatingBoxShapePosition); oscillatingBoxShapePosition);
mNavigator->updateObject(ObjectId(&oscillatingBoxShape), oscillatingBoxShape, transform); mNavigator->updateObject(ObjectId(&oscillatingBoxShape), oscillatingBoxShape, transform);
mNavigator->update(mPlayerPosition); mNavigator->update(mPlayerPosition);
mNavigator->wait(); mNavigator->wait(mListener);
} }
ASSERT_EQ(navMeshes.size(), 1); ASSERT_EQ(navMeshes.size(), 1);

View file

@ -6,6 +6,7 @@
#include <components/debug/debuglog.hpp> #include <components/debug/debuglog.hpp>
#include <components/misc/thread.hpp> #include <components/misc/thread.hpp>
#include <components/loadinglistener/loadinglistener.hpp>
#include <osg/Stats> #include <osg/Stats>
@ -20,6 +21,16 @@ namespace
{ {
return std::abs(lhs.x() - rhs.x()) + std::abs(lhs.y() - rhs.y()); return std::abs(lhs.x() - rhs.x()) + std::abs(lhs.y() - rhs.y());
} }
int getMinDistanceTo(const TilePosition& position, int maxDistance,
const std::map<osg::Vec3f, std::set<TilePosition>>& tilesPerHalfExtents)
{
int result = maxDistance;
for (const auto& [halfExtents, tiles] : tilesPerHalfExtents)
for (const TilePosition& tile : tiles)
result = std::min(result, getManhattanDistance(position, tile));
return result;
}
} }
namespace DetourNavigator namespace DetourNavigator
@ -111,13 +122,61 @@ namespace DetourNavigator
mHasJob.notify_all(); mHasJob.notify_all();
} }
void AsyncNavMeshUpdater::wait() void AsyncNavMeshUpdater::wait(Loading::Listener& listener)
{ {
if (mSettings.get().mWaitUntilMinDistanceToPlayer == 0)
return;
listener.setLabel("Building navigation mesh");
const std::size_t initialJobsLeft = getTotalJobs();
std::size_t maxProgress = initialJobsLeft + mThreads.size();
listener.setProgressRange(maxProgress);
const int minDistanceToPlayer = waitUntilJobsDone(initialJobsLeft, maxProgress, listener);
if (minDistanceToPlayer < mSettings.get().mWaitUntilMinDistanceToPlayer)
{ {
std::unique_lock<std::mutex> lock(mMutex);
mDone.wait(lock, [&] { return mJobs.empty() && getTotalThreadJobsUnsafe() == 0; });
}
mProcessingTiles.wait(mProcessed, [] (const auto& v) { return v.empty(); }); mProcessingTiles.wait(mProcessed, [] (const auto& v) { return v.empty(); });
listener.setProgress(maxProgress);
}
}
int AsyncNavMeshUpdater::waitUntilJobsDone(const std::size_t initialJobsLeft, std::size_t& maxProgress, Loading::Listener& listener)
{
std::size_t prevJobsLeft = initialJobsLeft;
std::size_t jobsDone = 0;
std::size_t jobsLeft = 0;
const int maxDistanceToPlayer = mSettings.get().mWaitUntilMinDistanceToPlayer;
const TilePosition playerPosition = *mPlayerTile.lockConst();
int minDistanceToPlayer = 0;
const auto isDone = [&]
{
jobsLeft = mJobs.size() + getTotalThreadJobsUnsafe();
if (jobsLeft == 0)
{
minDistanceToPlayer = 0;
return true;
}
minDistanceToPlayer = getMinDistanceTo(playerPosition, maxDistanceToPlayer, mPushed);
for (const auto& [threadId, queue] : mThreadsQueues)
minDistanceToPlayer = getMinDistanceTo(playerPosition, minDistanceToPlayer, queue.mPushed);
return minDistanceToPlayer >= maxDistanceToPlayer;
};
std::unique_lock<std::mutex> lock(mMutex);
while (!mDone.wait_for(lock, std::chrono::milliseconds(250), isDone))
{
if (maxProgress < jobsLeft)
{
maxProgress = jobsLeft + mThreads.size();
listener.setProgressRange(maxProgress);
listener.setProgress(jobsDone);
}
else if (jobsLeft < prevJobsLeft)
{
const std::size_t newJobsDone = prevJobsLeft - jobsLeft;
jobsDone += newJobsDone;
prevJobsLeft = jobsLeft;
listener.increaseProgress(newJobsDone);
}
}
return minDistanceToPlayer;
} }
void AsyncNavMeshUpdater::reportStats(unsigned int frameNumber, osg::Stats& stats) const void AsyncNavMeshUpdater::reportStats(unsigned int frameNumber, osg::Stats& stats) const
@ -381,6 +440,12 @@ namespace DetourNavigator
mProcessed.notify_all(); mProcessed.notify_all();
} }
std::size_t AsyncNavMeshUpdater::getTotalJobs() const
{
const std::scoped_lock lock(mMutex);
return mJobs.size() + getTotalThreadJobsUnsafe();
}
std::size_t AsyncNavMeshUpdater::getTotalThreadJobsUnsafe() const std::size_t AsyncNavMeshUpdater::getTotalThreadJobsUnsafe() const
{ {
return std::accumulate(mThreadsQueues.begin(), mThreadsQueues.end(), std::size_t(0), return std::accumulate(mThreadsQueues.begin(), mThreadsQueues.end(), std::size_t(0),

View file

@ -20,6 +20,11 @@
class dtNavMesh; class dtNavMesh;
namespace Loading
{
class Listener;
}
namespace DetourNavigator namespace DetourNavigator
{ {
enum class ChangeType enum class ChangeType
@ -55,7 +60,7 @@ namespace DetourNavigator
void post(const osg::Vec3f& agentHalfExtents, const SharedNavMeshCacheItem& mNavMeshCacheItem, void post(const osg::Vec3f& agentHalfExtents, const SharedNavMeshCacheItem& mNavMeshCacheItem,
const TilePosition& playerTile, const std::map<TilePosition, ChangeType>& changedTiles); const TilePosition& playerTile, const std::map<TilePosition, ChangeType>& changedTiles);
void wait(); void wait(Loading::Listener& listener);
void reportStats(unsigned int frameNumber, osg::Stats& stats) const; void reportStats(unsigned int frameNumber, osg::Stats& stats) const;
@ -131,9 +136,13 @@ namespace DetourNavigator
void unlockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile); void unlockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile);
inline std::size_t getTotalJobs() const;
inline std::size_t getTotalThreadJobsUnsafe() const; inline std::size_t getTotalThreadJobsUnsafe() const;
void cleanupLastUpdates(); void cleanupLastUpdates();
int waitUntilJobsDone(const std::size_t initialJobsLeft, std::size_t& maxJobsLeft, Loading::Listener& listener);
}; };
} }

View file

@ -14,6 +14,11 @@ namespace ESM
struct Pathgrid; struct Pathgrid;
} }
namespace Loading
{
class Listener;
}
namespace DetourNavigator namespace DetourNavigator
{ {
struct ObjectShapes struct ObjectShapes
@ -162,7 +167,7 @@ namespace DetourNavigator
/** /**
* @brief wait locks thread until all tiles are updated from last update call. * @brief wait locks thread until all tiles are updated from last update call.
*/ */
virtual void wait() = 0; virtual void wait(Loading::Listener& listener) = 0;
/** /**
* @brief findPath fills output iterator with points of scene surfaces to be used for actor to walk through. * @brief findPath fills output iterator with points of scene surfaces to be used for actor to walk through.

View file

@ -153,9 +153,9 @@ namespace DetourNavigator
mUpdatesEnabled = enabled; mUpdatesEnabled = enabled;
} }
void NavigatorImpl::wait() void NavigatorImpl::wait(Loading::Listener& listener)
{ {
mNavMeshManager.wait(); mNavMeshManager.wait(listener);
} }
SharedNavMeshCacheItem NavigatorImpl::getNavMesh(const osg::Vec3f& agentHalfExtents) const SharedNavMeshCacheItem NavigatorImpl::getNavMesh(const osg::Vec3f& agentHalfExtents) const

View file

@ -48,7 +48,7 @@ namespace DetourNavigator
void setUpdatesEnabled(bool enabled) override; void setUpdatesEnabled(bool enabled) override;
void wait() override; void wait(Loading::Listener& listener) override;
SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& agentHalfExtents) const override; SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& agentHalfExtents) const override;

View file

@ -3,6 +3,11 @@
#include "navigator.hpp" #include "navigator.hpp"
namespace Loading
{
class Listener;
}
namespace DetourNavigator namespace DetourNavigator
{ {
class NavigatorStub final : public Navigator class NavigatorStub final : public Navigator
@ -68,7 +73,7 @@ namespace DetourNavigator
void setUpdatesEnabled(bool /*enabled*/) override {} void setUpdatesEnabled(bool /*enabled*/) override {}
void wait() override {} void wait(Loading::Listener& /*listener*/) override {}
SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& /*agentHalfExtents*/) const override SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& /*agentHalfExtents*/) const override
{ {

View file

@ -190,9 +190,9 @@ namespace DetourNavigator
" recastMeshManagerRevision=" << lastRevision; " recastMeshManagerRevision=" << lastRevision;
} }
void NavMeshManager::wait() void NavMeshManager::wait(Loading::Listener& listener)
{ {
mAsyncNavMeshUpdater.wait(); mAsyncNavMeshUpdater.wait(listener);
} }
SharedNavMeshCacheItem NavMeshManager::getNavMesh(const osg::Vec3f& agentHalfExtents) const SharedNavMeshCacheItem NavMeshManager::getNavMesh(const osg::Vec3f& agentHalfExtents) const

View file

@ -45,7 +45,7 @@ namespace DetourNavigator
void update(osg::Vec3f playerPosition, const osg::Vec3f& agentHalfExtents); void update(osg::Vec3f playerPosition, const osg::Vec3f& agentHalfExtents);
void wait(); void wait(Loading::Listener& listener);
SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& agentHalfExtents) const; SharedNavMeshCacheItem getNavMesh(const osg::Vec3f& agentHalfExtents) const;

View file

@ -29,6 +29,7 @@ namespace DetourNavigator
navigatorSettings.mRegionMergeSize = ::Settings::Manager::getInt("region merge size", "Navigator"); navigatorSettings.mRegionMergeSize = ::Settings::Manager::getInt("region merge size", "Navigator");
navigatorSettings.mRegionMinSize = ::Settings::Manager::getInt("region min size", "Navigator"); navigatorSettings.mRegionMinSize = ::Settings::Manager::getInt("region min size", "Navigator");
navigatorSettings.mTileSize = ::Settings::Manager::getInt("tile size", "Navigator"); navigatorSettings.mTileSize = ::Settings::Manager::getInt("tile size", "Navigator");
navigatorSettings.mWaitUntilMinDistanceToPlayer = ::Settings::Manager::getInt("wait until min distance to player", "Navigator");
navigatorSettings.mAsyncNavMeshUpdaterThreads = static_cast<std::size_t>(::Settings::Manager::getInt("async nav mesh updater threads", "Navigator")); navigatorSettings.mAsyncNavMeshUpdaterThreads = static_cast<std::size_t>(::Settings::Manager::getInt("async nav mesh updater threads", "Navigator"));
navigatorSettings.mMaxNavMeshTilesCacheSize = static_cast<std::size_t>(::Settings::Manager::getInt("max nav mesh tiles cache size", "Navigator")); navigatorSettings.mMaxNavMeshTilesCacheSize = static_cast<std::size_t>(::Settings::Manager::getInt("max nav mesh tiles cache size", "Navigator"));
navigatorSettings.mMaxPolygonPathSize = static_cast<std::size_t>(::Settings::Manager::getInt("max polygon path size", "Navigator")); navigatorSettings.mMaxPolygonPathSize = static_cast<std::size_t>(::Settings::Manager::getInt("max polygon path size", "Navigator"));

View file

@ -31,6 +31,7 @@ namespace DetourNavigator
int mRegionMergeSize = 0; int mRegionMergeSize = 0;
int mRegionMinSize = 0; int mRegionMinSize = 0;
int mTileSize = 0; int mTileSize = 0;
int mWaitUntilMinDistanceToPlayer = 0;
std::size_t mAsyncNavMeshUpdaterThreads = 0; std::size_t mAsyncNavMeshUpdaterThreads = 0;
std::size_t mMaxNavMeshTilesCacheSize = 0; std::size_t mMaxNavMeshTilesCacheSize = 0;
std::size_t mMaxPolygonPathSize = 0; std::size_t mMaxPolygonPathSize = 0;

View file

@ -75,7 +75,7 @@ namespace Misc
return Locked<T>(mMutex, mValue); return Locked<T>(mMutex, mValue);
} }
Locked<const T> lockConst() Locked<const T> lockConst() const
{ {
return Locked<const T>(mMutex, mValue); return Locked<const T>(mMutex, mValue);
} }
@ -88,7 +88,7 @@ namespace Misc
} }
private: private:
std::mutex mMutex; mutable std::mutex mMutex;
T mValue; T mValue;
}; };
} }

View file

@ -42,6 +42,18 @@ Increasing this value may decrease performance.
This condition is always true: ``max tiles number * max polygons per tile <= 4194304``. This condition is always true: ``max tiles number * max polygons per tile <= 4194304``.
It's a limitation of `Recastnavigation <https://github.com/recastnavigation/recastnavigation>`_ library. It's a limitation of `Recastnavigation <https://github.com/recastnavigation/recastnavigation>`_ library.
wait until min distance to player
------------------------------
:Type: integer
:Range: >= 0
:Default: 5
Distance in navmesh tiles around the player to keep loading screen until navigation mesh is generated.
Allows to complete cell loading only when minimal navigation mesh area is generated to correctly find path for actors
nearby the player. Increasing this value will keep loading screen longer but will slightly increase nav mesh generation
speed on systems bound by CPU. Zero means no waiting.
Advanced settings Advanced settings
***************** *****************

View file

@ -908,6 +908,10 @@ max tiles number = 512
# Min time duration for the same tile update in milliseconds (value >= 0) # Min time duration for the same tile update in milliseconds (value >= 0)
min update interval ms = 250 min update interval ms = 250
# Keep loading screen until navmesh is generated around the player for all tiles within manhattan distance (value >= 0).
# Distance is measured in the number of tiles and can be only an integer value.
wait until min distance to player = 5
[Shadows] [Shadows]
# Enable or disable shadows. Bear in mind that this will force OpenMW to use shaders as if "[Shaders]/force shaders" was set to true. # Enable or disable shadows. Bear in mind that this will force OpenMW to use shaders as if "[Shaders]/force shaders" was set to true.