From ff47df4f2ccd8ff41d78db6a07ba31793ac7cc34 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 8 Mar 2019 15:28:32 +0300 Subject: [PATCH] Repost navmesh update jobs when failed because of out of memory DT_OUT_OF_MEMORY error is returned when limit of tiles is reached. --- .../detournavigator/asyncnavmeshupdater.cpp | 45 ++++++++++++++----- .../detournavigator/asyncnavmeshupdater.hpp | 9 ++-- components/detournavigator/makenavmesh.cpp | 11 ++++- components/detournavigator/makenavmesh.hpp | 9 +++- 4 files changed, 59 insertions(+), 15 deletions(-) diff --git a/components/detournavigator/asyncnavmeshupdater.cpp b/components/detournavigator/asyncnavmeshupdater.cpp index 6cfd75b27..ee3b6d77a 100644 --- a/components/detournavigator/asyncnavmeshupdater.cpp +++ b/components/detournavigator/asyncnavmeshupdater.cpp @@ -1,4 +1,4 @@ -#include "asyncnavmeshupdater.hpp" +#include "asyncnavmeshupdater.hpp" #include "debug.hpp" #include "makenavmesh.hpp" #include "settings.hpp" @@ -30,6 +30,10 @@ namespace DetourNavigator return stream << "add"; case UpdateNavMeshStatus::replaced: return stream << "replaced"; + case UpdateNavMeshStatus::failed: + return stream << "failed"; + case UpdateNavMeshStatus::lost: + return stream << "lost"; } return stream << "unknown"; } @@ -77,6 +81,7 @@ namespace DetourNavigator job.mAgentHalfExtents = agentHalfExtents; job.mNavMeshCacheItem = navMeshCacheItem; job.mChangedTile = changedTile.first; + job.mTryNumber = 0; job.mChangeType = changedTile.second; job.mDistanceToPlayer = getManhattanDistance(changedTile.first, playerTile); job.mDistanceToOrigin = getManhattanDistance(changedTile.first, TilePosition {0, 0}); @@ -104,8 +109,9 @@ namespace DetourNavigator { try { - if (const auto job = getNextJob()) - processJob(*job); + if (auto job = getNextJob()) + if (!processJob(*job)) + repost(std::move(*job)); } catch (const std::exception& e) { @@ -115,7 +121,7 @@ namespace DetourNavigator log("stop process jobs"); } - void AsyncNavMeshUpdater::processJob(const Job& job) + bool AsyncNavMeshUpdater::processJob(const Job& job) { log("process job for agent=", job.mAgentHalfExtents); @@ -136,12 +142,16 @@ namespace DetourNavigator using FloatMs = std::chrono::duration; - const auto locked = job.mNavMeshCacheItem.lockConst(); - log("cache updated for agent=", job.mAgentHalfExtents, " status=", status, - " generation=", locked->getGeneration(), - " revision=", locked->getNavMeshRevision(), - " time=", std::chrono::duration_cast(finish - start).count(), "ms", - " total_time=", std::chrono::duration_cast(finish - firstStart).count(), "ms"); + { + const auto locked = job.mNavMeshCacheItem.lockConst(); + log("cache updated for agent=", job.mAgentHalfExtents, " status=", status, + " generation=", locked->getGeneration(), + " revision=", locked->getNavMeshRevision(), + " time=", std::chrono::duration_cast(finish - start).count(), "ms", + " total_time=", std::chrono::duration_cast(finish - firstStart).count(), "ms"); + } + + return isSuccess(status); } boost::optional AsyncNavMeshUpdater::getNextJob() @@ -194,4 +204,19 @@ namespace DetourNavigator *locked = value; return *locked.get(); } + + void AsyncNavMeshUpdater::repost(Job&& job) + { + if (mShouldStop || job.mTryNumber > 2) + return; + + const std::lock_guard lock(mMutex); + + if (mPushed[job.mAgentHalfExtents].insert(job.mChangedTile).second) + { + ++job.mTryNumber; + mJobs.push(std::move(job)); + mHasJob.notify_all(); + } + } } diff --git a/components/detournavigator/asyncnavmeshupdater.hpp b/components/detournavigator/asyncnavmeshupdater.hpp index da9733362..98359964d 100644 --- a/components/detournavigator/asyncnavmeshupdater.hpp +++ b/components/detournavigator/asyncnavmeshupdater.hpp @@ -50,13 +50,14 @@ namespace DetourNavigator osg::Vec3f mAgentHalfExtents; SharedNavMeshCacheItem mNavMeshCacheItem; TilePosition mChangedTile; + unsigned mTryNumber; ChangeType mChangeType; int mDistanceToPlayer; int mDistanceToOrigin; - std::tuple getPriority() const + std::tuple getPriority() const { - return std::make_tuple(mChangeType, mDistanceToPlayer, mDistanceToOrigin); + return std::make_tuple(mTryNumber, mChangeType, mDistanceToPlayer, mDistanceToOrigin); } friend inline bool operator <(const Job& lhs, const Job& rhs) @@ -83,13 +84,15 @@ namespace DetourNavigator void process() throw(); - void processJob(const Job& job); + bool processJob(const Job& job); boost::optional getNextJob(); void writeDebugFiles(const Job& job, const RecastMesh* recastMesh) const; std::chrono::steady_clock::time_point setFirstStart(const std::chrono::steady_clock::time_point& value); + + void repost(Job&& job); }; } diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index a03e9fd8d..e62509940 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -464,6 +464,15 @@ namespace return *this; } + UpdateNavMeshStatusBuilder failed(bool value) + { + if (value) + set(UpdateNavMeshStatus::failed); + else + unset(UpdateNavMeshStatus::failed); + return *this; + } + UpdateNavMeshStatus getResult() const { return mResult; @@ -531,7 +540,7 @@ namespace if (removed) locked->removeUsedTile(changedTile); log("failed to add tile with status=", WriteDtStatus {addStatus}); - return UpdateNavMeshStatusBuilder().removed(removed).getResult(); + return UpdateNavMeshStatusBuilder().removed(removed).failed((addStatus & DT_OUT_OF_MEMORY) != 0).getResult(); } } } diff --git a/components/detournavigator/makenavmesh.hpp b/components/detournavigator/makenavmesh.hpp index 20198047c..1dfa242ee 100644 --- a/components/detournavigator/makenavmesh.hpp +++ b/components/detournavigator/makenavmesh.hpp @@ -26,8 +26,15 @@ namespace DetourNavigator removed = 1 << 0, added = 1 << 1, replaced = removed | added, + failed = 1 << 2, + lost = removed | failed, }; + inline bool isSuccess(UpdateNavMeshStatus value) + { + return (static_cast(value) & static_cast(UpdateNavMeshStatus::failed)) == 0; + } + inline float getLength(const osg::Vec2i& value) { return std::sqrt(float(osg::square(value.x()) + osg::square(value.y()))); @@ -41,7 +48,7 @@ namespace DetourNavigator inline bool shouldAddTile(const TilePosition& changedTile, const TilePosition& playerTile, int maxTiles) { const auto expectedTilesCount = std::ceil(osg::PI * osg::square(getDistance(changedTile, playerTile))); - return expectedTilesCount * 3 <= maxTiles; + return expectedTilesCount <= maxTiles; } NavMeshPtr makeEmptyNavMesh(const Settings& settings);