diff options
author | Shauren <shauren.trinity@gmail.com> | 2022-01-12 15:09:36 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2022-01-12 15:09:36 +0100 |
commit | 6ca301e8637bc71ff6fb89180bda6a3a8f4db205 (patch) | |
tree | 1afdd51f308a3d55fcd6d8afd394cc3d52433ab9 /src/server/game/Phasing/PhasingHandler.cpp | |
parent | 6f8d6f5c9bc32bbe11de3377501453da1106f98a (diff) |
Core/Phasing: Fixed stack overflow happening when modifying vehicle passenger phases (looping player->vehicle->passenger(player)->vehicle...)
Closes #27599
Diffstat (limited to 'src/server/game/Phasing/PhasingHandler.cpp')
-rw-r--r-- | src/server/game/Phasing/PhasingHandler.cpp | 119 |
1 files changed, 82 insertions, 37 deletions
diff --git a/src/server/game/Phasing/PhasingHandler.cpp b/src/server/game/Phasing/PhasingHandler.cpp index 31a28010c71..50e7afe586f 100644 --- a/src/server/game/Phasing/PhasingHandler.cpp +++ b/src/server/game/Phasing/PhasingHandler.cpp @@ -30,6 +30,8 @@ #include "Player.h" #include "SpellAuraEffects.h" #include "Vehicle.h" +#include <boost/container/flat_set.hpp> +#include <boost/container/small_vector.hpp> #include <sstream> namespace @@ -49,33 +51,49 @@ inline PhaseFlags GetPhaseFlags(uint32 phaseId) return PhaseFlags::None; } +} -template<typename Func> -inline void ForAllControlled(Unit* unit, Func&& func) +class PhasingHandler::ControlledUnitVisitor { - for (Unit* controlled : unit->m_Controlled) - if (controlled->GetTypeId() != TYPEID_PLAYER - && !controlled->GetVehicle()) // Player inside nested vehicle should not phase the root vehicle and its accessories (only direct root vehicle control does) - func(controlled); +public: + explicit ControlledUnitVisitor(WorldObject* owner) + { + _visited.insert(owner); + } - for (ObjectGuid summonGuid : unit->m_SummonSlot) - if (!summonGuid.IsEmpty()) - if (Creature* summon = unit->GetMap()->GetCreature(summonGuid)) - func(summon); + template<typename Func> + inline void VisitControlledOf(Unit* unit, Func&& func) + { + for (Unit* controlled : unit->m_Controlled) + if (controlled->GetTypeId() != TYPEID_PLAYER + && !controlled->GetVehicle()) // Player inside nested vehicle should not phase the root vehicle and its accessories (only direct root vehicle control does) + if (_visited.insert(controlled).second) + func(controlled); + + for (ObjectGuid summonGuid : unit->m_SummonSlot) + if (!summonGuid.IsEmpty()) + if (Creature* summon = unit->GetMap()->GetCreature(summonGuid)) + if (_visited.insert(summon).second) + func(summon); + + if (Vehicle const* vehicle = unit->GetVehicleKit()) + for (auto seat = vehicle->Seats.begin(); seat != vehicle->Seats.end(); ++seat) + if (Unit* passenger = ObjectAccessor::GetUnit(*unit, seat->second.Passenger.Guid); passenger && passenger != unit) + if (_visited.insert(passenger).second) + func(passenger); + } - if (Vehicle const* vehicle = unit->GetVehicleKit()) - for (auto seat = vehicle->Seats.begin(); seat != vehicle->Seats.end(); ++seat) - if (Unit* passenger = ObjectAccessor::GetUnit(*unit, seat->second.Passenger.Guid)) - func(passenger); -} -} +private: + boost::container::flat_set<WorldObject*, std::less<WorldObject*>, boost::container::small_vector<WorldObject*, 8>> _visited; +}; void PhasingHandler::AddPhase(WorldObject* object, uint32 phaseId, bool updateVisibility) { - AddPhase(object, phaseId, object->GetGUID(), updateVisibility); + ControlledUnitVisitor visitor(object); + AddPhase(object, phaseId, object->GetGUID(), updateVisibility, visitor); } -void PhasingHandler::AddPhase(WorldObject* object, uint32 phaseId, ObjectGuid const& personalGuid, bool updateVisibility) +void PhasingHandler::AddPhase(WorldObject* object, uint32 phaseId, ObjectGuid const& personalGuid, bool updateVisibility, ControlledUnitVisitor& visitor) { bool changed = object->GetPhaseShift().AddPhase(phaseId, GetPhaseFlags(phaseId), nullptr); @@ -85,9 +103,9 @@ void PhasingHandler::AddPhase(WorldObject* object, uint32 phaseId, ObjectGuid co if (Unit* unit = object->ToUnit()) { unit->OnPhaseChange(); - ForAllControlled(unit, [&](Unit* controlled) + visitor.VisitControlledOf(unit, [&](Unit* controlled) { - AddPhase(controlled, phaseId, personalGuid, updateVisibility); + AddPhase(controlled, phaseId, personalGuid, updateVisibility, visitor); }); unit->RemoveNotOwnSingleTargetAuras(true); } @@ -97,14 +115,20 @@ void PhasingHandler::AddPhase(WorldObject* object, uint32 phaseId, ObjectGuid co void PhasingHandler::RemovePhase(WorldObject* object, uint32 phaseId, bool updateVisibility) { + ControlledUnitVisitor visitor(object); + RemovePhase(object, phaseId, updateVisibility, visitor); +} + +void PhasingHandler::RemovePhase(WorldObject* object, uint32 phaseId, bool updateVisibility, ControlledUnitVisitor& visitor) +{ bool changed = object->GetPhaseShift().RemovePhase(phaseId).Erased; if (Unit* unit = object->ToUnit()) { unit->OnPhaseChange(); - ForAllControlled(unit, [&](Unit* controlled) + visitor.VisitControlledOf(unit, [&](Unit* controlled) { - RemovePhase(controlled, phaseId, updateVisibility); + RemovePhase(controlled, phaseId, updateVisibility, visitor); }); unit->RemoveNotOwnSingleTargetAuras(true); } @@ -114,15 +138,16 @@ void PhasingHandler::RemovePhase(WorldObject* object, uint32 phaseId, bool updat void PhasingHandler::AddPhaseGroup(WorldObject* object, uint32 phaseGroupId, bool updateVisibility) { - AddPhaseGroup(object, phaseGroupId, object->GetGUID(), updateVisibility); -} - -void PhasingHandler::AddPhaseGroup(WorldObject* object, uint32 phaseGroupId, ObjectGuid const& personalGuid, bool updateVisibility) -{ std::vector<uint32> const* phasesInGroup = sDB2Manager.GetPhasesForGroup(phaseGroupId); if (!phasesInGroup) return; + ControlledUnitVisitor visitor(object); + AddPhaseGroup(object, phasesInGroup, object->GetGUID(), updateVisibility, visitor); +} + +void PhasingHandler::AddPhaseGroup(WorldObject* object, std::vector<uint32> const* phasesInGroup, ObjectGuid const& personalGuid, bool updateVisibility, ControlledUnitVisitor& visitor) +{ bool changed = false; for (uint32 phaseId : *phasesInGroup) changed = object->GetPhaseShift().AddPhase(phaseId, GetPhaseFlags(phaseId), nullptr) || changed; @@ -133,9 +158,9 @@ void PhasingHandler::AddPhaseGroup(WorldObject* object, uint32 phaseGroupId, Obj if (Unit* unit = object->ToUnit()) { unit->OnPhaseChange(); - ForAllControlled(unit, [&](Unit* controlled) + visitor.VisitControlledOf(unit, [&](Unit* controlled) { - AddPhaseGroup(controlled, phaseGroupId, personalGuid, updateVisibility); + AddPhaseGroup(controlled, phasesInGroup, personalGuid, updateVisibility, visitor); }); unit->RemoveNotOwnSingleTargetAuras(true); } @@ -149,6 +174,12 @@ void PhasingHandler::RemovePhaseGroup(WorldObject* object, uint32 phaseGroupId, if (!phasesInGroup) return; + ControlledUnitVisitor visitor(object); + RemovePhaseGroup(object, phasesInGroup, updateVisibility, visitor); +} + +void PhasingHandler::RemovePhaseGroup(WorldObject* object, std::vector<uint32> const* phasesInGroup, bool updateVisibility, ControlledUnitVisitor& visitor) +{ bool changed = false; for (uint32 phaseId : *phasesInGroup) changed = object->GetPhaseShift().RemovePhase(phaseId).Erased || changed; @@ -156,9 +187,9 @@ void PhasingHandler::RemovePhaseGroup(WorldObject* object, uint32 phaseGroupId, if (Unit* unit = object->ToUnit()) { unit->OnPhaseChange(); - ForAllControlled(unit, [&](Unit* controlled) + visitor.VisitControlledOf(unit, [&](Unit* controlled) { - RemovePhaseGroup(controlled, phaseGroupId, updateVisibility); + RemovePhaseGroup(controlled, phasesInGroup, updateVisibility, visitor); }); unit->RemoveNotOwnSingleTargetAuras(true); } @@ -168,6 +199,12 @@ void PhasingHandler::RemovePhaseGroup(WorldObject* object, uint32 phaseGroupId, void PhasingHandler::AddVisibleMapId(WorldObject* object, uint32 visibleMapId) { + ControlledUnitVisitor visitor(object); + AddVisibleMapId(object, visibleMapId, visitor); +} + +void PhasingHandler::AddVisibleMapId(WorldObject* object, uint32 visibleMapId, ControlledUnitVisitor& visitor) +{ TerrainSwapInfo const* terrainSwapInfo = sObjectMgr->GetTerrainSwapInfo(visibleMapId); bool changed = object->GetPhaseShift().AddVisibleMapId(visibleMapId, terrainSwapInfo); @@ -176,9 +213,9 @@ void PhasingHandler::AddVisibleMapId(WorldObject* object, uint32 visibleMapId) if (Unit* unit = object->ToUnit()) { - ForAllControlled(unit, [&](Unit* controlled) + visitor.VisitControlledOf(unit, [&](Unit* controlled) { - AddVisibleMapId(controlled, visibleMapId); + AddVisibleMapId(controlled, visibleMapId, visitor); }); } @@ -187,6 +224,12 @@ void PhasingHandler::AddVisibleMapId(WorldObject* object, uint32 visibleMapId) void PhasingHandler::RemoveVisibleMapId(WorldObject* object, uint32 visibleMapId) { + ControlledUnitVisitor visitor(object); + RemoveVisibleMapId(object, visibleMapId, visitor); +} + +void PhasingHandler::RemoveVisibleMapId(WorldObject* object, uint32 visibleMapId, ControlledUnitVisitor& visitor) +{ TerrainSwapInfo const* terrainSwapInfo = sObjectMgr->GetTerrainSwapInfo(visibleMapId); bool changed = object->GetPhaseShift().RemoveVisibleMapId(visibleMapId).Erased; @@ -195,9 +238,9 @@ void PhasingHandler::RemoveVisibleMapId(WorldObject* object, uint32 visibleMapId if (Unit* unit = object->ToUnit()) { - ForAllControlled(unit, [&](Unit* controlled) + visitor.VisitControlledOf(unit, [&](Unit* controlled) { - RemoveVisibleMapId(controlled, visibleMapId); + RemoveVisibleMapId(controlled, visibleMapId, visitor); }); } @@ -299,7 +342,8 @@ void PhasingHandler::OnAreaChange(WorldObject* object) if (changed) unit->OnPhaseChange(); - ForAllControlled(unit, [&](Unit* controlled) + ControlledUnitVisitor visitor(unit); + visitor.VisitControlledOf(unit, [&](Unit* controlled) { InheritPhaseShift(controlled, unit); }); @@ -418,7 +462,8 @@ void PhasingHandler::OnConditionChange(WorldObject* object) if (changed) unit->OnPhaseChange(); - ForAllControlled(unit, [&](Unit* controlled) + ControlledUnitVisitor visitor(unit); + visitor.VisitControlledOf(unit, [&](Unit* controlled) { InheritPhaseShift(controlled, unit); }); |