mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-20 23:49:25 +02:00
refactor(Core/Travel): Drop TravelPlan struct; GetFullPath returns TravelPath
This commit is contained in:
parent
7ab57c184e
commit
3952ebff6e
@ -3069,11 +3069,7 @@ TravelPath MovementAction::ResolveMovePath(WorldPosition const& startPos,
|
|||||||
|
|
||||||
if (needsLongPath && !sTravelNodeMap.getNodes().empty() && !bot->InBattleground())
|
if (needsLongPath && !sTravelNodeMap.getNodes().empty() && !bot->InBattleground())
|
||||||
{
|
{
|
||||||
// Wrap the legacy TravelPlan-populating call; the steps field on
|
out = sTravelNodeMap.GetFullPath(startPos, bot->GetZoneId(), endPos, bot);
|
||||||
// TravelPlan IS a TravelPath, so extract it directly.
|
|
||||||
TravelPlan tmp;
|
|
||||||
if (sTravelNodeMap.GetFullPath(tmp, startPos, bot->GetZoneId(), endPos, bot))
|
|
||||||
out = tmp.steps;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@ -77,7 +77,6 @@ void NewRpgInfo::Reset()
|
|||||||
{
|
{
|
||||||
data = Idle{};
|
data = Idle{};
|
||||||
startT = getMSTime();
|
startT = getMSTime();
|
||||||
ClearTravel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NewRpgStatus NewRpgInfo::GetStatus()
|
NewRpgStatus NewRpgInfo::GetStatus()
|
||||||
|
|||||||
@ -78,11 +78,6 @@ struct NewRpgInfo
|
|||||||
|
|
||||||
uint32 startT{0}; // start timestamp of the current status
|
uint32 startT{0}; // start timestamp of the current status
|
||||||
|
|
||||||
// Travel Node System
|
|
||||||
TravelPlan travelPlan;
|
|
||||||
bool HasActiveTravelPlan() const { return travelPlan.IsActive(); }
|
|
||||||
void ClearTravel() { travelPlan.Reset(); }
|
|
||||||
|
|
||||||
using RpgData = std::variant<
|
using RpgData = std::variant<
|
||||||
Idle,
|
Idle,
|
||||||
GoGrind,
|
GoGrind,
|
||||||
|
|||||||
@ -1512,23 +1512,10 @@ TravelNodeRoute TravelNodeMap::FindRouteNearestNodes(WorldPosition startPos, Wor
|
|||||||
return TravelNodeRoute();
|
return TravelNodeRoute();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TravelNodeMap::GetFullPath(TravelPlan& plan,
|
TravelPath TravelNodeMap::GetFullPath(WorldPosition botPos, uint32 botZoneId,
|
||||||
WorldPosition botPos, uint32 botZoneId,
|
|
||||||
WorldPosition destination, Unit* bot)
|
WorldPosition destination, Unit* bot)
|
||||||
{
|
{
|
||||||
// Capture previous pathToStart from the about-to-be-reset plan so we
|
TravelPath path;
|
||||||
// can try cropPathTo to reuse it across the per-tick re-resolve.
|
|
||||||
std::vector<WorldPosition> prevPathToStart;
|
|
||||||
for (auto const& pt : plan.steps.GetPathRef())
|
|
||||||
{
|
|
||||||
if (pt.type == PathNodeType::NODE_PREPATH)
|
|
||||||
prevPathToStart.push_back(pt.point);
|
|
||||||
else
|
|
||||||
break; // PREPATH is always at the head
|
|
||||||
}
|
|
||||||
|
|
||||||
plan.Reset();
|
|
||||||
plan.destination = destination;
|
|
||||||
|
|
||||||
// mmap-probe first: if a 40-step probe makes meaningful progress,
|
// mmap-probe first: if a 40-step probe makes meaningful progress,
|
||||||
// prefer it over the graph. Loosened from "reaches within spellDistance"
|
// prefer it over the graph. Loosened from "reaches within spellDistance"
|
||||||
@ -1556,10 +1543,10 @@ bool TravelNodeMap::GetFullPath(TravelPlan& plan,
|
|||||||
|
|
||||||
if (closeEnough || meaningfulProgress)
|
if (closeEnough || meaningfulProgress)
|
||||||
{
|
{
|
||||||
plan.steps.addPoint(botPos, PathNodeType::NODE_PREPATH);
|
path.addPoint(botPos, PathNodeType::NODE_PREPATH);
|
||||||
for (size_t i = 1; i < probe.size(); ++i)
|
for (size_t i = 1; i < probe.size(); ++i)
|
||||||
plan.steps.addPoint(probe[i], PathNodeType::NODE_PATH);
|
path.addPoint(probe[i], PathNodeType::NODE_PATH);
|
||||||
return true;
|
return path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1595,7 +1582,7 @@ bool TravelNodeMap::GetFullPath(TravelPlan& plan,
|
|||||||
std::vector<TravelNode*> endCandidates = pickKNearest(destination, destZone);
|
std::vector<TravelNode*> endCandidates = pickKNearest(destination, destZone);
|
||||||
|
|
||||||
if (startCandidates.empty() || endCandidates.empty())
|
if (startCandidates.empty() || endCandidates.empty())
|
||||||
return false;
|
return path; // empty
|
||||||
|
|
||||||
TravelNode* startNode = nullptr;
|
TravelNode* startNode = nullptr;
|
||||||
TravelNode* endNode = nullptr;
|
TravelNode* endNode = nullptr;
|
||||||
@ -1621,24 +1608,14 @@ bool TravelNodeMap::GetFullPath(TravelPlan& plan,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (route.isEmpty() || !startNode || !endNode)
|
if (route.isEmpty() || !startNode || !endNode)
|
||||||
return false;
|
return path; // empty
|
||||||
|
|
||||||
WorldPosition startNodePos = *startNode->getPosition();
|
WorldPosition startNodePos = *startNode->getPosition();
|
||||||
WorldPosition endNodePos = *endNode->getPosition();
|
WorldPosition endNodePos = *endNode->getPosition();
|
||||||
|
|
||||||
// pathToStart: mmap-path from bot to the first node. Try cropping
|
// pathToStart: fresh mmap-path from bot to the first node.
|
||||||
// the previous pathToStart first (cmangos parity) — if it still
|
|
||||||
// reaches the chosen startNode within reactDistance we avoid a full
|
|
||||||
// re-probe. Falls back to fresh getPathTo if crop fails or invalid.
|
|
||||||
std::vector<WorldPosition> pathToStart;
|
std::vector<WorldPosition> pathToStart;
|
||||||
if (!prevPathToStart.empty())
|
if (bot && botPos.GetMapId() == startNodePos.GetMapId())
|
||||||
{
|
|
||||||
std::vector<WorldPosition> cropped = prevPathToStart;
|
|
||||||
bool ok = startNodePos.cropPathTo(cropped, sPlayerbotAIConfig.reactDistance);
|
|
||||||
if (ok && cropped.size() >= 2)
|
|
||||||
pathToStart = cropped;
|
|
||||||
}
|
|
||||||
if (pathToStart.empty() && bot && botPos.GetMapId() == startNodePos.GetMapId())
|
|
||||||
{
|
{
|
||||||
std::vector<WorldPosition> probe = botPos.getPathTo(startNodePos, bot);
|
std::vector<WorldPosition> probe = botPos.getPathTo(startNodePos, bot);
|
||||||
if (probe.size() >= 2)
|
if (probe.size() >= 2)
|
||||||
@ -1663,9 +1640,9 @@ bool TravelNodeMap::GetFullPath(TravelPlan& plan,
|
|||||||
if (pathToEnd.empty())
|
if (pathToEnd.empty())
|
||||||
pathToEnd = {destination};
|
pathToEnd = {destination};
|
||||||
|
|
||||||
plan.steps = route.BuildPath(pathToStart, pathToEnd, nullptr);
|
path = route.BuildPath(pathToStart, pathToEnd, nullptr);
|
||||||
|
|
||||||
return !plan.steps.empty();
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TravelNodeMap::cropUselessNode(TravelNode* startNode)
|
bool TravelNodeMap::cropUselessNode(TravelNode* startNode)
|
||||||
|
|||||||
@ -68,7 +68,9 @@
|
|||||||
//
|
//
|
||||||
// GetFullPath finds nearest nodes (zone-indexed), runs A* to get a node route, then
|
// GetFullPath finds nearest nodes (zone-indexed), runs A* to get a node route, then
|
||||||
// BuildPath assembles a flat TravelPath with typed waypoints (walk, portal, transport, flight).
|
// BuildPath assembles a flat TravelPath with typed waypoints (walk, portal, transport, flight).
|
||||||
// ExecuteTravelPlan iterates the path by stepIdx, dispatching on each point's PathNodeType.
|
// MoveFarTo re-resolves a fresh TravelPath each tick; UpcommingSpecialMovement cuts
|
||||||
|
// to the head segment when special; HandleSpecialMovement dispatches the matching
|
||||||
|
// action (portal interact, area-trigger marker, transport board, flight taxi).
|
||||||
// Cross-map travel is handled naturally by portal/transport edges in the A* graph.
|
// Cross-map travel is handled naturally by portal/transport edges in the A* graph.
|
||||||
//
|
//
|
||||||
// If setup cannot resolve (no node, no route, no flight), the bot teleports directly to the destination
|
// If setup cannot resolve (no node, no route, no flight), the bot teleports directly to the destination
|
||||||
@ -585,34 +587,6 @@ public:
|
|||||||
uint32 currentGold = 0;
|
uint32 currentGold = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TravelPlan
|
|
||||||
{
|
|
||||||
WorldPosition destination;
|
|
||||||
|
|
||||||
// Flat waypoint path built upfront by GetFullPath:
|
|
||||||
TravelPath steps;
|
|
||||||
uint32 stepIdx{0};
|
|
||||||
|
|
||||||
// Spline scratch (used by executor):
|
|
||||||
std::vector<G3D::Vector3> walkPoints;
|
|
||||||
uint32 expectedDuration{0}; // used to derive the lastMove delay
|
|
||||||
|
|
||||||
// Taxi scratch:
|
|
||||||
std::vector<uint32> route;
|
|
||||||
|
|
||||||
bool IsActive() const { return !steps.empty(); }
|
|
||||||
|
|
||||||
void Reset()
|
|
||||||
{
|
|
||||||
destination = WorldPosition();
|
|
||||||
steps.clear();
|
|
||||||
stepIdx = 0;
|
|
||||||
walkPoints.clear();
|
|
||||||
expectedDuration = 0;
|
|
||||||
route.clear();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// The container of all nodes.
|
// The container of all nodes.
|
||||||
class TravelNodeMap
|
class TravelNodeMap
|
||||||
{
|
{
|
||||||
@ -742,8 +716,11 @@ public:
|
|||||||
// empty static vector for unknown zones.
|
// empty static vector for unknown zones.
|
||||||
std::vector<TravelNode*> const& GetNodesInZone(uint32 zoneId) const;
|
std::vector<TravelNode*> const& GetNodesInZone(uint32 zoneId) const;
|
||||||
|
|
||||||
bool GetFullPath(TravelPlan& plan, WorldPosition botPos,
|
// Resolve a full TravelPath from botPos to destination. Returns an
|
||||||
uint32 botZoneId, WorldPosition destination, Unit* bot = nullptr);
|
// empty TravelPath if no graph route + mmap stitch is reachable;
|
||||||
|
// the caller is then expected to fall back to a single-point path.
|
||||||
|
TravelPath GetFullPath(WorldPosition botPos, uint32 botZoneId,
|
||||||
|
WorldPosition destination, Unit* bot = nullptr);
|
||||||
|
|
||||||
// Resolve A* route between two world positions (returns node vector)
|
// Resolve A* route between two world positions (returns node vector)
|
||||||
std::vector<TravelNode*> ResolveRoute(WorldPosition startPos,
|
std::vector<TravelNode*> ResolveRoute(WorldPosition startPos,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user