From 5a76eb456b4afcfda15ce1ed1cf9a84bde8986cf Mon Sep 17 00:00:00 2001 From: bash Date: Fri, 8 May 2026 10:29:34 +0200 Subject: [PATCH] fix(Core/Travel): Apply 70y cap at batch loop so stepIdx stays in sync --- src/Ai/Base/Actions/MovementActions.cpp | 46 +++++++++++-------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/src/Ai/Base/Actions/MovementActions.cpp b/src/Ai/Base/Actions/MovementActions.cpp index eb38a8fef..2c3893224 100644 --- a/src/Ai/Base/Actions/MovementActions.cpp +++ b/src/Ai/Base/Actions/MovementActions.cpp @@ -3232,29 +3232,6 @@ bool MovementAction::LaunchWalkSpline(TravelPlan& state) for (auto& pt : state.walkPoints) bot->UpdateAllowedPositionZ(pt.x, pt.y, pt.z); - // Cap dispatched path length at ~70y. 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 = 70.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 if (!bot->IsMounted() && !bot->IsInCombat() && bot->IsOutdoors() && bot->IsAlive()) botAI->DoSpecificAction("check mount state", Event(), true); @@ -3428,15 +3405,34 @@ bool MovementAction::ExecuteTravelPlan(TravelPlan& state) case PathNodeType::NODE_PATH: case PathNodeType::NODE_NODE: { - // Batch consecutive walk points into one spline. Capped small 20 points per tick. + // Batch consecutive walk points into one spline. Capped at + // 20 points OR ~70y of accumulated distance — whichever + // comes first. The distance cap gives the planner regular + // re-evaluation points without committing the whole + // remaining route up front; stepIdx advances exactly in + // step with what's actually dispatched, so the next tick + // picks up from the truncation point. static constexpr uint32 MAX_SPLINE_POINTS = 20; + static constexpr float MAX_BATCH_LENGTH = 70.0f; state.walkPoints.clear(); + float accumulated = 0.f; while (state.stepIdx < state.steps.size() && state.walkPoints.size() < MAX_SPLINE_POINTS) { const PathNodePoint& wp = state.steps[state.stepIdx]; if (wp.type != PathNodeType::NODE_PATH && wp.type != PathNodeType::NODE_NODE) break; - state.walkPoints.push_back(G3D::Vector3(wp.point.GetPositionX(), wp.point.GetPositionY(), wp.point.GetPositionZ())); + G3D::Vector3 next(wp.point.GetPositionX(), wp.point.GetPositionY(), wp.point.GetPositionZ()); + if (!state.walkPoints.empty()) + { + accumulated += (next - state.walkPoints.back()).length(); + if (accumulated >= MAX_BATCH_LENGTH) + { + state.walkPoints.push_back(next); + state.stepIdx++; + break; + } + } + state.walkPoints.push_back(next); state.stepIdx++; }