From 0ae2133254f9a3ebe178ea9a38bd9dde2ddc4002 Mon Sep 17 00:00:00 2001 From: VladimirMangos Date: Sun, 16 Nov 2008 23:29:08 +0300 Subject: [PATCH 1/3] [6833] More correct aura cancel for channeled spells. Remove auras at channeled target. Cancel channeled spell at spell aura cancel. Also move battleground resurection spell code to more appropriate place. --- src/game/SpellAuras.cpp | 11 ++++++++ src/game/SpellHandler.cpp | 22 ++++++++++----- src/game/Unit.cpp | 59 +++++++++++++++++++++++++++++++-------- src/game/Unit.h | 1 + src/shared/revision_nr.h | 2 +- 5 files changed, 76 insertions(+), 19 deletions(-) diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index 82770dfd0..fbb1d2e84 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -2010,6 +2010,17 @@ void Aura::HandleAuraDummy(bool apply, bool Real) caster->CastSpell(m_target,finalSpelId,true,NULL,this); return; } + + // Waiting to Resurrect + if(GetId()==2584) + { + // Waiting to resurrect spell cancel, we must remove player from resurrect queue + if(m_target->GetTypeId() == TYPEID_PLAYER) + if(BattleGround *bg = ((Player*)m_target)->GetBattleGround()) + bg->RemovePlayerFromResurrectQueue(m_target->GetGUID()); + return; + } + // Dark Fiend if(GetId()==45934) { diff --git a/src/game/SpellHandler.cpp b/src/game/SpellHandler.cpp index 773ae004f..ecc17cf70 100644 --- a/src/game/SpellHandler.cpp +++ b/src/game/SpellHandler.cpp @@ -355,15 +355,23 @@ void WorldSession::HandleCancelAuraOpcode( WorldPacket& recvPacket) if(!IsPositiveSpell(spellId) || (spellInfo->Attributes & SPELL_ATTR_CANT_CANCEL)) return; - _player->RemoveAurasDueToSpellByCancel(spellId); - - if (spellId == 2584) // Waiting to resurrect spell cancel, we must remove player from resurrect queue + // channeled spell case (it currently casted then) + if(IsChanneledSpell(spellInfo)) { - BattleGround *bg = _player->GetBattleGround(); - if(!bg) - return; - bg->RemovePlayerFromResurrectQueue(_player->GetGUID()); + if(Spell* spell = _player->m_currentSpells[CURRENT_CHANNELED_SPELL]) + { + if(spell->m_spellInfo->Id==spellId) + { + spell->cancel(); + spell->SetReferencedFromCurrent(false); + _player->m_currentSpells[CURRENT_CHANNELED_SPELL] = NULL; + } + } + return; } + + // non channeled case + _player->RemoveAurasDueToSpellByCancel(spellId); } void WorldSession::HandlePetCancelAuraOpcode( WorldPacket& recvPacket) diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 30d4f9e17..4bd6e5fe8 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -4098,12 +4098,17 @@ void Unit::RemoveNotOwnSingleTargetAuras() void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode) { - if (IsSingleTargetSpell((*i).second->GetSpellProto())) + Aura* Aur = i->second; + SpellEntry const* AurSpellInfo = Aur->GetSpellProto(); + + Unit* caster = NULL; + if (IsSingleTargetSpell(AurSpellInfo)) { - if(Unit* caster = (*i).second->GetCaster()) + caster = Aur->GetCaster(); + if(!caster) { AuraList& scAuras = caster->GetSingleCastAuras(); - scAuras.remove((*i).second); + scAuras.remove(Aur); } else { @@ -4112,13 +4117,12 @@ void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode) } } - if ((*i).second->GetModifier()->m_auraname < TOTAL_AURAS) + // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order) + if (Aur->GetModifier()->m_auraname < TOTAL_AURAS) { - m_modAuras[(*i).second->GetModifier()->m_auraname].remove((*i).second); + m_modAuras[Aur->GetModifier()->m_auraname].remove(Aur); } - // remove from list before mods removing (prevent cyclic calls, mods added before including to aura list - use reverse order) - Aura* Aur = i->second; // Set remove mode Aur->SetRemoveMode(mode); // some ShapeshiftBoosts at remove trigger removing other auras including parent Shapeshift aura @@ -4126,18 +4130,31 @@ void Unit::RemoveAura(AuraMap::iterator &i, AuraRemoveMode mode) m_Auras.erase(i); ++m_removedAuras; // internal count used by unit update - // Status unsummoned at aura remove + // Statue unsummoned at aura remove Totem* statue = NULL; - if(IsChanneledSpell(Aur->GetSpellProto())) - if(Unit* caster = Aur->GetCaster()) + bool caster_channeled = false; + if(IsChanneledSpell(AurSpellInfo)) + { + if(!caster) // can be already located for IsSingleTargetSpell case + caster = Aur->GetCaster(); + + if(caster) + { if(caster->GetTypeId()==TYPEID_UNIT && ((Creature*)caster)->isTotem() && ((Totem*)caster)->GetTotemType()==TOTEM_STATUE) statue = ((Totem*)caster); + else + caster_channeled = caster==this; + } + } sLog.outDebug("Aura %u now is remove mode %d",Aur->GetModifier()->m_auraname, mode); Aur->ApplyModifier(false,true); Aur->_RemoveAura(); delete Aur; + if(caster_channeled) + RemoveAurasAtChanneledTarget (AurSpellInfo); + if(statue) statue->UnSummon(); @@ -10859,4 +10876,24 @@ bool Unit::HandleMeandingAuraProc( Aura* triggeredByAura ) // heal CastCustomSpell(this,33110,&heal,NULL,NULL,true,NULL,NULL,caster_guid); return true; -} \ No newline at end of file +} + +void Unit::RemoveAurasAtChanneledTarget(SpellEntry const* spellInfo) +{ + uint64 target_guid = GetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT); + + if(!IS_UNIT_GUID(target_guid)) + return; + + Unit* target = ObjectAccessor::GetUnit(*this, target_guid); + if(!target) + return; + + for (AuraMap::iterator iter = target->GetAuras().begin(); iter != target->GetAuras().end(); ) + { + if (iter->second->GetId() == spellInfo->Id && iter->second->GetCasterGUID()==GetGUID()) + target->RemoveAura(iter); + else + ++iter; + } +} diff --git a/src/game/Unit.h b/src/game/Unit.h index 9447c5d93..a81308c51 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -997,6 +997,7 @@ class MANGOS_DLL_SPEC Unit : public WorldObject void RemoveAurasDueToSpellByDispel(uint32 spellId, uint64 casterGUID, Unit *dispeler); void RemoveAurasDueToSpellBySteal(uint32 spellId, uint64 casterGUID, Unit *stealer); void RemoveAurasDueToSpellByCancel(uint32 spellId); + void RemoveAurasAtChanneledTarget(SpellEntry const* spellInfo); void RemoveNotOwnSingleTargetAuras(); void RemoveSpellsCausingAura(AuraType auraType); diff --git a/src/shared/revision_nr.h b/src/shared/revision_nr.h index d2d1ba018..1cf8f518c 100644 --- a/src/shared/revision_nr.h +++ b/src/shared/revision_nr.h @@ -1,4 +1,4 @@ #ifndef __REVISION_NR_H__ #define __REVISION_NR_H__ - #define REVISION_NR "6832" + #define REVISION_NR "6833" #endif // __REVISION_NR_H__ From 79558a32d907d3163a504eb593c9652582c4c432 Mon Sep 17 00:00:00 2001 From: hunuza Date: Sun, 16 Nov 2008 21:37:19 +0100 Subject: [PATCH 2/3] Introduce player map references. --- .../Utilities/LinkedReference/RefManager.h | 2 + .../Utilities/LinkedReference/Reference.h | 1 + src/game/Makefile.am | 2 + src/game/Map.cpp | 128 ++++++++---------- src/game/Map.h | 19 ++- src/game/MapManager.cpp | 2 +- src/game/MapRefManager.h | 44 ++++++ src/game/MapReference.h | 50 +++++++ src/game/Player.h | 4 + win/VC71/game.vcproj | 6 + win/VC80/game.vcproj | 8 ++ win/VC90/game.vcproj | 8 ++ 12 files changed, 194 insertions(+), 80 deletions(-) create mode 100644 src/game/MapRefManager.h create mode 100644 src/game/MapReference.h diff --git a/src/framework/Utilities/LinkedReference/RefManager.h b/src/framework/Utilities/LinkedReference/RefManager.h index 876c44119..080133371 100644 --- a/src/framework/Utilities/LinkedReference/RefManager.h +++ b/src/framework/Utilities/LinkedReference/RefManager.h @@ -31,7 +31,9 @@ template class RefManager : public LinkedListHead virtual ~RefManager() { clearReferences(); } Reference* getFirst() { return ((Reference*) LinkedListHead::getFirst()); } + Reference const* getFirst() const { return ((Reference const*) LinkedListHead::getFirst()); } Reference* getLast() { return ((Reference*) LinkedListHead::getLast()); } + Reference const* getLast() const { return ((Reference const*) LinkedListHead::getLast()); } iterator begin() { return iterator(getFirst()); } iterator end() { return iterator(NULL); } diff --git a/src/framework/Utilities/LinkedReference/Reference.h b/src/framework/Utilities/LinkedReference/Reference.h index 03fce374e..a3c879709 100644 --- a/src/framework/Utilities/LinkedReference/Reference.h +++ b/src/framework/Utilities/LinkedReference/Reference.h @@ -72,6 +72,7 @@ template class Reference : public LinkedListElement } Reference* next() { return((Reference*)LinkedListElement::next()); } + Referenceconst* next() const { return((Reference const*)LinkedListElement::next()); } Reference* prev() { return((Reference*)LinkedListElement::prev()); } inline TO* operator ->() const { return iRefTo; } diff --git a/src/game/Makefile.am b/src/game/Makefile.am index 03dbeef61..d099b35d7 100644 --- a/src/game/Makefile.am +++ b/src/game/Makefile.am @@ -155,6 +155,8 @@ libmangosgame_a_SOURCES = \ MapInstanced.h \ MapManager.cpp \ MapManager.h \ + MapReference.h \ + MapRefManager.h \ MiscHandler.cpp \ MotionMaster.cpp \ MotionMaster.h \ diff --git a/src/game/Map.cpp b/src/game/Map.cpp index 972a08916..d583551eb 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -33,6 +33,7 @@ #include "World.h" #include "ScriptCalls.h" #include "Group.h" +#include "MapRefManager.h" #include "MapInstanced.h" #include "InstanceSaveMgr.h" @@ -418,6 +419,8 @@ Map::LoadGrid(const Cell& cell, bool no_unload) bool Map::Add(Player *player) { + player->GetMapRef().link(this, player); + player->SetInstanceId(GetInstanceId()); // update player state for other player and visa-versa @@ -570,22 +573,13 @@ void Map::Update(const uint32 &t_diff) // for pets TypeContainerVisitor world_object_update(updater); - //TODO: Player guard - HashMapHolder::MapType& playerMap = HashMapHolder::GetContainer(); - for(HashMapHolder::MapType::iterator iter = playerMap.begin(); iter != playerMap.end(); ++iter) + for(MapRefManager::iterator iter = m_mapRefManager.begin(); iter != m_mapRefManager.end(); ++iter) { - WorldObject* obj = iter->second; - - if(!obj->IsInWorld()) + Player* plr = iter->getSource(); + if(!plr->IsInWorld()) continue; - if(obj->GetMapId() != GetId()) - continue; - - if(obj->GetInstanceId() != GetInstanceId()) - continue; - - CellPair standing_cell(MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY())); + CellPair standing_cell(MaNGOS::ComputeCellPair(plr->GetPositionX(), plr->GetPositionY())); // Check for correctness of standing_cell, it also avoids problems with update_cell if (standing_cell.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || standing_cell.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) @@ -637,6 +631,7 @@ void Map::Update(const uint32 &t_diff) void Map::Remove(Player *player, bool remove) { + player->GetMapRef().unlink(); CellPair p = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); if(p.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || p.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP) { @@ -1434,6 +1429,21 @@ bool Map::CanUnload(const uint32 &diff) return false; } +uint32 Map::GetPlayersCountExceptGMs() const +{ + uint32 count = 0; + for(MapRefManager::const_iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) + if(!itr->getSource()->isGameMaster()) + ++count; + return count; +} + +void Map::SendToPlayers(WorldPacket const* data) const +{ + for(MapRefManager::const_iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) + itr->getSource()->GetSession()->SendPacket(data); +} + template void Map::Add(Corpse *); template void Map::Add(Creature *); template void Map::Add(GameObject *); @@ -1469,7 +1479,7 @@ InstanceMap::~InstanceMap() */ bool InstanceMap::CanEnter(Player *player) { - if(std::find(i_Players.begin(),i_Players.end(),player)!=i_Players.end()) + if(player->GetMapRef().getTarget() == this) { sLog.outError("InstanceMap::CanEnter - player %s(%u) already in map %d,%d,%d!", player->GetName(), player->GetGUIDLow(), GetId(), GetInstanceId(), GetSpawnMode()); assert(false); @@ -1586,7 +1596,6 @@ bool InstanceMap::Add(Player *player) if(i_data) i_data->OnPlayerEnter(player); SetResetSchedule(false); - i_Players.push_back(player); player->SendInitWorldStates(); sLog.outDetail("MAP: Player '%s' entered the instance '%u' of map '%s'", player->GetName(), GetInstanceId(), GetMapName()); // initialize unload state @@ -1611,9 +1620,9 @@ void InstanceMap::Update(const uint32& t_diff) void InstanceMap::Remove(Player *player, bool remove) { sLog.outDetail("MAP: Removing player '%s' from instance '%u' of map '%s' before relocating to other map", player->GetName(), GetInstanceId(), GetMapName()); - i_Players.remove(player); SetResetSchedule(true); - if(!m_unloadTimer && i_Players.empty()) + //if last player set unload timer + if(!m_unloadTimer && m_mapRefManager.getSize() == 1) m_unloadTimer = m_unloadWhenEmpty ? MIN_UNLOAD_DELAY : std::max(sWorld.getConfig(CONFIG_INSTANCE_UNLOAD_DELAY), (uint32)MIN_UNLOAD_DELAY); Map::Remove(player, remove); } @@ -1664,21 +1673,21 @@ bool InstanceMap::Reset(uint8 method) // note: since the map may not be loaded when the instance needs to be reset // the instance must be deleted from the DB by InstanceSaveManager - if(!i_Players.empty()) + if(HavePlayers()) { if(method == INSTANCE_RESET_ALL) { // notify the players to leave the instance so it can be reset - for(PlayerList::iterator itr = i_Players.begin(); itr != i_Players.end(); ++itr) - (*itr)->SendResetFailedNotify(GetId()); + for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) + itr->getSource()->SendResetFailedNotify(GetId()); } else { if(method == INSTANCE_RESET_GLOBAL) { // set the homebind timer for players inside (1 minute) - for(PlayerList::iterator itr = i_Players.begin(); itr != i_Players.end(); ++itr) - (*itr)->m_InstanceValid = false; + for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) + itr->getSource()->m_InstanceValid = false; } // the unload timer is not started @@ -1694,16 +1703,7 @@ bool InstanceMap::Reset(uint8 method) m_resetAfterUnload = true; } - return i_Players.empty(); -} - -uint32 InstanceMap::GetPlayersCountExceptGMs() const -{ - uint32 count = 0; - for(PlayerList::const_iterator itr = i_Players.begin(); itr != i_Players.end(); ++itr) - if(!(*itr)->isGameMaster()) - ++count; - return count; + return m_mapRefManager.isEmpty(); } void InstanceMap::PermBindAllPlayers(Player *player) @@ -1717,25 +1717,23 @@ void InstanceMap::PermBindAllPlayers(Player *player) Group *group = player->GetGroup(); // group members outside the instance group don't get bound - for(PlayerList::iterator itr = i_Players.begin(); itr != i_Players.end(); ++itr) + for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) { - if(*itr) + Player* plr = itr->getSource(); + // players inside an instance cannot be bound to other instances + // some players may already be permanently bound, in this case nothing happens + InstancePlayerBind *bind = plr->GetBoundInstance(save->GetMapId(), save->GetDifficulty()); + if(!bind || !bind->perm) { - // players inside an instance cannot be bound to other instances - // some players may already be permanently bound, in this case nothing happens - InstancePlayerBind *bind = (*itr)->GetBoundInstance(save->GetMapId(), save->GetDifficulty()); - if(!bind || !bind->perm) - { - (*itr)->BindToInstance(save, true); - WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4); - data << uint32(0); - (*itr)->GetSession()->SendPacket(&data); - } - - // if the leader is not in the instance the group will not get a perm bind - if(group && group->GetLeaderGUID() == (*itr)->GetGUID()) - group->BindToInstance(save, true); + plr->BindToInstance(save, true); + WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4); + data << uint32(0); + plr->GetSession()->SendPacket(&data); } + + // if the leader is not in the instance the group will not get a perm bind + if(group && group->GetLeaderGUID() == plr->GetGUID()) + group->BindToInstance(save, true); } } @@ -1747,11 +1745,14 @@ time_t InstanceMap::GetResetTime() void InstanceMap::UnloadAll(bool pForce) { - if(!i_Players.empty()) + if(HavePlayers()) { sLog.outError("InstanceMap::UnloadAll: there are still players in the instance at unload, should not happen!"); - for(PlayerList::iterator itr = i_Players.begin(); itr != i_Players.end(); ++itr) - if(*itr) (*itr)->TeleportTo((*itr)->m_homebindMapId, (*itr)->m_homebindX, (*itr)->m_homebindY, (*itr)->m_homebindZ, (*itr)->GetOrientation()); + for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) + { + Player* plr = itr->getSource(); + plr->TeleportTo(plr->m_homebindMapId, plr->m_homebindX, plr->m_homebindY, plr->m_homebindZ, plr->GetOrientation()); + } } if(m_resetAfterUnload == true) @@ -1762,8 +1763,8 @@ void InstanceMap::UnloadAll(bool pForce) void InstanceMap::SendResetWarnings(uint32 timeLeft) { - for(PlayerList::iterator itr = i_Players.begin(); itr != i_Players.end(); ++itr) - (*itr)->SendInstanceResetWarning(GetId(), timeLeft); + for(MapRefManager::iterator itr = m_mapRefManager.begin(); itr != m_mapRefManager.end(); ++itr) + itr->getSource()->SendInstanceResetWarning(GetId(), timeLeft); } void InstanceMap::SetResetSchedule(bool on) @@ -1771,7 +1772,7 @@ void InstanceMap::SetResetSchedule(bool on) // only for normal instances // the reset time is only scheduled when there are no payers inside // it is assumed that the reset time will rarely (if ever) change while the reset is scheduled - if(i_Players.empty() && !IsRaid() && !IsHeroic()) + if(!HavePlayers() && !IsRaid() && !IsHeroic()) { InstanceSave *save = sInstanceSaveManager.GetInstanceSave(GetInstanceId()); if(!save) sLog.outError("InstanceMap::SetResetSchedule: cannot turn schedule %s, no save available for instance %d of %d", on ? "on" : "off", GetInstanceId(), GetId()); @@ -1779,12 +1780,6 @@ void InstanceMap::SetResetSchedule(bool on) } } -void InstanceMap::SendToPlayers(WorldPacket const* data) const -{ - for(PlayerList::const_iterator itr = i_Players.begin(); itr != i_Players.end(); ++itr) - (*itr)->GetSession()->SendPacket(data); -} - /* ******* Battleground Instance Maps ******* */ BattleGroundMap::BattleGroundMap(uint32 id, time_t expiry, uint32 InstanceId) @@ -1798,7 +1793,7 @@ BattleGroundMap::~BattleGroundMap() bool BattleGroundMap::CanEnter(Player * player) { - if(std::find(i_Players.begin(),i_Players.end(),player)!=i_Players.end()) + if(player->GetMapRef().getTarget() == this) { sLog.outError("BGMap::CanEnter - player %u already in map!", player->GetGUIDLow()); assert(false); @@ -1819,7 +1814,6 @@ bool BattleGroundMap::Add(Player * player) Guard guard(*this); if(!CanEnter(player)) return false; - i_Players.push_back(player); // reset instance validity, battleground maps do not homebind player->m_InstanceValid = true; } @@ -1829,7 +1823,6 @@ bool BattleGroundMap::Add(Player * player) void BattleGroundMap::Remove(Player *player, bool remove) { sLog.outDetail("MAP: Removing player '%s' from bg '%u' of map '%s' before relocating to other map", player->GetName(), GetInstanceId(), GetMapName()); - i_Players.remove(player); Map::Remove(player, remove); } @@ -1840,15 +1833,14 @@ void BattleGroundMap::SetUnload() void BattleGroundMap::UnloadAll(bool pForce) { - while(!i_Players.empty()) + while(HavePlayers()) { - PlayerList::iterator itr = i_Players.begin(); - Player * plr = *itr; - if(plr) (plr)->TeleportTo((*itr)->m_homebindMapId, (*itr)->m_homebindX, (*itr)->m_homebindY, (*itr)->m_homebindZ, (*itr)->GetOrientation()); + Player * plr = m_mapRefManager.getFirst()->getSource(); + if(plr) (plr)->TeleportTo(plr->m_homebindMapId, plr->m_homebindX, plr->m_homebindY, plr->m_homebindZ, plr->GetOrientation()); // TeleportTo removes the player from this map (if the map exists) -> calls BattleGroundMap::Remove -> invalidates the iterator. // just in case, remove the player from the list explicitly here as well to prevent a possible infinite loop // note that this remove is not needed if the code works well in other places - i_Players.remove(plr); + plr->GetMapRef().unlink(); } Map::UnloadAll(pForce); diff --git a/src/game/Map.h b/src/game/Map.h index cf67a566d..889efecf7 100644 --- a/src/game/Map.h +++ b/src/game/Map.h @@ -31,6 +31,7 @@ #include "Timer.h" #include "SharedDefines.h" #include "GameSystem/GridRefManager.h" +#include "MapRefManager.h" #include #include @@ -233,6 +234,13 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj bool isCellMarked(uint32 pCellId) { return marked_cells.test(pCellId); } void markCell(uint32 pCellId) { marked_cells.set(pCellId); } + bool HavePlayers() const { return !m_mapRefManager.isEmpty(); } + uint32 GetPlayersCountExceptGMs() const; + + void SendToPlayers(WorldPacket const* data) const; + + MapRefManager m_mapRefManager; + private: void LoadVMap(int pX, int pY); void LoadMap(uint32 mapid, uint32 instanceid, int x,int y); @@ -332,13 +340,9 @@ class MANGOS_DLL_SPEC InstanceMap : public Map uint32 GetScriptId() { return i_script_id; } InstanceData* GetInstanceData() { return i_data; } void PermBindAllPlayers(Player *player); - PlayerList const& GetPlayers() const { return i_Players;} - void SendToPlayers(WorldPacket const* data) const; time_t GetResetTime(); void UnloadAll(bool pForce); bool CanEnter(Player* player); - uint32 GetPlayersCountExceptGMs() const; - uint32 HavePlayers() const { return !i_Players.empty(); } void SendResetWarnings(uint32 timeLeft); void SetResetSchedule(bool on); private: @@ -346,16 +350,11 @@ class MANGOS_DLL_SPEC InstanceMap : public Map bool m_unloadWhenEmpty; InstanceData* i_data; uint32 i_script_id; - // only online players that are inside the instance currently - // TODO ? - use the grid instead to access the players - PlayerList i_Players; }; class MANGOS_DLL_SPEC BattleGroundMap : public Map { public: - typedef std::list PlayerList; // online players only - BattleGroundMap(uint32 id, time_t, uint32 InstanceId); ~BattleGroundMap(); @@ -364,8 +363,6 @@ class MANGOS_DLL_SPEC BattleGroundMap : public Map bool CanEnter(Player* player); void SetUnload(); void UnloadAll(bool pForce); - private: - PlayerList i_Players; }; /*inline diff --git a/src/game/MapManager.cpp b/src/game/MapManager.cpp index e044b1084..bf2239e6e 100644 --- a/src/game/MapManager.cpp +++ b/src/game/MapManager.cpp @@ -336,7 +336,7 @@ uint32 MapManager::GetNumPlayersInInstances() MapInstanced::InstancedMaps &maps = ((MapInstanced *)map)->GetInstancedMaps(); for(MapInstanced::InstancedMaps::iterator mitr = maps.begin(); mitr != maps.end(); ++mitr) if(mitr->second->IsDungeon()) - ret += ((InstanceMap*)mitr->second)->GetPlayers().size(); + ret += ((InstanceMap*)mitr->second)->m_mapRefManager.getSize(); } return ret; } diff --git a/src/game/MapRefManager.h b/src/game/MapRefManager.h new file mode 100644 index 000000000..05d93903c --- /dev/null +++ b/src/game/MapRefManager.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _MAPREFMANAGER +#define _MAPREFMANAGER + +#include "Utilities/LinkedReference/RefManager.h" + +class MapReference; + +class MapRefManager : public RefManager +{ + public: + typedef LinkedListHead::Iterator< MapReference > iterator; + typedef LinkedListHead::Iterator< MapReference const > const_iterator; + + MapReference* getFirst() { return (MapReference*)RefManager::getFirst(); } + MapReference const* getFirst() const { return (MapReference const*)RefManager::getFirst(); } + MapReference* getLast() { return (MapReference*)RefManager::getLast(); } + MapReference const* getLast() const { return (MapReference const*)RefManager::getLast(); } + + iterator begin() { return iterator(getFirst()); } + iterator end() { return iterator(NULL); } + iterator rbegin() { return iterator(getLast()); } + iterator rend() { return iterator(NULL); } + const_iterator begin() const { return const_iterator(getFirst()); } + const_iterator end() const { return const_iterator(getLast()); } +}; +#endif diff --git a/src/game/MapReference.h b/src/game/MapReference.h new file mode 100644 index 000000000..4ab1d116d --- /dev/null +++ b/src/game/MapReference.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2005-2008 MaNGOS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _MAPREFERENCE_H +#define _MAPREFERENCE_H + +#include "Utilities/LinkedReference/Reference.h" +#include "Map.h" + +class MANGOS_DLL_SPEC MapReference : public Reference +{ + protected: + void targetObjectBuildLink() + { + // called from link() + getTarget()->m_mapRefManager.insertFirst(this); + getTarget()->m_mapRefManager.incSize(); + } + void targetObjectDestroyLink() + { + // called from unlink() + if(isValid()) getTarget()->m_mapRefManager.decSize(); + } + void sourceObjectDestroyLink() + { + // called from invalidate() + getTarget()->m_mapRefManager.decSize(); + } + public: + MapReference() : Reference() {} + ~MapReference() { unlink(); } + MapReference *next() { return (MapReference*)Reference::next(); } + MapReference const *next() const { return (MapReference const*)Reference::next(); } +}; +#endif diff --git a/src/game/Player.h b/src/game/Player.h index 3308c08e2..ec8f4f3cc 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -31,6 +31,7 @@ #include "Bag.h" #include "WorldSession.h" #include "Pet.h" +#include "MapReference.h" #include "Util.h" // for Tokens typedef #include @@ -2015,6 +2016,8 @@ class MANGOS_DLL_SPEC Player : public Unit Player* GetNextRandomRaidMember(float radius); GridReference &GetGridRef() { return m_gridRef; } + MapReference &GetMapRef() { return m_mapRef; } + bool isAllowedToLoot(Creature* creature); WorldLocation& GetTeleportDest() { return m_teleport_dest; } @@ -2259,6 +2262,7 @@ class MANGOS_DLL_SPEC Player : public Unit Item* _StoreItem( uint16 pos, Item *pItem, uint32 count, bool clone, bool update ); GridReference m_gridRef; + MapReference m_mapRef; }; void AddItemsSetItem(Player*player,Item *item); diff --git a/win/VC71/game.vcproj b/win/VC71/game.vcproj index d131d0f62..743751103 100644 --- a/win/VC71/game.vcproj +++ b/win/VC71/game.vcproj @@ -853,6 +853,12 @@ + + + + diff --git a/win/VC80/game.vcproj b/win/VC80/game.vcproj index 80aa58b04..37fcfc736 100644 --- a/win/VC80/game.vcproj +++ b/win/VC80/game.vcproj @@ -1310,6 +1310,14 @@ RelativePath="..\..\src\game\HostilRefManager.h" > + + + + diff --git a/win/VC90/game.vcproj b/win/VC90/game.vcproj index 19b0ae4ec..20e2a8cbc 100644 --- a/win/VC90/game.vcproj +++ b/win/VC90/game.vcproj @@ -1311,6 +1311,14 @@ RelativePath="..\..\src\game\HostilRefManager.h" > + + + + From 520fce4b27533fc1ed880dd6ba5610b91e3b7409 Mon Sep 17 00:00:00 2001 From: hunuza Date: Sun, 16 Nov 2008 13:32:47 +0100 Subject: [PATCH 3/3] Move PlayersNearGrid() to Map class. --- src/game/GridStates.cpp | 2 +- src/game/Map.cpp | 24 +++++++++++++++++++++++- src/game/Map.h | 1 + src/game/ObjectAccessor.cpp | 26 -------------------------- src/game/ObjectAccessor.h | 2 -- 5 files changed, 25 insertions(+), 30 deletions(-) diff --git a/src/game/GridStates.cpp b/src/game/GridStates.cpp index 339dad86e..392829737 100644 --- a/src/game/GridStates.cpp +++ b/src/game/GridStates.cpp @@ -34,7 +34,7 @@ ActiveState::Update(Map &m, NGridType &grid, GridInfo & info, const uint32 &x, c info.UpdateTimeTracker(t_diff); if( info.getTimeTracker().Passed() ) { - if( grid.ActiveObjectsInGrid() == 0 && !ObjectAccessor::Instance().PlayersNearGrid(x, y, m.GetId(), m.GetInstanceId()) ) + if( grid.ActiveObjectsInGrid() == 0 && !m.PlayersNearGrid(x, y) ) { ObjectGridStoper stoper(grid); stoper.StopN(); diff --git a/src/game/Map.cpp b/src/game/Map.cpp index d583551eb..59c99e61a 100644 --- a/src/game/Map.cpp +++ b/src/game/Map.cpp @@ -920,7 +920,7 @@ bool Map::UnloadGrid(const uint32 &x, const uint32 &y, bool pForce) assert( grid != NULL); { - if(!pForce && ObjectAccessor::Instance().PlayersNearGrid(x, y, i_id, i_InstanceId) ) + if(!pForce && PlayersNearGrid(x, y) ) return false; DEBUG_LOG("Unloading grid[%u,%u] for map %u", x,y, i_id); @@ -1444,6 +1444,28 @@ void Map::SendToPlayers(WorldPacket const* data) const itr->getSource()->GetSession()->SendPacket(data); } +bool Map::PlayersNearGrid(uint32 x, uint32 y) const +{ + CellPair cell_min(x*MAX_NUMBER_OF_CELLS, y*MAX_NUMBER_OF_CELLS); + CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS); + cell_min << 2; + cell_min -= 2; + cell_max >> 2; + cell_max += 2; + + for(MapRefManager::const_iterator iter = m_mapRefManager.begin(); iter != m_mapRefManager.end(); ++iter) + { + Player* plr = iter->getSource(); + + CellPair p = MaNGOS::ComputeCellPair(plr->GetPositionX(), plr->GetPositionY()); + if( (cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) && + (cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord) ) + return true; + } + + return false; +} + template void Map::Add(Corpse *); template void Map::Add(Creature *); template void Map::Add(GameObject *); diff --git a/src/game/Map.h b/src/game/Map.h index 889efecf7..b3f85215b 100644 --- a/src/game/Map.h +++ b/src/game/Map.h @@ -236,6 +236,7 @@ class MANGOS_DLL_SPEC Map : public GridRefManager, public MaNGOS::Obj bool HavePlayers() const { return !m_mapRefManager.isEmpty(); } uint32 GetPlayersCountExceptGMs() const; + bool PlayersNearGrid(uint32 x,uint32 y) const; void SendToPlayers(WorldPacket const* data) const; diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp index b32743b28..26b5be0e4 100644 --- a/src/game/ObjectAccessor.cpp +++ b/src/game/ObjectAccessor.cpp @@ -511,32 +511,6 @@ ObjectAccessor::UpdatePlayers(uint32 diff) iter->second->Update(diff); } -bool -ObjectAccessor::PlayersNearGrid(uint32 x, uint32 y, uint32 m_id, uint32 i_id) const -{ - CellPair cell_min(x*MAX_NUMBER_OF_CELLS, y*MAX_NUMBER_OF_CELLS); - CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS); - cell_min << 2; - cell_min -= 2; - cell_max >> 2; - cell_max += 2; - - //TODO: Guard player - HashMapHolder::MapType& playerMap = HashMapHolder::GetContainer(); - for(HashMapHolder::MapType::const_iterator iter=playerMap.begin(); iter != playerMap.end(); ++iter) - { - if( m_id != iter->second->GetMapId() || i_id != iter->second->GetInstanceId() ) - continue; - - CellPair p = MaNGOS::ComputeCellPair(iter->second->GetPositionX(), iter->second->GetPositionY()); - if( (cell_min.x_coord <= p.x_coord && p.x_coord <= cell_max.x_coord) && - (cell_min.y_coord <= p.y_coord && p.y_coord <= cell_max.y_coord) ) - return true; - } - - return false; -} - void ObjectAccessor::WorldObjectChangeAccumulator::Visit(PlayerMapType &m) { diff --git a/src/game/ObjectAccessor.h b/src/game/ObjectAccessor.h index 628312901..6b724408a 100644 --- a/src/game/ObjectAccessor.h +++ b/src/game/ObjectAccessor.h @@ -192,8 +192,6 @@ class MANGOS_DLL_DECL ObjectAccessor : public MaNGOS::Singleton