diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 99bd1c2cd..31ac64e9e 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -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 ) diff --git a/apps/openmw/mwmechanics/aicombat.cpp b/apps/openmw/mwmechanics/aicombat.cpp index 883a8cc1c..a77539a1f 100644 --- a/apps/openmw/mwmechanics/aicombat.cpp +++ b/apps/openmw/mwmechanics/aicombat.cpp @@ -1,6 +1,7 @@ #include "aicombat.hpp" #include +#include #include @@ -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); diff --git a/apps/openmw/mwmechanics/aipackage.cpp b/apps/openmw/mwmechanics/aipackage.cpp index 66b41db54..0c06697dc 100644 --- a/apps/openmw/mwmechanics/aipackage.cpp +++ b/apps/openmw/mwmechanics/aipackage.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #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 @@ -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 diff --git a/apps/openmw/mwmechanics/aiwander.cpp b/apps/openmw/mwmechanics/aiwander.cpp index fd978717e..015859c4b 100644 --- a/apps/openmw/mwmechanics/aiwander.cpp +++ b/apps/openmw/mwmechanics/aiwander.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #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& 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); diff --git a/apps/openmw/mwmechanics/coordinateconverter.cpp b/apps/openmw/mwmechanics/coordinateconverter.cpp deleted file mode 100644 index 04155ea49..000000000 --- a/apps/openmw/mwmechanics/coordinateconverter.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "coordinateconverter.hpp" - -#include -#include - -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(mCellX); - point.y() += static_cast(mCellY); - } - - void CoordinateConverter::toLocal(osg::Vec3f& point) - { - point.x() -= static_cast(mCellX); - point.y() -= static_cast(mCellY); - } - - osg::Vec3f CoordinateConverter::toLocalVec3(const osg::Vec3f& point) - { - return osg::Vec3f( - point.x() - static_cast(mCellX), - point.y() - static_cast(mCellY), - point.z() - ); - } -} diff --git a/apps/openmw/mwmechanics/coordinateconverter.hpp b/apps/openmw/mwmechanics/coordinateconverter.hpp deleted file mode 100644 index f7dda33cb..000000000 --- a/apps/openmw/mwmechanics/coordinateconverter.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef GAME_MWMECHANICS_COORDINATECONVERTER_H -#define GAME_MWMECHANICS_COORDINATECONVERTER_H - -#include -#include - -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 diff --git a/apps/openmw/mwmechanics/pathfinding.cpp b/apps/openmw/mwmechanics/pathfinding.cpp index b072f55f8..824100c60 100644 --- a/apps/openmw/mwmechanics/pathfinding.cpp +++ b/apps/openmw/mwmechanics/pathfinding.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #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)); diff --git a/apps/openmw/mwrender/pathgrid.cpp b/apps/openmw/mwrender/pathgrid.cpp index 797794457..c20e81bb2 100644 --- a/apps/openmw/mwrender/pathgrid.cpp +++ b/apps/openmw/mwrender/pathgrid.cpp @@ -8,6 +8,7 @@ #include #include +#include #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 cellPathGrid = new osg::PositionAttitudeTransform; cellPathGrid->setPosition(cellPathGridPos); diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index a366f9a75..1e1d39bec 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -365,6 +365,9 @@ namespace MWWorld if ((*iter)->getCell()->hasWater()) navigator->removeWater(osg::Vec2i(cellX, cellY)); + if (const auto pathgrid = world->getStore().get().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().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); diff --git a/components/detournavigator/areatype.hpp b/components/detournavigator/areatype.hpp index 0daa524ca..962a67847 100644 --- a/components/detournavigator/areatype.hpp +++ b/components/detournavigator/areatype.hpp @@ -9,6 +9,8 @@ namespace DetourNavigator { AreaType_null = RC_NULL_AREA, AreaType_water, + AreaType_door, + AreaType_pathgrid, AreaType_ground = RC_WALKABLE_AREA, }; } diff --git a/components/detournavigator/flags.hpp b/components/detournavigator/flags.hpp index 684d4fbba..887fd4264 100644 --- a/components/detournavigator/flags.hpp +++ b/components/detournavigator/flags.hpp @@ -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) { diff --git a/components/detournavigator/makenavmesh.cpp b/components/detournavigator/makenavmesh.cpp index ae26ced7e..beee95113 100644 --- a/components/detournavigator/makenavmesh.cpp +++ b/components/detournavigator/makenavmesh.cpp @@ -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 getOffMeshConAreas(const std::vector& connections) + { + std::vector 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 getOffMeshFlags(const std::vector& connections) + { + std::vector 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(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 offMeshConRad(offMeshConnections.size(), getRadius(settings, agentHalfExtents)); const std::vector offMeshConDir(offMeshConnections.size(), DT_OFFMESH_CON_BIDIR); - const std::vector offMeshConAreas(offMeshConnections.size(), AreaType_ground); - const std::vector offMeshConFlags(offMeshConnections.size(), Flag_openDoor); + const std::vector offMeshConAreas = getOffMeshConAreas(offMeshConnections); + const std::vector offMeshConFlags = getOffMeshFlags(offMeshConnections); dtNavMeshCreateParams params; params.verts = polyMesh.verts; diff --git a/components/detournavigator/navigator.hpp b/components/detournavigator/navigator.hpp index 99f1e258d..cfdf92232 100644 --- a/components/detournavigator/navigator.hpp +++ b/components/detournavigator/navigator.hpp @@ -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. diff --git a/components/detournavigator/navigatorimpl.cpp b/components/detournavigator/navigatorimpl.cpp index 3ecfd8b51..d7889629e 100644 --- a/components/detournavigator/navigatorimpl.cpp +++ b/components/detournavigator/navigatorimpl.cpp @@ -2,6 +2,9 @@ #include "debug.hpp" #include "settingsutils.hpp" +#include +#include + #include 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(); diff --git a/components/detournavigator/navigatorimpl.hpp b/components/detournavigator/navigatorimpl.hpp index be291f501..66a4d8bb3 100644 --- a/components/detournavigator/navigatorimpl.hpp +++ b/components/detournavigator/navigatorimpl.hpp @@ -4,6 +4,8 @@ #include "navigator.hpp" #include "navmeshmanager.hpp" +#include + 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 mAgents; std::unordered_map mAvoidIds; std::unordered_map mWaterIds; + std::multimap mOffMeshConnectionIds; void updateAvoidShapeId(const ObjectId id, const ObjectId avoidId); void updateWaterShapeId(const ObjectId id, const ObjectId waterId); diff --git a/components/detournavigator/navigatorstub.hpp b/components/detournavigator/navigatorstub.hpp index ee23e67be..9c379338f 100644 --- a/components/detournavigator/navigatorstub.hpp +++ b/components/detournavigator/navigatorstub.hpp @@ -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 {} diff --git a/components/detournavigator/navmeshmanager.cpp b/components/detournavigator/navmeshmanager.cpp index d88d9706a..43d330648 100644 --- a/components/detournavigator/navmeshmanager.cpp +++ b/components/detournavigator/navmeshmanager.cpp @@ -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) diff --git a/components/detournavigator/navmeshmanager.hpp b/components/detournavigator/navmeshmanager.hpp index a6bdca09b..f3861f8f2 100644 --- a/components/detournavigator/navmeshmanager.hpp +++ b/components/detournavigator/navmeshmanager.hpp @@ -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); diff --git a/components/detournavigator/offmeshconnection.hpp b/components/detournavigator/offmeshconnection.hpp index 60e8ecbbb..ca999dbdb 100644 --- a/components/detournavigator/offmeshconnection.hpp +++ b/components/detournavigator/offmeshconnection.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_OFFMESHCONNECTION_H #define OPENMW_COMPONENTS_DETOURNAVIGATOR_OFFMESHCONNECTION_H +#include "areatype.hpp" + #include namespace DetourNavigator @@ -9,6 +11,7 @@ namespace DetourNavigator { osg::Vec3f mStart; osg::Vec3f mEnd; + AreaType mAreaType; }; } diff --git a/components/detournavigator/offmeshconnectionsmanager.hpp b/components/detournavigator/offmeshconnectionsmanager.hpp index 155ce3296..de707f3a8 100644 --- a/components/detournavigator/offmeshconnectionsmanager.hpp +++ b/components/detournavigator/offmeshconnectionsmanager.hpp @@ -11,14 +11,11 @@ #include -#include - #include #include -#include -#include #include #include +#include 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 remove(const ObjectId id) + std::set 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 removed; - values->mById.erase(itById); + 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); - const auto startTilePosition = getTilePosition(mSettings, result.mStart); - const auto endTilePosition = getTilePosition(mSettings, result.mEnd); + removed.emplace(startTilePosition); + if (startTilePosition != endTilePosition) + removed.emplace(endTilePosition); + }); - removeByTilePosition(values->mByTilePosition, startTilePosition, id); + values->mById.erase(byId.first, byId.second); - if (startTilePosition != endTilePosition) - removeByTilePosition(values->mByTilePosition, endTilePosition, id); - - return result; + return removed; } std::vector 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 mById; + std::multimap mById; std::map> mByTilePosition; }; diff --git a/components/misc/convert.hpp b/components/misc/convert.hpp index c5671f016..c5784d33a 100644 --- a/components/misc/convert.hpp +++ b/components/misc/convert.hpp @@ -1,6 +1,8 @@ #ifndef OPENMW_COMPONENTS_MISC_CONVERT_H #define OPENMW_COMPONENTS_MISC_CONVERT_H +#include + #include #include #include @@ -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()); diff --git a/components/misc/coordinateconverter.hpp b/components/misc/coordinateconverter.hpp new file mode 100644 index 000000000..190641415 --- /dev/null +++ b/components/misc/coordinateconverter.hpp @@ -0,0 +1,68 @@ +#ifndef OPENMW_COMPONENTS_MISC_COORDINATECONVERTER_H +#define OPENMW_COMPONENTS_MISC_COORDINATECONVERTER_H + +#include +#include +#include +#include + +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(mCellX); + point.y() += static_cast(mCellY); + } + + /// in-place conversion from world to local + void toLocal(osg::Vec3f& point) const + { + point.x() -= static_cast(mCellX); + point.y() -= static_cast(mCellY); + } + + osg::Vec3f toLocalVec3(const osg::Vec3f& point) const + { + return osg::Vec3f( + point.x() - static_cast(mCellX), + point.y() - static_cast(mCellY), + point.z() + ); + } + + private: + int mCellX; + int mCellY; + }; +} + +#endif