Created
August 19, 2011 15:52
-
-
Save rsa/1157137 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/game/Map.cpp b/src/game/Map.cpp | |
index 15f4071..78b48a5 100644 | |
--- a/src/game/Map.cpp | |
+++ b/src/game/Map.cpp | |
@@ -285,6 +285,7 @@ bool Map::Add(Player *player) | |
{ | |
player->GetMapRef().link(this, player); | |
player->SetMap(this); | |
+ CreateAttackersStorageFor(player->GetObjectGuid()); | |
// update player state for other player and visa-versa | |
CellPair p = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); | |
@@ -319,6 +320,8 @@ Map::Add(T *obj) | |
} | |
obj->SetMap(this); | |
+ if (obj->GetTypeId() == TYPEID_UNIT) | |
+ CreateAttackersStorageFor(obj->GetObjectGuid()); | |
Cell cell(p); | |
if(obj->isActiveObject()) | |
@@ -610,6 +613,8 @@ void Map::Remove(Player *player, bool remove) | |
SendRemoveTransports(player); | |
UpdateObjectVisibility(player,cell,p); | |
+ RemoveAttackersStorageFor(player->GetObjectGuid()); | |
+ | |
if (!remove && !player->GetPlayerbotAI()) | |
player->ResetMap(); | |
@@ -647,6 +652,9 @@ Map::Remove(T *obj, bool remove) | |
UpdateObjectVisibility(obj,cell,p); // i think will be better to call this function while object still in grid, this changes nothing but logically is better(as for me) | |
RemoveFromGrid(obj,grid,cell); | |
+ if (obj->GetTypeId() == TYPEID_UNIT) | |
+ RemoveAttackersStorageFor(obj->GetObjectGuid()); | |
+ | |
obj->ResetMap(); | |
if( remove ) | |
{ | |
@@ -3262,3 +3270,77 @@ void Map::PlayDirectSoundToMap(uint32 soundId) | |
for (PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr) | |
itr->getSource()->SendDirectMessage(&data); | |
} | |
+ | |
+/** | |
+ * Function to operations with attackers per-map storage | |
+ * | |
+ * @param targetGuid (attackerGuid) | |
+ */ | |
+ | |
+void Map::AddAttackerFor(ObjectGuid targetGuid, ObjectGuid attackerGuid) | |
+{ | |
+ WriteGuard Guard(GetLock()); | |
+ AttackersMap::iterator itr = m_attackersMap.find(targetGuid); | |
+ if (itr != m_attackersMap.end()) | |
+ { | |
+ itr->second.insert(attackerGuid); | |
+ } | |
+} | |
+ | |
+void Map::RemoveAttackerFor(ObjectGuid targetGuid, ObjectGuid attackerGuid) | |
+{ | |
+ WriteGuard Guard(GetLock()); | |
+ AttackersMap::iterator itr = m_attackersMap.find(targetGuid); | |
+ if (itr != m_attackersMap.end()) | |
+ { | |
+ itr->second.erase(attackerGuid); | |
+ } | |
+} | |
+ | |
+void Map::RemoveAllAttackerFor(ObjectGuid targetGuid) | |
+{ | |
+ WriteGuard Guard(GetLock()); | |
+ AttackersMap::iterator itr = m_attackersMap.find(targetGuid); | |
+ if (itr != m_attackersMap.end()) | |
+ { | |
+ itr->second.clear(); | |
+ } | |
+} | |
+ | |
+ObjectGuidSet const& Map::GetAttackersFor(ObjectGuid targetGuid) | |
+{ | |
+ | |
+ ReadGuard Guard(GetLock()); | |
+ AttackersMap::const_iterator itr = m_attackersMap.find(targetGuid); | |
+ if (itr != m_attackersMap.end()) | |
+ return itr->second; | |
+ else | |
+ { | |
+ DEBUG_LOG("Map::GetAttackersFor - requester attackers list for target (guid %u), but his hot have it!", targetGuid.GetRawValue()); | |
+ if (!targetGuid.IsEmpty()) | |
+ { | |
+ CreateAttackersStorageFor(targetGuid); | |
+ return m_attackersMap[targetGuid]; | |
+ } | |
+ } | |
+ return ObjectGuidSet(); | |
+} | |
+ | |
+void Map::CreateAttackersStorageFor(ObjectGuid targetGuid) | |
+{ | |
+ AttackersMap::iterator itr = m_attackersMap.find(targetGuid); | |
+ if (itr != m_attackersMap.end()) | |
+ { | |
+ m_attackersMap.insert(std::make_pair(targetGuid,ObjectGuidSet())); | |
+ } | |
+} | |
+ | |
+void Map::RemoveAttackersStorageFor(ObjectGuid targetGuid) | |
+{ | |
+ WriteGuard Guard(GetLock()); | |
+ AttackersMap::iterator itr = m_attackersMap.find(targetGuid); | |
+ if (itr != m_attackersMap.end()) | |
+ { | |
+ m_attackersMap.erase(itr); | |
+ } | |
+} | |
diff --git a/src/game/Map.h b/src/game/Map.h | |
index 024d2be..8595ea3 100644 | |
--- a/src/game/Map.h | |
+++ b/src/game/Map.h | |
@@ -29,6 +29,7 @@ | |
#include "GridDefines.h" | |
#include "Cell.h" | |
#include "Object.h" | |
+#include "ObjectGuid.h" | |
#include "Timer.h" | |
#include "SharedDefines.h" | |
#include "GridMap.h" | |
@@ -90,6 +91,8 @@ enum LevelRequirementVsMode | |
#define MIN_UNLOAD_DELAY 1 // immediate unload | |
+typedef std::map<ObjectGuid,ObjectGuidSet> AttackersMap; | |
+ | |
class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType> | |
{ | |
friend class MapReference; | |
@@ -259,6 +262,20 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType> | |
void MonsterYellToMap(CreatureInfo const* cinfo, int32 textId, uint32 language, Unit* target, uint32 senderLowGuid = 0); | |
void PlayDirectSoundToMap(uint32 soundId); | |
+ // Attacker per-map storage operations | |
+ void AddAttackerFor(ObjectGuid targetGuid, ObjectGuid attackerGuid); | |
+ void RemoveAttackerFor(ObjectGuid targetGuid, ObjectGuid attackerGuid); | |
+ void RemoveAllAttackerFor(ObjectGuid targetGuid); | |
+ ObjectGuidSet const& GetAttackersFor(ObjectGuid targetGuid); | |
+ void CreateAttackersStorageFor(ObjectGuid targetGuid); | |
+ void RemoveAttackersStorageFor(ObjectGuid targetGuid); | |
+ | |
+ // multithread locking | |
+ typedef ACE_RW_Thread_Mutex LockType; | |
+ typedef ACE_Read_Guard<LockType> ReadGuard; | |
+ typedef ACE_Write_Guard<LockType> WriteGuard; | |
+ LockType& GetLock() { return i_lock; } | |
+ | |
private: | |
void LoadMapAndVMap(int gx, int gy); | |
@@ -347,6 +364,10 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType> | |
template<class T> | |
void RemoveFromGrid(T*, NGridType *, Cell const&); | |
+ | |
+ LockType i_lock; | |
+ AttackersMap m_attackersMap; | |
+ | |
}; | |
class MANGOS_DLL_SPEC WorldMap : public Map | |
diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp | |
index 067d992..83566e1 100644 | |
--- a/src/game/SpellEffects.cpp | |
+++ b/src/game/SpellEffects.cpp | |
@@ -3581,14 +3581,15 @@ void Spell::EffectDummy(SpellEffectIndex eff_idx) | |
ihit->effectMask &= ~(1<<1); | |
// not empty (checked), copy | |
- Unit::AttackerSet attackers = friendTarget->getAttackers(); | |
+ ObjectGuidSet attackers = friendTarget->getAttackers(); | |
// selected from list 3 | |
- for(uint32 i = 0; i < std::min(size_t(3),attackers.size()); ++i) | |
+ for(uint32 i = 0; i < std::min(size_t(3), attackers.size()); ++i) | |
{ | |
- Unit::AttackerSet::iterator aItr = attackers.begin(); | |
+ ObjectGuidSet::iterator aItr = attackers.begin(); | |
std::advance(aItr, rand() % attackers.size()); | |
- AddUnitTarget((*aItr), EFFECT_INDEX_1); | |
+ if (Unit* nTarget = friendTarget->GetMap()->GetUnit(*aItr)) | |
+ AddUnitTarget(nTarget, EFFECT_INDEX_1); | |
attackers.erase(aItr); | |
} | |
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp | |
index abc2249..e398f27 100644 | |
--- a/src/game/Unit.cpp | |
+++ b/src/game/Unit.cpp | |
@@ -6048,14 +6048,15 @@ Unit* Unit::getAttackerForHelper() | |
if (getVictim()) | |
return getVictim(); | |
- if (!m_attackers.empty()) | |
+ ObjectGuidSet const& attackers = GetMap()->GetAttackersFor(GetObjectGuid()); | |
+ if (!attackers.empty()) | |
{ | |
- for(AttackerSet::iterator i = m_attackers.begin(); i != m_attackers.end();) | |
+ for(ObjectGuidSet::const_iterator itr = attackers.begin(); itr != attackers.end();) | |
{ | |
- ObjectGuid guid = *i; | |
+ ObjectGuid guid = *itr++; | |
Unit* attacker = GetMap()->GetUnit(guid); | |
if (!attacker || !attacker->isAlive()) | |
- m_attackers.erase(guid); | |
+ GetMap()->RemoveAttackerFor(GetObjectGuid(),guid); | |
else | |
return attacker; | |
} | |
@@ -6127,7 +6128,8 @@ bool Unit::Attack(Unit *victim, bool meleeAttack) | |
addUnitState(UNIT_STAT_MELEE_ATTACKING); | |
m_attacking = victim; | |
- m_attacking->_addAttacker(GetObjectGuid()); | |
+ | |
+ GetMap()->AddAttackerFor(m_attacking->GetObjectGuid(),GetObjectGuid()); | |
if (GetTypeId() == TYPEID_UNIT) | |
{ | |
@@ -6170,8 +6172,7 @@ bool Unit::AttackStop(bool targetSwitch /*=false*/) | |
return false; | |
Unit* victim = m_attacking; | |
- | |
- m_attacking->_removeAttacker(GetObjectGuid()); | |
+ GetMap()->RemoveAttackerFor(m_attacking->GetObjectGuid(),GetObjectGuid()); | |
m_attacking = NULL; | |
// Clear our target | |
@@ -6249,15 +6250,20 @@ void Unit::RemoveAllAttackers() | |
if (!GetMap()) | |
return; | |
- while (!m_attackers.empty()) | |
+ ObjectGuidSet const& attackers = GetMap()->GetAttackersFor(ObjectGuid()); | |
+ | |
+ for (ObjectGuidSet::const_iterator itr = attackers.begin(); itr != attackers.end();) | |
{ | |
- AttackerSet::iterator iter = m_attackers.begin(); | |
- ObjectGuid guid = *iter; | |
+ ObjectGuid guid = *itr++; | |
Unit* attacker = GetMap()->GetUnit(guid); | |
if(!attacker || !attacker->AttackStop()) | |
{ | |
sLog.outError("WORLD: Unit has an attacker that isn't attacking it!"); | |
- m_attackers.erase(guid); | |
+ GetMap()->RemoveAttackerFor(GetObjectGuid(),guid); | |
+ } | |
+ else | |
+ { | |
+ attacker->AttackStop(); | |
} | |
} | |
} | |
@@ -8811,7 +8817,7 @@ bool Unit::isVisibleForOrDetect(Unit const* u, WorldObject const* viewPoint, boo | |
// Special cases | |
// If is attacked then stealth is lost, some creature can use stealth too | |
- if ( !getAttackers().empty() ) | |
+ if ( GetMap() && !GetMap()->GetAttackersFor(GetObjectGuid()).empty() ) | |
return true; | |
// If there is collision rogue is seen regardless of level difference | |
@@ -9424,7 +9430,9 @@ bool Unit::SelectHostileTarget() | |
// Note: creature not have targeted movement generator but have attacker in this case | |
if (GetMotionMaster()->GetCurrentMovementGeneratorType() != CHASE_MOTION_TYPE) | |
{ | |
- for(AttackerSet::const_iterator itr = m_attackers.begin(); itr != m_attackers.end(); ++itr) | |
+ ObjectGuidSet const& attackers = GetMap()->GetAttackersFor(ObjectGuid()); | |
+ | |
+ for (ObjectGuidSet::const_iterator itr = attackers.begin(); itr != attackers.end(); ++itr) | |
{ | |
Unit* attacker = GetMap()->GetUnit(*itr); | |
if (attacker && attacker->IsInMap(this) && attacker->isTargetableForAttack() && attacker->isInAccessablePlaceFor((Creature*)this)) | |
@@ -11993,10 +12001,11 @@ void Unit::StopAttackFaction(uint32 faction_id) | |
} | |
} | |
- AttackerSet const& attackers = getAttackers(); | |
- for(AttackerSet::const_iterator itr = attackers.begin(); itr != attackers.end();) | |
+ ObjectGuidSet const& attackers = GetMap()->GetAttackersFor(GetObjectGuid()); | |
+ for(ObjectGuidSet::const_iterator itr = attackers.begin(); itr != attackers.end();) | |
{ | |
Unit* attacker = GetMap()->GetUnit(*itr); | |
+ | |
if (attacker && attacker->getFactionTemplateEntry()->faction==faction_id) | |
{ | |
attacker->AttackStop(); | |
diff --git a/src/game/Unit.h b/src/game/Unit.h | |
index a03b7cf..43bf043 100644 | |
--- a/src/game/Unit.h | |
+++ b/src/game/Unit.h | |
@@ -1152,7 +1152,6 @@ class VehicleKit; | |
class MANGOS_DLL_SPEC Unit : public WorldObject | |
{ | |
public: | |
- typedef std::set<ObjectGuid> AttackerSet; | |
typedef std::multimap< uint32, SpellAuraHolder*> SpellAuraHolderMap; | |
typedef std::pair<SpellAuraHolderMap::iterator, SpellAuraHolderMap::iterator> SpellAuraHolderBounds; | |
typedef std::pair<SpellAuraHolderMap::const_iterator, SpellAuraHolderMap::const_iterator> SpellAuraHolderConstBounds; | |
@@ -1208,29 +1207,13 @@ class MANGOS_DLL_SPEC Unit : public WorldObject | |
bool CanReachWithMeleeAttack(Unit* pVictim, float flat_mod = 0.0f) const; | |
uint32 m_extraAttacks; | |
- void _addAttacker(ObjectGuid attackerGuid) // must be called only from Unit::Attack(Unit*) | |
- { | |
- if (attackerGuid.IsEmpty()) | |
- return; | |
- | |
- if (m_attackers.find(attackerGuid) == m_attackers.end()) | |
- m_attackers.insert(attackerGuid); | |
- } | |
- void _removeAttacker(ObjectGuid attackerGuid) // must be called only from Unit::AttackStop() | |
- { | |
- if (attackerGuid.IsEmpty()) | |
- return; | |
- | |
- if (m_attackers.find(attackerGuid) != m_attackers.end()) | |
- m_attackers.erase(attackerGuid); | |
- } | |
+ ObjectGuidSet const& getAttackers() const { return GetMap()->GetAttackersFor(GetObjectGuid()); } | |
Unit* getAttackerForHelper(); // If someone wants to help, who to give them | |
bool Attack(Unit *victim, bool meleeAttack); | |
void AttackedBy(Unit *attacker); | |
void CastStop(uint32 except_spellid = 0); | |
bool AttackStop(bool targetSwitch = false); | |
void RemoveAllAttackers(); | |
- AttackerSet const& getAttackers() const { return m_attackers; } | |
bool isAttackingPlayer() const; | |
Unit* getVictim() const { return m_attacking; } | |
void CombatStop(bool includingCast = false); | |
@@ -2090,7 +2073,6 @@ class MANGOS_DLL_SPEC Unit : public WorldObject | |
float m_createStats[MAX_STATS]; | |
- AttackerSet m_attackers; | |
Unit* m_attacking; | |
DeathState m_deathState; | |
diff --git a/src/game/WorldSession.cpp b/src/game/WorldSession.cpp | |
index 10a759d..54d8a9c 100644 | |
--- a/src/game/WorldSession.cpp | |
+++ b/src/game/WorldSession.cpp | |
@@ -411,7 +411,7 @@ void WorldSession::LogoutPlayer(bool Save) | |
// build set of player who attack _player or who have pet attacking of _player | |
std::set<Player*> aset; | |
- for(Unit::AttackerSet::const_iterator itr = _player->getAttackers().begin(); itr != _player->getAttackers().end(); ++itr) | |
+ for(ObjectGuidSet::const_iterator itr = _player->getAttackers().begin(); itr != _player->getAttackers().end(); ++itr) | |
{ | |
Unit* attacker = _player->GetMap()->GetUnit(*itr); | |
if (!attacker) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment