feat(Core/Movement): Cap each MoveSplinePath dispatch at 100y for periodic replanning

This commit is contained in:
bash 2026-05-08 10:10:06 +02:00
parent 83e9ad3a97
commit fc2e42cddc
2 changed files with 46 additions and 7 deletions

View File

@ -3232,6 +3232,29 @@ bool MovementAction::LaunchWalkSpline(TravelPlan& state)
for (auto& pt : state.walkPoints) for (auto& pt : state.walkPoints)
bot->UpdateAllowedPositionZ(pt.x, pt.y, pt.z); bot->UpdateAllowedPositionZ(pt.x, pt.y, pt.z);
// Cap dispatched path length at ~100y. The active spline runs
// until the bot is within ~10y of its endpoint, then MoveFarTo /
// ExecuteTravelPlan replans from the new position. Capping per-
// dispatch distance gives the planner regular re-evaluation
// points (terrain shifts, combat, position drift) instead of
// committing the whole batch upfront.
{
constexpr float maxDispatchLength = 100.0f;
float accumulated = 0.f;
size_t cutoff = state.walkPoints.size();
for (size_t i = 1; i < state.walkPoints.size(); ++i)
{
accumulated += (state.walkPoints[i] - state.walkPoints[i - 1]).length();
if (accumulated >= maxDispatchLength)
{
cutoff = i + 1;
break;
}
}
if (cutoff < state.walkPoints.size())
state.walkPoints.resize(cutoff);
}
// Mount up // Mount up
if (!bot->IsMounted() && !bot->IsInCombat() && bot->IsOutdoors() && bot->IsAlive()) if (!bot->IsMounted() && !bot->IsInCombat() && bot->IsOutdoors() && bot->IsAlive())
botAI->DoSpecificAction("check mount state", Event(), true); botAI->DoSpecificAction("check mount state", Event(), true);

View File

@ -236,13 +236,29 @@ bool NewRpgBaseAction::MoveFarTo(WorldPosition dest)
if (points.size() >= 2) if (points.size() >= 2)
{ {
// Cap the chain at 20 waypoints. Beyond that, the // Cap dispatched path length at ~100y. MoveFarTo's
// chained probe's accuracy degrades (more chained // early-exit (top of function) lets the active spline
// PathGenerator calls = more stitching artifacts) and // run until bot is within 10y of its endpoint, then
// the spline interpolation between distant waypoints // replans from the new position. Capping per-dispatch
// is more likely to drift through air. // distance gives the planner regular re-evaluation
if (points.size() > 20) // points without the per-tick replan cost of fully
points.resize(20); // unbounded chunks.
{
constexpr float maxDispatchLength = 100.0f;
float accumulated = 0.f;
size_t cutoff = points.size();
for (size_t i = 1; i < points.size(); ++i)
{
accumulated += (points[i] - points[i - 1]).length();
if (accumulated >= maxDispatchLength)
{
cutoff = i + 1;
break;
}
}
if (cutoff < points.size())
points.resize(cutoff);
}
LOG_INFO("playerbots", "[MoveFar] {} mmap-path | dis={:.0f} | endDist={:.0f} | wp={} | mmapFails={} nodeFails={} | flags={}{}{}", LOG_INFO("playerbots", "[MoveFar] {} mmap-path | dis={:.0f} | endDist={:.0f} | wp={} | mmapFails={} nodeFails={} | flags={}{}{}",
bot->GetName(), dis, endDistToDest, (uint32)points.size(), bot->GetName(), dis, endDistToDest, (uint32)points.size(),