mirror of
https://github.com/liyunfan1223/mod-playerbots.git
synced 2026-06-20 15:39:25 +02:00
fix(Core/Travel): Path-type bitmask, loop-breaker convergence, LaunchWalkSpline LOS-cull
This commit is contained in:
parent
5077e01096
commit
83e9ad3a97
@ -3232,39 +3232,6 @@ 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);
|
||||||
|
|
||||||
// Drop waypoints whose segment from the previous point crosses
|
|
||||||
// solid geometry. Z-snapping each point to ground is necessary
|
|
||||||
// but not sufficient — two ground-level waypoints A and B with a
|
|
||||||
// mountain between them produce a spline that linearly
|
|
||||||
// interpolates straight through the mountain. vmap LoS check on
|
|
||||||
// each segment catches that. We only drop the offending B
|
|
||||||
// (skipping it) — if A→C is also blocked, the loop drops C too,
|
|
||||||
// until either the path becomes contiguous or empties out.
|
|
||||||
if (Map* losMap = bot->GetMap())
|
|
||||||
{
|
|
||||||
uint32 const phaseMask = bot->GetPhaseMask();
|
|
||||||
for (size_t i = 1; i < state.walkPoints.size(); /* incremented in body */)
|
|
||||||
{
|
|
||||||
G3D::Vector3 const& a = state.walkPoints[i - 1];
|
|
||||||
G3D::Vector3 const& b = state.walkPoints[i];
|
|
||||||
// +2y on Z so the raycast starts/ends near the bot's
|
|
||||||
// chest level rather than ground (avoids false positives
|
|
||||||
// from sub-floor poly).
|
|
||||||
if (!losMap->isInLineOfSight(a.x, a.y, a.z + 2.0f, b.x, b.y, b.z + 2.0f,
|
|
||||||
phaseMask, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::Nothing))
|
|
||||||
{
|
|
||||||
state.walkPoints.erase(state.walkPoints.begin() + i);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
++i;
|
|
||||||
}
|
|
||||||
if (state.walkPoints.size() < 2)
|
|
||||||
{
|
|
||||||
state.walkPoints.clear();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
||||||
|
|||||||
@ -78,12 +78,25 @@ void NewRpgInfo::Reset()
|
|||||||
data = Idle{};
|
data = Idle{};
|
||||||
startT = getMSTime();
|
startT = getMSTime();
|
||||||
ClearTravel();
|
ClearTravel();
|
||||||
recentMoveFarAttempts.clear();
|
// recentMoveFarAttempts is intentionally NOT cleared. Reset() runs
|
||||||
|
// on every state change (ChangeToDoQuest, ChangeToIdle, etc.) and
|
||||||
|
// the do-quest action oscillates through transitions during a
|
||||||
|
// failure cycle — wiping the deque here would prevent the
|
||||||
|
// MoveFarTo loop-breaker (nF >= 3 AND mF >= 3 → bothExhausted)
|
||||||
|
// from converging. CountRecentAttempts already filters by
|
||||||
|
// destination (within 10y), so stale entries for previous quests
|
||||||
|
// don't affect new ones.
|
||||||
}
|
}
|
||||||
|
|
||||||
void NewRpgInfo::RecordMoveFarAttempt(WorldPosition const& dest, bool wasNodeTravel)
|
void NewRpgInfo::RecordMoveFarAttempt(WorldPosition const& dest, bool wasNodeTravel)
|
||||||
{
|
{
|
||||||
if (recentMoveFarAttempts.size() >= 3)
|
// Cap at 6 (3 node + 3 mmap). The loop-breaker in MoveFarTo
|
||||||
|
// requires nF >= 3 AND mF >= 3 to declare bothExhausted. Each
|
||||||
|
// MoveFarTo failure cycle records BOTH a node attempt and a mmap
|
||||||
|
// attempt, so a single 3-cap deque would pop the older type
|
||||||
|
// before its count reached 3, structurally preventing
|
||||||
|
// bothExhausted from triggering.
|
||||||
|
if (recentMoveFarAttempts.size() >= 6)
|
||||||
recentMoveFarAttempts.pop_front();
|
recentMoveFarAttempts.pop_front();
|
||||||
MoveFarAttempt a;
|
MoveFarAttempt a;
|
||||||
a.dest = dest;
|
a.dest = dest;
|
||||||
|
|||||||
@ -739,7 +739,14 @@ std::vector<WorldPosition> WorldPosition::getPathStepFrom(WorldPosition startPos
|
|||||||
if (tempCreature)
|
if (tempCreature)
|
||||||
delete tempCreature;
|
delete tempCreature;
|
||||||
|
|
||||||
if (type == PATHFIND_INCOMPLETE || type == PATHFIND_NORMAL)
|
// PathType is a bitmask (PathGenerator.h). Detour can return e.g.
|
||||||
|
// PATHFIND_INCOMPLETE | PATHFIND_FARFROMPOLY_END (0x84) when the
|
||||||
|
// destination is a few yards off the nearest polygon — a strict
|
||||||
|
// `== PATHFIND_INCOMPLETE` check would reject the perfectly usable
|
||||||
|
// partial path and the chained probe would terminate empty on the
|
||||||
|
// very first call. PathGenerator's own internal code uses bitwise
|
||||||
|
// tests like `!(_type & PATHFIND_INCOMPLETE)`.
|
||||||
|
if (type & (PATHFIND_NORMAL | PATHFIND_INCOMPLETE))
|
||||||
return fromPointsArray(points);
|
return fromPointsArray(points);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user