diff --git a/src/common/Dynamic/TypeContainerVisitor.h b/src/common/Dynamic/TypeContainerVisitor.h index cab848b4b..f593f3b5d 100644 --- a/src/common/Dynamic/TypeContainerVisitor.h +++ b/src/common/Dynamic/TypeContainerVisitor.h @@ -74,17 +74,17 @@ void VisitorHelper(VISITOR& v, ContainerUnorderedMap, KEY_TYPE>& VisitorHelper(v, c._TailElements); } -template +template void VisitorHelper(VISITOR& v, TypeUnorderedMapContainer& c) { VisitorHelper(v, c.GetElements()); } -template +template class TypeContainerVisitor { public: - TypeContainerVisitor(VISITOR& v) : i_visitor(v) { } + TypeContainerVisitor(VISITOR& v) : i_visitor(v) {} void Visit(TYPE_CONTAINER& c) { diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 3945a0eae..a2a4ff585 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -640,6 +640,11 @@ ConditionMgr::~ConditionMgr() Clean(); } +bool ConditionMgr::IsSpellUsedInSpellClickConditions(uint32 spellId) const +{ + return SpellsUsedInSpellClickConditions.find(spellId) != SpellsUsedInSpellClickConditions.end(); +} + ConditionMgr* ConditionMgr::instance() { static ConditionMgr instance; @@ -694,7 +699,7 @@ uint32 ConditionMgr::GetSearcherTypeMaskForConditionList(ConditionList const& co return mask; } -bool ConditionMgr::IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, ConditionList const& conditions) +bool ConditionMgr::IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, ConditionList const& conditions) const { // groupId, groupCheckPassed std::map ElseGroupStore; @@ -738,19 +743,19 @@ bool ConditionMgr::IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, return false; } -bool ConditionMgr::IsObjectMeetToConditions(WorldObject* object, ConditionList const& conditions) +bool ConditionMgr::IsObjectMeetToConditions(WorldObject* object, ConditionList const& conditions) const { ConditionSourceInfo srcInfo = ConditionSourceInfo(object); return IsObjectMeetToConditions(srcInfo, conditions); } -bool ConditionMgr::IsObjectMeetToConditions(WorldObject* object1, WorldObject* object2, ConditionList const& conditions) +bool ConditionMgr::IsObjectMeetToConditions(WorldObject* object1, WorldObject* object2, ConditionList const& conditions) const { ConditionSourceInfo srcInfo = ConditionSourceInfo(object1, object2); return IsObjectMeetToConditions(srcInfo, conditions); } -bool ConditionMgr::IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, ConditionList const& conditions) +bool ConditionMgr::IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, ConditionList const& conditions) const { if (conditions.empty()) return true; @@ -1055,6 +1060,10 @@ void ConditionMgr::LoadConditions(bool isReload) case CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT: { SpellClickEventConditionStore[cond->SourceGroup][cond->SourceEntry].push_back(cond); + if (cond->ConditionType == CONDITION_AURA) + { + SpellsUsedInSpellClickConditions.insert(cond->ConditionValue1); + } valid = true; ++count; continue; // do not add to m_AllocatedMemory to avoid double deleting @@ -1123,6 +1132,10 @@ void ConditionMgr::LoadConditions(bool isReload) } // add new Condition to storage based on Type/Entry + if (cond->SourceType == CONDITION_SOURCE_TYPE_SPELL_CLICK_EVENT && cond->ConditionType == CONDITION_AURA) + { + SpellsUsedInSpellClickConditions.insert(cond->ConditionValue1); + } ConditionStore[cond->SourceType][cond->SourceEntry].push_back(cond); ++count; } while (result->NextRow()); @@ -2314,7 +2327,7 @@ void ConditionMgr::Clean() itr->second.clear(); } - SpellClickEventConditionStore.clear(); + SpellsUsedInSpellClickConditions.clear(); for (NpcVendorConditionContainer::iterator itr = NpcVendorConditionContainerStore.begin(); itr != NpcVendorConditionContainerStore.end(); ++itr) { diff --git a/src/server/game/Conditions/ConditionMgr.h b/src/server/game/Conditions/ConditionMgr.h index d3989dfeb..ce68f0b33 100644 --- a/src/server/game/Conditions/ConditionMgr.h +++ b/src/server/game/Conditions/ConditionMgr.h @@ -22,7 +22,10 @@ #include "Errors.h" #include #include +#include +#include +class Creature; class Player; class Unit; class WorldObject; @@ -254,9 +257,9 @@ public: ConditionList GetConditionReferences(uint32 refId); uint32 GetSearcherTypeMaskForConditionList(ConditionList const& conditions); - bool IsObjectMeetToConditions(WorldObject* object, ConditionList const& conditions); - bool IsObjectMeetToConditions(WorldObject* object1, WorldObject* object2, ConditionList const& conditions); - bool IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, ConditionList const& conditions); + bool IsObjectMeetToConditions(WorldObject* object, ConditionList const& conditions) const; + bool IsObjectMeetToConditions(WorldObject* object1, WorldObject* object2, ConditionList const& conditions) const; + bool IsObjectMeetToConditions(ConditionSourceInfo& sourceInfo, ConditionList const& conditions) const; [[nodiscard]] bool CanHaveSourceGroupSet(ConditionSourceType sourceType) const; [[nodiscard]] bool CanHaveSourceIdSet(ConditionSourceType sourceType) const; ConditionList GetConditionsForNotGroupedEntry(ConditionSourceType sourceType, uint32 entry); @@ -264,6 +267,7 @@ public: ConditionList GetConditionsForSmartEvent(int32 entryOrGuid, uint32 eventId, uint32 sourceType); ConditionList GetConditionsForVehicleSpell(uint32 creatureId, uint32 spellId); ConditionList GetConditionsForNpcVendorEvent(uint32 creatureId, uint32 itemId); + bool IsSpellUsedInSpellClickConditions(uint32 spellId) const; private: bool isSourceTypeValid(Condition* cond); @@ -271,7 +275,7 @@ private: bool addToGossipMenus(Condition* cond); bool addToGossipMenuItems(Condition* cond); bool addToSpellImplicitTargetConditions(Condition* cond); - bool IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, ConditionList const& conditions); + bool IsObjectMeetToConditionList(ConditionSourceInfo& sourceInfo, ConditionList const& conditions) const; void Clean(); // free up resources std::list AllocatedMemoryStore; // some garbage collection :) @@ -282,6 +286,8 @@ private: CreatureSpellConditionContainer SpellClickEventConditionStore; NpcVendorConditionContainer NpcVendorConditionContainerStore; SmartEventConditionContainer SmartEventConditionStore; + + std::unordered_set SpellsUsedInSpellClickConditions; }; #define sConditionMgr ConditionMgr::instance() diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 34c5faa1a..34000cee0 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1473,7 +1473,7 @@ public: [[nodiscard]] bool HasQuestForItem(uint32 itemId, uint32 excludeQuestId = 0, bool turnIn = false, bool* showInLoot = nullptr) const; [[nodiscard]] bool HasQuestForGO(int32 GOId) const; [[nodiscard]] bool HasQuest(uint32 questId) const; - void UpdateForQuestWorldObjects(); + void UpdateVisibleGameobjectsOrSpellClicks(); [[nodiscard]] bool CanShareQuest(uint32 quest_id) const; void SendQuestComplete(uint32 quest_id); diff --git a/src/server/game/Entities/Player/PlayerQuest.cpp b/src/server/game/Entities/Player/PlayerQuest.cpp index 2c5ccff18..b1271c008 100644 --- a/src/server/game/Entities/Player/PlayerQuest.cpp +++ b/src/server/game/Entities/Player/PlayerQuest.cpp @@ -1548,7 +1548,7 @@ void Player::SendQuestUpdate(uint32 questId) RemoveAurasDueToSpell(oldSpellId); } - UpdateForQuestWorldObjects(); + UpdateVisibleGameobjectsOrSpellClicks(); } QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver) @@ -1809,7 +1809,7 @@ void Player::ItemAddedQuestCheck(uint32 entry, uint32 count) } } } - UpdateForQuestWorldObjects(); + UpdateVisibleGameobjectsOrSpellClicks(); } void Player::ItemRemovedQuestCheck(uint32 entry, uint32 count) @@ -1850,7 +1850,7 @@ void Player::ItemRemovedQuestCheck(uint32 entry, uint32 count) } } } - UpdateForQuestWorldObjects(); + UpdateVisibleGameobjectsOrSpellClicks(); } void Player::KilledMonster(CreatureTemplate const* cInfo, ObjectGuid guid) diff --git a/src/server/game/Entities/Player/PlayerStorage.cpp b/src/server/game/Entities/Player/PlayerStorage.cpp index 43517b3f8..0a9cb59e5 100644 --- a/src/server/game/Entities/Player/PlayerStorage.cpp +++ b/src/server/game/Entities/Player/PlayerStorage.cpp @@ -2848,7 +2848,7 @@ Item* Player::EquipItem(uint16 pos, Item* pItem, bool update) UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM, pItem->GetEntry(), slot); sScriptMgr->OnEquip(this, pItem, bag, slot, update); - UpdateForQuestWorldObjects(); + UpdateVisibleGameobjectsOrSpellClicks(); return pItem; } diff --git a/src/server/game/Entities/Player/PlayerUpdates.cpp b/src/server/game/Entities/Player/PlayerUpdates.cpp index ae2a0f8ce..f33854f9a 100644 --- a/src/server/game/Entities/Player/PlayerUpdates.cpp +++ b/src/server/game/Entities/Player/PlayerUpdates.cpp @@ -1820,7 +1820,7 @@ void Player::UpdateTriggerVisibility() GetSession()->SendPacket(&packet); } -void Player::UpdateForQuestWorldObjects() +void Player::UpdateVisibleGameobjectsOrSpellClicks() { if (m_clientGUIDs.empty()) return; @@ -1847,19 +1847,9 @@ void Player::UpdateForQuestWorldObjects() SpellClickInfoMapBounds clickPair = sObjectMgr->GetSpellClickInfoMapBounds(obj->GetEntry()); for (SpellClickInfoContainer::const_iterator _itr = clickPair.first; _itr != clickPair.second; ++_itr) { - //! This code doesn't look right, but it was logically converted to condition system to do the exact - //! same thing it did before. It definitely needs to be overlooked for intended functionality. ConditionList conds = sConditionMgr->GetConditionsForSpellClickEvent(obj->GetEntry(), _itr->second.spellId); - bool buildUpdateBlock = false; - for (ConditionList::const_iterator jtr = conds.begin(); jtr != conds.end() && !buildUpdateBlock; ++jtr) - if ((*jtr)->ConditionType == CONDITION_QUESTREWARDED || (*jtr)->ConditionType == CONDITION_QUESTTAKEN) - buildUpdateBlock = true; - - if (buildUpdateBlock) - { - obj->BuildValuesUpdateBlockForPlayer(&udata, this); - break; - } + obj->BuildValuesUpdateBlockForPlayer(&udata, this); + break; } } } diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index bc189f346..0249cbb6c 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -4072,6 +4072,14 @@ void Unit::_ApplyAura(AuraApplication* aurApp, uint8 effMask) if (effMask & 1 << i && (!aurApp->GetRemoveMode())) aurApp->_HandleEffect(i, true); } + + if (Player* player = ToPlayer()) + { + if (sConditionMgr->IsSpellUsedInSpellClickConditions(aurApp->GetBase()->GetId())) + { + player->UpdateVisibleGameobjectsOrSpellClicks(); + } + } } // removes aura application from lists and unapplies effects @@ -4150,6 +4158,14 @@ void Unit::_UnapplyAura(AuraApplicationMap::iterator& i, AuraRemoveMode removeMo aura->HandleAuraSpecificMods(aurApp, caster, false, false); + if (Player* player = ToPlayer()) + { + if (sConditionMgr->IsSpellUsedInSpellClickConditions(aurApp->GetBase()->GetId())) + { + player->UpdateVisibleGameobjectsOrSpellClicks(); + } + } + // only way correctly remove all auras from list //if (removedAuras != m_removedAurasCount) new aura may be added i = m_appliedAuras.begin(); diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index 540d49112..2b5ac506a 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -165,6 +165,29 @@ namespace Acore // WorldObject searchers & workers + // Generic base class to insert elements into arbitrary containers using push_back + template class ContainerInserter + { + using InserterType = void (*)(void*, Type&&); + + void* ref; + InserterType inserter; + + // MSVC workaround + template static void InserterOf(void* ref, Type&& type) + { + static_cast(ref)->push_back(std::move(type)); + } + + protected: + template ContainerInserter(T& ref_) : ref(&ref_), inserter(&InserterOf) {} + + void Insert(Type type) + { + inserter(ref, std::move(type)); + } + }; + template struct WorldObjectSearcher { @@ -206,15 +229,15 @@ namespace Acore }; template - struct WorldObjectListSearcher + struct WorldObjectListSearcher : ContainerInserter { uint32 i_mapTypeMask; uint32 i_phaseMask; - std::list& i_objects; Check& i_check; - WorldObjectListSearcher(WorldObject const* searcher, std::list& objects, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL) - : i_mapTypeMask(mapTypeMask), i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {} + template WorldObjectListSearcher(WorldObject const* searcher, Container& container, Check& check, uint32 mapTypeMask = GRID_MAP_TYPE_MASK_ALL) + : ContainerInserter(container), + i_mapTypeMask(mapTypeMask), i_phaseMask(searcher->GetPhaseMask()), i_check(check) {} void Visit(PlayerMapType& m); void Visit(CreatureMapType& m); @@ -316,14 +339,14 @@ namespace Acore }; template - struct GameObjectListSearcher + struct GameObjectListSearcher : ContainerInserter { uint32 i_phaseMask; - std::list& i_objects; Check& i_check; - GameObjectListSearcher(WorldObject const* searcher, std::list& objects, Check& check) - : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {} + template GameObjectListSearcher(WorldObject const* searcher, Container& container, Check& check) + : ContainerInserter(container), + i_phaseMask(searcher->GetPhaseMask()), i_check(check) {} void Visit(GameObjectMapType& m); @@ -388,14 +411,14 @@ namespace Acore // All accepted by Check units if any template - struct UnitListSearcher + struct UnitListSearcher : ContainerInserter { uint32 i_phaseMask; - std::list& i_objects; Check& i_check; - UnitListSearcher(WorldObject const* searcher, std::list& objects, Check& check) - : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {} + template UnitListSearcher(WorldObject const* searcher, Container& container, Check& check) + : ContainerInserter(container), + i_phaseMask(searcher->GetPhaseMask()), i_check(check) {} void Visit(PlayerMapType& m); void Visit(CreatureMapType& m); @@ -437,14 +460,14 @@ namespace Acore }; template - struct CreatureListSearcher + struct CreatureListSearcher : ContainerInserter { uint32 i_phaseMask; - std::list& i_objects; Check& i_check; - CreatureListSearcher(WorldObject const* searcher, std::list& objects, Check& check) - : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {} + template CreatureListSearcher(WorldObject const* searcher, Container& container, Check& check) + : ContainerInserter(container), + i_phaseMask(searcher->GetPhaseMask()), i_check(check) {} void Visit(CreatureMapType& m); @@ -488,14 +511,14 @@ namespace Acore }; template - struct PlayerListSearcher + struct PlayerListSearcher : ContainerInserter { uint32 i_phaseMask; - std::list& i_objects; Check& i_check; - PlayerListSearcher(WorldObject const* searcher, std::list& objects, Check& check) - : i_phaseMask(searcher->GetPhaseMask()), i_objects(objects), i_check(check) {} + template PlayerListSearcher(WorldObject const* searcher, Container& container, Check& check) + : ContainerInserter(container), + i_phaseMask(searcher->GetPhaseMask()), i_check(check) {} void Visit(PlayerMapType& m); @@ -803,20 +826,23 @@ namespace Acore { public: AnyUnfriendlyUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) : i_obj(obj), i_funit(funit), i_range(range) {} - bool operator()(Unit* u) + + bool operator()(Unit* u) const { if (u->IsAlive() && i_obj->IsWithinDistInMap(u, i_range) && !i_funit->IsFriendlyTo(u) && - (i_funit->GetTypeId() != TYPEID_UNIT || !i_funit->ToCreature()->IsAvoidingAOE())) // pussywizard + (i_funit->GetTypeId() != TYPEID_UNIT || !i_funit->ToCreature()->IsAvoidingAOE())) // pussywizard) + { return true; - else - return false; + } + + return false; } + private: WorldObject const* i_obj; Unit const* i_funit; float i_range; }; - class AnyUnfriendlyNoTotemUnitInObjectRangeCheck { public: @@ -903,9 +929,19 @@ namespace Acore class AnyGroupedUnitInObjectRangeCheck { public: - AnyGroupedUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, bool raid) : _source(obj), _refUnit(funit), _range(range), _raid(raid) {} + AnyGroupedUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, bool raid, bool playerOnly = false) : _source(obj), _refUnit(funit), _range(range), _raid(raid), _playerOnly(playerOnly) {} bool operator()(Unit* u) { + if (G3D::fuzzyEq(_range, 0.0f)) + { + return false; + } + + if (_playerOnly && u->GetTypeId() != TYPEID_PLAYER) + { + return false; + } + if (_raid) { if (!_refUnit->IsInRaidWith(u)) @@ -922,6 +958,7 @@ namespace Acore Unit const* _refUnit; float _range; bool _raid; + bool _playerOnly; }; class AnyUnitInObjectRangeCheck @@ -968,27 +1005,35 @@ namespace Acore class AnyAoETargetUnitInObjectRangeCheck { public: - AnyAoETargetUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range) - : i_obj(obj), i_funit(funit), _spellInfo(nullptr), i_range(range) + AnyAoETargetUnitInObjectRangeCheck(WorldObject const* obj, Unit const* funit, float range, SpellInfo const* spellInfo = nullptr) + : i_obj(obj), i_funit(funit), _spellInfo(spellInfo), i_range(range) { Unit const* check = i_funit; Unit const* owner = i_funit->GetOwner(); if (owner) check = owner; i_targetForPlayer = (check->GetTypeId() == TYPEID_PLAYER); - if (i_obj->GetTypeId() == TYPEID_DYNAMICOBJECT) - _spellInfo = sSpellMgr->GetSpellInfo(((DynamicObject*)i_obj)->GetSpellId()); + + if (!_spellInfo) + { + if (DynamicObject const* dynObj = i_obj->ToDynObject()) + { + _spellInfo = sSpellMgr->GetSpellInfo(dynObj->GetSpellId()); + } + } } bool operator()(Unit* u) { // Check contains checks for: live, non-selectable, non-attackable flags, flight check and GM check, ignore totems - if (u->GetTypeId() == TYPEID_UNIT && ((Creature*)u)->IsTotem()) + if (u->GetTypeId() == TYPEID_UNIT && ((Creature*) u)->IsTotem()) + { return false; - - if (i_funit->_IsValidAttackTarget(u, _spellInfo, i_obj->GetTypeId() == TYPEID_DYNAMICOBJECT ? i_obj : nullptr) && i_obj->IsWithinDistInMap(u, i_range)) - return true; - - return false; + } + if (_spellInfo && _spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER) && u->GetTypeId() != TYPEID_PLAYER) + { + return false; + } + return i_funit->_IsValidAttackTarget(u, _spellInfo, i_obj->GetTypeId() == TYPEID_DYNAMICOBJECT ? i_obj : nullptr) && i_obj->IsWithinDistInMap(u, i_range); } private: bool i_targetForPlayer; diff --git a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h index 4cb57cfdf..3cd1b77dc 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiersImpl.h +++ b/src/server/game/Grids/Notifiers/GridNotifiersImpl.h @@ -253,7 +253,7 @@ void Acore::WorldObjectListSearcher::Visit(PlayerMapType& m) for (PlayerMapType::iterator itr = m.begin(); itr != m.end(); ++itr) if (i_check(itr->GetSource())) - i_objects.push_back(itr->GetSource()); + Insert(itr->GetSource()); } template @@ -264,7 +264,7 @@ void Acore::WorldObjectListSearcher::Visit(CreatureMapType& m) for (CreatureMapType::iterator itr = m.begin(); itr != m.end(); ++itr) if (i_check(itr->GetSource())) - i_objects.push_back(itr->GetSource()); + Insert(itr->GetSource()); } template @@ -275,7 +275,7 @@ void Acore::WorldObjectListSearcher::Visit(CorpseMapType& m) for (CorpseMapType::iterator itr = m.begin(); itr != m.end(); ++itr) if (i_check(itr->GetSource())) - i_objects.push_back(itr->GetSource()); + Insert(itr->GetSource()); } template @@ -286,7 +286,7 @@ void Acore::WorldObjectListSearcher::Visit(GameObjectMapType& m) for (GameObjectMapType::iterator itr = m.begin(); itr != m.end(); ++itr) if (i_check(itr->GetSource())) - i_objects.push_back(itr->GetSource()); + Insert(itr->GetSource()); } template @@ -297,7 +297,7 @@ void Acore::WorldObjectListSearcher::Visit(DynamicObjectMapType& m) for (DynamicObjectMapType::iterator itr = m.begin(); itr != m.end(); ++itr) if (i_check(itr->GetSource())) - i_objects.push_back(itr->GetSource()); + Insert(itr->GetSource()); } // Gameobject searchers @@ -341,7 +341,7 @@ void Acore::GameObjectListSearcher::Visit(GameObjectMapType& m) for (GameObjectMapType::iterator itr = m.begin(); itr != m.end(); ++itr) if (itr->GetSource()->InSamePhase(i_phaseMask)) if (i_check(itr->GetSource())) - i_objects.push_back(itr->GetSource()); + Insert(itr->GetSource()); } // Unit searchers @@ -418,7 +418,7 @@ void Acore::UnitListSearcher::Visit(PlayerMapType& m) for (PlayerMapType::iterator itr = m.begin(); itr != m.end(); ++itr) if (itr->GetSource()->InSamePhase(i_phaseMask)) if (i_check(itr->GetSource())) - i_objects.push_back(itr->GetSource()); + Insert(itr->GetSource()); } template @@ -427,7 +427,7 @@ void Acore::UnitListSearcher::Visit(CreatureMapType& m) for (CreatureMapType::iterator itr = m.begin(); itr != m.end(); ++itr) if (itr->GetSource()->InSamePhase(i_phaseMask)) if (i_check(itr->GetSource())) - i_objects.push_back(itr->GetSource()); + Insert(itr->GetSource()); } // Creature searchers @@ -471,7 +471,7 @@ void Acore::CreatureListSearcher::Visit(CreatureMapType& m) for (CreatureMapType::iterator itr = m.begin(); itr != m.end(); ++itr) if (itr->GetSource()->InSamePhase(i_phaseMask)) if (i_check(itr->GetSource())) - i_objects.push_back(itr->GetSource()); + Insert(itr->GetSource()); } template @@ -480,7 +480,7 @@ void Acore::PlayerListSearcher::Visit(PlayerMapType& m) for (PlayerMapType::iterator itr = m.begin(); itr != m.end(); ++itr) if (itr->GetSource()->InSamePhase(i_phaseMask)) if (i_check(itr->GetSource())) - i_objects.push_back(itr->GetSource()); + Insert(itr->GetSource()); } template diff --git a/src/server/game/Groups/Group.cpp b/src/server/game/Groups/Group.cpp index 3049b4c19..39c764555 100644 --- a/src/server/game/Groups/Group.cpp +++ b/src/server/game/Groups/Group.cpp @@ -298,7 +298,7 @@ void Group::ConvertToRaid() // update quest related GO states (quest activity dependent from raid membership) for (member_citerator citr = m_memberSlots.begin(); citr != m_memberSlots.end(); ++citr) if (Player* player = ObjectAccessor::FindPlayer(citr->guid)) - player->UpdateForQuestWorldObjects(); + player->UpdateVisibleGameobjectsOrSpellClicks(); // pussywizard: client automatically clears df "eye" near minimap, so remove from raid browser if (sLFGMgr->GetState(GetLeaderGUID()) == lfg::LFG_STATE_RAIDBROWSER) @@ -475,7 +475,7 @@ bool Group::AddMember(Player* player) // quest related GO state dependent from raid membership if (isRaidGroup()) - player->UpdateForQuestWorldObjects(); + player->UpdateVisibleGameobjectsOrSpellClicks(); { // Broadcast new player group member fields to rest of the group @@ -560,7 +560,7 @@ bool Group::RemoveMember(ObjectGuid guid, const RemoveMethod& method /*= GROUP_R player->SetGroup(nullptr); // quest related GO state dependent from raid membership - player->UpdateForQuestWorldObjects(); + player->UpdateVisibleGameobjectsOrSpellClicks(); } WorldPacket data; @@ -774,7 +774,7 @@ void Group::Disband(bool hideDestroy /* = false */) // quest related GO state dependent from raid membership if (isRaidGroup()) - player->UpdateForQuestWorldObjects(); + player->UpdateVisibleGameobjectsOrSpellClicks(); WorldPacket data; if (!hideDestroy) diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 026538e7c..706aacbd6 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -18,6 +18,7 @@ #include "ArenaSpectator.h" #include "CellImpl.h" #include "Common.h" +#include "ConditionMgr.h" #include "DynamicObject.h" #include "GridNotifiers.h" #include "GridNotifiersImpl.h" @@ -560,19 +561,18 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply) m_updateTargetMapInterval = UPDATE_TARGET_MAP_INTERVAL; // fill up to date target list - // target, effMask - std::map targets; - + // target, effMask + std::unordered_map targets; FillTargetMap(targets, caster); - UnitList targetsToRemove; + std::deque targetsToRemove; // mark all auras as ready to remove for (ApplicationMap::iterator appIter = m_applications.begin(); appIter != m_applications.end(); ++appIter) { - std::map::iterator existing = targets.find(appIter->second->GetTarget()); + auto itr = targets.find(appIter->second->GetTarget()); // not found in current area - remove the aura - if (existing == targets.end()) + if (itr == targets.end()) targetsToRemove.push_back(appIter->second->GetTarget()); else { @@ -580,22 +580,22 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply) if (IsArea()) for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) { - if ((existing->second & (1 << effIndex)) && existing->first->IsImmunedToSpellEffect(GetSpellInfo(), effIndex)) - existing->second &= ~(1 << effIndex); + if ((itr->second & (1 << effIndex)) && itr->first->IsImmunedToSpellEffect(GetSpellInfo(), effIndex)) + itr->second &= ~(1 << effIndex); } // needs readding - remove now, will be applied in next update cycle // (dbcs do not have auras which apply on same type of targets but have different radius, so this is not really needed) - if (appIter->second->GetEffectMask() != existing->second || !CanBeAppliedOn(existing->first)) + if (appIter->second->GetEffectMask() != itr->second || !CanBeAppliedOn(itr->first)) targetsToRemove.push_back(appIter->second->GetTarget()); // nothing todo - aura already applied // remove from auras to register list - targets.erase(existing); + targets.erase(itr); } } // register auras for units - for (std::map::iterator itr = targets.begin(); itr != targets.end();) + for (auto itr = targets.begin(); itr != targets.end();) { // aura mustn't be already applied on target if (AuraApplication* aurApp = GetApplicationOfTarget(itr->first->GetGUID())) @@ -608,7 +608,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply) if (aurApp->GetTarget() != itr->first) { // remove from auras to register list - targets.erase(itr++); + itr = targets.erase(itr); continue; } else @@ -675,7 +675,7 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply) } } if (!addUnit) - targets.erase(itr++); + itr = targets.erase(itr); else { // owner has to be in world, or effect has to be applied to self @@ -693,15 +693,15 @@ void Aura::UpdateTargetMap(Unit* caster, bool apply) } // remove auras from units no longer needing them - for (UnitList::iterator itr = targetsToRemove.begin(); itr != targetsToRemove.end(); ++itr) - if (AuraApplication* aurApp = GetApplicationOfTarget((*itr)->GetGUID())) - (*itr)->_UnapplyAura(aurApp, AURA_REMOVE_BY_DEFAULT); + for (Unit* unit : targetsToRemove) + if (AuraApplication* aurApp = GetApplicationOfTarget(unit->GetGUID())) + unit->_UnapplyAura(aurApp, AURA_REMOVE_BY_DEFAULT); if (!apply) return; // apply aura effects for units - for (std::map::iterator itr = targets.begin(); itr != targets.end(); ++itr) + for (auto itr = targets.begin(); itr != targets.end(); ++itr) { if (AuraApplication* aurApp = GetApplicationOfTarget(itr->first->GetGUID())) { @@ -2660,72 +2660,85 @@ void UnitAura::Remove(AuraRemoveMode removeMode) GetUnitOwner()->RemoveOwnedAura(this, removeMode); } -void UnitAura::FillTargetMap(std::map& targets, Unit* caster) +void UnitAura::FillTargetMap(std::unordered_map& targets, Unit* caster) { for (uint8 effIndex = 0; effIndex < MAX_SPELL_EFFECTS; ++effIndex) { if (!HasEffect(effIndex)) continue; - UnitList targetList; + + std::deque units; + // non-area aura if (GetSpellInfo()->Effects[effIndex].Effect == SPELL_EFFECT_APPLY_AURA) - { - targetList.push_back(GetUnitOwner()); - } + units.push_back(GetUnitOwner()); else { float radius = GetSpellInfo()->Effects[effIndex].CalcRadius(caster); if (!GetUnitOwner()->HasUnitState(UNIT_STATE_ISOLATED)) { + Unit* ref = caster; + ConditionList* condList = m_spellInfo->Effects[effIndex].ImplicitTargetConditions; + SpellTargetCheckTypes selectionType = TARGET_CHECK_DEFAULT; switch (GetSpellInfo()->Effects[effIndex].Effect) { case SPELL_EFFECT_APPLY_AREA_AURA_PARTY: case SPELL_EFFECT_APPLY_AREA_AURA_RAID: { - targetList.push_back(GetUnitOwner()); - Acore::AnyGroupedUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, GetSpellInfo()->Effects[effIndex].Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID); - Acore::UnitListSearcher searcher(GetUnitOwner(), targetList, u_check); + units.push_back(GetUnitOwner()); + Acore::AnyGroupedUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, m_spellInfo->Effects[effIndex].Effect == SPELL_EFFECT_APPLY_AREA_AURA_RAID, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER)); + Acore::UnitListSearcher searcher(GetUnitOwner(), units, u_check); Cell::VisitAllObjects(GetUnitOwner(), searcher, radius); break; } case SPELL_EFFECT_APPLY_AREA_AURA_FRIEND: { - targetList.push_back(GetUnitOwner()); - Acore::AnyFriendlyUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius); - Acore::UnitListSearcher searcher(GetUnitOwner(), targetList, u_check); + units.push_back(GetUnitOwner()); + Acore::AnyFriendlyUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER)); + Acore::UnitListSearcher searcher(GetUnitOwner(), units, u_check); Cell::VisitAllObjects(GetUnitOwner(), searcher, radius); break; } case SPELL_EFFECT_APPLY_AREA_AURA_ENEMY: { - Acore::AnyAoETargetUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius); // No GetCharmer in searcher - Acore::UnitListSearcher searcher(GetUnitOwner(), targetList, u_check); + Acore::AnyAoETargetUnitInObjectRangeCheck u_check(GetUnitOwner(), GetUnitOwner(), radius, m_spellInfo); // No GetCharmer in searcher + Acore::UnitListSearcher searcher(GetUnitOwner(), units, u_check); Cell::VisitAllObjects(GetUnitOwner(), searcher, radius); break; } case SPELL_EFFECT_APPLY_AREA_AURA_PET: - targetList.push_back(GetUnitOwner()); + if (!condList || sConditionMgr->IsObjectMeetToConditions(GetUnitOwner(), ref, *condList)) + units.push_back(GetUnitOwner()); [[fallthrough]]; // TODO: Not sure whether the fallthrough was a mistake (forgetting a break) or intended. This should be double-checked. case SPELL_EFFECT_APPLY_AREA_AURA_OWNER: { if (Unit* owner = GetUnitOwner()->GetCharmerOrOwner()) if (GetUnitOwner()->IsWithinDistInMap(owner, radius)) - targetList.push_back(owner); + if (!condList || sConditionMgr->IsObjectMeetToConditions(owner, ref, *condList)) + units.push_back(owner); break; } + default: + break; + } + if (selectionType != TARGET_CHECK_DEFAULT) + { + Acore::WorldObjectSpellAreaTargetCheck check(radius, GetUnitOwner(), ref, GetUnitOwner(), m_spellInfo, selectionType, condList); + Acore::UnitListSearcher searcher(GetUnitOwner(), units, check); + Cell::VisitAllObjects(GetUnitOwner(), searcher, radius); + } + + for (Unit* unit : units) + { + auto itr = targets.find(unit); + if (itr != targets.end()) + itr->second |= 1 << effIndex; + else + targets[unit] = 1 << effIndex; } } } - - for (UnitList::iterator itr = targetList.begin(); itr != targetList.end(); ++itr) - { - std::map::iterator existing = targets.find(*itr); - if (existing != targets.end()) - existing->second |= 1 << effIndex; - else - targets[*itr] = 1 << effIndex; - } } } @@ -2747,7 +2760,7 @@ void DynObjAura::Remove(AuraRemoveMode removeMode) _Remove(removeMode); } -void DynObjAura::FillTargetMap(std::map& targets, Unit* /*caster*/) +void DynObjAura::FillTargetMap(std::unordered_map& targets, Unit* /*caster*/) { Unit* dynObjOwnerCaster = GetDynobjOwner()->GetCaster(); float radius = GetDynobjOwner()->GetRadius(); @@ -2756,12 +2769,13 @@ void DynObjAura::FillTargetMap(std::map& targets, Unit* /*caster*/ { if (!HasEffect(effIndex)) continue; - UnitList targetList; + + std::deque units; if (GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DYNOBJ_ALLY || GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_UNIT_DEST_AREA_ALLY) { - Acore::AnyFriendlyUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius); - Acore::UnitListSearcher searcher(GetDynobjOwner(), targetList, u_check); + Acore::AnyFriendlyUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius, m_spellInfo->HasAttribute(SPELL_ATTR3_ONLY_ON_PLAYER)); + Acore::UnitListSearcher searcher(GetDynobjOwner(), units, u_check); Cell::VisitAllObjects(GetDynobjOwner(), searcher, radius); } // pussywizard: TARGET_DEST_DYNOBJ_NONE is supposed to search for both friendly and unfriendly targets, so for any unit @@ -2769,30 +2783,35 @@ void DynObjAura::FillTargetMap(std::map& targets, Unit* /*caster*/ else if (GetSpellInfo()->Effects[effIndex].TargetB.GetTarget() == TARGET_DEST_DYNOBJ_NONE) { Acore::AnyAttackableUnitExceptForOriginalCasterInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius); - Acore::UnitListSearcher searcher(GetDynobjOwner(), targetList, u_check); + Acore::UnitListSearcher searcher(GetDynobjOwner(), units, u_check); Cell::VisitAllObjects(GetDynobjOwner(), searcher, radius); } else { Acore::AnyAoETargetUnitInObjectRangeCheck u_check(GetDynobjOwner(), dynObjOwnerCaster, radius); - Acore::UnitListSearcher searcher(GetDynobjOwner(), targetList, u_check); + Acore::UnitListSearcher searcher(GetDynobjOwner(), units, u_check); Cell::VisitAllObjects(GetDynobjOwner(), searcher, radius); } - for (UnitList::iterator itr = targetList.begin(); itr != targetList.end(); ++itr) + for (Unit* unit : units) { // xinef: check z level and los dependence - Unit* target = *itr; float zLevel = GetDynobjOwner()->GetPositionZ(); - if (target->GetPositionZ() + 3.0f < zLevel || target->GetPositionZ() - 5.0f > zLevel) - if (!target->IsWithinLOSInMap(GetDynobjOwner())) + if (unit->GetPositionZ() + 3.0f < zLevel || unit->GetPositionZ() - 5.0f > zLevel) + { + if (!unit->IsWithinLOSInMap(GetDynobjOwner())) + { continue; + } + } - std::map::iterator existing = targets.find(*itr); - if (existing != targets.end()) - existing->second |= 1 << effIndex; + auto itr = targets.find(unit); + if (itr != targets.end()) + { + itr->second |= 1 << effIndex; + } else - targets[*itr] = 1 << effIndex; + targets[unit] = 1 << effIndex; } } } diff --git a/src/server/game/Spells/Auras/SpellAuras.h b/src/server/game/Spells/Auras/SpellAuras.h index 15320e5a1..7cf4fbb95 100644 --- a/src/server/game/Spells/Auras/SpellAuras.h +++ b/src/server/game/Spells/Auras/SpellAuras.h @@ -105,7 +105,11 @@ public: ObjectGuid GetCasterGUID() const { return m_casterGuid; } Unit* GetCaster() const; WorldObject* GetOwner() const { return m_owner; } - Unit* GetUnitOwner() const { ASSERT(GetType() == UNIT_AURA_TYPE); return (Unit*)m_owner; } + Unit* GetUnitOwner() const + { + ASSERT(GetType() == UNIT_AURA_TYPE); + return (Unit*) m_owner->ToUnit(); + } DynamicObject* GetDynobjOwner() const { ASSERT(GetType() == DYNOBJ_AURA_TYPE); return (DynamicObject*)m_owner; } AuraObjectType GetType() const; @@ -115,7 +119,7 @@ public: void _Remove(AuraRemoveMode removeMode); virtual void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) = 0; - virtual void FillTargetMap(std::map& targets, Unit* caster) = 0; + virtual void FillTargetMap(std::unordered_map& targets, Unit* caster) = 0; void UpdateTargetMap(Unit* caster, bool apply = true); void _RegisterForTargets() {Unit* caster = GetCaster(); UpdateTargetMap(caster, false);} @@ -284,7 +288,7 @@ public: void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) override; - void FillTargetMap(std::map& targets, Unit* caster) override; + void FillTargetMap(std::unordered_map& targets, Unit* caster) override; // Allow Apply Aura Handler to modify and access m_AuraDRGroup void SetDiminishGroup(DiminishingGroup group) { m_AuraDRGroup = group; } @@ -304,6 +308,6 @@ protected: public: void Remove(AuraRemoveMode removeMode = AURA_REMOVE_BY_DEFAULT) override; - void FillTargetMap(std::map& targets, Unit* caster) override; + void FillTargetMap(std::unordered_map& targets, Unit* caster) override; }; #endif diff --git a/src/server/scripts/Pet/pet_dk.cpp b/src/server/scripts/Pet/pet_dk.cpp index 312db264d..6c33acc3e 100644 --- a/src/server/scripts/Pet/pet_dk.cpp +++ b/src/server/scripts/Pet/pet_dk.cpp @@ -169,7 +169,7 @@ public: _initialSelection = false; // Find victim of Summon Gargoyle spell std::list targets; - Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(me, me, 50); + Acore::AnyUnfriendlyUnitInObjectRangeCheck u_check(me, me, 50.0f); Acore::UnitListSearcher searcher(me, targets, u_check); Cell::VisitAllObjects(me, searcher, 50.0f); for (std::list::const_iterator iter = targets.begin(); iter != targets.end(); ++iter)