2018-03-13 22:49:08 +00:00
|
|
|
#include "navmeshmanager.hpp"
|
|
|
|
#include "debug.hpp"
|
2018-04-15 19:54:45 +00:00
|
|
|
#include "gettilespositions.hpp"
|
2018-04-01 00:44:16 +00:00
|
|
|
#include "makenavmesh.hpp"
|
2018-04-15 22:07:18 +00:00
|
|
|
#include "navmeshcacheitem.hpp"
|
2018-04-01 00:44:16 +00:00
|
|
|
#include "settings.hpp"
|
2022-08-11 22:09:49 +00:00
|
|
|
#include "settingsutils.hpp"
|
2021-05-14 19:06:29 +00:00
|
|
|
#include "waitconditiontype.hpp"
|
2018-04-01 00:44:16 +00:00
|
|
|
|
2018-11-01 10:08:33 +00:00
|
|
|
#include <components/debug/debuglog.hpp>
|
|
|
|
|
2022-06-26 17:36:03 +00:00
|
|
|
#include <osg/io_utils>
|
|
|
|
|
2018-04-01 00:44:16 +00:00
|
|
|
#include <DetourNavMesh.h>
|
|
|
|
|
2018-07-14 12:05:28 +00:00
|
|
|
namespace
|
|
|
|
{
|
2019-03-10 11:36:16 +00:00
|
|
|
/// Safely reset shared_ptr with definite underlying object destrutor call.
|
|
|
|
/// Assuming there is another thread holding copy of this shared_ptr or weak_ptr to this shared_ptr.
|
|
|
|
template <class T>
|
|
|
|
bool resetIfUnique(std::shared_ptr<T>& ptr)
|
|
|
|
{
|
2019-03-17 18:24:49 +00:00
|
|
|
const std::weak_ptr<T> weak(ptr);
|
|
|
|
ptr.reset();
|
2019-03-10 11:36:16 +00:00
|
|
|
if (auto shared = weak.lock())
|
|
|
|
{
|
|
|
|
ptr = std::move(shared);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2018-07-14 12:05:28 +00:00
|
|
|
}
|
|
|
|
|
2018-03-13 22:49:08 +00:00
|
|
|
namespace DetourNavigator
|
|
|
|
{
|
2022-02-01 00:21:47 +00:00
|
|
|
namespace
|
|
|
|
{
|
2023-01-15 02:24:37 +00:00
|
|
|
TilesPositionsRange makeRange(const TilePosition& center, int maxTiles)
|
2022-02-01 00:21:47 +00:00
|
|
|
{
|
2023-01-15 02:24:37 +00:00
|
|
|
const int radius = static_cast<int>(std::ceil(std::sqrt(static_cast<float>(maxTiles) / osg::PIf) + 1));
|
|
|
|
return TilesPositionsRange{
|
|
|
|
.mBegin = center - TilePosition(radius, radius),
|
|
|
|
.mEnd = center + TilePosition(radius + 1, radius + 1),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
TilePosition toNavMeshTilePosition(const RecastSettings& settings, const osg::Vec3f& position)
|
|
|
|
{
|
|
|
|
return getTilePosition(settings, toNavMeshCoordinates(settings, position));
|
2022-02-01 00:21:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-09 20:51:42 +00:00
|
|
|
NavMeshManager::NavMeshManager(const Settings& settings, std::unique_ptr<NavMeshDb>&& db)
|
2018-04-01 00:44:16 +00:00
|
|
|
: mSettings(settings)
|
2021-07-09 20:51:42 +00:00
|
|
|
, mRecastMeshManager(settings.mRecast)
|
|
|
|
, mOffMeshConnectionsManager(settings.mRecast)
|
|
|
|
, mAsyncNavMeshUpdater(settings, mRecastMeshManager, mOffMeshConnectionsManager, std::move(db))
|
2018-07-12 08:44:11 +00:00
|
|
|
{
|
|
|
|
}
|
2018-03-13 22:49:08 +00:00
|
|
|
|
2023-01-21 13:54:46 +00:00
|
|
|
void NavMeshManager::setWorldspace(std::string_view worldspace, const UpdateGuard* guard)
|
2021-07-09 20:51:42 +00:00
|
|
|
{
|
|
|
|
if (worldspace == mWorldspace)
|
|
|
|
return;
|
2023-04-20 23:45:21 +00:00
|
|
|
mRecastMeshManager.setWorldspace(worldspace, guard);
|
2021-07-09 20:51:42 +00:00
|
|
|
for (auto& [agent, cache] : mCache)
|
2023-02-17 13:55:05 +00:00
|
|
|
cache = std::make_shared<GuardedNavMeshCacheItem>(++mGenerationCounter, mSettings);
|
2021-07-09 20:51:42 +00:00
|
|
|
mWorldspace = worldspace;
|
|
|
|
}
|
|
|
|
|
2022-09-05 07:23:14 +00:00
|
|
|
void NavMeshManager::updateBounds(const osg::Vec3f& playerPosition, const UpdateGuard* guard)
|
2022-02-01 00:21:47 +00:00
|
|
|
{
|
2023-01-15 02:24:37 +00:00
|
|
|
const TilePosition playerTile = toNavMeshTilePosition(mSettings.mRecast, playerPosition);
|
|
|
|
const TilesPositionsRange range = makeRange(playerTile, mSettings.mMaxTilesNumber);
|
2023-04-20 23:45:21 +00:00
|
|
|
mRecastMeshManager.setRange(range, guard);
|
2022-02-01 00:21:47 +00:00
|
|
|
}
|
|
|
|
|
2021-08-01 00:13:55 +00:00
|
|
|
bool NavMeshManager::addObject(const ObjectId id, const CollisionShape& shape, const btTransform& transform,
|
2022-09-05 07:23:14 +00:00
|
|
|
const AreaType areaType, const UpdateGuard* guard)
|
2018-04-02 21:04:19 +00:00
|
|
|
{
|
2023-04-20 23:45:21 +00:00
|
|
|
return mRecastMeshManager.addObject(id, shape, transform, areaType, guard);
|
2018-04-02 21:04:19 +00:00
|
|
|
}
|
|
|
|
|
2022-09-05 07:23:14 +00:00
|
|
|
bool NavMeshManager::updateObject(
|
|
|
|
const ObjectId id, const btTransform& transform, const AreaType areaType, const UpdateGuard* guard)
|
2018-05-26 14:44:25 +00:00
|
|
|
{
|
2023-04-20 23:45:21 +00:00
|
|
|
return mRecastMeshManager.updateObject(id, transform, areaType, guard);
|
2018-05-26 14:44:25 +00:00
|
|
|
}
|
|
|
|
|
2022-09-05 07:23:14 +00:00
|
|
|
void NavMeshManager::removeObject(const ObjectId id, const UpdateGuard* guard)
|
2018-03-13 22:49:08 +00:00
|
|
|
{
|
2023-04-20 23:45:21 +00:00
|
|
|
mRecastMeshManager.removeObject(id, guard);
|
2018-03-13 22:49:08 +00:00
|
|
|
}
|
|
|
|
|
2022-09-05 07:23:14 +00:00
|
|
|
void NavMeshManager::addWater(const osg::Vec2i& cellPosition, int cellSize, float level, const UpdateGuard* guard)
|
2018-07-20 19:11:34 +00:00
|
|
|
{
|
2023-04-20 23:45:21 +00:00
|
|
|
mRecastMeshManager.addWater(cellPosition, cellSize, level, guard);
|
2018-07-20 19:11:34 +00:00
|
|
|
}
|
|
|
|
|
2022-09-05 07:23:14 +00:00
|
|
|
void NavMeshManager::removeWater(const osg::Vec2i& cellPosition, const UpdateGuard* guard)
|
2018-07-20 19:11:34 +00:00
|
|
|
{
|
2023-04-20 23:45:21 +00:00
|
|
|
mRecastMeshManager.removeWater(cellPosition, guard);
|
2018-07-20 19:11:34 +00:00
|
|
|
}
|
|
|
|
|
2022-09-05 07:23:14 +00:00
|
|
|
void NavMeshManager::addHeightfield(
|
|
|
|
const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape, const UpdateGuard* guard)
|
2021-07-14 18:57:52 +00:00
|
|
|
{
|
2023-04-20 23:45:21 +00:00
|
|
|
mRecastMeshManager.addHeightfield(cellPosition, cellSize, shape, guard);
|
2021-07-14 18:57:52 +00:00
|
|
|
}
|
|
|
|
|
2022-09-05 07:23:14 +00:00
|
|
|
void NavMeshManager::removeHeightfield(const osg::Vec2i& cellPosition, const UpdateGuard* guard)
|
2021-07-14 18:57:52 +00:00
|
|
|
{
|
2023-04-20 23:45:21 +00:00
|
|
|
mRecastMeshManager.removeHeightfield(cellPosition, guard);
|
2021-07-14 18:57:52 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 22:28:44 +00:00
|
|
|
void NavMeshManager::addAgent(const AgentBounds& agentBounds)
|
2018-04-01 17:24:02 +00:00
|
|
|
{
|
2022-06-16 22:28:44 +00:00
|
|
|
auto cached = mCache.find(agentBounds);
|
2018-04-01 17:24:02 +00:00
|
|
|
if (cached != mCache.end())
|
|
|
|
return;
|
2023-02-17 13:55:05 +00:00
|
|
|
mCache.emplace(agentBounds, std::make_shared<GuardedNavMeshCacheItem>(++mGenerationCounter, mSettings));
|
2022-08-26 18:33:34 +00:00
|
|
|
mPlayerTile.reset();
|
2022-06-16 22:28:44 +00:00
|
|
|
Log(Debug::Debug) << "cache add for agent=" << agentBounds;
|
2018-04-01 17:24:02 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 22:28:44 +00:00
|
|
|
bool NavMeshManager::reset(const AgentBounds& agentBounds)
|
2018-03-13 22:49:08 +00:00
|
|
|
{
|
2022-06-16 22:28:44 +00:00
|
|
|
const auto it = mCache.find(agentBounds);
|
2019-03-10 11:36:16 +00:00
|
|
|
if (it == mCache.end())
|
|
|
|
return true;
|
|
|
|
if (!resetIfUnique(it->second))
|
|
|
|
return false;
|
2022-06-16 22:28:44 +00:00
|
|
|
mCache.erase(agentBounds);
|
2022-08-26 18:33:34 +00:00
|
|
|
mPlayerTile.reset();
|
2019-03-10 11:36:16 +00:00
|
|
|
return true;
|
2018-03-13 22:49:08 +00:00
|
|
|
}
|
|
|
|
|
2020-06-11 21:23:30 +00:00
|
|
|
void NavMeshManager::addOffMeshConnection(
|
|
|
|
const ObjectId id, const osg::Vec3f& start, const osg::Vec3f& end, const AreaType areaType)
|
2018-08-26 20:27:38 +00:00
|
|
|
{
|
2020-06-11 21:23:30 +00:00
|
|
|
mOffMeshConnectionsManager.add(id, OffMeshConnection{ start, end, areaType });
|
2018-08-26 20:27:38 +00:00
|
|
|
|
2021-11-06 12:46:43 +00:00
|
|
|
const auto startTilePosition = getTilePosition(mSettings.mRecast, start);
|
|
|
|
const auto endTilePosition = getTilePosition(mSettings.mRecast, end);
|
2018-08-26 20:27:38 +00:00
|
|
|
|
2022-08-26 18:33:34 +00:00
|
|
|
mRecastMeshManager.addChangedTile(startTilePosition, ChangeType::add);
|
2018-08-26 20:27:38 +00:00
|
|
|
|
|
|
|
if (startTilePosition != endTilePosition)
|
2022-08-26 18:33:34 +00:00
|
|
|
mRecastMeshManager.addChangedTile(endTilePosition, ChangeType::add);
|
2018-08-26 20:27:38 +00:00
|
|
|
}
|
|
|
|
|
2020-06-11 21:23:30 +00:00
|
|
|
void NavMeshManager::removeOffMeshConnections(const ObjectId id)
|
2018-08-26 20:27:38 +00:00
|
|
|
{
|
2020-06-11 21:23:30 +00:00
|
|
|
const auto changedTiles = mOffMeshConnectionsManager.remove(id);
|
|
|
|
for (const auto& tile : changedTiles)
|
2022-08-26 18:33:34 +00:00
|
|
|
mRecastMeshManager.addChangedTile(tile, ChangeType::update);
|
2018-08-26 20:27:38 +00:00
|
|
|
}
|
|
|
|
|
2022-09-05 07:23:14 +00:00
|
|
|
void NavMeshManager::update(const osg::Vec3f& playerPosition, const UpdateGuard* guard)
|
2018-03-13 22:49:08 +00:00
|
|
|
{
|
2023-01-15 02:24:37 +00:00
|
|
|
const TilePosition playerTile = toNavMeshTilePosition(mSettings.mRecast, playerPosition);
|
2022-08-26 18:33:34 +00:00
|
|
|
if (mLastRecastMeshManagerRevision == mRecastMeshManager.getRevision() && mPlayerTile.has_value()
|
|
|
|
&& *mPlayerTile == playerTile)
|
2018-04-20 23:57:01 +00:00
|
|
|
return;
|
2022-08-26 18:33:34 +00:00
|
|
|
mLastRecastMeshManagerRevision = mRecastMeshManager.getRevision();
|
|
|
|
mPlayerTile = playerTile;
|
2024-01-08 21:17:02 +00:00
|
|
|
mRecastMeshManager.setRange(makeRange(playerTile, mSettings.mMaxTilesNumber), guard);
|
2023-04-20 23:45:21 +00:00
|
|
|
const auto changedTiles = mRecastMeshManager.takeChangedTiles(guard);
|
2023-01-15 02:24:37 +00:00
|
|
|
const TilesPositionsRange range = mRecastMeshManager.getLimitedObjectsRange();
|
2022-08-26 18:33:34 +00:00
|
|
|
for (const auto& [agentBounds, cached] : mCache)
|
2022-08-28 14:43:43 +00:00
|
|
|
update(agentBounds, playerTile, range, cached, changedTiles);
|
2022-08-26 18:33:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void NavMeshManager::update(const AgentBounds& agentBounds, const TilePosition& playerTile,
|
2022-08-28 14:43:43 +00:00
|
|
|
const TilesPositionsRange& range, const SharedNavMeshCacheItem& cached,
|
|
|
|
const std::map<osg::Vec2i, ChangeType>& changedTiles)
|
2022-08-26 18:33:34 +00:00
|
|
|
{
|
2022-08-28 14:43:43 +00:00
|
|
|
std::map<osg::Vec2i, ChangeType> tilesToPost = changedTiles;
|
2018-04-01 00:44:16 +00:00
|
|
|
{
|
2024-04-06 13:40:42 +00:00
|
|
|
const int maxTiles = mSettings.mMaxTilesNumber;
|
2019-03-10 13:49:56 +00:00
|
|
|
const auto locked = cached->lockConst();
|
2019-03-10 12:48:12 +00:00
|
|
|
const auto& navMesh = locked->getImpl();
|
2022-08-28 14:43:43 +00:00
|
|
|
getTilesPositions(range, [&](const TilePosition& tile) {
|
|
|
|
if (changedTiles.find(tile) != changedTiles.end())
|
2018-04-20 23:57:01 +00:00
|
|
|
return;
|
2022-08-28 14:43:43 +00:00
|
|
|
const bool shouldAdd = shouldAddTile(tile, playerTile, maxTiles);
|
|
|
|
const bool presentInNavMesh = navMesh.getTileAt(tile.x(), tile.y(), 0) != nullptr;
|
2018-07-14 12:05:28 +00:00
|
|
|
if (shouldAdd && !presentInNavMesh)
|
2022-08-26 18:33:34 +00:00
|
|
|
tilesToPost.emplace(tile, locked->isEmptyTile(tile) ? ChangeType::update : ChangeType::add);
|
2018-07-14 12:05:28 +00:00
|
|
|
else if (!shouldAdd && presentInNavMesh)
|
2024-04-05 23:10:48 +00:00
|
|
|
tilesToPost.emplace(tile, ChangeType::remove);
|
2018-04-20 23:57:01 +00:00
|
|
|
});
|
2024-04-06 13:40:42 +00:00
|
|
|
locked->forEachTilePosition([&](const TilePosition& tile) {
|
|
|
|
if (!shouldAddTile(tile, playerTile, maxTiles))
|
|
|
|
tilesToPost.emplace(tile, ChangeType::remove);
|
|
|
|
});
|
2018-04-01 00:44:16 +00:00
|
|
|
}
|
2022-08-28 14:43:43 +00:00
|
|
|
mAsyncNavMeshUpdater.post(agentBounds, cached, playerTile, mWorldspace, tilesToPost);
|
2022-06-16 22:28:44 +00:00
|
|
|
Log(Debug::Debug) << "Cache update posted for agent=" << agentBounds << " playerTile=" << playerTile
|
2022-08-26 18:33:34 +00:00
|
|
|
<< " recastMeshManagerRevision=" << mLastRecastMeshManagerRevision;
|
2018-03-13 22:49:08 +00:00
|
|
|
}
|
|
|
|
|
2022-09-05 07:23:14 +00:00
|
|
|
void NavMeshManager::wait(WaitConditionType waitConditionType, Loading::Listener* listener)
|
2018-03-13 22:49:08 +00:00
|
|
|
{
|
2022-09-05 07:23:14 +00:00
|
|
|
mAsyncNavMeshUpdater.wait(waitConditionType, listener);
|
2018-03-13 22:49:08 +00:00
|
|
|
}
|
|
|
|
|
2022-06-16 22:28:44 +00:00
|
|
|
SharedNavMeshCacheItem NavMeshManager::getNavMesh(const AgentBounds& agentBounds) const
|
2018-03-13 22:49:08 +00:00
|
|
|
{
|
2022-06-16 22:28:44 +00:00
|
|
|
return getCached(agentBounds);
|
2018-03-13 22:49:08 +00:00
|
|
|
}
|
2018-04-01 00:44:16 +00:00
|
|
|
|
2022-06-16 22:28:44 +00:00
|
|
|
std::map<AgentBounds, SharedNavMeshCacheItem> NavMeshManager::getNavMeshes() const
|
2018-04-07 13:11:23 +00:00
|
|
|
{
|
|
|
|
return mCache;
|
|
|
|
}
|
|
|
|
|
2022-08-28 12:52:12 +00:00
|
|
|
Stats NavMeshManager::getStats() const
|
2019-03-17 17:18:53 +00:00
|
|
|
{
|
2022-08-28 12:52:12 +00:00
|
|
|
return Stats{ .mUpdater = mAsyncNavMeshUpdater.getStats() };
|
2019-03-17 17:18:53 +00:00
|
|
|
}
|
|
|
|
|
2021-10-09 16:36:37 +00:00
|
|
|
RecastMeshTiles NavMeshManager::getRecastMeshTiles() const
|
2019-11-27 22:45:01 +00:00
|
|
|
{
|
|
|
|
RecastMeshTiles result;
|
2023-01-15 02:24:37 +00:00
|
|
|
getTilesPositions(mRecastMeshManager.getLimitedObjectsRange(), [&](const TilePosition& v) {
|
2022-08-28 14:43:43 +00:00
|
|
|
if (auto mesh = mRecastMeshManager.getCachedMesh(mWorldspace, v))
|
|
|
|
result.emplace(v, std::move(mesh));
|
|
|
|
});
|
2019-11-27 22:45:01 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-06-16 22:28:44 +00:00
|
|
|
SharedNavMeshCacheItem NavMeshManager::getCached(const AgentBounds& agentBounds) const
|
2018-04-01 17:24:02 +00:00
|
|
|
{
|
2022-06-16 22:28:44 +00:00
|
|
|
const auto cached = mCache.find(agentBounds);
|
2018-04-01 17:24:02 +00:00
|
|
|
if (cached != mCache.end())
|
|
|
|
return cached->second;
|
2019-02-16 12:32:47 +00:00
|
|
|
return SharedNavMeshCacheItem();
|
2018-04-01 17:24:02 +00:00
|
|
|
}
|
2018-03-13 22:49:08 +00:00
|
|
|
}
|