mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-11-04 07:56:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			121 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			121 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "navmeshtilescache.hpp"
 | 
						|
#include "stats.hpp"
 | 
						|
 | 
						|
#include <cstring>
 | 
						|
 | 
						|
namespace DetourNavigator
 | 
						|
{
 | 
						|
    NavMeshTilesCache::NavMeshTilesCache(const std::size_t maxNavMeshDataSize)
 | 
						|
        : mMaxNavMeshDataSize(maxNavMeshDataSize)
 | 
						|
        , mUsedNavMeshDataSize(0)
 | 
						|
        , mFreeNavMeshDataSize(0)
 | 
						|
        , mHitCount(0)
 | 
						|
        , mGetCount(0)
 | 
						|
    {
 | 
						|
    }
 | 
						|
 | 
						|
    NavMeshTilesCache::Value NavMeshTilesCache::get(
 | 
						|
        const AgentBounds& agentBounds, const TilePosition& changedTile, const RecastMesh& recastMesh)
 | 
						|
    {
 | 
						|
        const std::lock_guard<std::mutex> lock(mMutex);
 | 
						|
 | 
						|
        ++mGetCount;
 | 
						|
 | 
						|
        const auto tile = mValues.find(std::tie(agentBounds, changedTile, recastMesh));
 | 
						|
        if (tile == mValues.end())
 | 
						|
            return Value();
 | 
						|
 | 
						|
        acquireItemUnsafe(tile->second);
 | 
						|
 | 
						|
        ++mHitCount;
 | 
						|
 | 
						|
        return Value(*this, tile->second);
 | 
						|
    }
 | 
						|
 | 
						|
    NavMeshTilesCache::Value NavMeshTilesCache::set(const AgentBounds& agentBounds, const TilePosition& changedTile,
 | 
						|
        const RecastMesh& recastMesh, std::unique_ptr<PreparedNavMeshData>&& value)
 | 
						|
    {
 | 
						|
        const auto itemSize = sizeof(RecastMesh) + getSize(recastMesh)
 | 
						|
            + (value == nullptr ? 0 : sizeof(PreparedNavMeshData) + getSize(*value));
 | 
						|
 | 
						|
        const std::lock_guard<std::mutex> lock(mMutex);
 | 
						|
 | 
						|
        if (itemSize > mFreeNavMeshDataSize + (mMaxNavMeshDataSize - mUsedNavMeshDataSize))
 | 
						|
            return Value();
 | 
						|
 | 
						|
        while (!mFreeItems.empty() && mUsedNavMeshDataSize + itemSize > mMaxNavMeshDataSize)
 | 
						|
            removeLeastRecentlyUsed();
 | 
						|
 | 
						|
        RecastMeshData key{ recastMesh.getMesh(), recastMesh.getWater(), recastMesh.getHeightfields(),
 | 
						|
            recastMesh.getFlatHeightfields() };
 | 
						|
 | 
						|
        const auto iterator = mFreeItems.emplace(mFreeItems.end(), agentBounds, changedTile, std::move(key), itemSize);
 | 
						|
        const auto emplaced = mValues.emplace(
 | 
						|
            std::make_tuple(agentBounds, changedTile, std::cref(iterator->mRecastMeshData)), iterator);
 | 
						|
 | 
						|
        if (!emplaced.second)
 | 
						|
        {
 | 
						|
            mFreeItems.erase(iterator);
 | 
						|
            acquireItemUnsafe(emplaced.first->second);
 | 
						|
            ++mGetCount;
 | 
						|
            ++mHitCount;
 | 
						|
            return Value(*this, emplaced.first->second);
 | 
						|
        }
 | 
						|
 | 
						|
        iterator->mPreparedNavMeshData = std::move(value);
 | 
						|
        ++iterator->mUseCount;
 | 
						|
        mUsedNavMeshDataSize += itemSize;
 | 
						|
        mBusyItems.splice(mBusyItems.end(), mFreeItems, iterator);
 | 
						|
 | 
						|
        return Value(*this, iterator);
 | 
						|
    }
 | 
						|
 | 
						|
    NavMeshTilesCacheStats NavMeshTilesCache::getStats() const
 | 
						|
    {
 | 
						|
        NavMeshTilesCacheStats result;
 | 
						|
        {
 | 
						|
            const std::lock_guard<std::mutex> lock(mMutex);
 | 
						|
            result.mNavMeshCacheSize = mUsedNavMeshDataSize;
 | 
						|
            result.mUsedNavMeshTiles = mBusyItems.size();
 | 
						|
            result.mCachedNavMeshTiles = mFreeItems.size();
 | 
						|
            result.mHitCount = mHitCount;
 | 
						|
            result.mGetCount = mGetCount;
 | 
						|
        }
 | 
						|
        return result;
 | 
						|
    }
 | 
						|
 | 
						|
    void NavMeshTilesCache::removeLeastRecentlyUsed()
 | 
						|
    {
 | 
						|
        const auto& item = mFreeItems.back();
 | 
						|
 | 
						|
        const auto value = mValues.find(std::tie(item.mAgentBounds, item.mChangedTile, item.mRecastMeshData));
 | 
						|
        if (value == mValues.end())
 | 
						|
            return;
 | 
						|
 | 
						|
        mUsedNavMeshDataSize -= item.mSize;
 | 
						|
        mFreeNavMeshDataSize -= item.mSize;
 | 
						|
 | 
						|
        mValues.erase(value);
 | 
						|
        mFreeItems.pop_back();
 | 
						|
    }
 | 
						|
 | 
						|
    void NavMeshTilesCache::acquireItemUnsafe(ItemIterator iterator)
 | 
						|
    {
 | 
						|
        if (++iterator->mUseCount > 1)
 | 
						|
            return;
 | 
						|
 | 
						|
        mBusyItems.splice(mBusyItems.end(), mFreeItems, iterator);
 | 
						|
        mFreeNavMeshDataSize -= iterator->mSize;
 | 
						|
    }
 | 
						|
 | 
						|
    void NavMeshTilesCache::releaseItem(ItemIterator iterator)
 | 
						|
    {
 | 
						|
        if (--iterator->mUseCount > 0)
 | 
						|
            return;
 | 
						|
 | 
						|
        const std::lock_guard<std::mutex> lock(mMutex);
 | 
						|
 | 
						|
        mFreeItems.splice(mFreeItems.begin(), mBusyItems, iterator);
 | 
						|
        mFreeNavMeshDataSize += iterator->mSize;
 | 
						|
    }
 | 
						|
}
 |