mirror of https://github.com/OpenMW/openmw.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
159 lines
5.3 KiB
C++
159 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();
|
|
}
|
|
}
|