mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-20 15:39:25 +02:00
fix(Core/Travel): Port cmangos path-cheating guards to BuildPath and runtime refine
This commit is contained in:
parent
c1a59c13e9
commit
49be0f279a
@ -3237,6 +3237,15 @@ bool MovementAction::RefineWalkPoints(std::vector<G3D::Vector3>& walkPoints)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reject "pathfinder cheating" — same checks the offline gen
|
||||
// applies to BuildPath. Catches cached segments where the
|
||||
// live navmesh still produces a near-vertical hop or a
|
||||
// 2-point straight line through geometry.
|
||||
if (TravelPath::IsPathCheating(segPath, aPos.distance(bPos)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// First segment: include its start point so the spline
|
||||
// begins from the original A. Later segments: skip the first
|
||||
// point — it duplicates the previous segment's tail.
|
||||
|
||||
@ -226,6 +226,14 @@ TravelNodePath* TravelNode::BuildPath(TravelNode* endNode, Unit* bot, bool postP
|
||||
|
||||
bool canPath = endPos->isPathTo(path); // Check if we reached our destination.
|
||||
|
||||
// Reject "pathfinder cheating" — too-short or too-steep results
|
||||
// that mmap accepts but a player can't actually walk. Without this,
|
||||
// the segment gets cached + saved to playerbots_travelnode_path
|
||||
// and dispatched at runtime as straight-line spline through whatever
|
||||
// mountain/cliff sat between A and B (cmangos parity).
|
||||
if (canPath && TravelPath::IsPathCheating(path, getPosition()->distance(endNode->getPosition())))
|
||||
canPath = false;
|
||||
|
||||
if (!canPath && endNode->hasLinkTo(this)) // Unable to find a path? See if the reverse is possible.
|
||||
{
|
||||
TravelNodePath backNodePath = *endNode->getPathTo(this);
|
||||
@ -678,6 +686,39 @@ void TravelNode::print([[maybe_unused]] bool printFailed)
|
||||
}
|
||||
|
||||
// Attempts to move ahead of the path.
|
||||
bool TravelPath::IsPathCheating(std::vector<WorldPosition> const& path, float endpointDistance)
|
||||
{
|
||||
if (path.empty())
|
||||
return false;
|
||||
|
||||
// Guard 1: 2-point path for >5y is navmesh "gave up" — straight
|
||||
// line through whatever's between A and B.
|
||||
if (path.size() == 2 && endpointDistance > 5.0f)
|
||||
return true;
|
||||
|
||||
// Guard 2: steep slope at start or end suggests the pathfinder
|
||||
// hopped through a near-vertical step. >10y drop with >2:1 slope
|
||||
// is too steep to walk.
|
||||
if (path.size() > 2)
|
||||
{
|
||||
WorldPosition const& a = path.front();
|
||||
WorldPosition const& b = path[1];
|
||||
float vDist = std::fabs(a.GetPositionZ() - b.GetPositionZ());
|
||||
float hDist = a.GetExactDist2d(b.GetPositionX(), b.GetPositionY());
|
||||
if (vDist > 10.0f && (hDist == 0.0f || vDist / hDist > 2.0f))
|
||||
return true;
|
||||
|
||||
WorldPosition const& c = path.back();
|
||||
WorldPosition const& d = path[path.size() - 2];
|
||||
float vDist2 = std::fabs(c.GetPositionZ() - d.GetPositionZ());
|
||||
float hDist2 = c.GetExactDist2d(d.GetPositionX(), d.GetPositionY());
|
||||
if (vDist2 > 10.0f && (hDist2 == 0.0f || vDist2 / hDist2 > 2.0f))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TravelPath::makeShortCut(WorldPosition startPos, float maxDist, Unit* bot)
|
||||
{
|
||||
if (GetPath().empty())
|
||||
|
||||
@ -493,6 +493,19 @@ public:
|
||||
|
||||
bool makeShortCut(WorldPosition startPos, float maxDist, Unit* bot = nullptr);
|
||||
|
||||
// Detect "pathfinder cheating" — paths that PathGenerator accepts
|
||||
// but a player can't actually walk:
|
||||
// * a 2-point path for an endpoint distance > 5y means navmesh
|
||||
// gave up and returned the straight A->B line.
|
||||
// * a vertical drop > 10y combined with a slope steeper than
|
||||
// 2:1 at either start or end means the pathfinder hopped
|
||||
// through a near-vertical step the navmesh permits but a
|
||||
// player wouldn't survive.
|
||||
// cmangos applies the same two checks in TravelNode::buildPath
|
||||
// before caching a node-to-node segment.
|
||||
static bool IsPathCheating(std::vector<WorldPosition> const& path,
|
||||
float endpointDistance);
|
||||
|
||||
std::ostringstream const print();
|
||||
|
||||
private:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user