mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-31 23:15:43 +00:00
Merge branch 'navmesh_fix_remove_tiles' into 'master'
Fix removing navmesh tiles at high player speed See merge request OpenMW/openmw!1151
This commit is contained in:
commit
7cc58fa20d
3 changed files with 55 additions and 78 deletions
|
@ -8,6 +8,8 @@
|
||||||
#include <components/misc/thread.hpp>
|
#include <components/misc/thread.hpp>
|
||||||
#include <components/loadinglistener/loadinglistener.hpp>
|
#include <components/loadinglistener/loadinglistener.hpp>
|
||||||
|
|
||||||
|
#include <DetourNavMesh.h>
|
||||||
|
|
||||||
#include <osg/Stats>
|
#include <osg/Stats>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -48,7 +50,7 @@ namespace
|
||||||
|
|
||||||
auto getPriority(const Job& job) noexcept
|
auto getPriority(const Job& job) noexcept
|
||||||
{
|
{
|
||||||
return std::make_tuple(job.mProcessTime, job.mTryNumber, job.mChangeType, job.mDistanceToPlayer, job.mDistanceToOrigin);
|
return std::make_tuple(job.mProcessTime, job.mChangeType, job.mTryNumber, job.mDistanceToPlayer, job.mDistanceToOrigin);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LessByJobPriority
|
struct LessByJobPriority
|
||||||
|
@ -102,7 +104,6 @@ namespace DetourNavigator
|
||||||
{
|
{
|
||||||
mShouldStop = true;
|
mShouldStop = true;
|
||||||
std::unique_lock<std::mutex> lock(mMutex);
|
std::unique_lock<std::mutex> lock(mMutex);
|
||||||
mThreadsQueues.clear();
|
|
||||||
mWaiting.clear();
|
mWaiting.clear();
|
||||||
mHasJob.notify_all();
|
mHasJob.notify_all();
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
|
@ -124,11 +125,19 @@ namespace DetourNavigator
|
||||||
if (!playerTileChanged && changedTiles.empty())
|
if (!playerTileChanged && changedTiles.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const dtNavMeshParams params = *navMeshCacheItem->lockConst()->getImpl().getParams();
|
||||||
|
|
||||||
const std::lock_guard<std::mutex> lock(mMutex);
|
const std::lock_guard<std::mutex> lock(mMutex);
|
||||||
|
|
||||||
if (playerTileChanged)
|
if (playerTileChanged)
|
||||||
|
{
|
||||||
for (JobIt job : mWaiting)
|
for (JobIt job : mWaiting)
|
||||||
|
{
|
||||||
job->mDistanceToPlayer = getManhattanDistance(job->mChangedTile, playerTile);
|
job->mDistanceToPlayer = getManhattanDistance(job->mChangedTile, playerTile);
|
||||||
|
if (!shouldAddTile(job->mChangedTile, playerTile, std::min(mSettings.get().mMaxTilesNumber, params.maxTiles)))
|
||||||
|
job->mChangeType = ChangeType::remove;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (const auto& [changedTile, changeType] : changedTiles)
|
for (const auto& [changedTile, changeType] : changedTiles)
|
||||||
{
|
{
|
||||||
|
@ -235,13 +244,20 @@ namespace DetourNavigator
|
||||||
void AsyncNavMeshUpdater::reportStats(unsigned int frameNumber, osg::Stats& stats) const
|
void AsyncNavMeshUpdater::reportStats(unsigned int frameNumber, osg::Stats& stats) const
|
||||||
{
|
{
|
||||||
std::size_t jobs = 0;
|
std::size_t jobs = 0;
|
||||||
|
std::size_t waiting = 0;
|
||||||
|
std::size_t pushed = 0;
|
||||||
|
|
||||||
{
|
{
|
||||||
const std::lock_guard<std::mutex> lock(mMutex);
|
const std::lock_guard<std::mutex> lock(mMutex);
|
||||||
jobs = mJobs.size();
|
jobs = mJobs.size();
|
||||||
|
waiting = mWaiting.size();
|
||||||
|
pushed = mPushed.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
stats.setAttribute(frameNumber, "NavMesh UpdateJobs", jobs);
|
stats.setAttribute(frameNumber, "NavMesh Jobs", jobs);
|
||||||
|
stats.setAttribute(frameNumber, "NavMesh Waiting", waiting);
|
||||||
|
stats.setAttribute(frameNumber, "NavMesh Pushed", pushed);
|
||||||
|
stats.setAttribute(frameNumber, "NavMesh Processing", mProcessingTiles.lockConst()->size());
|
||||||
|
|
||||||
mNavMeshTilesCache.reportStats(frameNumber, stats);
|
mNavMeshTilesCache.reportStats(frameNumber, stats);
|
||||||
}
|
}
|
||||||
|
@ -340,18 +356,12 @@ namespace DetourNavigator
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(mMutex);
|
std::unique_lock<std::mutex> lock(mMutex);
|
||||||
|
|
||||||
const auto threadId = std::this_thread::get_id();
|
|
||||||
auto& threadQueue = mThreadsQueues[threadId];
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
bool shouldStop = false;
|
bool shouldStop = false;
|
||||||
|
const auto hasJob = [&]
|
||||||
const auto hasJob = [&] {
|
{
|
||||||
shouldStop = mShouldStop;
|
shouldStop = mShouldStop;
|
||||||
return shouldStop
|
return shouldStop
|
||||||
|| (!mWaiting.empty() && mWaiting.front()->mProcessTime <= std::chrono::steady_clock::now())
|
|| (!mWaiting.empty() && mWaiting.front()->mProcessTime <= std::chrono::steady_clock::now());
|
||||||
|| !threadQueue.empty();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!mHasJob.wait_for(lock, std::chrono::milliseconds(10), hasJob))
|
if (!mHasJob.wait_for(lock, std::chrono::milliseconds(10), hasJob))
|
||||||
|
@ -364,40 +374,20 @@ namespace DetourNavigator
|
||||||
if (shouldStop)
|
if (shouldStop)
|
||||||
return mJobs.end();
|
return mJobs.end();
|
||||||
|
|
||||||
Log(Debug::Debug) << "Got " << mJobs.size() << " navigator jobs and "
|
const JobIt job = mWaiting.front();
|
||||||
<< threadQueue.size() << " thread jobs by thread=" << std::this_thread::get_id();
|
|
||||||
|
|
||||||
const JobIt job = threadQueue.empty()
|
mWaiting.pop_front();
|
||||||
? getJob(mWaiting, true)
|
|
||||||
: getJob(threadQueue, false);
|
|
||||||
|
|
||||||
if (job == mJobs.end())
|
if (!lockTile(job->mAgentHalfExtents, job->mChangedTile))
|
||||||
continue;
|
|
||||||
|
|
||||||
const auto owner = lockTile(job->mAgentHalfExtents, job->mChangedTile);
|
|
||||||
|
|
||||||
if (owner == threadId)
|
|
||||||
{
|
{
|
||||||
mPushed.erase(getAgentAndTile(*job));
|
++job->mTryNumber;
|
||||||
return job;
|
insertPrioritizedJob(job, mWaiting);
|
||||||
}
|
|
||||||
|
|
||||||
postThreadJob(job, mThreadsQueues[owner]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JobIt AsyncNavMeshUpdater::getJob(std::deque<JobIt>& jobs, bool changeLastUpdate)
|
|
||||||
{
|
|
||||||
const auto now = std::chrono::steady_clock::now();
|
|
||||||
JobIt job = jobs.front();
|
|
||||||
|
|
||||||
if (job->mProcessTime > now)
|
|
||||||
return mJobs.end();
|
return mJobs.end();
|
||||||
|
}
|
||||||
|
|
||||||
jobs.pop_front();
|
if (job->mChangeType == ChangeType::update)
|
||||||
|
mLastUpdates[getAgentAndTile(*job)] = std::chrono::steady_clock::now();
|
||||||
if (changeLastUpdate && job->mChangeType == ChangeType::update)
|
mPushed.erase(getAgentAndTile(*job));
|
||||||
mLastUpdates[getAgentAndTile(*job)] = now;
|
|
||||||
|
|
||||||
return job;
|
return job;
|
||||||
}
|
}
|
||||||
|
@ -435,7 +425,7 @@ namespace DetourNavigator
|
||||||
if (mPushed.emplace(job->mAgentHalfExtents, job->mChangedTile).second)
|
if (mPushed.emplace(job->mAgentHalfExtents, job->mChangedTile).second)
|
||||||
{
|
{
|
||||||
++job->mTryNumber;
|
++job->mTryNumber;
|
||||||
mWaiting.push_back(job);
|
insertPrioritizedJob(job, mWaiting);
|
||||||
mHasJob.notify_all();
|
mHasJob.notify_all();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -443,26 +433,11 @@ namespace DetourNavigator
|
||||||
mJobs.erase(job);
|
mJobs.erase(job);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncNavMeshUpdater::postThreadJob(JobIt job, std::deque<JobIt>& queue)
|
bool AsyncNavMeshUpdater::lockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile)
|
||||||
{
|
|
||||||
queue.push_back(job);
|
|
||||||
mHasJob.notify_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::thread::id AsyncNavMeshUpdater::lockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile)
|
|
||||||
{
|
{
|
||||||
if (mSettings.get().mAsyncNavMeshUpdaterThreads <= 1)
|
if (mSettings.get().mAsyncNavMeshUpdaterThreads <= 1)
|
||||||
return std::this_thread::get_id();
|
return true;
|
||||||
|
return mProcessingTiles.lock()->emplace(agentHalfExtents, changedTile).second;
|
||||||
auto locked = mProcessingTiles.lock();
|
|
||||||
const auto tile = locked->find(std::make_tuple(agentHalfExtents, changedTile));
|
|
||||||
if (tile == locked->end())
|
|
||||||
{
|
|
||||||
const auto threadId = std::this_thread::get_id();
|
|
||||||
locked->emplace(std::tie(agentHalfExtents, changedTile), threadId);
|
|
||||||
return threadId;
|
|
||||||
}
|
|
||||||
return tile->second;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncNavMeshUpdater::unlockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile)
|
void AsyncNavMeshUpdater::unlockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile)
|
||||||
|
|
|
@ -60,7 +60,7 @@ namespace DetourNavigator
|
||||||
const TilePosition mChangedTile;
|
const TilePosition mChangedTile;
|
||||||
const std::chrono::steady_clock::time_point mProcessTime;
|
const std::chrono::steady_clock::time_point mProcessTime;
|
||||||
unsigned mTryNumber = 0;
|
unsigned mTryNumber = 0;
|
||||||
const ChangeType mChangeType;
|
ChangeType mChangeType;
|
||||||
int mDistanceToPlayer;
|
int mDistanceToPlayer;
|
||||||
const int mDistanceToOrigin;
|
const int mDistanceToOrigin;
|
||||||
|
|
||||||
|
@ -99,10 +99,9 @@ namespace DetourNavigator
|
||||||
std::set<std::tuple<osg::Vec3f, TilePosition>> mPushed;
|
std::set<std::tuple<osg::Vec3f, TilePosition>> mPushed;
|
||||||
Misc::ScopeGuarded<TilePosition> mPlayerTile;
|
Misc::ScopeGuarded<TilePosition> mPlayerTile;
|
||||||
NavMeshTilesCache mNavMeshTilesCache;
|
NavMeshTilesCache mNavMeshTilesCache;
|
||||||
Misc::ScopeGuarded<std::map<std::tuple<osg::Vec3f, TilePosition>, std::thread::id>> mProcessingTiles;
|
Misc::ScopeGuarded<std::set<std::tuple<osg::Vec3f, TilePosition>>> mProcessingTiles;
|
||||||
std::map<std::tuple<osg::Vec3f, TilePosition>, std::chrono::steady_clock::time_point> mLastUpdates;
|
std::map<std::tuple<osg::Vec3f, TilePosition>, std::chrono::steady_clock::time_point> mLastUpdates;
|
||||||
std::set<std::tuple<osg::Vec3f, TilePosition>> mPresentTiles;
|
std::set<std::tuple<osg::Vec3f, TilePosition>> mPresentTiles;
|
||||||
std::map<std::thread::id, std::deque<JobIt>> mThreadsQueues;
|
|
||||||
std::vector<std::thread> mThreads;
|
std::vector<std::thread> mThreads;
|
||||||
|
|
||||||
void process() noexcept;
|
void process() noexcept;
|
||||||
|
@ -119,7 +118,7 @@ namespace DetourNavigator
|
||||||
|
|
||||||
void repost(JobIt job);
|
void repost(JobIt job);
|
||||||
|
|
||||||
std::thread::id lockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile);
|
bool lockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile);
|
||||||
|
|
||||||
void unlockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile);
|
void unlockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile);
|
||||||
|
|
||||||
|
|
|
@ -390,7 +390,10 @@ void StatsHandler::setUpScene(osgViewer::ViewerBase *viewer)
|
||||||
"Land",
|
"Land",
|
||||||
"Composite",
|
"Composite",
|
||||||
"",
|
"",
|
||||||
"NavMesh UpdateJobs",
|
"NavMesh Jobs",
|
||||||
|
"NavMesh Waiting",
|
||||||
|
"NavMesh Pushed",
|
||||||
|
"NavMesh Processing",
|
||||||
"NavMesh CacheSize",
|
"NavMesh CacheSize",
|
||||||
"NavMesh UsedTiles",
|
"NavMesh UsedTiles",
|
||||||
"NavMesh CachedTiles",
|
"NavMesh CachedTiles",
|
||||||
|
|
Loading…
Reference in a new issue