mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-20 15:39:25 +02:00
fix(Core/Travel): Audit fixes and probe correctness in MoveFarTo
This commit is contained in:
parent
3710c35a41
commit
753248510a
@ -9,23 +9,6 @@
|
|||||||
|
|
||||||
LastMovement::LastMovement() { clear(); }
|
LastMovement::LastMovement() { clear(); }
|
||||||
|
|
||||||
LastMovement::LastMovement(LastMovement& other)
|
|
||||||
: taxiNodes(other.taxiNodes),
|
|
||||||
taxiMaster(other.taxiMaster),
|
|
||||||
lastFollow(other.lastFollow),
|
|
||||||
lastAreaTrigger(other.lastAreaTrigger),
|
|
||||||
lastMoveToX(other.lastMoveToX),
|
|
||||||
lastMoveToY(other.lastMoveToY),
|
|
||||||
lastMoveToZ(other.lastMoveToZ),
|
|
||||||
lastMoveToOri(other.lastMoveToOri),
|
|
||||||
lastFlee(other.lastFlee)
|
|
||||||
{
|
|
||||||
lastMoveShort = other.lastMoveShort;
|
|
||||||
nextTeleport = other.nextTeleport;
|
|
||||||
lastPath = other.lastPath;
|
|
||||||
priority = other.priority;
|
|
||||||
}
|
|
||||||
|
|
||||||
void LastMovement::clear()
|
void LastMovement::clear()
|
||||||
{
|
{
|
||||||
lastMoveShort = WorldPosition();
|
lastMoveShort = WorldPosition();
|
||||||
|
|||||||
@ -27,20 +27,11 @@ class LastMovement
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LastMovement();
|
LastMovement();
|
||||||
LastMovement(LastMovement& other);
|
|
||||||
|
|
||||||
LastMovement& operator=(LastMovement const& other)
|
// Non-copyable: holds a std::future and several state fields the
|
||||||
{
|
// historical copy-helpers omitted. Always pass by reference.
|
||||||
taxiNodes = other.taxiNodes;
|
LastMovement(LastMovement const&) = delete;
|
||||||
taxiMaster = other.taxiMaster;
|
LastMovement& operator=(LastMovement const&) = delete;
|
||||||
lastFollow = other.lastFollow;
|
|
||||||
lastAreaTrigger = other.lastAreaTrigger;
|
|
||||||
lastMoveShort = other.lastMoveShort;
|
|
||||||
lastPath = other.lastPath;
|
|
||||||
nextTeleport = other.nextTeleport;
|
|
||||||
priority = other.priority;
|
|
||||||
return *this;
|
|
||||||
};
|
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
@ -75,7 +66,7 @@ public:
|
|||||||
LastMovementValue(PlayerbotAI* botAI) : ManualSetValue<LastMovement&>(botAI, data) {}
|
LastMovementValue(PlayerbotAI* botAI) : ManualSetValue<LastMovement&>(botAI, data) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LastMovement data = LastMovement();
|
LastMovement data{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class StayTimeValue : public ManualSetValue<time_t>
|
class StayTimeValue : public ManualSetValue<time_t>
|
||||||
|
|||||||
@ -137,11 +137,15 @@ bool NewRpgBaseAction::MoveFarTo(WorldPosition dest)
|
|||||||
bool const needsLongPath = (bot->GetMapId() != dest.GetMapId()) ||
|
bool const needsLongPath = (bot->GetMapId() != dest.GetMapId()) ||
|
||||||
(dis > sPlayerbotAIConfig.sightDistance);
|
(dis > sPlayerbotAIConfig.sightDistance);
|
||||||
|
|
||||||
// Skip travel-node planning inside battlegrounds — the graph is
|
// needsLongPath branch — graph routing only. cmangos's getFullPath
|
||||||
// built for the open world and yields nonsense routes inside BGs.
|
// already attempts a 40-step mmap probe internally before falling
|
||||||
// Mirrors cmangos MovementActions.cpp:705.
|
// back to A* node routing, so we don't need a second probe here.
|
||||||
if (needsLongPath && sPlayerbotAIConfig.enableTravelNodes &&
|
// If the graph yields no plan, fall straight to the single-point
|
||||||
!bot->InBattleground())
|
// fallback (cmangos addPoint(endPosition)). BG gate per
|
||||||
|
// MovementActions.cpp:705.
|
||||||
|
if (needsLongPath)
|
||||||
|
{
|
||||||
|
if (sPlayerbotAIConfig.enableTravelNodes && !bot->InBattleground())
|
||||||
{
|
{
|
||||||
StartTravelPlan(dest);
|
StartTravelPlan(dest);
|
||||||
if (botAI->rpgInfo.HasActiveTravelPlan())
|
if (botAI->rpgInfo.HasActiveTravelPlan())
|
||||||
@ -154,7 +158,19 @@ bool NewRpgBaseAction::MoveFarTo(WorldPosition dest)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 40-step chained mmap probe.
|
// Long-path fallback. Cross-map can't be served by a same-map
|
||||||
|
// straight-line spline — bail rather than splining toward
|
||||||
|
// unreachable coords.
|
||||||
|
if (bot->GetMapId() != dest.GetMapId())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Movement::PointsArray fallback;
|
||||||
|
fallback.emplace_back(bot->GetPositionX(), bot->GetPositionY(), bot->GetPositionZ());
|
||||||
|
fallback.emplace_back(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ());
|
||||||
|
return DispatchPathPoints(dest, fallback, "spline-long");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Short-path branch — 40-step chained mmap probe.
|
||||||
WorldPosition botPos(bot);
|
WorldPosition botPos(bot);
|
||||||
std::vector<WorldPosition> probe = botPos.getPathTo(dest, bot);
|
std::vector<WorldPosition> probe = botPos.getPathTo(dest, bot);
|
||||||
|
|
||||||
@ -245,14 +261,12 @@ bool NewRpgBaseAction::DispatchPathPoints(WorldPosition const& dest,
|
|||||||
lm.setPath(TravelPath(wpts));
|
lm.setPath(TravelPath(wpts));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Item 5 — underwater fixup. Push waypoints submerged below the
|
// Push submerged waypoints to the water surface unless dest is itself underwater.
|
||||||
// water surface up to the surface itself, unless the destination
|
if (Map* map = bot->GetMap())
|
||||||
// is itself underwater (e.g. fishing-loot quest GO, sunken ruins).
|
|
||||||
{
|
{
|
||||||
WorldPosition destWp = dest;
|
WorldPosition destWp = dest;
|
||||||
if (!destWp.isUnderWater())
|
if (!destWp.isUnderWater())
|
||||||
{
|
{
|
||||||
Map* map = bot->GetMap();
|
|
||||||
for (auto& pt : points)
|
for (auto& pt : points)
|
||||||
{
|
{
|
||||||
WorldPosition wp(dest.GetMapId(), pt.x, pt.y, pt.z);
|
WorldPosition wp(dest.GetMapId(), pt.x, pt.y, pt.z);
|
||||||
@ -307,11 +321,21 @@ bool NewRpgBaseAction::DispatchPathPoints(WorldPosition const& dest,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (clipAt > 0 && clipAt + 1 < points.size())
|
// Truncate after the first hostile waypoint. cmangos's
|
||||||
|
// analog at TravelNode.cpp:1158 sets endP=path.begin() if
|
||||||
|
// i=0 (mob right at start) and erases everything after,
|
||||||
|
// collapsing to a 1-point path. Our caller then sees
|
||||||
|
// points.size() < 2 and bails out — the bot just stops.
|
||||||
|
if (clipAt < points.size() && clipAt + 1 < points.size())
|
||||||
points.erase(points.begin() + clipAt + 1, points.end());
|
points.erase(points.begin() + clipAt + 1, points.end());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// After clip, points may have collapsed to one element (mob right
|
||||||
|
// at start). Bail rather than dispatching a degenerate spline.
|
||||||
|
if (points.size() < 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
G3D::Vector3 const& last = points.back();
|
G3D::Vector3 const& last = points.back();
|
||||||
|
|
||||||
float totalDist = 0.f;
|
float totalDist = 0.f;
|
||||||
|
|||||||
@ -50,7 +50,7 @@ void NewRpgInfo::ChangeToTravelFlight(uint32 flightMasterEntry, WorldPosition fl
|
|||||||
|
|
||||||
void NewRpgInfo::ChangeToOutdoorPvp(ObjectGuid::LowType capturePointSpawnId)
|
void NewRpgInfo::ChangeToOutdoorPvp(ObjectGuid::LowType capturePointSpawnId)
|
||||||
{
|
{
|
||||||
startT = getMSTime();
|
Reset();
|
||||||
OutdoorPvP pvp;
|
OutdoorPvP pvp;
|
||||||
pvp.capturePointSpawnId = capturePointSpawnId;
|
pvp.capturePointSpawnId = capturePointSpawnId;
|
||||||
data = pvp;
|
data = pvp;
|
||||||
|
|||||||
@ -873,14 +873,20 @@ std::vector<WorldPosition> WorldPosition::getPathFromPath(std::vector<WorldPosit
|
|||||||
PathGenerator path(pathUnit);
|
PathGenerator path(pathUnit);
|
||||||
path.AddExcludeFlag(NAV_GROUND_STEEP);
|
path.AddExcludeFlag(NAV_GROUND_STEEP);
|
||||||
|
|
||||||
// Area-cost biases. Mirrors cmangos WorldPosition.cpp:1098-1100.
|
|
||||||
// NAV_WATER weighted 10x so A* prefers shore routes over wading
|
|
||||||
// through lakes when both are reachable.
|
|
||||||
path.SetAreaCost(NAV_WATER, 10.0f);
|
|
||||||
|
|
||||||
// Limit the pathfinding attempts
|
// Limit the pathfinding attempts
|
||||||
for (uint32 i = 0; i < maxAttempt; i++)
|
for (uint32 i = 0; i < maxAttempt; i++)
|
||||||
{
|
{
|
||||||
|
// Drop cached poly state from the previous step. AC's
|
||||||
|
// BuildPolyPath has a subpath-prefix optimization
|
||||||
|
// (PathGenerator.cpp:285-389) that keeps ~80% of the prior
|
||||||
|
// call's poly chain when the new startPoly is anywhere in
|
||||||
|
// it, then computes a suffix from there. For a chained
|
||||||
|
// walker this implicitly snaps the start to the previous
|
||||||
|
// corridor instead of using the explicit startPos we pass
|
||||||
|
// in, bending the route. Reset wipes the cache so each step
|
||||||
|
// is a fresh A*.
|
||||||
|
path.Clear();
|
||||||
|
|
||||||
// Try to pathfind to this position.
|
// Try to pathfind to this position.
|
||||||
subPath = getPathStepFrom(currentPos, path);
|
subPath = getPathStepFrom(currentPos, path);
|
||||||
|
|
||||||
|
|||||||
@ -1297,7 +1297,13 @@ bool TravelNodeMap::GetFullPath(TravelPlan& plan,
|
|||||||
if (botPos.GetMapId() == destination.GetMapId())
|
if (botPos.GetMapId() == destination.GetMapId())
|
||||||
{
|
{
|
||||||
std::vector<WorldPosition> probe = destination.getPathFromPath({botPos}, bot, 40);
|
std::vector<WorldPosition> probe = destination.getPathFromPath({botPos}, bot, 40);
|
||||||
if (destination.isPathTo(probe, sPlayerbotAIConfig.spellDistance))
|
// Guard the degenerate case: getPathFromPath always returns at
|
||||||
|
// least {botPos}, and isPathTo(probe, spellDistance) succeeds
|
||||||
|
// when the bot is already within spellDistance of dest.
|
||||||
|
// Without this guard we'd emit a 1-element plan [botPos as
|
||||||
|
// PREPATH] and ExecuteTravelPlan would silently no-op every
|
||||||
|
// tick.
|
||||||
|
if (probe.size() >= 2 && destination.isPathTo(probe, sPlayerbotAIConfig.spellDistance))
|
||||||
{
|
{
|
||||||
plan.steps.addPoint(botPos, PathNodeType::NODE_PREPATH);
|
plan.steps.addPoint(botPos, PathNodeType::NODE_PREPATH);
|
||||||
for (size_t i = 1; i < probe.size(); ++i)
|
for (size_t i = 1; i < probe.size(); ++i)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user