1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-04 04:09:41 +00:00
openmw/components/detournavigator/navigatorimpl.cpp
elsid cf1d8544e3
Check agent bounds on adding agent to navigator
Do not add agent bounds which are not supported by recastnavigation with given
settings and log such events.

To avoid reaching navmesh tile generation to find out it can't be generated for
such agent bounds.
2023-01-18 12:00:48 +01:00

220 lines
8 KiB
C++

#include "navigatorimpl.hpp"
#include "makenavmesh.hpp"
#include "settingsutils.hpp"
#include "stats.hpp"
#include <components/esm3/loadpgrd.hpp>
#include <components/misc/algorithm.hpp>
#include <components/misc/convert.hpp>
#include <components/misc/coordinateconverter.hpp>
namespace DetourNavigator
{
NavigatorImpl::NavigatorImpl(const Settings& settings, std::unique_ptr<NavMeshDb>&& db)
: mSettings(settings)
, mNavMeshManager(mSettings, std::move(db))
{
}
bool NavigatorImpl::addAgent(const AgentBounds& agentBounds)
{
if (!isSupportedAgentBounds(mSettings.mRecast, agentBounds))
return false;
++mAgents[agentBounds];
mNavMeshManager.addAgent(agentBounds);
return true;
}
void NavigatorImpl::removeAgent(const AgentBounds& agentBounds)
{
const auto it = mAgents.find(agentBounds);
if (it == mAgents.end())
return;
if (it->second > 0)
--it->second;
}
void NavigatorImpl::setWorldspace(const ESM::RefId& worldspace, const UpdateGuard* guard)
{
mNavMeshManager.setWorldspace(worldspace, getImpl(guard));
}
void NavigatorImpl::updateBounds(const osg::Vec3f& playerPosition, const UpdateGuard* guard)
{
mNavMeshManager.updateBounds(playerPosition, getImpl(guard));
}
void NavigatorImpl::addObject(
const ObjectId id, const ObjectShapes& shapes, const btTransform& transform, const UpdateGuard* guard)
{
addObjectImpl(id, shapes, transform, guard);
}
bool NavigatorImpl::addObjectImpl(
const ObjectId id, const ObjectShapes& shapes, const btTransform& transform, const UpdateGuard* guard)
{
const CollisionShape collisionShape(
shapes.mShapeInstance, *shapes.mShapeInstance->mCollisionShape, shapes.mTransform);
bool result = mNavMeshManager.addObject(id, collisionShape, transform, AreaType_ground, getImpl(guard));
if (const btCollisionShape* const avoidShape = shapes.mShapeInstance->mAvoidCollisionShape.get())
{
const ObjectId avoidId(avoidShape);
const CollisionShape avoidCollisionShape(shapes.mShapeInstance, *avoidShape, shapes.mTransform);
if (mNavMeshManager.addObject(avoidId, avoidCollisionShape, transform, AreaType_null, getImpl(guard)))
{
updateAvoidShapeId(id, avoidId, guard);
result = true;
}
}
return result;
}
void NavigatorImpl::addObject(
const ObjectId id, const DoorShapes& shapes, const btTransform& transform, const UpdateGuard* guard)
{
if (addObjectImpl(id, static_cast<const ObjectShapes&>(shapes), transform, guard))
{
const osg::Vec3f start = toNavMeshCoordinates(mSettings.mRecast, shapes.mConnectionStart);
const osg::Vec3f end = toNavMeshCoordinates(mSettings.mRecast, shapes.mConnectionEnd);
mNavMeshManager.addOffMeshConnection(id, start, end, AreaType_door);
mNavMeshManager.addOffMeshConnection(id, end, start, AreaType_door);
}
}
void NavigatorImpl::updateObject(
const ObjectId id, const ObjectShapes& shapes, const btTransform& transform, const UpdateGuard* guard)
{
mNavMeshManager.updateObject(id, transform, AreaType_ground, getImpl(guard));
if (const btCollisionShape* const avoidShape = shapes.mShapeInstance->mAvoidCollisionShape.get())
{
const ObjectId avoidId(avoidShape);
if (mNavMeshManager.updateObject(avoidId, transform, AreaType_null, getImpl(guard)))
updateAvoidShapeId(id, avoidId, guard);
}
}
void NavigatorImpl::updateObject(
const ObjectId id, const DoorShapes& shapes, const btTransform& transform, const UpdateGuard* guard)
{
return updateObject(id, static_cast<const ObjectShapes&>(shapes), transform, guard);
}
void NavigatorImpl::removeObject(const ObjectId id, const UpdateGuard* guard)
{
mNavMeshManager.removeObject(id, getImpl(guard));
const auto avoid = mAvoidIds.find(id);
if (avoid != mAvoidIds.end())
mNavMeshManager.removeObject(avoid->second, getImpl(guard));
const auto water = mWaterIds.find(id);
if (water != mWaterIds.end())
mNavMeshManager.removeObject(water->second, getImpl(guard));
mNavMeshManager.removeOffMeshConnections(id);
}
void NavigatorImpl::addWater(const osg::Vec2i& cellPosition, int cellSize, float level, const UpdateGuard* guard)
{
mNavMeshManager.addWater(cellPosition, cellSize, level, getImpl(guard));
}
void NavigatorImpl::removeWater(const osg::Vec2i& cellPosition, const UpdateGuard* guard)
{
mNavMeshManager.removeWater(cellPosition, getImpl(guard));
}
void NavigatorImpl::addHeightfield(
const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape, const UpdateGuard* guard)
{
mNavMeshManager.addHeightfield(cellPosition, cellSize, shape, getImpl(guard));
}
void NavigatorImpl::removeHeightfield(const osg::Vec2i& cellPosition, const UpdateGuard* guard)
{
mNavMeshManager.removeHeightfield(cellPosition, getImpl(guard));
}
void NavigatorImpl::addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid)
{
Misc::CoordinateConverter converter(&cell);
for (const auto& edge : pathgrid.mEdges)
{
const auto src = Misc::Convert::makeOsgVec3f(converter.toWorldPoint(pathgrid.mPoints[edge.mV0]));
const auto dst = Misc::Convert::makeOsgVec3f(converter.toWorldPoint(pathgrid.mPoints[edge.mV1]));
mNavMeshManager.addOffMeshConnection(ObjectId(&pathgrid), toNavMeshCoordinates(mSettings.mRecast, src),
toNavMeshCoordinates(mSettings.mRecast, dst), AreaType_pathgrid);
}
}
void NavigatorImpl::removePathgrid(const ESM::Pathgrid& pathgrid)
{
mNavMeshManager.removeOffMeshConnections(ObjectId(&pathgrid));
}
void NavigatorImpl::update(const osg::Vec3f& playerPosition, const UpdateGuard* guard)
{
removeUnusedNavMeshes();
mNavMeshManager.update(playerPosition, getImpl(guard));
}
void NavigatorImpl::wait(WaitConditionType waitConditionType, Loading::Listener* listener)
{
mNavMeshManager.wait(waitConditionType, listener);
}
SharedNavMeshCacheItem NavigatorImpl::getNavMesh(const AgentBounds& agentBounds) const
{
return mNavMeshManager.getNavMesh(agentBounds);
}
std::map<AgentBounds, SharedNavMeshCacheItem> NavigatorImpl::getNavMeshes() const
{
return mNavMeshManager.getNavMeshes();
}
const Settings& NavigatorImpl::getSettings() const
{
return mSettings;
}
Stats NavigatorImpl::getStats() const
{
return mNavMeshManager.getStats();
}
RecastMeshTiles NavigatorImpl::getRecastMeshTiles() const
{
return mNavMeshManager.getRecastMeshTiles();
}
void NavigatorImpl::updateAvoidShapeId(const ObjectId id, const ObjectId avoidId, const UpdateGuard* guard)
{
updateId(id, avoidId, mWaterIds, guard);
}
void NavigatorImpl::updateId(const ObjectId id, const ObjectId updateId,
std::unordered_map<ObjectId, ObjectId>& ids, const UpdateGuard* guard)
{
auto inserted = ids.insert(std::make_pair(id, updateId));
if (!inserted.second)
{
mNavMeshManager.removeObject(inserted.first->second, getImpl(guard));
inserted.first->second = updateId;
}
}
void NavigatorImpl::removeUnusedNavMeshes()
{
for (auto it = mAgents.begin(); it != mAgents.end();)
{
if (it->second == 0 && mNavMeshManager.reset(it->first))
it = mAgents.erase(it);
else
++it;
}
}
float NavigatorImpl::getMaxNavmeshAreaRealRadius() const
{
const auto& settings = getSettings();
return getRealTileSize(settings.mRecast) * getMaxNavmeshAreaRadius(settings);
}
}