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:
commit
fd89582e0c
16 changed files with 147 additions and 37 deletions
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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"));
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
*****************
|
*****************
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in a new issue