mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-11-04 07:56:40 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			158 lines
		
	
	
	
		
			5.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			158 lines
		
	
	
	
		
			5.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include "navmeshcacheitem.hpp"
 | 
						|
#include "debug.hpp"
 | 
						|
#include "makenavmesh.hpp"
 | 
						|
#include "navmeshdata.hpp"
 | 
						|
#include "navmeshtilescache.hpp"
 | 
						|
#include "navmeshtileview.hpp"
 | 
						|
#include "settings.hpp"
 | 
						|
#include "tileposition.hpp"
 | 
						|
 | 
						|
#include <DetourNavMesh.h>
 | 
						|
 | 
						|
#include <ostream>
 | 
						|
#include <sstream>
 | 
						|
 | 
						|
namespace
 | 
						|
{
 | 
						|
    using DetourNavigator::TilePosition;
 | 
						|
 | 
						|
    bool removeTile(dtNavMesh& navMesh, const TilePosition& position)
 | 
						|
    {
 | 
						|
        const int layer = 0;
 | 
						|
        const auto tileRef = navMesh.getTileRefAt(position.x(), position.y(), layer);
 | 
						|
        if (tileRef == 0)
 | 
						|
            return false;
 | 
						|
        unsigned char** const data = nullptr;
 | 
						|
        int* const dataSize = nullptr;
 | 
						|
        return dtStatusSucceed(navMesh.removeTile(tileRef, data, dataSize));
 | 
						|
    }
 | 
						|
 | 
						|
    dtStatus addTile(dtNavMesh& navMesh, unsigned char* data, int size)
 | 
						|
    {
 | 
						|
        const int doNotTransferOwnership = 0;
 | 
						|
        const dtTileRef lastRef = 0;
 | 
						|
        dtTileRef* const result = nullptr;
 | 
						|
        return navMesh.addTile(data, size, doNotTransferOwnership, lastRef, result);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
namespace DetourNavigator
 | 
						|
{
 | 
						|
    std::ostream& operator<<(std::ostream& stream, UpdateNavMeshStatus value)
 | 
						|
    {
 | 
						|
        switch (value)
 | 
						|
        {
 | 
						|
            case UpdateNavMeshStatus::ignored:
 | 
						|
                return stream << "ignore";
 | 
						|
            case UpdateNavMeshStatus::removed:
 | 
						|
                return stream << "removed";
 | 
						|
            case UpdateNavMeshStatus::added:
 | 
						|
                return stream << "add";
 | 
						|
            case UpdateNavMeshStatus::replaced:
 | 
						|
                return stream << "replaced";
 | 
						|
            case UpdateNavMeshStatus::failed:
 | 
						|
                return stream << "failed";
 | 
						|
            case UpdateNavMeshStatus::lost:
 | 
						|
                return stream << "lost";
 | 
						|
            case UpdateNavMeshStatus::cached:
 | 
						|
                return stream << "cached";
 | 
						|
            case UpdateNavMeshStatus::unchanged:
 | 
						|
                return stream << "unchanged";
 | 
						|
            case UpdateNavMeshStatus::restored:
 | 
						|
                return stream << "restored";
 | 
						|
        }
 | 
						|
        return stream << "unknown(" << static_cast<unsigned>(value) << ")";
 | 
						|
    }
 | 
						|
 | 
						|
    const dtMeshTile* getTile(const dtNavMesh& navMesh, const TilePosition& position)
 | 
						|
    {
 | 
						|
        const int layer = 0;
 | 
						|
        return navMesh.getTileAt(position.x(), position.y(), layer);
 | 
						|
    }
 | 
						|
 | 
						|
    NavMeshCacheItem::NavMeshCacheItem(std::size_t generation, const Settings& settings)
 | 
						|
        : mVersion{ generation, 0 }
 | 
						|
    {
 | 
						|
        initEmptyNavMesh(settings, mImpl);
 | 
						|
 | 
						|
        if (const dtStatus status = mQuery.init(&mImpl, settings.mDetour.mMaxNavMeshQueryNodes);
 | 
						|
            !dtStatusSucceed(status))
 | 
						|
        {
 | 
						|
            std::ostringstream error;
 | 
						|
            error << "Failed to init navmesh query: " << WriteDtStatus{ status };
 | 
						|
            throw std::runtime_error(error.str());
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    UpdateNavMeshStatus NavMeshCacheItem::updateTile(
 | 
						|
        const TilePosition& position, NavMeshTilesCache::Value&& cached, NavMeshData&& navMeshData)
 | 
						|
    {
 | 
						|
        const dtMeshTile* currentTile = getTile(mImpl, position);
 | 
						|
        if (currentTile != nullptr
 | 
						|
            && asNavMeshTileConstView(*currentTile) == asNavMeshTileConstView(navMeshData.mValue.get()))
 | 
						|
        {
 | 
						|
            return UpdateNavMeshStatus::ignored;
 | 
						|
        }
 | 
						|
        bool removed = ::removeTile(mImpl, position);
 | 
						|
        removed = mEmptyTiles.erase(position) > 0 || removed;
 | 
						|
        const auto addStatus = addTile(mImpl, navMeshData.mValue.get(), navMeshData.mSize);
 | 
						|
        if (dtStatusSucceed(addStatus))
 | 
						|
        {
 | 
						|
            auto tile = mUsedTiles.find(position);
 | 
						|
            if (tile == mUsedTiles.end())
 | 
						|
            {
 | 
						|
                mUsedTiles.emplace_hint(tile, position,
 | 
						|
                    Tile{ Version{ mVersion.mRevision, 1 }, std::move(cached), std::move(navMeshData) });
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                ++tile->second.mVersion.mRevision;
 | 
						|
                tile->second.mCached = std::move(cached);
 | 
						|
                tile->second.mData = std::move(navMeshData);
 | 
						|
            }
 | 
						|
            ++mVersion.mRevision;
 | 
						|
            return UpdateNavMeshStatusBuilder().added(true).removed(removed).getResult();
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            if (removed)
 | 
						|
            {
 | 
						|
                mUsedTiles.erase(position);
 | 
						|
                ++mVersion.mRevision;
 | 
						|
            }
 | 
						|
            return UpdateNavMeshStatusBuilder()
 | 
						|
                .removed(removed)
 | 
						|
                .failed((addStatus & DT_OUT_OF_MEMORY) != 0)
 | 
						|
                .getResult();
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    UpdateNavMeshStatus NavMeshCacheItem::removeTile(const TilePosition& position)
 | 
						|
    {
 | 
						|
        bool removed = ::removeTile(mImpl, position);
 | 
						|
        removed = mEmptyTiles.erase(position) > 0 || removed;
 | 
						|
        if (removed)
 | 
						|
        {
 | 
						|
            mUsedTiles.erase(position);
 | 
						|
            ++mVersion.mRevision;
 | 
						|
        }
 | 
						|
        return UpdateNavMeshStatusBuilder().removed(removed).getResult();
 | 
						|
    }
 | 
						|
 | 
						|
    UpdateNavMeshStatus NavMeshCacheItem::markAsEmpty(const TilePosition& position)
 | 
						|
    {
 | 
						|
        bool removed = ::removeTile(mImpl, position);
 | 
						|
        removed = mEmptyTiles.insert(position).second || removed;
 | 
						|
        if (removed)
 | 
						|
        {
 | 
						|
            mUsedTiles.erase(position);
 | 
						|
            ++mVersion.mRevision;
 | 
						|
        }
 | 
						|
        return UpdateNavMeshStatusBuilder().removed(removed).getResult();
 | 
						|
    }
 | 
						|
 | 
						|
    bool NavMeshCacheItem::isEmptyTile(const TilePosition& position) const
 | 
						|
    {
 | 
						|
        return mEmptyTiles.find(position) != mEmptyTiles.end();
 | 
						|
    }
 | 
						|
}
 |