diff options
author | ModoX <moardox@gmail.com> | 2025-09-03 21:45:38 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-09-03 21:45:38 +0200 |
commit | 26fc14419142e3188370035ce4144cdb125bec05 (patch) | |
tree | 2ca947a0ebbea98cdbd321de8d103efade4898d0 | |
parent | 32b293a4570ba0657a8217f3f737bf6a93b7b9de (diff) |
Core/AreaTriggers: Handle exit areatrigger on player map change (#31077)
-rw-r--r-- | src/server/game/Entities/AreaTrigger/AreaTrigger.cpp | 88 | ||||
-rw-r--r-- | src/server/game/Entities/AreaTrigger/AreaTrigger.h | 6 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 3 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.cpp | 18 | ||||
-rw-r--r-- | src/server/game/Entities/Unit/Unit.h | 7 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.cpp | 3 |
6 files changed, 91 insertions, 34 deletions
diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp index b58668e7836..f4a556df130 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp +++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.cpp @@ -867,51 +867,63 @@ void AreaTrigger::HandleUnitEnterExit(std::vector<Unit*> const& newTargetList) // Handle after _insideUnits have been reinserted so we can use GetInsideUnits() in hooks for (Unit* unit : enteringUnits) - { - if (Player* player = unit->ToPlayer()) - { - if (player->isDebugAreaTriggers) - ChatHandler(player->GetSession()).PSendSysMessage(LANG_DEBUG_AREATRIGGER_ENTITY_ENTERED, GetEntry(), IsCustom(), IsStaticSpawn(), _spawnId); + HandleUnitEnter(unit); - player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_AREA_TRIGGER_ENTER, GetEntry(), 1); + for (ObjectGuid const& exitUnitGuid : exitUnits) + if (Unit* leavingUnit = ObjectAccessor::GetUnit(*this, exitUnitGuid)) + HandleUnitExitInternal(leavingUnit); - if (GetTemplate()->ActionSetId) - player->UpdateCriteria(CriteriaType::EnterAreaTriggerWithActionSet, GetTemplate()->ActionSetId); - } + UpdateHasPlayersFlag(); + + if (IsStaticSpawn()) + setActive(!_insideUnits.empty()); +} + +void AreaTrigger::HandleUnitEnter(Unit* unit) +{ + if (Player* player = unit->ToPlayer()) + { + if (player->isDebugAreaTriggers) + ChatHandler(player->GetSession()).PSendSysMessage(LANG_DEBUG_AREATRIGGER_ENTITY_ENTERED, GetEntry(), IsCustom(), IsStaticSpawn(), _spawnId); - DoActions(unit); + player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_AREA_TRIGGER_ENTER, GetEntry(), 1); - _ai->OnUnitEnter(unit); + if (GetTemplate()->ActionSetId) + player->UpdateCriteria(CriteriaType::EnterAreaTriggerWithActionSet, GetTemplate()->ActionSetId); } - for (ObjectGuid const& exitUnitGuid : exitUnits) - { - if (Unit* leavingUnit = ObjectAccessor::GetUnit(*this, exitUnitGuid)) - { - if (Player* player = leavingUnit->ToPlayer()) - { - if (player->isDebugAreaTriggers) - ChatHandler(player->GetSession()).PSendSysMessage(LANG_DEBUG_AREATRIGGER_ENTITY_LEFT, GetEntry(), IsCustom(), IsStaticSpawn(), _spawnId); + DoActions(unit); - player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_AREA_TRIGGER_EXIT, GetEntry(), 1); + _ai->OnUnitEnter(unit); + unit->EnterAreaTrigger(this); +} - if (GetTemplate()->ActionSetId) - player->UpdateCriteria(CriteriaType::LeaveAreaTriggerWithActionSet, GetTemplate()->ActionSetId); - } +void AreaTrigger::HandleUnitExitInternal(Unit* unit) +{ + if (Player* player = unit->ToPlayer()) + { + if (player->isDebugAreaTriggers) + ChatHandler(player->GetSession()).PSendSysMessage(LANG_DEBUG_AREATRIGGER_ENTITY_LEFT, GetEntry(), IsCustom(), IsStaticSpawn(), _spawnId); - UndoActions(leavingUnit); + player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_AREA_TRIGGER_EXIT, GetEntry(), 1); - _ai->OnUnitExit(leavingUnit); - } + if (GetTemplate()->ActionSetId) + player->UpdateCriteria(CriteriaType::LeaveAreaTriggerWithActionSet, GetTemplate()->ActionSetId); } - if (std::ranges::any_of(_insideUnits, [](ObjectGuid const& guid) { return guid.IsPlayer(); })) - SetAreaTriggerFlag(AreaTriggerFieldFlags::HasPlayers); - else - RemoveAreaTriggerFlag(AreaTriggerFieldFlags::HasPlayers); + UndoActions(unit); - if (IsStaticSpawn()) - setActive(!_insideUnits.empty()); + _ai->OnUnitExit(unit); + unit->ExitAreaTrigger(this); +} + +void AreaTrigger::HandleUnitExit(Unit* unit) +{ + _insideUnits.erase(unit->GetGUID()); + + HandleUnitExitInternal(unit); + + UpdateHasPlayersFlag(); } uint32 AreaTrigger::GetScriptId() const @@ -1177,7 +1189,7 @@ void AreaTrigger::UndoActions(Unit* unit) case AREATRIGGER_ACTION_CAST: [[fallthrough]]; case AREATRIGGER_ACTION_ADDAURA: - unit->RemoveAurasDueToSpell(action.Param, GetCasterGuid()); + unit->RemoveAurasDueToSpell(action.Param, GetCasterGuid()); break; case AREATRIGGER_ACTION_TAVERN: if (Player* player = unit->ToPlayer()) @@ -1185,7 +1197,7 @@ void AreaTrigger::UndoActions(Unit* unit) break; default: break; - } +} } } } @@ -1442,6 +1454,14 @@ void AreaTrigger::UpdateOverridePosition() GetMap()->AreaTriggerRelocation(this, x, y, z, orientation); } +void AreaTrigger::UpdateHasPlayersFlag() +{ + if (std::ranges::any_of(_insideUnits, [](ObjectGuid const& guid) { return guid.IsPlayer(); })) + SetAreaTriggerFlag(AreaTriggerFieldFlags::HasPlayers); + else + RemoveAreaTriggerFlag(AreaTriggerFieldFlags::HasPlayers); +} + void AreaTrigger::DebugVisualizePosition() { if (Unit* caster = GetCaster()) diff --git a/src/server/game/Entities/AreaTrigger/AreaTrigger.h b/src/server/game/Entities/AreaTrigger/AreaTrigger.h index 6d10f853063..24312586042 100644 --- a/src/server/game/Entities/AreaTrigger/AreaTrigger.h +++ b/src/server/game/Entities/AreaTrigger/AreaTrigger.h @@ -193,6 +193,8 @@ class TC_GAME_API AreaTrigger final : public WorldObject, public GridObject<Area void UpdateShape(); + void HandleUnitExit(Unit* unit); + UF::UpdateField<UF::AreaTriggerData, int32(WowCS::EntityFragment::CGObject), TYPEID_AREATRIGGER> m_areaTriggerData; protected: @@ -219,6 +221,8 @@ class TC_GAME_API AreaTrigger final : public WorldObject, public GridObject<Area void SearchUnitInDisk(UF::AreaTriggerDisk const& disk, std::vector<Unit*>& targetList); void SearchUnitInBoundedPlane(UF::AreaTriggerBoundedPlane const& boundedPlane, std::vector<Unit*>& targetList); void HandleUnitEnterExit(std::vector<Unit*> const& targetList); + void HandleUnitEnter(Unit* unit); + void HandleUnitExitInternal(Unit* unit); void DoActions(Unit* unit); void UndoActions(Unit* unit); @@ -231,6 +235,8 @@ class TC_GAME_API AreaTrigger final : public WorldObject, public GridObject<Area Position const* GetOrbitCenterPosition() const; Position CalculateOrbitPosition() const; + void UpdateHasPlayersFlag(); + void DebugVisualizePosition(); // Debug purpose only ObjectGuid::LowType _spawnId; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 6bd0b7c320b..4d828fbebc8 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -21839,6 +21839,9 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent) pet->CombatStop(); + // exit areatriggers before saving to remove auras applied by them + pet->ExitAllAreaTriggers(); + // only if current pet in slot pet->SavePetToDB(mode); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index fe31ff4b40b..9925f04084b 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -5499,6 +5499,23 @@ void Unit::RemoveAllAreaTriggers(AreaTriggerRemoveReason reason /*= AreaTriggerR } } +void Unit::EnterAreaTrigger(AreaTrigger* areaTrigger) +{ + m_insideAreaTriggers.push_back(areaTrigger); +} + +void Unit::ExitAreaTrigger(AreaTrigger* areaTrigger) +{ + std::erase(m_insideAreaTriggers, areaTrigger); +} + +void Unit::ExitAllAreaTriggers() +{ + AreaTriggerList atList = std::move(m_insideAreaTriggers); + for (AreaTrigger* at : atList) + at->HandleUnitExit(this); +} + void Unit::SendSpellNonMeleeDamageLog(SpellNonMeleeDamage const* log) { WorldPackets::CombatLog::SpellNonMeleeDamageLog packet; @@ -10083,6 +10100,7 @@ void Unit::RemoveFromWorld() RemoveAllGameObjects(); RemoveAllDynObjects(); RemoveAllAreaTriggers(AreaTriggerRemoveReason::UnitDespawn); + ExitAllAreaTriggers(); // exit all areatriggers the unit is in ExitVehicle(); // Remove applied auras with SPELL_AURA_CONTROL_VEHICLE UnsummonAllTotems(); diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index ab91bf1f62b..8d5502ff16b 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1639,6 +1639,12 @@ class TC_GAME_API Unit : public WorldObject void RemoveAreaTrigger(AuraEffect const* aurEff); void RemoveAllAreaTriggers(AreaTriggerRemoveReason reason = AreaTriggerRemoveReason::Default); + void EnterAreaTrigger(AreaTrigger* areaTrigger); + void ExitAreaTrigger(AreaTrigger* areaTrigger); + + std::vector<AreaTrigger*> const& GetInsideAreaTriggers() const { return m_insideAreaTriggers; } + void ExitAllAreaTriggers(); + void ModifyAuraState(AuraStateType flag, bool apply); uint32 BuildAuraStateUpdateForTarget(Unit const* target) const; bool HasAuraState(AuraStateType flag, SpellInfo const* spellProto = nullptr, Unit const* Caster = nullptr) const; @@ -1896,6 +1902,7 @@ class TC_GAME_API Unit : public WorldObject typedef std::vector<AreaTrigger*> AreaTriggerList; AreaTriggerList m_areaTrigger; + AreaTriggerList m_insideAreaTriggers; uint32 m_transformSpell; diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index b62697bce23..e0daa6751d5 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -632,6 +632,9 @@ void WorldSession::LogoutPlayer(bool save) _player->FailQuestsWithFlag(QUEST_FLAGS_FAIL_ON_LOGOUT); + // exit areatriggers before saving to remove auras applied by them + _player->ExitAllAreaTriggers(); + ///- empty buyback items and save the player in the database // some save parts only correctly work in case player present in map/player_lists (pets, etc) if (save) |