1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-29 00:32:49 +00:00
OpenMW/components/detournavigator/tilecachedrecastmeshmanager.hpp
elsid 44429f0393
Limit NavMeshManager update range by player tile and max tiles
Object AABB may be much larger than area currently covered by navmesh. In this
case all tiles beyond covered range should be ignored. Attempt to iterate over
them will not result in any new tile updates but can take quite a while. At
maximum this can be pow(INT_MAX - INT_MIN, 2) iterations.

Use arbitrary time limit to check for update call to finish in the test.
2023-01-15 04:46:29 +01:00

167 lines
6.1 KiB
C++

#ifndef OPENMW_COMPONENTS_DETOURNAVIGATOR_TILECACHEDRECASTMESHMANAGER_H
#define OPENMW_COMPONENTS_DETOURNAVIGATOR_TILECACHEDRECASTMESHMANAGER_H
#include "areatype.hpp"
#include "changetype.hpp"
#include "commulativeaabb.hpp"
#include "gettilespositions.hpp"
#include "heightfieldshape.hpp"
#include "objectid.hpp"
#include "recastmesh.hpp"
#include "recastmeshobject.hpp"
#include "tileposition.hpp"
#include "version.hpp"
#include <components/esm/refid.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/index/rtree.hpp>
#include <map>
#include <mutex>
#include <optional>
#include <vector>
namespace DetourNavigator
{
class RecastMesh;
class TileCachedRecastMeshManager
{
public:
class UpdateGuard
{
public:
explicit UpdateGuard(TileCachedRecastMeshManager& manager)
: mImpl(manager.mMutex)
{
}
private:
const std::lock_guard<std::mutex> mImpl;
};
explicit TileCachedRecastMeshManager(const RecastSettings& settings);
void setRange(const TilesPositionsRange& range, const UpdateGuard* guard);
TilesPositionsRange getLimitedObjectsRange() const;
void setWorldspace(const ESM::RefId& worldspace, const UpdateGuard* guard);
bool addObject(ObjectId id, const CollisionShape& shape, const btTransform& transform, AreaType areaType,
const UpdateGuard* guard);
bool updateObject(ObjectId id, const btTransform& transform, AreaType areaType, const UpdateGuard* guard);
void removeObject(ObjectId id, const UpdateGuard* guard);
void addWater(const osg::Vec2i& cellPosition, int cellSize, float level, const UpdateGuard* guard);
void removeWater(const osg::Vec2i& cellPosition, const UpdateGuard* guard);
void addHeightfield(
const osg::Vec2i& cellPosition, int cellSize, const HeightfieldShape& shape, const UpdateGuard* guard);
void removeHeightfield(const osg::Vec2i& cellPosition, const UpdateGuard* guard);
std::shared_ptr<RecastMesh> getMesh(const ESM::RefId& worldspace, const TilePosition& tilePosition);
std::shared_ptr<RecastMesh> getCachedMesh(const ESM::RefId& worldspace, const TilePosition& tilePosition) const;
std::shared_ptr<RecastMesh> getNewMesh(const ESM::RefId& worldspace, const TilePosition& tilePosition) const;
std::size_t getRevision() const { return mRevision; }
void reportNavMeshChange(const TilePosition& tilePosition, Version recastMeshVersion, Version navMeshVersion);
void addChangedTile(const TilePosition& tilePosition, ChangeType changeType);
std::map<osg::Vec2i, ChangeType> takeChangedTiles(const UpdateGuard* guard);
private:
struct Report
{
std::size_t mRevision;
Version mNavMeshVersion;
};
struct ObjectData
{
RecastMeshObject mObject;
TilesPositionsRange mRange;
CommulativeAabb mAabb;
std::size_t mGeneration = 0;
std::size_t mRevision = 0;
std::optional<Report> mLastNavMeshReportedChange;
std::optional<Report> mLastNavMeshReport;
};
struct WaterData
{
Water mWater;
std::optional<TilesPositionsRange> mRange;
std::size_t mRevision;
};
struct HeightfieldData
{
int mCellSize;
HeightfieldShape mShape;
std::optional<TilesPositionsRange> mRange;
std::size_t mRevision;
};
struct CachedTile
{
Version mVersion;
std::shared_ptr<RecastMesh> mRecastMesh;
};
using IndexPoint = boost::geometry::model::point<int, 2, boost::geometry::cs::cartesian>;
using IndexBox = boost::geometry::model::box<IndexPoint>;
using ObjectIndexValue = std::pair<IndexBox, ObjectData*>;
using WaterIndexValue = std::pair<IndexBox, std::map<osg::Vec2i, WaterData>::const_iterator>;
using HeightfieldIndexValue = std::pair<IndexBox, std::map<osg::Vec2i, HeightfieldData>::const_iterator>;
const RecastSettings& mSettings;
TilesPositionsRange mRange;
ESM::RefId mWorldspace;
std::unordered_map<ObjectId, std::unique_ptr<ObjectData>> mObjects;
boost::geometry::index::rtree<ObjectIndexValue, boost::geometry::index::quadratic<16>> mObjectIndex;
std::map<osg::Vec2i, WaterData> mWater;
std::map<osg::Vec2i, WaterData>::const_iterator mInfiniteWater = mWater.end();
boost::geometry::index::rtree<WaterIndexValue, boost::geometry::index::linear<4>> mWaterIndex;
std::map<osg::Vec2i, HeightfieldData> mHeightfields;
std::map<osg::Vec2i, HeightfieldData>::const_iterator mInfiniteHeightfield = mHeightfields.end();
boost::geometry::index::rtree<HeightfieldIndexValue, boost::geometry::index::linear<4>> mHeightfieldIndex;
std::map<osg::Vec2i, ChangeType> mChangedTiles;
std::map<TilePosition, CachedTile> mCache;
std::size_t mGeneration = 0;
std::size_t mRevision = 0;
mutable std::mutex mMutex;
inline static IndexPoint makeIndexPoint(const TilePosition& tilePosition);
inline static IndexBox makeIndexBox(const TilesPositionsRange& range);
inline static ObjectIndexValue makeObjectIndexValue(const TilesPositionsRange& range, ObjectData* data);
inline static WaterIndexValue makeWaterIndexValue(
const TilesPositionsRange& range, std::map<osg::Vec2i, WaterData>::const_iterator it);
inline static HeightfieldIndexValue makeHeightfieldIndexValue(
const TilesPositionsRange& range, std::map<osg::Vec2i, HeightfieldData>::const_iterator it);
inline static auto makeIndexQuery(const TilePosition& tilePosition)
-> decltype(boost::geometry::index::intersects(IndexBox()));
inline std::shared_ptr<RecastMesh> makeMesh(const TilePosition& tilePosition) const;
inline void addChangedTiles(const std::optional<TilesPositionsRange>& range, ChangeType changeType);
};
}
#endif