fix(Core/Movement): Bypass stale lastMove gate when bot stopped + loosen probe short-circuit

This commit is contained in:
bash 2026-05-30 20:56:05 +02:00
parent 7278a3bfcb
commit dd05767dcc
2 changed files with 35 additions and 8 deletions

View File

@ -1060,7 +1060,14 @@ bool MovementAction::IsWaitingForLastMove(MovementPriority priority)
if (priority > lastMove.priority) if (priority > lastMove.priority)
return false; return false;
// heuristic 5s // Stale delay bypass: if the bot has actually stopped moving (spline
// finalized + no movement flags), the delay is meaningless — common
// after combat ends with MOVEMENT_COMBAT priority still recorded,
// which would otherwise silently gate every non-combat MoveFarTo /
// MoveRandomNear request until the leftover delay expires.
if (bot->movespline->Finalized() && !bot->isMoving())
return false;
if (lastMove.lastdelayTime + lastMove.msTime > getMSTime()) if (lastMove.lastdelayTime + lastMove.msTime > getMSTime())
return true; return true;

View File

@ -1280,12 +1280,31 @@ bool TravelNodeMap::GetFullPath(TravelPlan& plan,
plan.Reset(); plan.Reset();
plan.destination = destination; plan.destination = destination;
// mmap-probe first: if a 40-step probe reaches dest, skip the // mmap-probe first: if a 40-step probe makes meaningful progress,
// graph entirely — a direct walk beats a node hop. // prefer it over the graph. Loosened from "reaches within spellDistance"
// because the strict gate falls through to graph routing whenever the
// probe stops a few yards short of the destination (e.g., bot can't
// reach the exact GO position, or destination is inside an area the
// probe can't fully enter). Graph paths come from DB-cached walk
// edges baked at offline generation time and can route through
// terrain that current mmaps treat as unwalkable.
//
// Accept the probe if EITHER:
// (a) it reaches within 30y of destination, OR
// (b) it makes >50% progress and got at least 30y total
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 (probe.size() >= 2 && destination.isPathTo(probe, sPlayerbotAIConfig.spellDistance)) if (probe.size() >= 2)
{
float const totalDist = botPos.distance(destination);
float const probeEndToDest = destination.distance(probe.back());
float const probeProgress = totalDist - probeEndToDest;
bool const closeEnough = probeEndToDest < 30.0f;
bool const meaningfulProgress = probeProgress > totalDist * 0.5f && probeProgress > 30.0f;
if (closeEnough || meaningfulProgress)
{ {
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)
@ -1293,6 +1312,7 @@ bool TravelNodeMap::GetFullPath(TravelPlan& plan,
return true; return true;
} }
} }
}
std::shared_lock<std::shared_timed_mutex> guard(m_nMapMtx); std::shared_lock<std::shared_timed_mutex> guard(m_nMapMtx);