Skip to content

Instantly share code, notes, and snippets.

@rsa
Created August 19, 2011 15:52
Show Gist options
  • Save rsa/1157137 to your computer and use it in GitHub Desktop.
Save rsa/1157137 to your computer and use it in GitHub Desktop.
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