mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-15 15:49:56 +00:00
d0ea9c482a
When player tile changes distance to player that is part of jobs priority is invalidated. So jobs are no longer in the right order. This can lead to processing of farests tiles first. Sort queue each time player tile is changed.
150 lines
4.8 KiB
C++
150 lines
4.8 KiB
C++
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_ASYNCNAVMESHUPDATER_H
|
|
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_ASYNCNAVMESHUPDATER_H
|
|
|
|
#include "navmeshcacheitem.hpp"
|
|
#include "offmeshconnectionsmanager.hpp"
|
|
#include "tilecachedrecastmeshmanager.hpp"
|
|
#include "tileposition.hpp"
|
|
#include "navmeshtilescache.hpp"
|
|
|
|
#include <osg/Vec3f>
|
|
|
|
#include <atomic>
|
|
#include <chrono>
|
|
#include <condition_variable>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <deque>
|
|
#include <set>
|
|
#include <thread>
|
|
#include <tuple>
|
|
|
|
class dtNavMesh;
|
|
|
|
namespace Loading
|
|
{
|
|
class Listener;
|
|
}
|
|
|
|
namespace DetourNavigator
|
|
{
|
|
enum class ChangeType
|
|
{
|
|
remove = 0,
|
|
mixed = 1,
|
|
add = 2,
|
|
update = 3,
|
|
};
|
|
|
|
inline std::ostream& operator <<(std::ostream& stream, ChangeType value)
|
|
{
|
|
switch (value) {
|
|
case ChangeType::remove:
|
|
return stream << "ChangeType::remove";
|
|
case ChangeType::mixed:
|
|
return stream << "ChangeType::mixed";
|
|
case ChangeType::add:
|
|
return stream << "ChangeType::add";
|
|
case ChangeType::update:
|
|
return stream << "ChangeType::update";
|
|
}
|
|
return stream << "ChangeType::" << static_cast<int>(value);
|
|
}
|
|
|
|
class AsyncNavMeshUpdater
|
|
{
|
|
public:
|
|
AsyncNavMeshUpdater(const Settings& settings, TileCachedRecastMeshManager& recastMeshManager,
|
|
OffMeshConnectionsManager& offMeshConnectionsManager);
|
|
~AsyncNavMeshUpdater();
|
|
|
|
void post(const osg::Vec3f& agentHalfExtents, const SharedNavMeshCacheItem& mNavMeshCacheItem,
|
|
const TilePosition& playerTile, const std::map<TilePosition, ChangeType>& changedTiles);
|
|
|
|
void wait(Loading::Listener& listener);
|
|
|
|
void reportStats(unsigned int frameNumber, osg::Stats& stats) const;
|
|
|
|
private:
|
|
struct Job
|
|
{
|
|
osg::Vec3f mAgentHalfExtents;
|
|
std::weak_ptr<GuardedNavMeshCacheItem> mNavMeshCacheItem;
|
|
TilePosition mChangedTile;
|
|
unsigned mTryNumber;
|
|
ChangeType mChangeType;
|
|
int mDistanceToPlayer;
|
|
int mDistanceToOrigin;
|
|
std::chrono::steady_clock::time_point mProcessTime;
|
|
|
|
std::tuple<std::chrono::steady_clock::time_point, unsigned, ChangeType, int, int> getPriority() const
|
|
{
|
|
return std::make_tuple(mProcessTime, mTryNumber, mChangeType, mDistanceToPlayer, mDistanceToOrigin);
|
|
}
|
|
|
|
friend inline bool operator <(const Job& lhs, const Job& rhs)
|
|
{
|
|
return lhs.getPriority() < rhs.getPriority();
|
|
}
|
|
};
|
|
|
|
using Jobs = std::deque<Job>;
|
|
using Pushed = std::map<osg::Vec3f, std::set<TilePosition>>;
|
|
|
|
struct Queue
|
|
{
|
|
Jobs mJobs;
|
|
Pushed mPushed;
|
|
|
|
Queue() = default;
|
|
};
|
|
|
|
std::reference_wrapper<const Settings> mSettings;
|
|
std::reference_wrapper<TileCachedRecastMeshManager> mRecastMeshManager;
|
|
std::reference_wrapper<OffMeshConnectionsManager> mOffMeshConnectionsManager;
|
|
std::atomic_bool mShouldStop;
|
|
mutable std::mutex mMutex;
|
|
std::condition_variable mHasJob;
|
|
std::condition_variable mDone;
|
|
std::condition_variable mProcessed;
|
|
Jobs mJobs;
|
|
std::map<osg::Vec3f, std::set<TilePosition>> mPushed;
|
|
Misc::ScopeGuarded<TilePosition> mPlayerTile;
|
|
Misc::ScopeGuarded<std::optional<std::chrono::steady_clock::time_point>> mFirstStart;
|
|
NavMeshTilesCache mNavMeshTilesCache;
|
|
Misc::ScopeGuarded<std::map<osg::Vec3f, std::map<TilePosition, std::thread::id>>> mProcessingTiles;
|
|
std::map<osg::Vec3f, std::map<TilePosition, std::chrono::steady_clock::time_point>> mLastUpdates;
|
|
std::map<std::thread::id, Queue> mThreadsQueues;
|
|
std::vector<std::thread> mThreads;
|
|
|
|
void process() noexcept;
|
|
|
|
bool processJob(const Job& job);
|
|
|
|
std::optional<Job> getNextJob();
|
|
|
|
std::optional<Job> getJob(Jobs& jobs, Pushed& pushed, bool changeLastUpdate);
|
|
|
|
void postThreadJob(Job&& job, Queue& queue);
|
|
|
|
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);
|
|
|
|
std::thread::id lockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile);
|
|
|
|
void unlockTile(const osg::Vec3f& agentHalfExtents, const TilePosition& changedTile);
|
|
|
|
inline std::size_t getTotalJobs() const;
|
|
|
|
inline std::size_t getTotalThreadJobsUnsafe() const;
|
|
|
|
void cleanupLastUpdates();
|
|
|
|
int waitUntilJobsDone(const std::size_t initialJobsLeft, std::size_t& maxJobsLeft, Loading::Listener& listener);
|
|
};
|
|
}
|
|
|
|
#endif
|