Repost navmesh update jobs when failed because of out of memory

DT_OUT_OF_MEMORY error is returned when limit of tiles is reached.
pull/2225/head
elsid 6 years ago
parent 82e2739bae
commit ff47df4f2c
No known key found for this signature in database
GPG Key ID: B845CB9FEE18AB40

@ -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<float, std::milli>;
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<FloatMs>(finish - start).count(), "ms",
" total_time=", std::chrono::duration_cast<FloatMs>(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<FloatMs>(finish - start).count(), "ms",
" total_time=", std::chrono::duration_cast<FloatMs>(finish - firstStart).count(), "ms");
}
return isSuccess(status);
}
boost::optional<AsyncNavMeshUpdater::Job> 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<std::mutex> lock(mMutex);
if (mPushed[job.mAgentHalfExtents].insert(job.mChangedTile).second)
{
++job.mTryNumber;
mJobs.push(std::move(job));
mHasJob.notify_all();
}
}
}

@ -50,13 +50,14 @@ namespace DetourNavigator
osg::Vec3f mAgentHalfExtents;
SharedNavMeshCacheItem mNavMeshCacheItem;
TilePosition mChangedTile;
unsigned mTryNumber;
ChangeType mChangeType;
int mDistanceToPlayer;
int mDistanceToOrigin;
std::tuple<ChangeType, int, int> getPriority() const
std::tuple<unsigned, ChangeType, int, int> 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<Job> 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);
};
}

@ -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();
}
}
}

@ -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<unsigned>(value) & static_cast<unsigned>(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);

Loading…
Cancel
Save