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 "Log.h"
#include "MoveSpline.h" #include "MoveSpline.h"
#include "MoveSplineInit.h" #include "MoveSplineInit.h"
#include "Player.h"
#include "PointMovementGenerator.h" #include "PointMovementGenerator.h"
#include "RandomMovementGenerator.h" #include "RandomMovementGenerator.h"
#include "TargetedMovementGenerator.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); LOG_DEBUG("movement.motionmaster", "{} taxi to (Path {} node {})", _owner->GetName(), path, pathnode);
FlightPathMovementGenerator* mgen = new FlightPathMovementGenerator(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); Mutate(mgen, MOTION_SLOT_CONTROLLED);
} }
else else
@@ -568,26 +568,34 @@ 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; 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(); _pointsForPathSwitch.clear();
auto fail = [&]()
{
i_path.clear();
_pointsForPathSwitch.clear();
return false;
};
std::deque<uint32> const& taxi = player->m_taxi.GetPath(); std::deque<uint32> const& taxi = player->m_taxi.GetPath();
float discount = player->GetReputationPriceDiscount(player->m_taxi.GetFlightMasterFactionTemplate()); float discount = player->GetReputationPriceDiscount(player->m_taxi.GetFlightMasterFactionTemplate());
for (uint32 src = 0, dst = 1; dst < taxi.size(); src = dst++) for (uint32 src = 0, dst = 1; dst < taxi.size(); src = dst++)
{ {
uint32 path, cost; uint32 path, cost;
sObjectMgr->GetTaxiPath(taxi[src], taxi[dst], path, cost); sObjectMgr->GetTaxiPath(taxi[src], taxi[dst], path, cost);
if (path > sTaxiPathNodesByPath.size()) if (path >= sTaxiPathNodesByPath.size())
{ return fail();
return;
}
TaxiPathNodeList const& nodes = sTaxiPathNodesByPath[path]; TaxiPathNodeList const& nodes = sTaxiPathNodesByPath[path];
if (!nodes.empty()) if (nodes.empty())
{ return fail();
TaxiPathNodeEntry const* start = nodes[0]; TaxiPathNodeEntry const* start = nodes[0];
TaxiPathNodeEntry const* end = nodes[nodes.size() - 1]; TaxiPathNodeEntry const* end = nodes[nodes.size() - 1];
bool passedPreviousSegmentProximityCheck = false; bool passedPreviousSegmentProximityCheck = false;
bool addedPathNode = false;
for (uint32 i = 0; i < nodes.size(); ++i) 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]))
@@ -597,6 +605,7 @@ void FlightPathMovementGenerator::LoadPath(Player* player)
{ {
passedPreviousSegmentProximityCheck = true; passedPreviousSegmentProximityCheck = true;
i_path.push_back(nodes[i]); i_path.push_back(nodes[i]);
addedPathNode = true;
} }
} }
else else
@@ -605,7 +614,9 @@ void FlightPathMovementGenerator::LoadPath(Player* player)
--_pointsForPathSwitch.back().PathIndex; --_pointsForPathSwitch.back().PathIndex;
} }
} }
}
if (!addedPathNode || i_path.empty())
return fail();
_pointsForPathSwitch.push_back({ uint32(i_path.size() - 1), int32(ceil(cost * discount)) }); _pointsForPathSwitch.push_back({ uint32(i_path.size() - 1), int32(ceil(cost * discount)) });
} }
@@ -630,6 +641,11 @@ void FlightPathMovementGenerator::LoadPath(Player* player)
else else
i_currentNode = 0; i_currentNode = 0;
} }
if (i_path.empty())
return fail();
return true;
} }
void FlightPathMovementGenerator::DoInitialize(Player* player) void FlightPathMovementGenerator::DoInitialize(Player* player)
@@ -108,7 +108,7 @@ class FlightPathMovementGenerator : public MovementGeneratorMedium< Player, Flig
_endMapId = 0; _endMapId = 0;
_preloadTargetNode = 0; _preloadTargetNode = 0;
} }
void LoadPath(Player* player); bool LoadPath(Player* player);
void DoInitialize(Player*); void DoInitialize(Player*);
void DoReset(Player*); void DoReset(Player*);
void DoFinalize(Player*); void DoFinalize(Player*);