mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 18:19:55 +00:00
Add pathgrid to navmesh as off mesh connection
This commit is contained in:
parent
095a45c714
commit
c4cd3b2c4f
22 changed files with 224 additions and 147 deletions
|
@ -86,7 +86,7 @@ add_openmw_dir (mwmechanics
|
|||
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor aibreathe
|
||||
aicast aiescort aiface aiactivate aicombat recharge repair enchanting pathfinding pathgrid security spellcasting spellresistance
|
||||
disease pickpocket levelledlist combat steering obstacle autocalcspell difficultyscaling aicombataction actor summoning
|
||||
character actors objects aistate coordinateconverter trading weaponpriority spellpriority weapontype spellutil tickableeffects
|
||||
character actors objects aistate trading weaponpriority spellpriority weapontype spellutil tickableeffects
|
||||
spellabsorption linkedeffects
|
||||
)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "aicombat.hpp"
|
||||
|
||||
#include <components/misc/rng.hpp>
|
||||
#include <components/misc/coordinateconverter.hpp>
|
||||
|
||||
#include <components/esm/aisequence.hpp>
|
||||
|
||||
|
@ -21,7 +22,6 @@
|
|||
#include "movement.hpp"
|
||||
#include "character.hpp"
|
||||
#include "aicombataction.hpp"
|
||||
#include "coordinateconverter.hpp"
|
||||
#include "actorutil.hpp"
|
||||
|
||||
namespace
|
||||
|
@ -302,7 +302,7 @@ namespace MWMechanics
|
|||
if (pathgrid && !actor.getClass().isPureWaterCreature(actor))
|
||||
{
|
||||
ESM::Pathgrid::PointList points;
|
||||
CoordinateConverter coords(storage.mCell->getCell());
|
||||
Misc::CoordinateConverter coords(storage.mCell->getCell());
|
||||
|
||||
osg::Vec3f localPos = actor.getRefData().getPosition().asVec3();
|
||||
coords.toLocal(localPos);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <components/esm/loadland.hpp>
|
||||
#include <components/esm/loadmgef.hpp>
|
||||
#include <components/detournavigator/navigator.hpp>
|
||||
#include <components/misc/coordinateconverter.hpp>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -20,7 +21,6 @@
|
|||
#include "movement.hpp"
|
||||
#include "steering.hpp"
|
||||
#include "actorutil.hpp"
|
||||
#include "coordinateconverter.hpp"
|
||||
|
||||
#include <osg/Quat>
|
||||
|
||||
|
@ -341,7 +341,7 @@ bool MWMechanics::AiPackage::isNearInactiveCell(osg::Vec3f position)
|
|||
if (playerCell->isExterior())
|
||||
{
|
||||
// get actor's distance from origin of center cell
|
||||
CoordinateConverter(playerCell).toLocal(position);
|
||||
Misc::CoordinateConverter(playerCell).toLocal(position);
|
||||
|
||||
// currently assumes 3 x 3 grid for exterior cells, with player at center cell.
|
||||
// ToDo: (Maybe) use "exterior cell load distance" setting to get count of actual active cells
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <components/misc/rng.hpp>
|
||||
#include <components/esm/aisequence.hpp>
|
||||
#include <components/detournavigator/navigator.hpp>
|
||||
#include <components/misc/coordinateconverter.hpp>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -21,7 +22,6 @@
|
|||
#include "pathgrid.hpp"
|
||||
#include "creaturestats.hpp"
|
||||
#include "movement.hpp"
|
||||
#include "coordinateconverter.hpp"
|
||||
#include "actorutil.hpp"
|
||||
|
||||
namespace MWMechanics
|
||||
|
@ -566,7 +566,7 @@ namespace MWMechanics
|
|||
|
||||
void AiWander::ToWorldCoordinates(ESM::Pathgrid::Point& point, const ESM::Cell * cell)
|
||||
{
|
||||
CoordinateConverter(cell).toWorld(point);
|
||||
Misc::CoordinateConverter(cell).toWorld(point);
|
||||
}
|
||||
|
||||
void AiWander::trimAllowedNodes(std::vector<ESM::Pathgrid::Point>& nodes,
|
||||
|
@ -767,7 +767,7 @@ namespace MWMechanics
|
|||
{
|
||||
// get NPC's position in local (i.e. cell) coordinates
|
||||
osg::Vec3f npcPos(mInitialActorPosition);
|
||||
CoordinateConverter(cell).toLocal(npcPos);
|
||||
Misc::CoordinateConverter(cell).toLocal(npcPos);
|
||||
|
||||
// Find closest pathgrid point
|
||||
int closestPointIndex = PathFinder::getClosestPoint(pathgrid, npcPos);
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
#include "coordinateconverter.hpp"
|
||||
|
||||
#include <components/esm/loadcell.hpp>
|
||||
#include <components/esm/loadland.hpp>
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
CoordinateConverter::CoordinateConverter(const ESM::Cell* cell)
|
||||
: mCellX(0), mCellY(0)
|
||||
{
|
||||
if (cell->isExterior())
|
||||
{
|
||||
mCellX = cell->mData.mX * ESM::Land::REAL_SIZE;
|
||||
mCellY = cell->mData.mY * ESM::Land::REAL_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
void CoordinateConverter::toWorld(ESM::Pathgrid::Point& point)
|
||||
{
|
||||
point.mX += mCellX;
|
||||
point.mY += mCellY;
|
||||
}
|
||||
|
||||
void CoordinateConverter::toWorld(osg::Vec3f& point)
|
||||
{
|
||||
point.x() += static_cast<float>(mCellX);
|
||||
point.y() += static_cast<float>(mCellY);
|
||||
}
|
||||
|
||||
void CoordinateConverter::toLocal(osg::Vec3f& point)
|
||||
{
|
||||
point.x() -= static_cast<float>(mCellX);
|
||||
point.y() -= static_cast<float>(mCellY);
|
||||
}
|
||||
|
||||
osg::Vec3f CoordinateConverter::toLocalVec3(const osg::Vec3f& point)
|
||||
{
|
||||
return osg::Vec3f(
|
||||
point.x() - static_cast<float>(mCellX),
|
||||
point.y() - static_cast<float>(mCellY),
|
||||
point.z()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
#ifndef GAME_MWMECHANICS_COORDINATECONVERTER_H
|
||||
#define GAME_MWMECHANICS_COORDINATECONVERTER_H
|
||||
|
||||
#include <components/esm/defs.hpp>
|
||||
#include <components/esm/loadpgrd.hpp>
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct Cell;
|
||||
}
|
||||
|
||||
namespace MWMechanics
|
||||
{
|
||||
/// \brief convert coordinates between world and local cell
|
||||
class CoordinateConverter
|
||||
{
|
||||
public:
|
||||
CoordinateConverter(const ESM::Cell* cell);
|
||||
|
||||
/// in-place conversion from local to world
|
||||
void toWorld(ESM::Pathgrid::Point& point);
|
||||
|
||||
/// in-place conversion from local to world
|
||||
void toWorld(osg::Vec3f& point);
|
||||
|
||||
/// in-place conversion from world to local
|
||||
void toLocal(osg::Vec3f& point);
|
||||
|
||||
osg::Vec3f toLocalVec3(const osg::Vec3f& point);
|
||||
|
||||
private:
|
||||
int mCellX;
|
||||
int mCellY;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -7,6 +7,7 @@
|
|||
#include <components/detournavigator/debug.hpp>
|
||||
#include <components/detournavigator/navigator.hpp>
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/misc/coordinateconverter.hpp>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -17,7 +18,6 @@
|
|||
#include "../mwworld/class.hpp"
|
||||
|
||||
#include "pathgrid.hpp"
|
||||
#include "coordinateconverter.hpp"
|
||||
#include "actorutil.hpp"
|
||||
|
||||
namespace
|
||||
|
@ -164,7 +164,7 @@ namespace MWMechanics
|
|||
}
|
||||
|
||||
// NOTE: getClosestPoint expects local coordinates
|
||||
CoordinateConverter converter(mCell->getCell());
|
||||
Misc::CoordinateConverter converter(mCell->getCell());
|
||||
|
||||
// NOTE: It is possible that getClosestPoint returns a pathgrind point index
|
||||
// that is unreachable in some situations. e.g. actor is standing
|
||||
|
@ -331,6 +331,10 @@ namespace MWMechanics
|
|||
if (!actor.getClass().isPureWaterCreature(actor) && !actor.getClass().isPureFlyingCreature(actor))
|
||||
buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents, flags, std::back_inserter(mPath));
|
||||
|
||||
if (mPath.empty())
|
||||
buildPathByNavigatorImpl(actor, startPoint, endPoint, halfExtents,
|
||||
flags | DetourNavigator::Flag_usePathgrid, std::back_inserter(mPath));
|
||||
|
||||
if (mPath.empty())
|
||||
buildPathByPathgridImpl(startPoint, endPoint, pathgridGraph, std::back_inserter(mPath));
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <components/esm/loadpgrd.hpp>
|
||||
#include <components/sceneutil/pathgridutil.hpp>
|
||||
#include <components/misc/coordinateconverter.hpp>
|
||||
|
||||
#include "../mwbase/world.hpp" // these includes can be removed once the static-hack is gone
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
@ -15,7 +16,6 @@
|
|||
#include "../mwworld/cellstore.hpp"
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
#include "../mwmechanics/pathfinding.hpp"
|
||||
#include "../mwmechanics/coordinateconverter.hpp"
|
||||
|
||||
#include "vismask.hpp"
|
||||
|
||||
|
@ -105,7 +105,7 @@ void Pathgrid::enableCellPathgrid(const MWWorld::CellStore *store)
|
|||
if (!pathgrid) return;
|
||||
|
||||
osg::Vec3f cellPathGridPos(0, 0, 0);
|
||||
MWMechanics::CoordinateConverter(store->getCell()).toWorld(cellPathGridPos);
|
||||
Misc::CoordinateConverter(store->getCell()).toWorld(cellPathGridPos);
|
||||
|
||||
osg::ref_ptr<osg::PositionAttitudeTransform> cellPathGrid = new osg::PositionAttitudeTransform;
|
||||
cellPathGrid->setPosition(cellPathGridPos);
|
||||
|
|
|
@ -365,6 +365,9 @@ namespace MWWorld
|
|||
if ((*iter)->getCell()->hasWater())
|
||||
navigator->removeWater(osg::Vec2i(cellX, cellY));
|
||||
|
||||
if (const auto pathgrid = world->getStore().get<ESM::Pathgrid>().search(*(*iter)->getCell()))
|
||||
navigator->removePathgrid(*pathgrid);
|
||||
|
||||
const auto player = world->getPlayerPtr();
|
||||
navigator->update(player.getRefData().getPosition().asVec3());
|
||||
|
||||
|
@ -393,7 +396,8 @@ namespace MWWorld
|
|||
float verts = ESM::Land::LAND_SIZE;
|
||||
float worldsize = ESM::Land::REAL_SIZE;
|
||||
|
||||
const auto navigator = MWBase::Environment::get().getWorld()->getNavigator();
|
||||
const auto world = MWBase::Environment::get().getWorld();
|
||||
const auto navigator = world->getNavigator();
|
||||
|
||||
const int cellX = cell->getCell()->getGridX();
|
||||
const int cellY = cell->getCell()->getGridY();
|
||||
|
@ -419,6 +423,9 @@ namespace MWWorld
|
|||
heightField->getCollisionObject()->getWorldTransform());
|
||||
}
|
||||
|
||||
if (const auto pathgrid = world->getStore().get<ESM::Pathgrid>().search(*cell->getCell()))
|
||||
navigator->addPathgrid(*cell->getCell(), *pathgrid);
|
||||
|
||||
// register local scripts
|
||||
// do this before insertCell, to make sure we don't add scripts from levelled creature spawning twice
|
||||
MWBase::Environment::get().getWorld()->getLocalScripts().addCell (cell);
|
||||
|
|
|
@ -9,6 +9,8 @@ namespace DetourNavigator
|
|||
{
|
||||
AreaType_null = RC_NULL_AREA,
|
||||
AreaType_water,
|
||||
AreaType_door,
|
||||
AreaType_pathgrid,
|
||||
AreaType_ground = RC_WALKABLE_AREA,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace DetourNavigator
|
|||
Flag_walk = 1 << 0,
|
||||
Flag_swim = 1 << 1,
|
||||
Flag_openDoor = 1 << 2,
|
||||
Flag_usePathgrid = 1 << 3,
|
||||
};
|
||||
|
||||
inline std::ostream& operator <<(std::ostream& stream, const Flag value)
|
||||
|
@ -27,6 +28,8 @@ namespace DetourNavigator
|
|||
return stream << "swim";
|
||||
case Flag_openDoor:
|
||||
return stream << "openDoor";
|
||||
case Flag_usePathgrid:
|
||||
return stream << "usePathgrid";
|
||||
}
|
||||
|
||||
return stream;
|
||||
|
@ -45,7 +48,7 @@ namespace DetourNavigator
|
|||
else
|
||||
{
|
||||
bool first = true;
|
||||
for (const auto flag : {Flag_walk, Flag_swim, Flag_openDoor})
|
||||
for (const auto flag : {Flag_walk, Flag_swim, Flag_openDoor, Flag_usePathgrid})
|
||||
{
|
||||
if (value.mValue & flag)
|
||||
{
|
||||
|
|
|
@ -98,6 +98,42 @@ namespace
|
|||
return result;
|
||||
}
|
||||
|
||||
Flag getFlag(AreaType areaType)
|
||||
{
|
||||
switch (areaType)
|
||||
{
|
||||
case AreaType_null:
|
||||
return Flag_none;
|
||||
case AreaType_ground:
|
||||
return Flag_walk;
|
||||
case AreaType_water:
|
||||
return Flag_swim;
|
||||
case AreaType_door:
|
||||
return Flag_openDoor;
|
||||
case AreaType_pathgrid:
|
||||
return Flag_usePathgrid;
|
||||
}
|
||||
return Flag_none;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> getOffMeshConAreas(const std::vector<OffMeshConnection>& connections)
|
||||
{
|
||||
std::vector<unsigned char> result;
|
||||
result.reserve(connections.size());
|
||||
std::transform(connections.begin(), connections.end(), std::back_inserter(result),
|
||||
[] (const OffMeshConnection& v) { return v.mAreaType; });
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<unsigned short> getOffMeshFlags(const std::vector<OffMeshConnection>& connections)
|
||||
{
|
||||
std::vector<unsigned short> result;
|
||||
result.reserve(connections.size());
|
||||
std::transform(connections.begin(), connections.end(), std::back_inserter(result),
|
||||
[] (const OffMeshConnection& v) { return getFlag(v.mAreaType); });
|
||||
return result;
|
||||
}
|
||||
|
||||
rcConfig makeConfig(const osg::Vec3f& agentHalfExtents, const osg::Vec3f& boundsMin, const osg::Vec3f& boundsMax,
|
||||
const Settings& settings)
|
||||
{
|
||||
|
@ -334,12 +370,7 @@ namespace
|
|||
void setPolyMeshFlags(rcPolyMesh& polyMesh)
|
||||
{
|
||||
for (int i = 0; i < polyMesh.npolys; ++i)
|
||||
{
|
||||
if (polyMesh.areas[i] == AreaType_ground)
|
||||
polyMesh.flags[i] = Flag_walk;
|
||||
else if (polyMesh.areas[i] == AreaType_water)
|
||||
polyMesh.flags[i] = Flag_swim;
|
||||
}
|
||||
polyMesh.flags[i] = getFlag(static_cast<AreaType>(polyMesh.areas[i]));
|
||||
}
|
||||
|
||||
bool fillPolyMesh(rcContext& context, const rcConfig& config, rcHeightfield& solid, rcPolyMesh& polyMesh,
|
||||
|
@ -395,8 +426,8 @@ namespace
|
|||
const auto offMeshConVerts = getOffMeshVerts(offMeshConnections);
|
||||
const std::vector<float> offMeshConRad(offMeshConnections.size(), getRadius(settings, agentHalfExtents));
|
||||
const std::vector<unsigned char> offMeshConDir(offMeshConnections.size(), DT_OFFMESH_CON_BIDIR);
|
||||
const std::vector<unsigned char> offMeshConAreas(offMeshConnections.size(), AreaType_ground);
|
||||
const std::vector<unsigned short> offMeshConFlags(offMeshConnections.size(), Flag_openDoor);
|
||||
const std::vector<unsigned char> offMeshConAreas = getOffMeshConAreas(offMeshConnections);
|
||||
const std::vector<unsigned short> offMeshConFlags = getOffMeshFlags(offMeshConnections);
|
||||
|
||||
dtNavMeshCreateParams params;
|
||||
params.verts = polyMesh.verts;
|
||||
|
|
|
@ -9,6 +9,12 @@
|
|||
#include "recastmesh.hpp"
|
||||
#include "recastmeshtiles.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct Cell;
|
||||
struct Pathgrid;
|
||||
}
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
struct ObjectShapes
|
||||
|
@ -139,6 +145,10 @@ namespace DetourNavigator
|
|||
*/
|
||||
virtual bool removeWater(const osg::Vec2i& cellPosition) = 0;
|
||||
|
||||
virtual void addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) = 0;
|
||||
|
||||
virtual void removePathgrid(const ESM::Pathgrid& pathgrid) = 0;
|
||||
|
||||
/**
|
||||
* @brief update start background navmesh update using current scene state.
|
||||
* @param playerPosition setup initial point to order build tiles of navmesh.
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
#include "debug.hpp"
|
||||
#include "settingsutils.hpp"
|
||||
|
||||
#include <components/esm/loadpgrd.hpp>
|
||||
#include <components/misc/coordinateconverter.hpp>
|
||||
|
||||
#include <Recast.h>
|
||||
|
||||
namespace DetourNavigator
|
||||
|
@ -54,7 +57,8 @@ namespace DetourNavigator
|
|||
mNavMeshManager.addOffMeshConnection(
|
||||
id,
|
||||
toNavMeshCoordinates(mSettings, shapes.mConnectionStart),
|
||||
toNavMeshCoordinates(mSettings, shapes.mConnectionEnd)
|
||||
toNavMeshCoordinates(mSettings, shapes.mConnectionEnd),
|
||||
AreaType_door
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
@ -95,7 +99,7 @@ namespace DetourNavigator
|
|||
const auto water = mWaterIds.find(id);
|
||||
if (water != mWaterIds.end())
|
||||
result = mNavMeshManager.removeObject(water->second) || result;
|
||||
mNavMeshManager.removeOffMeshConnection(id);
|
||||
mNavMeshManager.removeOffMeshConnections(id);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -111,6 +115,27 @@ namespace DetourNavigator
|
|||
return mNavMeshManager.removeWater(cellPosition);
|
||||
}
|
||||
|
||||
void NavigatorImpl::addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid)
|
||||
{
|
||||
Misc::CoordinateConverter converter(&cell);
|
||||
for (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, src),
|
||||
toNavMeshCoordinates(mSettings, dst),
|
||||
AreaType_pathgrid
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void NavigatorImpl::removePathgrid(const ESM::Pathgrid& pathgrid)
|
||||
{
|
||||
mNavMeshManager.removeOffMeshConnections(ObjectId(&pathgrid));
|
||||
}
|
||||
|
||||
void NavigatorImpl::update(const osg::Vec3f& playerPosition)
|
||||
{
|
||||
removeUnusedNavMeshes();
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include "navigator.hpp"
|
||||
#include "navmeshmanager.hpp"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
class NavigatorImpl final : public Navigator
|
||||
|
@ -38,6 +40,10 @@ namespace DetourNavigator
|
|||
|
||||
bool removeWater(const osg::Vec2i& cellPosition) override;
|
||||
|
||||
void addPathgrid(const ESM::Cell& cell, const ESM::Pathgrid& pathgrid) final;
|
||||
|
||||
void removePathgrid(const ESM::Pathgrid& pathgrid) final;
|
||||
|
||||
void update(const osg::Vec3f& playerPosition) override;
|
||||
|
||||
void wait() override;
|
||||
|
@ -58,6 +64,7 @@ namespace DetourNavigator
|
|||
std::map<osg::Vec3f, std::size_t> mAgents;
|
||||
std::unordered_map<ObjectId, ObjectId> mAvoidIds;
|
||||
std::unordered_map<ObjectId, ObjectId> mWaterIds;
|
||||
std::multimap<ObjectId, ObjectId> mOffMeshConnectionIds;
|
||||
|
||||
void updateAvoidShapeId(const ObjectId id, const ObjectId avoidId);
|
||||
void updateWaterShapeId(const ObjectId id, const ObjectId waterId);
|
||||
|
|
|
@ -60,6 +60,10 @@ namespace DetourNavigator
|
|||
return false;
|
||||
}
|
||||
|
||||
void addPathgrid(const ESM::Cell& /*cell*/, const ESM::Pathgrid& /*pathgrid*/) final {}
|
||||
|
||||
void removePathgrid(const ESM::Pathgrid& /*pathgrid*/) final {}
|
||||
|
||||
void update(const osg::Vec3f& /*playerPosition*/) override {}
|
||||
|
||||
void wait() override {}
|
||||
|
|
|
@ -110,10 +110,9 @@ namespace DetourNavigator
|
|||
return true;
|
||||
}
|
||||
|
||||
void NavMeshManager::addOffMeshConnection(const ObjectId id, const osg::Vec3f& start, const osg::Vec3f& end)
|
||||
void NavMeshManager::addOffMeshConnection(const ObjectId id, const osg::Vec3f& start, const osg::Vec3f& end, const AreaType areaType)
|
||||
{
|
||||
if (!mOffMeshConnectionsManager.add(id, OffMeshConnection {start, end}))
|
||||
return;
|
||||
mOffMeshConnectionsManager.add(id, OffMeshConnection {start, end, areaType});
|
||||
|
||||
const auto startTilePosition = getTilePosition(mSettings, start);
|
||||
const auto endTilePosition = getTilePosition(mSettings, end);
|
||||
|
@ -124,18 +123,11 @@ namespace DetourNavigator
|
|||
addChangedTile(endTilePosition, ChangeType::add);
|
||||
}
|
||||
|
||||
void NavMeshManager::removeOffMeshConnection(const ObjectId id)
|
||||
void NavMeshManager::removeOffMeshConnections(const ObjectId id)
|
||||
{
|
||||
if (const auto connection = mOffMeshConnectionsManager.remove(id))
|
||||
{
|
||||
const auto startTilePosition = getTilePosition(mSettings, connection->mStart);
|
||||
const auto endTilePosition = getTilePosition(mSettings, connection->mEnd);
|
||||
|
||||
addChangedTile(startTilePosition, ChangeType::remove);
|
||||
|
||||
if (startTilePosition != endTilePosition)
|
||||
addChangedTile(endTilePosition, ChangeType::remove);
|
||||
}
|
||||
const auto changedTiles = mOffMeshConnectionsManager.remove(id);
|
||||
for (const auto& tile : changedTiles)
|
||||
addChangedTile(tile, ChangeType::update);
|
||||
}
|
||||
|
||||
void NavMeshManager::update(osg::Vec3f playerPosition, const osg::Vec3f& agentHalfExtents)
|
||||
|
|
|
@ -39,9 +39,9 @@ namespace DetourNavigator
|
|||
|
||||
bool reset(const osg::Vec3f& agentHalfExtents);
|
||||
|
||||
void addOffMeshConnection(const ObjectId id, const osg::Vec3f& start, const osg::Vec3f& end);
|
||||
void addOffMeshConnection(const ObjectId id, const osg::Vec3f& start, const osg::Vec3f& end, const AreaType areaType);
|
||||
|
||||
void removeOffMeshConnection(const ObjectId id);
|
||||
void removeOffMeshConnections(const ObjectId id);
|
||||
|
||||
void update(osg::Vec3f playerPosition, const osg::Vec3f& agentHalfExtents);
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_OFFMESHCONNECTION_H
|
||||
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_OFFMESHCONNECTION_H
|
||||
|
||||
#include "areatype.hpp"
|
||||
|
||||
#include <osg/Vec3f>
|
||||
|
||||
namespace DetourNavigator
|
||||
|
@ -9,6 +11,7 @@ namespace DetourNavigator
|
|||
{
|
||||
osg::Vec3f mStart;
|
||||
osg::Vec3f mEnd;
|
||||
AreaType mAreaType;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -11,14 +11,11 @@
|
|||
|
||||
#include <osg/Vec3f>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
namespace DetourNavigator
|
||||
{
|
||||
|
@ -29,12 +26,11 @@ namespace DetourNavigator
|
|||
: mSettings(settings)
|
||||
{}
|
||||
|
||||
bool add(const ObjectId id, const OffMeshConnection& value)
|
||||
void add(const ObjectId id, const OffMeshConnection& value)
|
||||
{
|
||||
const auto values = mValues.lock();
|
||||
|
||||
if (!values->mById.insert(std::make_pair(id, value)).second)
|
||||
return false;
|
||||
values->mById.insert(std::make_pair(id, value));
|
||||
|
||||
const auto startTilePosition = getTilePosition(mSettings, value.mStart);
|
||||
const auto endTilePosition = getTilePosition(mSettings, value.mEnd);
|
||||
|
@ -43,32 +39,32 @@ namespace DetourNavigator
|
|||
|
||||
if (startTilePosition != endTilePosition)
|
||||
values->mByTilePosition[endTilePosition].insert(id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
boost::optional<OffMeshConnection> remove(const ObjectId id)
|
||||
std::set<TilePosition> remove(const ObjectId id)
|
||||
{
|
||||
const auto values = mValues.lock();
|
||||
|
||||
const auto itById = values->mById.find(id);
|
||||
const auto byId = values->mById.equal_range(id);
|
||||
|
||||
if (itById == values->mById.end())
|
||||
return boost::none;
|
||||
if (byId.first == byId.second) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto result = itById->second;
|
||||
std::set<TilePosition> removed;
|
||||
|
||||
values->mById.erase(itById);
|
||||
|
||||
const auto startTilePosition = getTilePosition(mSettings, result.mStart);
|
||||
const auto endTilePosition = getTilePosition(mSettings, result.mEnd);
|
||||
|
||||
removeByTilePosition(values->mByTilePosition, startTilePosition, id);
|
||||
std::for_each(byId.first, byId.second, [&] (const auto& v) {
|
||||
const auto startTilePosition = getTilePosition(mSettings, v.second.mStart);
|
||||
const auto endTilePosition = getTilePosition(mSettings, v.second.mEnd);
|
||||
|
||||
removed.emplace(startTilePosition);
|
||||
if (startTilePosition != endTilePosition)
|
||||
removeByTilePosition(values->mByTilePosition, endTilePosition, id);
|
||||
removed.emplace(endTilePosition);
|
||||
});
|
||||
|
||||
return result;
|
||||
values->mById.erase(byId.first, byId.second);
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
std::vector<OffMeshConnection> get(const TilePosition& tilePosition)
|
||||
|
@ -85,9 +81,8 @@ namespace DetourNavigator
|
|||
std::for_each(itByTilePosition->second.begin(), itByTilePosition->second.end(),
|
||||
[&] (const ObjectId v)
|
||||
{
|
||||
const auto itById = values->mById.find(v);
|
||||
if (itById != values->mById.end())
|
||||
result.push_back(itById->second);
|
||||
const auto byId = values->mById.equal_range(v);
|
||||
std::for_each(byId.first, byId.second, [&] (const auto& v) { result.push_back(v.second); });
|
||||
});
|
||||
|
||||
return result;
|
||||
|
@ -96,7 +91,7 @@ namespace DetourNavigator
|
|||
private:
|
||||
struct Values
|
||||
{
|
||||
std::unordered_map<ObjectId, OffMeshConnection> mById;
|
||||
std::multimap<ObjectId, OffMeshConnection> mById;
|
||||
std::map<TilePosition, std::unordered_set<ObjectId>> mByTilePosition;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef OPENMW_COMPONENTS_MISC_CONVERT_H
|
||||
#define OPENMW_COMPONENTS_MISC_CONVERT_H
|
||||
|
||||
#include <components/esm/loadpgrd.hpp>
|
||||
|
||||
#include <LinearMath/btTransform.h>
|
||||
#include <LinearMath/btVector3.h>
|
||||
#include <LinearMath/btQuaternion.h>
|
||||
|
@ -21,6 +23,11 @@ namespace Convert
|
|||
return osg::Vec3f(value.x(), value.y(), value.z());
|
||||
}
|
||||
|
||||
inline osg::Vec3f makeOsgVec3f(const ESM::Pathgrid::Point& value)
|
||||
{
|
||||
return osg::Vec3f(value.mX, value.mY, value.mZ);
|
||||
}
|
||||
|
||||
inline btVector3 toBullet(const osg::Vec3f& vec)
|
||||
{
|
||||
return btVector3(vec.x(), vec.y(), vec.z());
|
||||
|
|
68
components/misc/coordinateconverter.hpp
Normal file
68
components/misc/coordinateconverter.hpp
Normal file
|
@ -0,0 +1,68 @@
|
|||
#ifndef OPENMW_COMPONENTS_MISC_COORDINATECONVERTER_H
|
||||
#define OPENMW_COMPONENTS_MISC_COORDINATECONVERTER_H
|
||||
|
||||
#include <components/esm/defs.hpp>
|
||||
#include <components/esm/loadcell.hpp>
|
||||
#include <components/esm/loadland.hpp>
|
||||
#include <components/esm/loadpgrd.hpp>
|
||||
|
||||
namespace Misc
|
||||
{
|
||||
/// \brief convert coordinates between world and local cell
|
||||
class CoordinateConverter
|
||||
{
|
||||
public:
|
||||
CoordinateConverter(bool exterior, int cellX, int cellY)
|
||||
: mCellX(exterior ? cellX * ESM::Land::REAL_SIZE : 0),
|
||||
mCellY(exterior ? cellY * ESM::Land::REAL_SIZE : 0)
|
||||
{
|
||||
}
|
||||
|
||||
explicit CoordinateConverter(const ESM::Cell* cell)
|
||||
: CoordinateConverter(cell->isExterior(), cell->mData.mX, cell->mData.mY)
|
||||
{
|
||||
}
|
||||
|
||||
/// in-place conversion from local to world
|
||||
void toWorld(ESM::Pathgrid::Point& point) const
|
||||
{
|
||||
point.mX += mCellX;
|
||||
point.mY += mCellY;
|
||||
}
|
||||
|
||||
ESM::Pathgrid::Point toWorldPoint(ESM::Pathgrid::Point point) const
|
||||
{
|
||||
toWorld(point);
|
||||
return point;
|
||||
}
|
||||
|
||||
/// in-place conversion from local to world
|
||||
void toWorld(osg::Vec3f& point) const
|
||||
{
|
||||
point.x() += static_cast<float>(mCellX);
|
||||
point.y() += static_cast<float>(mCellY);
|
||||
}
|
||||
|
||||
/// in-place conversion from world to local
|
||||
void toLocal(osg::Vec3f& point) const
|
||||
{
|
||||
point.x() -= static_cast<float>(mCellX);
|
||||
point.y() -= static_cast<float>(mCellY);
|
||||
}
|
||||
|
||||
osg::Vec3f toLocalVec3(const osg::Vec3f& point) const
|
||||
{
|
||||
return osg::Vec3f(
|
||||
point.x() - static_cast<float>(mCellX),
|
||||
point.y() - static_cast<float>(mCellY),
|
||||
point.z()
|
||||
);
|
||||
}
|
||||
|
||||
private:
|
||||
int mCellX;
|
||||
int mCellY;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue