mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 05:56:38 +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();
 | |
|     }
 | |
| }
 |