mirror of
https://github.com/OpenMW/openmw.git
synced 2025-03-03 07:09:40 +00:00
Wait until navmesh is generated within given distance around player
Add a setting to change this distance. To prevent situations when there is not enough navmesh generated and actors can't find path correctly.
This commit is contained in:
parent
f169f8e6f0
commit
7a51d0db18
9 changed files with 55 additions and 6 deletions
|
@ -141,6 +141,7 @@
|
|||
Feature #5456: Basic collada animation support
|
||||
Feature #5457: Realistic diagonal movement
|
||||
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 #5519: Code Patch tab in launcher
|
||||
Feature #5524: Resume failed script execution after reload
|
||||
|
|
|
@ -620,6 +620,8 @@ namespace MWWorld
|
|||
|
||||
if (changeEvent)
|
||||
mCellChanged = true;
|
||||
|
||||
mNavigator.wait(*loadingListener);
|
||||
}
|
||||
|
||||
void Scene::testExteriorCells()
|
||||
|
|
|
@ -66,6 +66,7 @@ namespace
|
|||
mSettings.mRegionMergeSize = 20;
|
||||
mSettings.mRegionMinSize = 8;
|
||||
mSettings.mTileSize = 64;
|
||||
mSettings.mWaitUntilMinDistanceToPlayer = std::numeric_limits<int>::max();
|
||||
mSettings.mAsyncNavMeshUpdaterThreads = 1;
|
||||
mSettings.mMaxNavMeshTilesCacheSize = 1024 * 1024;
|
||||
mSettings.mMaxPolygonPathSize = 1024;
|
||||
|
|
|
@ -21,6 +21,16 @@ namespace
|
|||
{
|
||||
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
|
||||
|
@ -114,24 +124,40 @@ namespace DetourNavigator
|
|||
|
||||
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);
|
||||
waitUntilJobsDone(initialJobsLeft, maxProgress, listener);
|
||||
mProcessingTiles.wait(mProcessed, [] (const auto& v) { return v.empty(); });
|
||||
listener.setProgress(maxProgress);
|
||||
const int minDistanceToPlayer = waitUntilJobsDone(initialJobsLeft, maxProgress, listener);
|
||||
if (minDistanceToPlayer < mSettings.get().mWaitUntilMinDistanceToPlayer)
|
||||
{
|
||||
mProcessingTiles.wait(mProcessed, [] (const auto& v) { return v.empty(); });
|
||||
listener.setProgress(maxProgress);
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncNavMeshUpdater::waitUntilJobsDone(const std::size_t initialJobsLeft, std::size_t& maxProgress, Loading::Listener& listener)
|
||||
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();
|
||||
return jobsLeft == 0;
|
||||
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))
|
||||
|
@ -150,6 +176,7 @@ namespace DetourNavigator
|
|||
listener.increaseProgress(newJobsDone);
|
||||
}
|
||||
}
|
||||
return minDistanceToPlayer;
|
||||
}
|
||||
|
||||
void AsyncNavMeshUpdater::reportStats(unsigned int frameNumber, osg::Stats& stats) const
|
||||
|
|
|
@ -142,7 +142,7 @@ namespace DetourNavigator
|
|||
|
||||
void cleanupLastUpdates();
|
||||
|
||||
void waitUntilJobsDone(const std::size_t initialJobsLeft, std::size_t& maxJobsLeft, Loading::Listener& listener);
|
||||
int waitUntilJobsDone(const std::size_t initialJobsLeft, std::size_t& maxJobsLeft, Loading::Listener& listener);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace DetourNavigator
|
|||
navigatorSettings.mRegionMergeSize = ::Settings::Manager::getInt("region merge size", "Navigator");
|
||||
navigatorSettings.mRegionMinSize = ::Settings::Manager::getInt("region min 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.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"));
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace DetourNavigator
|
|||
int mRegionMergeSize = 0;
|
||||
int mRegionMinSize = 0;
|
||||
int mTileSize = 0;
|
||||
int mWaitUntilMinDistanceToPlayer = 0;
|
||||
std::size_t mAsyncNavMeshUpdaterThreads = 0;
|
||||
std::size_t mMaxNavMeshTilesCacheSize = 0;
|
||||
std::size_t mMaxPolygonPathSize = 0;
|
||||
|
|
|
@ -42,6 +42,18 @@ Increasing this value may decrease performance.
|
|||
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.
|
||||
|
||||
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
|
||||
*****************
|
||||
|
||||
|
|
|
@ -908,6 +908,10 @@ max tiles number = 512
|
|||
# Min time duration for the same tile update in milliseconds (value >= 0)
|
||||
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]
|
||||
|
||||
# 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