#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_NAVMESHTILESCACHE_H #define OPENMW_COMPONENTS_DETOURNAVIGATOR_NAVMESHTILESCACHE_H #include "agentbounds.hpp" #include "preparednavmeshdata.hpp" #include "recastmesh.hpp" #include "tileposition.hpp" #include #include #include #include #include #include #include namespace DetourNavigator { struct RecastMeshData { Mesh mMesh; std::vector mWater; std::vector mHeightfields; std::vector mFlatHeightfields; }; inline bool operator<(const RecastMeshData& lhs, const RecastMeshData& rhs) { return std::tie(lhs.mMesh, lhs.mWater, lhs.mHeightfields, lhs.mFlatHeightfields) < std::tie(rhs.mMesh, rhs.mWater, rhs.mHeightfields, rhs.mFlatHeightfields); } inline bool operator<(const RecastMeshData& lhs, const RecastMesh& rhs) { return std::tie(lhs.mMesh, lhs.mWater, lhs.mHeightfields, lhs.mFlatHeightfields) < std::tie(rhs.getMesh(), rhs.getWater(), rhs.getHeightfields(), rhs.getFlatHeightfields()); } inline bool operator<(const RecastMesh& lhs, const RecastMeshData& rhs) { return std::tie(lhs.getMesh(), lhs.getWater(), lhs.getHeightfields(), lhs.getFlatHeightfields()) < std::tie(rhs.mMesh, rhs.mWater, rhs.mHeightfields, rhs.mFlatHeightfields); } struct NavMeshTilesCacheStats; class NavMeshTilesCache { public: struct Item { std::atomic mUseCount; AgentBounds mAgentBounds; TilePosition mChangedTile; RecastMeshData mRecastMeshData; std::unique_ptr mPreparedNavMeshData; std::size_t mSize; Item(const AgentBounds& agentBounds, const TilePosition& changedTile, RecastMeshData&& recastMeshData, std::size_t size) : mUseCount(0) , mAgentBounds(agentBounds) , mChangedTile(changedTile) , mRecastMeshData(std::move(recastMeshData)) , mSize(size) { } }; using ItemIterator = std::list::iterator; class Value { public: Value() : mOwner(nullptr) , mIterator() { } Value(NavMeshTilesCache& owner, ItemIterator iterator) : mOwner(&owner) , mIterator(iterator) { } Value(const Value& other) = delete; Value(Value&& other) : mOwner(other.mOwner) , mIterator(other.mIterator) { other.mOwner = nullptr; } ~Value() { if (mOwner) mOwner->releaseItem(mIterator); } Value& operator=(const Value& other) = delete; Value& operator=(Value&& other) { if (mOwner) mOwner->releaseItem(mIterator); mOwner = other.mOwner; mIterator = other.mIterator; other.mOwner = nullptr; return *this; } const PreparedNavMeshData& get() const { return *mIterator->mPreparedNavMeshData; } operator bool() const { return mOwner; } private: NavMeshTilesCache* mOwner; ItemIterator mIterator; }; NavMeshTilesCache(const std::size_t maxNavMeshDataSize); Value get(const AgentBounds& agentBounds, const TilePosition& changedTile, const RecastMesh& recastMesh); Value set(const AgentBounds& agentBounds, const TilePosition& changedTile, const RecastMesh& recastMesh, std::unique_ptr&& value); NavMeshTilesCacheStats getStats() const; private: mutable std::mutex mMutex; std::size_t mMaxNavMeshDataSize; std::size_t mUsedNavMeshDataSize; std::size_t mFreeNavMeshDataSize; std::size_t mHitCount; std::size_t mGetCount; std::list mBusyItems; std::list mFreeItems; std::map>, ItemIterator, std::less<>> mValues; void removeLeastRecentlyUsed(); void acquireItemUnsafe(ItemIterator iterator); void releaseItem(ItemIterator iterator); }; } #endif