mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-15 15:19:55 +00:00
3e67f5ffa5
To avoid triggering NavMesh update when RecastMesh change should not change NavMesh. Based on the following assumption: Given a set of transformations and a bounding shape for all these tranformations, a new object transformation that does not change this bounding shape also should not change navmesh if for all of this object transformations resulting navmesh tiles are equivalent The idea is to report back to RecastMeshManager all changes of NavMesh if there are any assiciated with RecastMesh version. So we know the last time when RecastMesh change resulted into the NavMesh change. When later report shows that there was no NavMesh change for a new RecastMesh version we can assume that any object transformation within the same bounding box should not change NavMesh.
194 lines
7.1 KiB
C++
194 lines
7.1 KiB
C++
#include "tilecachedrecastmeshmanager.hpp"
|
|
#include "makenavmesh.hpp"
|
|
#include "gettilespositions.hpp"
|
|
#include "settingsutils.hpp"
|
|
|
|
namespace DetourNavigator
|
|
{
|
|
TileCachedRecastMeshManager::TileCachedRecastMeshManager(const Settings& settings)
|
|
: mSettings(settings)
|
|
{}
|
|
|
|
bool TileCachedRecastMeshManager::addObject(const ObjectId id, const btCollisionShape& shape,
|
|
const btTransform& transform, const AreaType areaType)
|
|
{
|
|
bool result = false;
|
|
auto& tilesPositions = mObjectsTilesPositions[id];
|
|
const auto border = getBorderSize(mSettings);
|
|
{
|
|
auto tiles = mTiles.lock();
|
|
getTilesPositions(shape, transform, mSettings, [&] (const TilePosition& tilePosition)
|
|
{
|
|
if (addTile(id, shape, transform, areaType, tilePosition, border, tiles.get()))
|
|
{
|
|
tilesPositions.insert(tilePosition);
|
|
result = true;
|
|
}
|
|
});
|
|
}
|
|
if (result)
|
|
++mRevision;
|
|
return result;
|
|
}
|
|
|
|
std::optional<RemovedRecastMeshObject> TileCachedRecastMeshManager::removeObject(const ObjectId id)
|
|
{
|
|
const auto object = mObjectsTilesPositions.find(id);
|
|
if (object == mObjectsTilesPositions.end())
|
|
return std::nullopt;
|
|
std::optional<RemovedRecastMeshObject> result;
|
|
{
|
|
auto tiles = mTiles.lock();
|
|
for (const auto& tilePosition : object->second)
|
|
{
|
|
const auto removed = removeTile(id, tilePosition, tiles.get());
|
|
if (removed && !result)
|
|
result = removed;
|
|
}
|
|
}
|
|
if (result)
|
|
++mRevision;
|
|
return result;
|
|
}
|
|
|
|
bool TileCachedRecastMeshManager::addWater(const osg::Vec2i& cellPosition, const int cellSize,
|
|
const btTransform& transform)
|
|
{
|
|
const auto border = getBorderSize(mSettings);
|
|
|
|
auto& tilesPositions = mWaterTilesPositions[cellPosition];
|
|
|
|
bool result = false;
|
|
|
|
if (cellSize == std::numeric_limits<int>::max())
|
|
{
|
|
const auto tiles = mTiles.lock();
|
|
for (auto& tile : *tiles)
|
|
{
|
|
if (tile.second.addWater(cellPosition, cellSize, transform))
|
|
{
|
|
tilesPositions.push_back(tile.first);
|
|
result = true;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
getTilesPositions(cellSize, transform, mSettings, [&] (const TilePosition& tilePosition)
|
|
{
|
|
const auto tiles = mTiles.lock();
|
|
auto tile = tiles->find(tilePosition);
|
|
if (tile == tiles->end())
|
|
{
|
|
auto tileBounds = makeTileBounds(mSettings, tilePosition);
|
|
tileBounds.mMin -= osg::Vec2f(border, border);
|
|
tileBounds.mMax += osg::Vec2f(border, border);
|
|
tile = tiles->insert(std::make_pair(tilePosition,
|
|
CachedRecastMeshManager(mSettings, tileBounds, mTilesGeneration))).first;
|
|
}
|
|
if (tile->second.addWater(cellPosition, cellSize, transform))
|
|
{
|
|
tilesPositions.push_back(tilePosition);
|
|
result = true;
|
|
}
|
|
});
|
|
}
|
|
|
|
if (result)
|
|
++mRevision;
|
|
|
|
return result;
|
|
}
|
|
|
|
std::optional<RecastMeshManager::Water> TileCachedRecastMeshManager::removeWater(const osg::Vec2i& cellPosition)
|
|
{
|
|
const auto object = mWaterTilesPositions.find(cellPosition);
|
|
if (object == mWaterTilesPositions.end())
|
|
return std::nullopt;
|
|
std::optional<RecastMeshManager::Water> result;
|
|
for (const auto& tilePosition : object->second)
|
|
{
|
|
const auto tiles = mTiles.lock();
|
|
const auto tile = tiles->find(tilePosition);
|
|
if (tile == tiles->end())
|
|
continue;
|
|
const auto tileResult = tile->second.removeWater(cellPosition);
|
|
if (tile->second.isEmpty())
|
|
{
|
|
tiles->erase(tile);
|
|
++mTilesGeneration;
|
|
}
|
|
if (tileResult && !result)
|
|
result = tileResult;
|
|
}
|
|
if (result)
|
|
++mRevision;
|
|
return result;
|
|
}
|
|
|
|
std::shared_ptr<RecastMesh> TileCachedRecastMeshManager::getMesh(const TilePosition& tilePosition)
|
|
{
|
|
const auto tiles = mTiles.lock();
|
|
const auto it = tiles->find(tilePosition);
|
|
if (it == tiles->end())
|
|
return nullptr;
|
|
return it->second.getMesh();
|
|
}
|
|
|
|
bool TileCachedRecastMeshManager::hasTile(const TilePosition& tilePosition)
|
|
{
|
|
return mTiles.lockConst()->count(tilePosition);
|
|
}
|
|
|
|
std::size_t TileCachedRecastMeshManager::getRevision() const
|
|
{
|
|
return mRevision;
|
|
}
|
|
|
|
void TileCachedRecastMeshManager::reportNavMeshChange(const TilePosition& tilePosition, Version recastMeshVersion, Version navMeshVersion)
|
|
{
|
|
const auto tiles = mTiles.lock();
|
|
const auto it = tiles->find(tilePosition);
|
|
if (it == tiles->end())
|
|
return;
|
|
it->second.reportNavMeshChange(recastMeshVersion, navMeshVersion);
|
|
}
|
|
|
|
bool TileCachedRecastMeshManager::addTile(const ObjectId id, const btCollisionShape& shape,
|
|
const btTransform& transform, const AreaType areaType, const TilePosition& tilePosition, float border,
|
|
std::map<TilePosition, CachedRecastMeshManager>& tiles)
|
|
{
|
|
auto tile = tiles.find(tilePosition);
|
|
if (tile == tiles.end())
|
|
{
|
|
auto tileBounds = makeTileBounds(mSettings, tilePosition);
|
|
tileBounds.mMin -= osg::Vec2f(border, border);
|
|
tileBounds.mMax += osg::Vec2f(border, border);
|
|
tile = tiles.insert(std::make_pair(
|
|
tilePosition, CachedRecastMeshManager(mSettings, tileBounds, mTilesGeneration))).first;
|
|
}
|
|
return tile->second.addObject(id, shape, transform, areaType);
|
|
}
|
|
|
|
bool TileCachedRecastMeshManager::updateTile(const ObjectId id, const btTransform& transform,
|
|
const AreaType areaType, const TilePosition& tilePosition, std::map<TilePosition, CachedRecastMeshManager>& tiles)
|
|
{
|
|
const auto tile = tiles.find(tilePosition);
|
|
return tile != tiles.end() && tile->second.updateObject(id, transform, areaType);
|
|
}
|
|
|
|
std::optional<RemovedRecastMeshObject> TileCachedRecastMeshManager::removeTile(const ObjectId id,
|
|
const TilePosition& tilePosition, std::map<TilePosition, CachedRecastMeshManager>& tiles)
|
|
{
|
|
const auto tile = tiles.find(tilePosition);
|
|
if (tile == tiles.end())
|
|
return std::optional<RemovedRecastMeshObject>();
|
|
const auto tileResult = tile->second.removeObject(id);
|
|
if (tile->second.isEmpty())
|
|
{
|
|
tiles.erase(tile);
|
|
++mTilesGeneration;
|
|
}
|
|
return tileResult;
|
|
}
|
|
}
|