mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 22:53:50 +00:00
Merge pull request #927 from Salgat/bug-2981
When waiting, NPCs can go where they wouldn't go normally (Bug #2981)
This commit is contained in:
commit
d15901b454
3 changed files with 52 additions and 45 deletions
|
@ -729,6 +729,7 @@ namespace MWMechanics
|
||||||
// infrequently used, therefore no benefit in caching it as a member
|
// infrequently used, therefore no benefit in caching it as a member
|
||||||
const ESM::Pathgrid *
|
const ESM::Pathgrid *
|
||||||
pathgrid = MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*cell);
|
pathgrid = MWBase::Environment::get().getWorld()->getStore().get<ESM::Pathgrid>().search(*cell);
|
||||||
|
const MWWorld::CellStore* cellStore = actor.getCell();
|
||||||
|
|
||||||
mAllowedNodes.clear();
|
mAllowedNodes.clear();
|
||||||
|
|
||||||
|
@ -750,13 +751,18 @@ namespace MWMechanics
|
||||||
osg::Vec3f npcPos(mInitialActorPosition);
|
osg::Vec3f npcPos(mInitialActorPosition);
|
||||||
CoordinateConverter(cell).toLocal(npcPos);
|
CoordinateConverter(cell).toLocal(npcPos);
|
||||||
|
|
||||||
|
// Find closest pathgrid point
|
||||||
|
int closestPointIndex = PathFinder::GetClosestPoint(pathgrid, npcPos);
|
||||||
|
|
||||||
// mAllowedNodes for this actor with pathgrid point indexes based on mDistance
|
// mAllowedNodes for this actor with pathgrid point indexes based on mDistance
|
||||||
|
// and if the point is connected to the closest current point
|
||||||
// NOTE: mPoints and mAllowedNodes are in local co-ordinates
|
// NOTE: mPoints and mAllowedNodes are in local co-ordinates
|
||||||
int pointIndex = 0;
|
int pointIndex = 0;
|
||||||
for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++)
|
for(unsigned int counter = 0; counter < pathgrid->mPoints.size(); counter++)
|
||||||
{
|
{
|
||||||
osg::Vec3f nodePos(PathFinder::MakeOsgVec3(pathgrid->mPoints[counter]));
|
osg::Vec3f nodePos(PathFinder::MakeOsgVec3(pathgrid->mPoints[counter]));
|
||||||
if((npcPos - nodePos).length2() <= mDistance * mDistance)
|
if((npcPos - nodePos).length2() <= mDistance * mDistance &&
|
||||||
|
cellStore->isPointConnected(closestPointIndex, counter))
|
||||||
{
|
{
|
||||||
mAllowedNodes.push_back(pathgrid->mPoints[counter]);
|
mAllowedNodes.push_back(pathgrid->mPoints[counter]);
|
||||||
pointIndex = counter;
|
pointIndex = counter;
|
||||||
|
|
|
@ -10,43 +10,6 @@
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
// Slightly cheaper version for comparisons.
|
|
||||||
// Caller needs to be careful for very short distances (i.e. less than 1)
|
|
||||||
// or when accumuating the results i.e. (a + b)^2 != a^2 + b^2
|
|
||||||
//
|
|
||||||
float distanceSquared(ESM::Pathgrid::Point point, const osg::Vec3f& pos)
|
|
||||||
{
|
|
||||||
return (MWMechanics::PathFinder::MakeOsgVec3(point) - pos).length2();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the closest pathgrid point index from the specified position co
|
|
||||||
// -ordinates. NOTE: Does not check if there is a sensible way to get there
|
|
||||||
// (e.g. a cliff in front).
|
|
||||||
//
|
|
||||||
// NOTE: pos is expected to be in local co-ordinates, as is grid->mPoints
|
|
||||||
//
|
|
||||||
int getClosestPoint(const ESM::Pathgrid* grid, const osg::Vec3f& pos)
|
|
||||||
{
|
|
||||||
assert(grid && !grid->mPoints.empty());
|
|
||||||
|
|
||||||
float distanceBetween = distanceSquared(grid->mPoints[0], pos);
|
|
||||||
int closestIndex = 0;
|
|
||||||
|
|
||||||
// TODO: if this full scan causes performance problems mapping pathgrid
|
|
||||||
// points to a quadtree may help
|
|
||||||
for(unsigned int counter = 1; counter < grid->mPoints.size(); counter++)
|
|
||||||
{
|
|
||||||
float potentialDistBetween = distanceSquared(grid->mPoints[counter], pos);
|
|
||||||
if(potentialDistBetween < distanceBetween)
|
|
||||||
{
|
|
||||||
distanceBetween = potentialDistBetween;
|
|
||||||
closestIndex = counter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return closestIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chooses a reachable end pathgrid point. start is assumed reachable.
|
// Chooses a reachable end pathgrid point. start is assumed reachable.
|
||||||
std::pair<int, bool> getClosestReachablePoint(const ESM::Pathgrid* grid,
|
std::pair<int, bool> getClosestReachablePoint(const ESM::Pathgrid* grid,
|
||||||
const MWWorld::CellStore *cell,
|
const MWWorld::CellStore *cell,
|
||||||
|
@ -62,7 +25,7 @@ namespace
|
||||||
// points to a quadtree may help
|
// points to a quadtree may help
|
||||||
for(unsigned int counter = 0; counter < grid->mPoints.size(); counter++)
|
for(unsigned int counter = 0; counter < grid->mPoints.size(); counter++)
|
||||||
{
|
{
|
||||||
float potentialDistBetween = distanceSquared(grid->mPoints[counter], pos);
|
float potentialDistBetween = MWMechanics::PathFinder::DistanceSquared(grid->mPoints[counter], pos);
|
||||||
if (potentialDistBetween < closestDistanceReachable)
|
if (potentialDistBetween < closestDistanceReachable)
|
||||||
{
|
{
|
||||||
// found a closer one
|
// found a closer one
|
||||||
|
@ -146,7 +109,7 @@ namespace MWMechanics
|
||||||
* pathgrid point (e.g. wander) then it may be worth while to call
|
* pathgrid point (e.g. wander) then it may be worth while to call
|
||||||
* pop_back() to remove the redundant entry.
|
* pop_back() to remove the redundant entry.
|
||||||
*
|
*
|
||||||
* NOTE: co-ordinates must be converted prior to calling getClosestPoint()
|
* NOTE: co-ordinates must be converted prior to calling GetClosestPoint()
|
||||||
*
|
*
|
||||||
* |
|
* |
|
||||||
* | cell
|
* | cell
|
||||||
|
@ -199,16 +162,16 @@ namespace MWMechanics
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: getClosestPoint expects local co-ordinates
|
// NOTE: GetClosestPoint expects local co-ordinates
|
||||||
CoordinateConverter converter(mCell->getCell());
|
CoordinateConverter converter(mCell->getCell());
|
||||||
|
|
||||||
// NOTE: It is possible that getClosestPoint returns a pathgrind point index
|
// NOTE: It is possible that GetClosestPoint returns a pathgrind point index
|
||||||
// that is unreachable in some situations. e.g. actor is standing
|
// that is unreachable in some situations. e.g. actor is standing
|
||||||
// outside an area enclosed by walls, but there is a pathgrid
|
// outside an area enclosed by walls, but there is a pathgrid
|
||||||
// point right behind the wall that is closer than any pathgrid
|
// point right behind the wall that is closer than any pathgrid
|
||||||
// point outside the wall
|
// point outside the wall
|
||||||
osg::Vec3f startPointInLocalCoords(converter.toLocalVec3(startPoint));
|
osg::Vec3f startPointInLocalCoords(converter.toLocalVec3(startPoint));
|
||||||
int startNode = getClosestPoint(mPathgrid, startPointInLocalCoords);
|
int startNode = GetClosestPoint(mPathgrid, startPointInLocalCoords);
|
||||||
|
|
||||||
osg::Vec3f endPointInLocalCoords(converter.toLocalVec3(endPoint));
|
osg::Vec3f endPointInLocalCoords(converter.toLocalVec3(endPoint));
|
||||||
std::pair<int, bool> endNode = getClosestReachablePoint(mPathgrid, cell,
|
std::pair<int, bool> endNode = getClosestReachablePoint(mPathgrid, cell,
|
||||||
|
@ -218,8 +181,8 @@ namespace MWMechanics
|
||||||
// if it's shorter for actor to travel from start to end, than to travel from either
|
// if it's shorter for actor to travel from start to end, than to travel from either
|
||||||
// start or end to nearest pathgrid point, just travel from start to end.
|
// start or end to nearest pathgrid point, just travel from start to end.
|
||||||
float startToEndLength2 = (endPointInLocalCoords - startPointInLocalCoords).length2();
|
float startToEndLength2 = (endPointInLocalCoords - startPointInLocalCoords).length2();
|
||||||
float endTolastNodeLength2 = distanceSquared(mPathgrid->mPoints[endNode.first], endPointInLocalCoords);
|
float endTolastNodeLength2 = DistanceSquared(mPathgrid->mPoints[endNode.first], endPointInLocalCoords);
|
||||||
float startTo1stNodeLength2 = distanceSquared(mPathgrid->mPoints[startNode], startPointInLocalCoords);
|
float startTo1stNodeLength2 = DistanceSquared(mPathgrid->mPoints[startNode], startPointInLocalCoords);
|
||||||
if ((startToEndLength2 < startTo1stNodeLength2) || (startToEndLength2 < endTolastNodeLength2))
|
if ((startToEndLength2 < startTo1stNodeLength2) || (startToEndLength2 < endTolastNodeLength2))
|
||||||
{
|
{
|
||||||
mPath.push_back(endPoint);
|
mPath.push_back(endPoint);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <components/esm/defs.hpp>
|
#include <components/esm/defs.hpp>
|
||||||
#include <components/esm/loadpgrd.hpp>
|
#include <components/esm/loadpgrd.hpp>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace MWWorld
|
namespace MWWorld
|
||||||
{
|
{
|
||||||
|
@ -90,6 +91,43 @@ namespace MWMechanics
|
||||||
return osg::Vec3f(static_cast<float>(p.mX), static_cast<float>(p.mY), static_cast<float>(p.mZ));
|
return osg::Vec3f(static_cast<float>(p.mX), static_cast<float>(p.mY), static_cast<float>(p.mZ));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Slightly cheaper version for comparisons.
|
||||||
|
// Caller needs to be careful for very short distances (i.e. less than 1)
|
||||||
|
// or when accumuating the results i.e. (a + b)^2 != a^2 + b^2
|
||||||
|
//
|
||||||
|
static float DistanceSquared(ESM::Pathgrid::Point point, const osg::Vec3f& pos)
|
||||||
|
{
|
||||||
|
return (MWMechanics::PathFinder::MakeOsgVec3(point) - pos).length2();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the closest pathgrid point index from the specified position co
|
||||||
|
// -ordinates. NOTE: Does not check if there is a sensible way to get there
|
||||||
|
// (e.g. a cliff in front).
|
||||||
|
//
|
||||||
|
// NOTE: pos is expected to be in local co-ordinates, as is grid->mPoints
|
||||||
|
//
|
||||||
|
static int GetClosestPoint(const ESM::Pathgrid* grid, const osg::Vec3f& pos)
|
||||||
|
{
|
||||||
|
assert(grid && !grid->mPoints.empty());
|
||||||
|
|
||||||
|
float distanceBetween = DistanceSquared(grid->mPoints[0], pos);
|
||||||
|
int closestIndex = 0;
|
||||||
|
|
||||||
|
// TODO: if this full scan causes performance problems mapping pathgrid
|
||||||
|
// points to a quadtree may help
|
||||||
|
for(unsigned int counter = 1; counter < grid->mPoints.size(); counter++)
|
||||||
|
{
|
||||||
|
float potentialDistBetween = DistanceSquared(grid->mPoints[counter], pos);
|
||||||
|
if(potentialDistBetween < distanceBetween)
|
||||||
|
{
|
||||||
|
distanceBetween = potentialDistBetween;
|
||||||
|
closestIndex = counter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return closestIndex;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
|
void buildPath(const ESM::Pathgrid::Point &startPoint, const ESM::Pathgrid::Point &endPoint,
|
||||||
const MWWorld::CellStore* cell, bool allowShortcuts = true);
|
const MWWorld::CellStore* cell, bool allowShortcuts = true);
|
||||||
|
|
Loading…
Reference in a new issue