|
|
@ -16,8 +16,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
#include <osg/io_utils>
|
|
|
|
#include <osg/io_utils>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <boost/geometry.hpp>
|
|
|
|
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <numeric>
|
|
|
|
|
|
|
|
#include <optional>
|
|
|
|
#include <optional>
|
|
|
|
#include <set>
|
|
|
|
#include <set>
|
|
|
|
#include <tuple>
|
|
|
|
#include <tuple>
|
|
|
@ -49,40 +50,6 @@ namespace DetourNavigator
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
auto getPriority(const Job& job) noexcept
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return std::make_tuple(-static_cast<std::underlying_type_t<JobState>>(job.mState), job.mProcessTime,
|
|
|
|
|
|
|
|
job.mChangeType, job.mTryNumber, job.mDistanceToPlayer, job.mDistanceToOrigin);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct LessByJobPriority
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
bool operator()(JobIt lhs, JobIt rhs) const noexcept { return getPriority(*lhs) < getPriority(*rhs); }
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void insertPrioritizedJob(JobIt job, std::deque<JobIt>& queue)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const auto it = std::upper_bound(queue.begin(), queue.end(), job, LessByJobPriority{});
|
|
|
|
|
|
|
|
queue.insert(it, job);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto getDbPriority(const Job& job) noexcept
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return std::make_tuple(static_cast<std::underlying_type_t<JobState>>(job.mState), job.mChangeType,
|
|
|
|
|
|
|
|
job.mDistanceToPlayer, job.mDistanceToOrigin);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct LessByJobDbPriority
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
bool operator()(JobIt lhs, JobIt rhs) const noexcept { return getDbPriority(*lhs) < getDbPriority(*rhs); }
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void insertPrioritizedDbJob(JobIt job, std::deque<JobIt>& queue)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const auto it = std::upper_bound(queue.begin(), queue.end(), job, LessByJobDbPriority{});
|
|
|
|
|
|
|
|
queue.insert(it, job);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto getAgentAndTile(const Job& job) noexcept
|
|
|
|
auto getAgentAndTile(const Job& job) noexcept
|
|
|
|
{
|
|
|
|
{
|
|
|
|
return std::make_tuple(job.mAgentBounds, job.mChangedTile);
|
|
|
|
return std::make_tuple(job.mAgentBounds, job.mChangedTile);
|
|
|
@ -97,16 +64,6 @@ namespace DetourNavigator
|
|
|
|
settings.mRecast, settings.mWriteToNavMeshDb);
|
|
|
|
settings.mRecast, settings.mWriteToNavMeshDb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void updateJobs(std::deque<JobIt>& jobs, TilePosition playerTile, int maxTiles)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
for (JobIt job : jobs)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
job->mDistanceToPlayer = getManhattanDistance(job->mChangedTile, playerTile);
|
|
|
|
|
|
|
|
if (!shouldAddTile(job->mChangedTile, playerTile, maxTiles))
|
|
|
|
|
|
|
|
job->mChangeType = ChangeType::remove;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::size_t getNextJobId()
|
|
|
|
std::size_t getNextJobId()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
static std::atomic_size_t nextJobId{ 1 };
|
|
|
|
static std::atomic_size_t nextJobId{ 1 };
|
|
|
@ -134,7 +91,7 @@ namespace DetourNavigator
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Job::Job(const AgentBounds& agentBounds, std::weak_ptr<GuardedNavMeshCacheItem> navMeshCacheItem,
|
|
|
|
Job::Job(const AgentBounds& agentBounds, std::weak_ptr<GuardedNavMeshCacheItem> navMeshCacheItem,
|
|
|
|
std::string_view worldspace, const TilePosition& changedTile, ChangeType changeType, int distanceToPlayer,
|
|
|
|
std::string_view worldspace, const TilePosition& changedTile, ChangeType changeType,
|
|
|
|
std::chrono::steady_clock::time_point processTime)
|
|
|
|
std::chrono::steady_clock::time_point processTime)
|
|
|
|
: mId(getNextJobId())
|
|
|
|
: mId(getNextJobId())
|
|
|
|
, mAgentBounds(agentBounds)
|
|
|
|
, mAgentBounds(agentBounds)
|
|
|
@ -143,11 +100,148 @@ namespace DetourNavigator
|
|
|
|
, mChangedTile(changedTile)
|
|
|
|
, mChangedTile(changedTile)
|
|
|
|
, mProcessTime(processTime)
|
|
|
|
, mProcessTime(processTime)
|
|
|
|
, mChangeType(changeType)
|
|
|
|
, mChangeType(changeType)
|
|
|
|
, mDistanceToPlayer(distanceToPlayer)
|
|
|
|
|
|
|
|
, mDistanceToOrigin(getManhattanDistance(changedTile, TilePosition{ 0, 0 }))
|
|
|
|
|
|
|
|
{
|
|
|
|
{
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SpatialJobQueue::clear()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
mValues.clear();
|
|
|
|
|
|
|
|
mIndex.clear();
|
|
|
|
|
|
|
|
mSize = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SpatialJobQueue::push(JobIt job)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
auto it = mValues.find(job->mChangedTile);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (it == mValues.end())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
it = mValues.emplace_hint(it, job->mChangedTile, std::deque<JobIt>());
|
|
|
|
|
|
|
|
mIndex.insert(IndexValue(IndexPoint(job->mChangedTile.x(), job->mChangedTile.y()), it));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it->second.push_back(job);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
++mSize;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::optional<JobIt> SpatialJobQueue::pop(TilePosition playerTile)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const IndexPoint point(playerTile.x(), playerTile.y());
|
|
|
|
|
|
|
|
const auto it = mIndex.qbegin(boost::geometry::index::nearest(point, 1));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (it == mIndex.qend())
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const UpdatingMap::iterator mapIt = it->second;
|
|
|
|
|
|
|
|
std::deque<JobIt>& tileJobs = mapIt->second;
|
|
|
|
|
|
|
|
JobIt result = tileJobs.front();
|
|
|
|
|
|
|
|
tileJobs.pop_front();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
--mSize;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (tileJobs.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
mValues.erase(mapIt);
|
|
|
|
|
|
|
|
mIndex.remove(*it);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void SpatialJobQueue::update(TilePosition playerTile, int maxTiles, std::vector<JobIt>& removing)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
for (auto it = mValues.begin(); it != mValues.end();)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (shouldAddTile(it->first, playerTile, maxTiles))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
++it;
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (JobIt job : it->second)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
job->mChangeType = ChangeType::remove;
|
|
|
|
|
|
|
|
removing.push_back(job);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mSize -= it->second.size();
|
|
|
|
|
|
|
|
mIndex.remove(IndexValue(IndexPoint(it->first.x(), it->first.y()), it));
|
|
|
|
|
|
|
|
it = mValues.erase(it);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool JobQueue::hasJob(std::chrono::steady_clock::time_point now) const
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
return !mRemoving.empty() || mUpdating.size() > 0
|
|
|
|
|
|
|
|
|| (!mDelayed.empty() && mDelayed.front()->mProcessTime <= now);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void JobQueue::clear()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
mRemoving.clear();
|
|
|
|
|
|
|
|
mDelayed.clear();
|
|
|
|
|
|
|
|
mUpdating.clear();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void JobQueue::push(JobIt job, std::chrono::steady_clock::time_point now)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (job->mProcessTime > now)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
mDelayed.push_back(job);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (job->mChangeType == ChangeType::remove)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
mRemoving.push_back(job);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mUpdating.push(job);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::optional<JobIt> JobQueue::pop(TilePosition playerTile, std::chrono::steady_clock::time_point now)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!mRemoving.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const JobIt result = mRemoving.back();
|
|
|
|
|
|
|
|
mRemoving.pop_back();
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (const std::optional<JobIt> result = mUpdating.pop(playerTile))
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (mDelayed.empty() || mDelayed.front()->mProcessTime > now)
|
|
|
|
|
|
|
|
return std::nullopt;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const JobIt result = mDelayed.front();
|
|
|
|
|
|
|
|
mDelayed.pop_front();
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void JobQueue::update(TilePosition playerTile, int maxTiles, std::chrono::steady_clock::time_point now)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
mUpdating.update(playerTile, maxTiles, mRemoving);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (!mDelayed.empty() && mDelayed.front()->mProcessTime <= now)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
const JobIt job = mDelayed.front();
|
|
|
|
|
|
|
|
mDelayed.pop_front();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (shouldAddTile(job->mChangedTile, playerTile, maxTiles))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
mUpdating.push(job);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
job->mChangeType = ChangeType::remove;
|
|
|
|
|
|
|
|
mRemoving.push_back(job);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AsyncNavMeshUpdater::AsyncNavMeshUpdater(const Settings& settings, TileCachedRecastMeshManager& recastMeshManager,
|
|
|
|
AsyncNavMeshUpdater::AsyncNavMeshUpdater(const Settings& settings, TileCachedRecastMeshManager& recastMeshManager,
|
|
|
|
OffMeshConnectionsManager& offMeshConnectionsManager, std::unique_ptr<NavMeshDb>&& db)
|
|
|
|
OffMeshConnectionsManager& offMeshConnectionsManager, std::unique_ptr<NavMeshDb>&& db)
|
|
|
|
: mSettings(settings)
|
|
|
|
: mSettings(settings)
|
|
|
@ -183,42 +277,44 @@ namespace DetourNavigator
|
|
|
|
std::unique_lock lock(mMutex);
|
|
|
|
std::unique_lock lock(mMutex);
|
|
|
|
|
|
|
|
|
|
|
|
if (playerTileChanged)
|
|
|
|
if (playerTileChanged)
|
|
|
|
updateJobs(mWaiting, playerTile, mSettings.get().mMaxTilesNumber);
|
|
|
|
{
|
|
|
|
|
|
|
|
Log(Debug::Debug) << "Player tile has been changed to " << playerTile;
|
|
|
|
|
|
|
|
mWaiting.update(playerTile, mSettings.get().mMaxTilesNumber);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (const auto& [changedTile, changeType] : changedTiles)
|
|
|
|
for (const auto& [changedTile, changeType] : changedTiles)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (mPushed.emplace(agentBounds, changedTile).second)
|
|
|
|
if (mPushed.emplace(agentBounds, changedTile).second)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
const auto processTime = changeType == ChangeType::update
|
|
|
|
const auto processTime = [&, changedTile = changedTile, changeType = changeType] {
|
|
|
|
? mLastUpdates[std::tie(agentBounds, changedTile)] + mSettings.get().mMinUpdateInterval
|
|
|
|
if (changeType != ChangeType::update)
|
|
|
|
: std::chrono::steady_clock::time_point();
|
|
|
|
return std::chrono::steady_clock::time_point();
|
|
|
|
|
|
|
|
const auto lastUpdate = mLastUpdates.find(std::tie(agentBounds, changedTile));
|
|
|
|
|
|
|
|
if (lastUpdate == mLastUpdates.end())
|
|
|
|
|
|
|
|
return std::chrono::steady_clock::time_point();
|
|
|
|
|
|
|
|
return lastUpdate->second + mSettings.get().mMinUpdateInterval;
|
|
|
|
|
|
|
|
}();
|
|
|
|
|
|
|
|
|
|
|
|
const JobIt it = mJobs.emplace(mJobs.end(), agentBounds, navMeshCacheItem, worldspace, changedTile,
|
|
|
|
const JobIt it = mJobs.emplace(
|
|
|
|
changeType, getManhattanDistance(changedTile, playerTile), processTime);
|
|
|
|
mJobs.end(), agentBounds, navMeshCacheItem, worldspace, changedTile, changeType, processTime);
|
|
|
|
|
|
|
|
|
|
|
|
Log(Debug::Debug) << "Post job " << it->mId << " for agent=(" << it->mAgentBounds << ")"
|
|
|
|
Log(Debug::Debug) << "Post job " << it->mId << " for agent=(" << it->mAgentBounds << ")"
|
|
|
|
<< " changedTile=(" << it->mChangedTile << ")"
|
|
|
|
<< " changedTile=(" << it->mChangedTile << ")"
|
|
|
|
<< " changeType=" << it->mChangeType;
|
|
|
|
<< " changeType=" << it->mChangeType;
|
|
|
|
|
|
|
|
|
|
|
|
if (playerTileChanged)
|
|
|
|
mWaiting.push(it);
|
|
|
|
mWaiting.push_back(it);
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
insertPrioritizedJob(it, mWaiting);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (playerTileChanged)
|
|
|
|
|
|
|
|
std::sort(mWaiting.begin(), mWaiting.end(), LessByJobPriority{});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Log(Debug::Debug) << "Posted " << mJobs.size() << " navigator jobs";
|
|
|
|
Log(Debug::Debug) << "Posted " << mJobs.size() << " navigator jobs";
|
|
|
|
|
|
|
|
|
|
|
|
if (!mWaiting.empty())
|
|
|
|
if (mWaiting.hasJob())
|
|
|
|
mHasJob.notify_all();
|
|
|
|
mHasJob.notify_all();
|
|
|
|
|
|
|
|
|
|
|
|
lock.unlock();
|
|
|
|
lock.unlock();
|
|
|
|
|
|
|
|
|
|
|
|
if (playerTileChanged && mDbWorker != nullptr)
|
|
|
|
if (playerTileChanged && mDbWorker != nullptr)
|
|
|
|
mDbWorker->updateJobs(playerTile, mSettings.get().mMaxTilesNumber);
|
|
|
|
mDbWorker->update(playerTile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AsyncNavMeshUpdater::wait(WaitConditionType waitConditionType, Loading::Listener* listener)
|
|
|
|
void AsyncNavMeshUpdater::wait(WaitConditionType waitConditionType, Loading::Listener* listener)
|
|
|
@ -310,7 +406,7 @@ namespace DetourNavigator
|
|
|
|
{
|
|
|
|
{
|
|
|
|
const std::lock_guard<std::mutex> lock(mMutex);
|
|
|
|
const std::lock_guard<std::mutex> lock(mMutex);
|
|
|
|
result.mJobs = mJobs.size();
|
|
|
|
result.mJobs = mJobs.size();
|
|
|
|
result.mWaiting = mWaiting.size();
|
|
|
|
result.mWaiting = mWaiting.getStats();
|
|
|
|
result.mPushed = mPushed.size();
|
|
|
|
result.mPushed = mPushed.size();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
result.mProcessing = mProcessingTiles.lockConst()->size();
|
|
|
|
result.mProcessing = mProcessingTiles.lockConst()->size();
|
|
|
@ -332,7 +428,8 @@ namespace DetourNavigator
|
|
|
|
if (JobIt job = getNextJob(); job != mJobs.end())
|
|
|
|
if (JobIt job = getNextJob(); job != mJobs.end())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
const JobStatus status = processJob(*job);
|
|
|
|
const JobStatus status = processJob(*job);
|
|
|
|
Log(Debug::Debug) << "Processed job " << job->mId << " with status=" << status;
|
|
|
|
Log(Debug::Debug) << "Processed job " << job->mId << " with status=" << status
|
|
|
|
|
|
|
|
<< " changeType=" << job->mChangeType;
|
|
|
|
switch (status)
|
|
|
|
switch (status)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
case JobStatus::Done:
|
|
|
|
case JobStatus::Done:
|
|
|
@ -366,7 +463,9 @@ namespace DetourNavigator
|
|
|
|
|
|
|
|
|
|
|
|
JobStatus AsyncNavMeshUpdater::processJob(Job& job)
|
|
|
|
JobStatus AsyncNavMeshUpdater::processJob(Job& job)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Log(Debug::Debug) << "Processing job " << job.mId << " by thread=" << std::this_thread::get_id();
|
|
|
|
Log(Debug::Debug) << "Processing job " << job.mId << " for agent=(" << job.mAgentBounds << ")"
|
|
|
|
|
|
|
|
<< " changedTile=(" << job.mChangedTile << ")"
|
|
|
|
|
|
|
|
<< " changeType=" << job.mChangeType << " by thread=" << std::this_thread::get_id();
|
|
|
|
|
|
|
|
|
|
|
|
const auto navMeshCacheItem = job.mNavMeshCacheItem.lock();
|
|
|
|
const auto navMeshCacheItem = job.mNavMeshCacheItem.lock();
|
|
|
|
|
|
|
|
|
|
|
@ -378,6 +477,7 @@ namespace DetourNavigator
|
|
|
|
if (!shouldAddTile(job.mChangedTile, playerTile, mSettings.get().mMaxTilesNumber))
|
|
|
|
if (!shouldAddTile(job.mChangedTile, playerTile, mSettings.get().mMaxTilesNumber))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Log(Debug::Debug) << "Ignore add tile by job " << job.mId << ": too far from player";
|
|
|
|
Log(Debug::Debug) << "Ignore add tile by job " << job.mId << ": too far from player";
|
|
|
|
|
|
|
|
job.mChangeType = ChangeType::remove;
|
|
|
|
navMeshCacheItem->lock()->removeTile(job.mChangedTile);
|
|
|
|
navMeshCacheItem->lock()->removeTile(job.mChangedTile);
|
|
|
|
return JobStatus::Done;
|
|
|
|
return JobStatus::Done;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -545,9 +645,8 @@ namespace DetourNavigator
|
|
|
|
|
|
|
|
|
|
|
|
bool shouldStop = false;
|
|
|
|
bool shouldStop = false;
|
|
|
|
const auto hasJob = [&] {
|
|
|
|
const auto hasJob = [&] {
|
|
|
|
shouldStop = mShouldStop;
|
|
|
|
shouldStop = mShouldStop.load();
|
|
|
|
return shouldStop
|
|
|
|
return shouldStop || mWaiting.hasJob();
|
|
|
|
|| (!mWaiting.empty() && mWaiting.front()->mProcessTime <= std::chrono::steady_clock::now());
|
|
|
|
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if (!mHasJob.wait_for(lock, std::chrono::milliseconds(10), hasJob))
|
|
|
|
if (!mHasJob.wait_for(lock, std::chrono::milliseconds(10), hasJob))
|
|
|
@ -560,9 +659,15 @@ namespace DetourNavigator
|
|
|
|
if (shouldStop)
|
|
|
|
if (shouldStop)
|
|
|
|
return mJobs.end();
|
|
|
|
return mJobs.end();
|
|
|
|
|
|
|
|
|
|
|
|
const JobIt job = mWaiting.front();
|
|
|
|
const TilePosition playerTile = *mPlayerTile.lockConst();
|
|
|
|
|
|
|
|
|
|
|
|
mWaiting.pop_front();
|
|
|
|
JobIt job = mJobs.end();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (const std::optional<JobIt> nextJob = mWaiting.pop(playerTile))
|
|
|
|
|
|
|
|
job = *nextJob;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (job == mJobs.end())
|
|
|
|
|
|
|
|
return job;
|
|
|
|
|
|
|
|
|
|
|
|
Log(Debug::Debug) << "Pop job " << job->mId << " by thread=" << std::this_thread::get_id();
|
|
|
|
Log(Debug::Debug) << "Pop job " << job->mId << " by thread=" << std::this_thread::get_id();
|
|
|
|
|
|
|
|
|
|
|
@ -571,9 +676,9 @@ namespace DetourNavigator
|
|
|
|
|
|
|
|
|
|
|
|
if (!lockTile(job->mId, job->mAgentBounds, job->mChangedTile))
|
|
|
|
if (!lockTile(job->mId, job->mAgentBounds, job->mChangedTile))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Log(Debug::Debug) << "Failed to lock tile by job " << job->mId << " try=" << job->mTryNumber;
|
|
|
|
Log(Debug::Debug) << "Failed to lock tile by job " << job->mId;
|
|
|
|
++job->mTryNumber;
|
|
|
|
job->mProcessTime = std::chrono::steady_clock::now() + mSettings.get().mMinUpdateInterval;
|
|
|
|
insertPrioritizedJob(job, mWaiting);
|
|
|
|
mWaiting.push(job);
|
|
|
|
return mJobs.end();
|
|
|
|
return mJobs.end();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -653,7 +758,7 @@ namespace DetourNavigator
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Log(Debug::Debug) << "Enqueueing job " << job->mId << " by thread=" << std::this_thread::get_id();
|
|
|
|
Log(Debug::Debug) << "Enqueueing job " << job->mId << " by thread=" << std::this_thread::get_id();
|
|
|
|
const std::lock_guard lock(mMutex);
|
|
|
|
const std::lock_guard lock(mMutex);
|
|
|
|
insertPrioritizedJob(job, mWaiting);
|
|
|
|
mWaiting.push(job);
|
|
|
|
mHasJob.notify_all();
|
|
|
|
mHasJob.notify_all();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -667,40 +772,47 @@ namespace DetourNavigator
|
|
|
|
void DbJobQueue::push(JobIt job)
|
|
|
|
void DbJobQueue::push(JobIt job)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
const std::lock_guard lock(mMutex);
|
|
|
|
const std::lock_guard lock(mMutex);
|
|
|
|
insertPrioritizedDbJob(job, mJobs);
|
|
|
|
|
|
|
|
if (isWritingDbJob(*job))
|
|
|
|
if (isWritingDbJob(*job))
|
|
|
|
++mWritingJobs;
|
|
|
|
mWriting.push_back(job);
|
|
|
|
else
|
|
|
|
else
|
|
|
|
++mReadingJobs;
|
|
|
|
mReading.push(job);
|
|
|
|
mHasJob.notify_all();
|
|
|
|
mHasJob.notify_all();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::optional<JobIt> DbJobQueue::pop()
|
|
|
|
std::optional<JobIt> DbJobQueue::pop()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
std::unique_lock lock(mMutex);
|
|
|
|
std::unique_lock lock(mMutex);
|
|
|
|
mHasJob.wait(lock, [&] { return mShouldStop || !mJobs.empty(); });
|
|
|
|
|
|
|
|
if (mJobs.empty())
|
|
|
|
const auto hasJob = [&] { return mShouldStop || mReading.size() > 0 || mWriting.size() > 0; };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mHasJob.wait(lock, hasJob);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (mShouldStop)
|
|
|
|
return std::nullopt;
|
|
|
|
return std::nullopt;
|
|
|
|
const JobIt job = mJobs.front();
|
|
|
|
|
|
|
|
mJobs.pop_front();
|
|
|
|
if (const std::optional<JobIt> job = mReading.pop(mPlayerTile))
|
|
|
|
if (isWritingDbJob(*job))
|
|
|
|
return job;
|
|
|
|
--mWritingJobs;
|
|
|
|
|
|
|
|
else
|
|
|
|
if (mWriting.empty())
|
|
|
|
--mReadingJobs;
|
|
|
|
return std::nullopt;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const JobIt job = mWriting.front();
|
|
|
|
|
|
|
|
mWriting.pop_front();
|
|
|
|
|
|
|
|
|
|
|
|
return job;
|
|
|
|
return job;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DbJobQueue::update(TilePosition playerTile, int maxTiles)
|
|
|
|
void DbJobQueue::update(TilePosition playerTile)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
const std::lock_guard lock(mMutex);
|
|
|
|
const std::lock_guard lock(mMutex);
|
|
|
|
updateJobs(mJobs, playerTile, maxTiles);
|
|
|
|
mPlayerTile = playerTile;
|
|
|
|
std::sort(mJobs.begin(), mJobs.end(), LessByJobDbPriority{});
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DbJobQueue::stop()
|
|
|
|
void DbJobQueue::stop()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
const std::lock_guard lock(mMutex);
|
|
|
|
const std::lock_guard lock(mMutex);
|
|
|
|
mJobs.clear();
|
|
|
|
mReading.clear();
|
|
|
|
|
|
|
|
mWriting.clear();
|
|
|
|
mShouldStop = true;
|
|
|
|
mShouldStop = true;
|
|
|
|
mHasJob.notify_all();
|
|
|
|
mHasJob.notify_all();
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -708,7 +820,10 @@ namespace DetourNavigator
|
|
|
|
DbJobQueueStats DbJobQueue::getStats() const
|
|
|
|
DbJobQueueStats DbJobQueue::getStats() const
|
|
|
|
{
|
|
|
|
{
|
|
|
|
const std::lock_guard lock(mMutex);
|
|
|
|
const std::lock_guard lock(mMutex);
|
|
|
|
return DbJobQueueStats{ .mWritingJobs = mWritingJobs, .mReadingJobs = mReadingJobs };
|
|
|
|
return DbJobQueueStats{
|
|
|
|
|
|
|
|
.mReadingJobs = mReading.size(),
|
|
|
|
|
|
|
|
.mWritingJobs = mWriting.size(),
|
|
|
|
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
DbWorker::DbWorker(AsyncNavMeshUpdater& updater, std::unique_ptr<NavMeshDb>&& db, TileVersion version,
|
|
|
|
DbWorker::DbWorker(AsyncNavMeshUpdater& updater, std::unique_ptr<NavMeshDb>&& db, TileVersion version,
|
|
|
@ -737,8 +852,10 @@ namespace DetourNavigator
|
|
|
|
|
|
|
|
|
|
|
|
DbWorkerStats DbWorker::getStats() const
|
|
|
|
DbWorkerStats DbWorker::getStats() const
|
|
|
|
{
|
|
|
|
{
|
|
|
|
return DbWorkerStats{ .mJobs = mQueue.getStats(),
|
|
|
|
return DbWorkerStats{
|
|
|
|
.mGetTileCount = mGetTileCount.load(std::memory_order_relaxed) };
|
|
|
|
.mJobs = mQueue.getStats(),
|
|
|
|
|
|
|
|
.mGetTileCount = mGetTileCount.load(std::memory_order_relaxed),
|
|
|
|
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DbWorker::stop()
|
|
|
|
void DbWorker::stop()
|
|
|
|