Move PathgridGraph out of CellStore

By definition this is not 'Mutable state of a cell' and does not belong in CellStore.

This change should improve startup times (graph is now loaded on demand) and edits to 'pathgrid.hpp' no longer cause the entirety of OpenMW to be rebuilt.
pull/349/head
scrawl 7 years ago
parent 5fe68ab062
commit c50b18b3bb
No known key found for this signature in database
GPG Key ID: 2E6CC3676024C402

@ -13,6 +13,7 @@
#include "../mwrender/animation.hpp"
#include "pathgrid.hpp"
#include "creaturestats.hpp"
#include "steering.hpp"
#include "movement.hpp"
@ -372,7 +373,7 @@ namespace MWMechanics
int closestPointIndex = PathFinder::GetClosestPoint(pathgrid, localPos);
for (int i = 0; i < static_cast<int>(pathgrid->mPoints.size()); i++)
{
if (i != closestPointIndex && storage.mCell->isPointConnected(closestPointIndex, i))
if (i != closestPointIndex && getPathGridGraph(storage.mCell).isPointConnected(closestPointIndex, i))
{
points.push_back(pathgrid->mPoints[static_cast<size_t>(i)]);
}

@ -14,6 +14,7 @@
#include "../mwworld/cellstore.hpp"
#include "../mwworld/inventorystore.hpp"
#include "pathgrid.hpp"
#include "creaturestats.hpp"
#include "movement.hpp"
#include "steering.hpp"
@ -107,7 +108,7 @@ bool MWMechanics::AiPackage::pathTo(const MWWorld::Ptr& actor, const ESM::Pathgr
{
if (wasShortcutting || doesPathNeedRecalc(dest, actor.getCell())) // if need to rebuild path
{
mPathFinder.buildSyncedPath(start, dest, actor.getCell());
mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell()));
mRotateOnTheRunChecks = 3;
// give priority to go directly on target if there is minimal opportunity
@ -220,6 +221,20 @@ void MWMechanics::AiPackage::evadeObstacles(const MWWorld::Ptr& actor, float dur
}
}
const MWMechanics::PathgridGraph& MWMechanics::AiPackage::getPathGridGraph(const MWWorld::CellStore *cell)
{
const ESM::CellId& id = cell->getCell()->getCellId();
// static cache is OK for now, pathgrids can never change during runtime
typedef std::map<ESM::CellId, std::unique_ptr<MWMechanics::PathgridGraph> > CacheMap;
static CacheMap cache;
CacheMap::iterator found = cache.find(id);
if (found == cache.end())
{
cache.insert(std::make_pair(id, std::unique_ptr<MWMechanics::PathgridGraph>(new MWMechanics::PathgridGraph(cell))));
}
return *cache[id].get();
}
bool MWMechanics::AiPackage::shortcutPath(const ESM::Pathgrid::Point& startPoint, const ESM::Pathgrid::Point& endPoint, const MWWorld::Ptr& actor, bool *destInLOS)
{
const MWWorld::Class& actorClass = actor.getClass();

@ -27,6 +27,7 @@ namespace MWMechanics
const float AI_REACTION_TIME = 0.25f;
class CharacterController;
class PathgridGraph;
/// \brief Base class for AI packages
class AiPackage
@ -119,6 +120,8 @@ namespace MWMechanics
void evadeObstacles(const MWWorld::Ptr& actor, float duration, const ESM::Position& pos);
const PathgridGraph& getPathGridGraph(const MWWorld::CellStore* cell);
// TODO: all this does not belong here, move into temporary storage
PathFinder mPathFinder;
ObstacleCheck mObstacleCheck;

@ -17,6 +17,7 @@
#include "../mwworld/esmstore.hpp"
#include "../mwworld/cellstore.hpp"
#include "pathgrid.hpp"
#include "creaturestats.hpp"
#include "steering.hpp"
#include "movement.hpp"
@ -217,7 +218,7 @@ namespace MWMechanics
ESM::Pathgrid::Point dest(PathFinder::MakePathgridPoint(mDestination));
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
mPathFinder.buildSyncedPath(start, dest, actor.getCell());
mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell()));
if (mPathFinder.isPathConstructed())
storage.setState(Wander_Walking);
@ -349,7 +350,7 @@ namespace MWMechanics
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(pos));
// don't take shortcuts for wandering
mPathFinder.buildSyncedPath(start, dest, actor.getCell());
mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell()));
if (mPathFinder.isPathConstructed())
{
@ -383,7 +384,7 @@ namespace MWMechanics
// Check if land creature will walk onto water or if water creature will swim onto land
if ((!isWaterCreature && !destinationIsAtWater(actor, mDestination)) ||
(isWaterCreature && !destinationThroughGround(currentPositionVec3f, mDestination))) {
mPathFinder.buildSyncedPath(currentPosition, destinationPosition, actor.getCell());
mPathFinder.buildSyncedPath(currentPosition, destinationPosition, actor.getCell(), getPathGridGraph(actor.getCell()));
mPathFinder.addPointToPath(destinationPosition);
if (mPathFinder.isPathConstructed())
@ -666,7 +667,7 @@ namespace MWMechanics
ESM::Pathgrid::Point start(PathFinder::MakePathgridPoint(actorPos));
// don't take shortcuts for wandering
mPathFinder.buildSyncedPath(start, dest, actor.getCell());
mPathFinder.buildSyncedPath(start, dest, actor.getCell(), getPathGridGraph(actor.getCell()));
if (mPathFinder.isPathConstructed())
{
@ -872,7 +873,7 @@ namespace MWMechanics
int index = PathFinder::GetClosestPoint(pathgrid, PathFinder::MakeOsgVec3(dest));
currentCell->getNeighbouringPoints(index, points);
getPathGridGraph(currentCell).getNeighbouringPoints(index, points);
}
void AiWander::getAllowedNodes(const MWWorld::Ptr& actor, const ESM::Cell* cell, AiWanderStorage& storage)
@ -913,7 +914,7 @@ namespace MWMechanics
{
osg::Vec3f nodePos(PathFinder::MakeOsgVec3(pathgrid->mPoints[counter]));
if((npcPos - nodePos).length2() <= mDistance * mDistance &&
cellStore->isPointConnected(closestPointIndex, counter))
getPathGridGraph(cellStore).isPointConnected(closestPointIndex, counter))
{
storage.mAllowedNodes.push_back(pathgrid->mPoints[counter]);
pointIndex = counter;

@ -5,16 +5,16 @@
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/cellstore.hpp"
#include "pathgrid.hpp"
#include "coordinateconverter.hpp"
namespace
{
// Chooses a reachable end pathgrid point. start is assumed reachable.
std::pair<int, bool> getClosestReachablePoint(const ESM::Pathgrid* grid,
const MWWorld::CellStore *cell,
const MWMechanics::PathgridGraph *graph,
const osg::Vec3f& pos, int start)
{
assert(grid && !grid->mPoints.empty());
@ -31,7 +31,7 @@ namespace
if (potentialDistBetween < closestDistanceReachable)
{
// found a closer one
if (cell->isPointConnected(start, counter))
if (graph->isPointConnected(start, counter))
{
closestDistanceReachable = potentialDistBetween;
closestReachableIndex = counter;
@ -45,7 +45,7 @@ namespace
}
// post-condition: start and endpoint must be connected
assert(cell->isPointConnected(start, closestReachableIndex));
assert(graph->isPointConnected(start, closestReachableIndex));
// AiWander has logic that depends on whether a path was created, deleting
// allowed nodes if not. Hence a path needs to be created even if the start
@ -120,8 +120,8 @@ namespace MWMechanics
}
PathFinder::PathFinder()
: mPathgrid(NULL),
mCell(NULL)
: mPathgrid(NULL)
, mCell(NULL)
{
}
@ -169,14 +169,15 @@ namespace MWMechanics
*/
void PathFinder::buildPath(const ESM::Pathgrid::Point &startPoint,
const ESM::Pathgrid::Point &endPoint,
const MWWorld::CellStore* cell)
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph)
{
mPath.clear();
// TODO: consider removing mCell / mPathgrid in favor of mPathgridGraph
if(mCell != cell || !mPathgrid)
{
mCell = cell;
mPathgrid = MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*mCell->getCell());
mPathgrid = pathgridGraph.getPathgrid();
}
// Refer to AiWander reseach topic on openmw forums for some background.
@ -200,7 +201,7 @@ namespace MWMechanics
int startNode = GetClosestPoint(mPathgrid, startPointInLocalCoords);
osg::Vec3f endPointInLocalCoords(converter.toLocalVec3(endPoint));
std::pair<int, bool> endNode = getClosestReachablePoint(mPathgrid, cell,
std::pair<int, bool> endNode = getClosestReachablePoint(mPathgrid, &pathgridGraph,
endPointInLocalCoords,
startNode);
@ -228,7 +229,7 @@ namespace MWMechanics
}
else
{
mPath = mCell->aStarSearch(startNode, endNode.first);
mPath = pathgridGraph.aStarSearch(startNode, endNode.first);
// convert supplied path to world coordinates
for (std::list<ESM::Pathgrid::Point>::iterator iter(mPath.begin()); iter != mPath.end(); ++iter)
@ -301,18 +302,18 @@ namespace MWMechanics
// see header for the rationale
void PathFinder::buildSyncedPath(const ESM::Pathgrid::Point &startPoint,
const ESM::Pathgrid::Point &endPoint,
const MWWorld::CellStore* cell)
const MWWorld::CellStore* cell, const MWMechanics::PathgridGraph& pathgridGraph)
{
if (mPath.size() < 2)
{
// if path has one point, then it's the destination.
// don't need to worry about bad path for this case
buildPath(startPoint, endPoint, cell);
buildPath(startPoint, endPoint, cell, pathgridGraph);
}
else
{
const ESM::Pathgrid::Point oldStart(*getPath().begin());
buildPath(startPoint, endPoint, cell);
buildPath(startPoint, endPoint, cell, pathgridGraph);
if (mPath.size() >= 2)
{
// if 2nd waypoint of new path == 1st waypoint of old,

@ -14,6 +14,8 @@ namespace MWWorld
namespace MWMechanics
{
class PathgridGraph;
float distance(const ESM::Pathgrid::Point& point, float x, float y, float);
float distance(const ESM::Pathgrid::Point& a, const ESM::Pathgrid::Point& b);
float getZAngleToDir(const osg::Vec3f& dir);
@ -54,7 +56,7 @@ namespace MWMechanics
void clearPath();
void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
const MWWorld::CellStore* cell);
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph);
bool checkPathCompleted(float x, float y, float tolerance = PathTolerance);
///< \Returns true if we are within \a tolerance units of the last path point.
@ -89,7 +91,7 @@ namespace MWMechanics
Which results in NPC "running in a circle" back to the just passed waypoint.
*/
void buildSyncedPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
const MWWorld::CellStore* cell);
const MWWorld::CellStore* cell, const PathgridGraph& pathgridGraph);
void addPointToPath(const ESM::Pathgrid::Point &point)
{

@ -49,7 +49,7 @@ namespace
namespace MWMechanics
{
PathgridGraph::PathgridGraph()
PathgridGraph::PathgridGraph(const MWWorld::CellStore *cell)
: mCell(NULL)
, mPathgrid(NULL)
, mIsExterior(0)
@ -58,6 +58,7 @@ namespace MWMechanics
, mSCCId(0)
, mSCCIndex(0)
{
load(cell);
}
/*
@ -130,6 +131,11 @@ namespace MWMechanics
return true;
}
const ESM::Pathgrid *PathgridGraph::getPathgrid() const
{
return mPathgrid;
}
// v is the pathgrid point index (some call them vertices)
void PathgridGraph::recursiveStrongConnect(int v)
{

@ -20,10 +20,12 @@ namespace MWMechanics
class PathgridGraph
{
public:
PathgridGraph();
PathgridGraph(const MWWorld::CellStore* cell);
bool load(const MWWorld::CellStore *cell);
const ESM::Pathgrid* getPathgrid() const;
// returns true if end point is strongly connected (i.e. reachable
// from start point) both start and end are pathgrid point indexes
bool isPointConnected(const int start, const int end) const;

@ -445,10 +445,6 @@ namespace MWWorld
loadRefs ();
mState = State_Loaded;
// TODO: the pathgrid graph only needs to be loaded for active cells, so move this somewhere else.
// In a simple test, loading the graph for all cells in MW + expansions took 200 ms
mPathgridGraph.load(this);
}
}
@ -937,21 +933,6 @@ namespace MWWorld
return !(left==right);
}
bool CellStore::isPointConnected(const int start, const int end) const
{
return mPathgridGraph.isPointConnected(start, end);
}
void CellStore::getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const
{
return mPathgridGraph.getNeighbouringPoints(index, nodes);
}
std::list<ESM::Pathgrid::Point> CellStore::aStarSearch(const int start, const int end) const
{
return mPathgridGraph.aStarSearch(start, end);
}
void CellStore::setFog(ESM::FogState *fog)
{
mFogState.reset(fog);

@ -32,13 +32,12 @@
#include <components/esm/loadmisc.hpp>
#include <components/esm/loadbody.hpp>
#include "../mwmechanics/pathgrid.hpp" // TODO: maybe belongs in mwworld
#include "timestamp.hpp"
#include "ptr.hpp"
namespace ESM
{
struct Cell;
struct CellState;
struct FogState;
struct CellId;
@ -376,11 +375,6 @@ namespace MWWorld
void respawn ();
///< Check mLastRespawn and respawn references if necessary. This is a no-op if the cell is not loaded.
bool isPointConnected(const int start, const int end) const;
void getNeighbouringPoints(const int index, ESM::Pathgrid::PointList &nodes) const;
std::list<ESM::Pathgrid::Point> aStarSearch(const int start, const int end) const;
private:
/// Run through references and store IDs
@ -392,8 +386,6 @@ namespace MWWorld
///< Make case-adjustments to \a ref and insert it into the respective container.
///
/// Invalid \a ref objects are silently dropped.
MWMechanics::PathgridGraph mPathgridGraph;
};
template<>

Loading…
Cancel
Save