Core/AreaTriggers: Handle exit areatrigger on player map change (#31077)

This commit is contained in:
ModoX
2025-09-03 21:45:38 +02:00
committed by GitHub
parent 32b293a457
commit 26fc144191
6 changed files with 97 additions and 40 deletions

View File

@@ -867,53 +867,65 @@ 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);
player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_AREA_TRIGGER_ENTER, GetEntry(), 1);
if (GetTemplate()->ActionSetId)
player->UpdateCriteria(CriteriaType::EnterAreaTriggerWithActionSet, GetTemplate()->ActionSetId);
}
DoActions(unit);
_ai->OnUnitEnter(unit);
}
HandleUnitEnter(unit);
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);
HandleUnitExitInternal(leavingUnit);
player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_AREA_TRIGGER_EXIT, GetEntry(), 1);
if (GetTemplate()->ActionSetId)
player->UpdateCriteria(CriteriaType::LeaveAreaTriggerWithActionSet, GetTemplate()->ActionSetId);
}
UndoActions(leavingUnit);
_ai->OnUnitExit(leavingUnit);
}
}
if (std::ranges::any_of(_insideUnits, [](ObjectGuid const& guid) { return guid.IsPlayer(); }))
SetAreaTriggerFlag(AreaTriggerFieldFlags::HasPlayers);
else
RemoveAreaTriggerFlag(AreaTriggerFieldFlags::HasPlayers);
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);
player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_AREA_TRIGGER_ENTER, GetEntry(), 1);
if (GetTemplate()->ActionSetId)
player->UpdateCriteria(CriteriaType::EnterAreaTriggerWithActionSet, GetTemplate()->ActionSetId);
}
DoActions(unit);
_ai->OnUnitEnter(unit);
unit->EnterAreaTrigger(this);
}
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);
player->UpdateQuestObjectiveProgress(QUEST_OBJECTIVE_AREA_TRIGGER_EXIT, GetEntry(), 1);
if (GetTemplate()->ActionSetId)
player->UpdateCriteria(CriteriaType::LeaveAreaTriggerWithActionSet, GetTemplate()->ActionSetId);
}
UndoActions(unit);
_ai->OnUnitExit(unit);
unit->ExitAreaTrigger(this);
}
void AreaTrigger::HandleUnitExit(Unit* unit)
{
_insideUnits.erase(unit->GetGUID());
HandleUnitExitInternal(unit);
UpdateHasPlayersFlag();
}
uint32 AreaTrigger::GetScriptId() const
{
if (_spawnId)
@@ -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())

View File

@@ -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;

View File

@@ -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);

View File

@@ -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();

View File

@@ -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;

View File

@@ -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)