fix(Core/Movement): guard empty taxi flight paths (#26468)

This commit is contained in:
Yehonal
2026-07-05 02:19:30 +02:00
committed by GitHub
parent 971a3f46f7
commit b79f7c3312
3 changed files with 51 additions and 24 deletions
+12 -1
View File
@@ -28,6 +28,7 @@
#include "Log.h"
#include "MoveSpline.h"
#include "MoveSplineInit.h"
#include "Player.h"
#include "PointMovementGenerator.h"
#include "RandomMovementGenerator.h"
#include "TargetedMovementGenerator.h"
@@ -837,7 +838,17 @@ void MotionMaster::MoveTaxiFlight(uint32 path, uint32 pathnode)
{
LOG_DEBUG("movement.motionmaster", "{} taxi to (Path {} node {})", _owner->GetName(), path, pathnode);
FlightPathMovementGenerator* mgen = new FlightPathMovementGenerator(pathnode);
mgen->LoadPath(_owner->ToPlayer());
Player* player = _owner->ToPlayer();
if (!mgen->LoadPath(player))
{
LOG_ERROR("movement.motionmaster", "{} failed to build taxi path (Path {} node {}), clearing taxi destinations",
_owner->GetName(), path, pathnode);
player->m_taxi.ClearTaxiDestinations();
player->Dismount();
delete mgen;
return;
}
Mutate(mgen, MOTION_SLOT_CONTROLLED);
}
else
@@ -568,45 +568,56 @@ bool IsNodeIncludedInShortenedPath(TaxiPathNodeEntry const* p1, TaxiPathNodeEntr
return p1->mapid != p2->mapid || std::pow(p1->x - p2->x, 2) + std::pow(p1->y - p2->y, 2) > SKIP_SPLINE_POINT_DISTANCE_SQ;
}
void FlightPathMovementGenerator::LoadPath(Player* player)
bool FlightPathMovementGenerator::LoadPath(Player* player)
{
i_path.clear();
_pointsForPathSwitch.clear();
auto fail = [&]()
{
i_path.clear();
_pointsForPathSwitch.clear();
return false;
};
std::deque<uint32> const& taxi = player->m_taxi.GetPath();
float discount = player->GetReputationPriceDiscount(player->m_taxi.GetFlightMasterFactionTemplate());
for (uint32 src = 0, dst = 1; dst < taxi.size(); src = dst++)
{
uint32 path, cost;
sObjectMgr->GetTaxiPath(taxi[src], taxi[dst], path, cost);
if (path > sTaxiPathNodesByPath.size())
{
return;
}
if (path >= sTaxiPathNodesByPath.size())
return fail();
TaxiPathNodeList const& nodes = sTaxiPathNodesByPath[path];
if (!nodes.empty())
if (nodes.empty())
return fail();
TaxiPathNodeEntry const* start = nodes[0];
TaxiPathNodeEntry const* end = nodes[nodes.size() - 1];
bool passedPreviousSegmentProximityCheck = false;
bool addedPathNode = false;
for (uint32 i = 0; i < nodes.size(); ++i)
{
TaxiPathNodeEntry const* start = nodes[0];
TaxiPathNodeEntry const* end = nodes[nodes.size() - 1];
bool passedPreviousSegmentProximityCheck = false;
for (uint32 i = 0; i < nodes.size(); ++i)
if (passedPreviousSegmentProximityCheck || !src || i_path.empty() || IsNodeIncludedInShortenedPath(i_path[i_path.size() - 1], nodes[i]))
{
if (passedPreviousSegmentProximityCheck || !src || i_path.empty() || IsNodeIncludedInShortenedPath(i_path[i_path.size() - 1], nodes[i]))
if ((!src || (IsNodeIncludedInShortenedPath(start, nodes[i]) && i >= 2)) &&
(dst == taxi.size() - 1 || (IsNodeIncludedInShortenedPath(end, nodes[i]) && i < nodes.size() - 1)))
{
if ((!src || (IsNodeIncludedInShortenedPath(start, nodes[i]) && i >= 2)) &&
(dst == taxi.size() - 1 || (IsNodeIncludedInShortenedPath(end, nodes[i]) && i < nodes.size() - 1)))
{
passedPreviousSegmentProximityCheck = true;
i_path.push_back(nodes[i]);
}
}
else
{
i_path.pop_back();
--_pointsForPathSwitch.back().PathIndex;
passedPreviousSegmentProximityCheck = true;
i_path.push_back(nodes[i]);
addedPathNode = true;
}
}
else
{
i_path.pop_back();
--_pointsForPathSwitch.back().PathIndex;
}
}
if (!addedPathNode || i_path.empty())
return fail();
_pointsForPathSwitch.push_back({ uint32(i_path.size() - 1), int32(ceil(cost * discount)) });
}
@@ -630,6 +641,11 @@ void FlightPathMovementGenerator::LoadPath(Player* player)
else
i_currentNode = 0;
}
if (i_path.empty())
return fail();
return true;
}
void FlightPathMovementGenerator::DoInitialize(Player* player)
@@ -108,7 +108,7 @@ class FlightPathMovementGenerator : public MovementGeneratorMedium< Player, Flig
_endMapId = 0;
_preloadTargetNode = 0;
}
void LoadPath(Player* player);
bool LoadPath(Player* player);
void DoInitialize(Player*);
void DoReset(Player*);
void DoFinalize(Player*);