Fix calculating min distance to nearest absent tile

Tile can be present in either mPushed (waiting in a queue), mProcessingTiles (
being processed or waiting in db queue), mPresentTiles (added to navmesh). It's
not enough to walk over mPushed tiles to find all not present. Need also to
check mProcessingTiles.

Otherwise if all tiles are in mProcessingTiles only
waitUntilJobsDoneForNotPresentTiles may return too early because there are none
in mPushed and therefore none tiles are considered to be absent on navmesh which
is not true.
crashfix_debugdraw
elsid 2 years ago
parent de80b86cc1
commit 98ddc31902
No known key found for this signature in database
GPG Key ID: 4DE04C198CBA7625

@ -21,6 +21,8 @@
#include <numeric> #include <numeric>
#include <set> #include <set>
#include <type_traits> #include <type_traits>
#include <optional>
#include <tuple>
namespace DetourNavigator namespace DetourNavigator
{ {
@ -31,15 +33,22 @@ namespace DetourNavigator
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, bool isAbsentTileTooClose(const TilePosition& position, int distance,
const std::set<std::tuple<AgentBounds, TilePosition>>& pushedTiles, const std::set<std::tuple<AgentBounds, TilePosition>>& pushedTiles,
const std::set<std::tuple<AgentBounds, TilePosition>>& presentTiles) const std::set<std::tuple<AgentBounds, TilePosition>>& presentTiles,
const Misc::ScopeGuarded<std::set<std::tuple<AgentBounds, TilePosition>>>& processingTiles)
{ {
int result = maxDistance; const auto isAbsentAndCloserThan = [&] (const std::tuple<AgentBounds, TilePosition>& v)
for (const auto& [agentBounds, tile] : pushedTiles) {
if (presentTiles.find(std::tie(agentBounds, tile)) == presentTiles.end()) return presentTiles.find(v) == presentTiles.end()
result = std::min(result, getManhattanDistance(position, tile)); && getManhattanDistance(position, std::get<1>(v)) < distance;
return result; };
if (std::any_of(pushedTiles.begin(), pushedTiles.end(), isAbsentAndCloserThan))
return true;
if (const auto locked = processingTiles.lockConst();
std::any_of(locked->begin(), locked->end(), isAbsentAndCloserThan))
return true;
return false;
} }
auto getPriority(const Job& job) noexcept auto getPriority(const Job& job) noexcept
@ -248,27 +257,22 @@ namespace DetourNavigator
void AsyncNavMeshUpdater::waitUntilJobsDoneForNotPresentTiles(Loading::Listener& listener) void AsyncNavMeshUpdater::waitUntilJobsDoneForNotPresentTiles(Loading::Listener& listener)
{ {
const std::size_t initialJobsLeft = getTotalJobs(); const std::size_t initialJobsLeft = getTotalJobs();
std::size_t maxProgress = initialJobsLeft + mThreads.size(); std::size_t maxProgress = initialJobsLeft;
std::size_t prevJobsLeft = initialJobsLeft; std::size_t prevJobsLeft = initialJobsLeft;
std::size_t jobsDone = 0; std::size_t jobsDone = 0;
std::size_t jobsLeft = 0; std::size_t jobsLeft = 0;
const int maxDistanceToPlayer = mSettings.get().mWaitUntilMinDistanceToPlayer; const int maxDistanceToPlayer = mSettings.get().mWaitUntilMinDistanceToPlayer;
const TilePosition playerPosition = *mPlayerTile.lockConst(); const TilePosition playerPosition = *mPlayerTile.lockConst();
int minDistanceToPlayer = 0;
const auto isDone = [&] const auto isDone = [&]
{ {
jobsLeft = mJobs.size(); jobsLeft = mJobs.size();
if (jobsLeft == 0) if (jobsLeft == 0)
{
minDistanceToPlayer = 0;
return true; return true;
} return !isAbsentTileTooClose(playerPosition, maxDistanceToPlayer, mPushed, mPresentTiles, mProcessingTiles);
minDistanceToPlayer = getMinDistanceTo(playerPosition, maxDistanceToPlayer, mPushed, mPresentTiles);
return minDistanceToPlayer >= maxDistanceToPlayer;
}; };
std::unique_lock<std::mutex> lock(mMutex); std::unique_lock<std::mutex> lock(mMutex);
if (getMinDistanceTo(playerPosition, maxDistanceToPlayer, mPushed, mPresentTiles) >= maxDistanceToPlayer if (!isAbsentTileTooClose(playerPosition, maxDistanceToPlayer, mPushed, mPresentTiles, mProcessingTiles)
|| (mJobs.empty() && mProcessingTiles.lockConst()->empty())) || mJobs.empty())
return; return;
Loading::ScopedLoad load(&listener); Loading::ScopedLoad load(&listener);
listener.setLabel("#{Navigation:BuildingNavigationMesh}"); listener.setLabel("#{Navigation:BuildingNavigationMesh}");
@ -277,7 +281,7 @@ namespace DetourNavigator
{ {
if (maxProgress < jobsLeft) if (maxProgress < jobsLeft)
{ {
maxProgress = jobsLeft + mThreads.size(); maxProgress = jobsLeft;
listener.setProgressRange(maxProgress); listener.setProgressRange(maxProgress);
listener.setProgress(jobsDone); listener.setProgress(jobsDone);
} }
@ -289,12 +293,6 @@ namespace DetourNavigator
listener.increaseProgress(newJobsDone); listener.increaseProgress(newJobsDone);
} }
} }
lock.unlock();
if (minDistanceToPlayer < maxDistanceToPlayer)
{
mProcessingTiles.wait(mProcessed, [] (const auto& v) { return v.empty(); });
listener.setProgress(maxProgress);
}
} }
void AsyncNavMeshUpdater::waitUntilAllJobsDone() void AsyncNavMeshUpdater::waitUntilAllJobsDone()

Loading…
Cancel
Save