rendered paste bodyIndex: src/game/AggressorAI.cpp===================================================================--- src/game/AggressorAI.cpp (revision 3877)+++ src/game/AggressorAI.cpp (working copy)@@ -166,7 +166,7 @@ assert((i_victimGuid != 0) == (i_creature.getVictim() != NULL) && "i_victimGuid and i_creature.getVictim() not synchronized."); - if( i_creature.IsWithinDistInMap(i_creature.getVictim(), ATTACK_DIST))+ if( i_creature.IsWithinDistInMap(i_creature.getVictim(), OBJECT_ATTACK_DIST)) { if( i_creature.isAttackReady() ) {Index: src/game/Corpse.cpp===================================================================--- src/game/Corpse.cpp (revision 3877)+++ src/game/Corpse.cpp (working copy)@@ -102,10 +102,7 @@ sLog.outError("Bones %u not found in world.", GetGUIDLow()); } else- {- ObjectAccessor::Instance().RemoveBonesFromPlayerView(corpse); ObjectAccessor::Instance().AddObjectToRemoveList(this);- } RemoveFromWorld(); }@@ -265,3 +262,8 @@ else bones->DeleteBonesFromWorld(); }++bool Corpse::isVisibleFor(Player const* u) const+{+ return IsInWorld() && u->IsInWorld() && IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject());+}Index: src/game/Corpse.h===================================================================--- src/game/Corpse.h (revision 3877)+++ src/game/Corpse.h (working copy)@@ -57,6 +57,8 @@ GridPair const& GetGrid() const { return m_grid; } + bool isVisibleFor(Player const* u) const;+ void _ConvertCorpseToBones(); // only call from ObjectAccessor::ConvertCorpseForPlayer private: CorpseType m_type;Index: src/game/Creature.cpp===================================================================--- src/game/Creature.cpp (revision 3877)+++ src/game/Creature.cpp (working copy)@@ -185,7 +185,6 @@ { m_deathTimer = 0; DEBUG_LOG("Removing corpse... %u ", GetUInt32Value(OBJECT_FIELD_ENTRY));- ObjectAccessor::Instance().RemoveCreatureCorpseFromPlayerView(this); lootForPickPocketed = false; lootForBody = false; loot.clear();@@ -1466,8 +1465,8 @@ bool Creature::IsVisibleInGridForPlayer(Player* pl) const {- // Live player see live creatures or death creatures with corpse dissappiring time > 0- if(pl->isAlive())+ // Live player (or with not release body see live creatures or death creatures with corpse dissappiring time > 0+ if(pl->isAlive() || m_deathTimer > 0) { if( (this->GetEntry() == VISUAL_WAYPOINT) && !pl->isGameMaster() ) {@@ -1477,22 +1476,19 @@ } // Dead player see live creatures near own corpse- if(pl->getDeathState() == CORPSE)+ if(isAlive()) {- if(isAlive())+ CorpsePtr &corpse = pl->GetCorpse();+ if(corpse) {- CorpsePtr &corpse = pl->GetCorpse();- if(corpse)- {- // 20 - aggro distance for same level, 25 - max additional distance if player level less that creature level- if(corpse->IsWithinDistInMap(this,(20+25)*sWorld.getRate(RATE_CREATURE_AGGRO)))- return true;- }+ // 20 - aggro distance for same level, 25 - max additional distance if player level less that creature level+ if(corpse->IsWithinDistInMap(this,(20+25)*sWorld.getRate(RATE_CREATURE_AGGRO)))+ return true; } } // Dead player see Spirit Healer or Spirit Guide- if(pl->isDead() && isSpiritService())+ if(isSpiritService()) return true; // and not see any otherIndex: src/game/DynamicObject.cpp===================================================================--- src/game/DynamicObject.cpp (revision 3877)+++ src/game/DynamicObject.cpp (working copy)@@ -127,3 +127,8 @@ if (*iunit) (*iunit)->DelayAura(m_spellId, m_effIndex, delaytime); }++bool DynamicObject::isVisibleFor(Player const* u) const+{+ return IsInWorld() && u->IsInWorld() && IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject());+}Index: src/game/DynamicObject.h===================================================================--- src/game/DynamicObject.h (revision 3877)+++ src/game/DynamicObject.h (working copy)@@ -43,7 +43,7 @@ void AddAffected(Unit *unit) { m_affected.insert(unit); } void RemoveAffected(Unit *unit) { m_affected.erase(unit); } void Delay(int32 delaytime);-+ bool isVisibleFor(Player const* u) const; protected: uint64 m_casterGuid; uint32 m_spellId;Index: src/game/GameObject.cpp===================================================================--- src/game/GameObject.cpp (revision 3877)+++ src/game/GameObject.cpp (working copy)@@ -508,3 +508,9 @@ if(m_respawnTime > time(NULL) && !GetOwnerGUID()) objmgr.SaveGORespawnTime(m_DBTableGuid,GetInstanceId(),m_respawnTime); }++bool GameObject::isVisibleFor(Player const* u) const+{+ return isSpawned() && IsInWorld() && u->IsInWorld() && IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject())+ || IsTransport() && IsInWorld() && u->IsInWorld() && IsInMap(u);+}Index: src/game/GameObject.h===================================================================--- src/game/GameObject.h (revision 3877)+++ src/game/GameObject.h (working copy)@@ -136,20 +136,20 @@ m_respawnDelayTime = respawn > 0 ? respawn : 0; } void Respawn() { if(m_respawnTime > 0) m_respawnTime = time(NULL); }- bool isSpawned() { return m_respawnDelayTime == 0 || m_respawnTime > 0 && GetOwnerGUID() || m_respawnTime == 0 && !GetOwnerGUID(); }+ bool isSpawned() const { return m_respawnDelayTime == 0 || m_respawnTime > 0 && GetOwnerGUID() || m_respawnTime == 0 && !GetOwnerGUID(); } void Refresh(); void Delete(); void SetSpellId(uint32 id) { m_spellId = id;}- uint32 GetSpellId() { return m_spellId;}+ uint32 GetSpellId() const { return m_spellId;} void getFishLoot(Loot *loot);- uint32 GetGoType() { return GetUInt32Value(GAMEOBJECT_TYPE_ID); }+ uint32 GetGoType() const { return GetUInt32Value(GAMEOBJECT_TYPE_ID); } - LootState getLootState() { return m_lootState; }+ LootState getLootState() const { return m_lootState; } void AddToSkillupList(uint32 PlayerGuidLow) { m_SkillupList.push_back(PlayerGuidLow); }- bool IsInSkillupList(uint32 PlayerGuidLow)+ bool IsInSkillupList(uint32 PlayerGuidLow) const {- for (std::list<uint32>::iterator i = m_SkillupList.begin(); i != m_SkillupList.end(); ++i)+ for (std::list<uint32>::const_iterator i = m_SkillupList.begin(); i != m_SkillupList.end(); ++i) if (*i == PlayerGuidLow) return true; return false; }@@ -166,6 +166,8 @@ bool hasQuest(uint32 quest_id) const; bool hasInvolvedQuest(uint32 quest_id) const;++ bool isVisibleFor(Player const* u) const; protected: uint32 m_spellId; time_t m_respawnTime; // (secs) time of next respawn (or despawn if GO have owner()),Index: src/game/GridNotifiers.cpp===================================================================--- src/game/GridNotifiers.cpp (revision 3877)+++ src/game/GridNotifiers.cpp (working copy)@@ -27,255 +27,7 @@ using namespace MaNGOS; -void PlayerNotifier::Visit(PlayerMapType &m)-{- BuildForMySelf();-- for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)- {- if( iter->second == &i_player )- continue;-- if( i_player.isAlive() && iter->second->isAlive() ||- i_player.isDead() && iter->second->isDead() )- {- if (iter->second->isVisibleFor(&i_player,false))- iter->second->SendUpdateToPlayer(&i_player);- if (i_player.isVisibleFor(iter->second,false))- i_player.SendUpdateToPlayer(iter->second);- }- else- {- i_player.DestroyForPlayer(iter->second);- iter->second->DestroyForPlayer(&i_player);- }- }-}- void-PlayerNotifier::BuildForMySelf()-{- if( !i_player.IsInWorld() )- {- WorldPacket packet;- UpdateData data;-- Transport *t = i_player.GetTransport();- if (t)- {- t->BuildCreateUpdateBlockForPlayer(&data, &i_player);- }-- sLog.outDetail("Creating player data for himself %u", i_player.GetGUIDLow());- i_player.BuildCreateUpdateBlockForPlayer(&data, &i_player);- data.BuildPacket(&packet);- i_player.GetSession()->SendPacket(&packet);- i_player.AddToWorld();-- // Hack to send out transports- WorldPacket packet2;- UpdateData transData;- if (MapManager::Instance().m_TransportsByMap.find(i_player.GetMapId()) != MapManager::Instance().m_TransportsByMap.end())- {- for (size_t i = 0; i < MapManager::Instance().m_TransportsByMap[i_player.GetMapId()].size(); ++i)- {- Transport *t = MapManager::Instance().m_TransportsByMap[i_player.GetMapId()][i];- t->BuildCreateUpdateBlockForPlayer(&transData, &i_player);- }- transData.BuildPacket(&packet2);- i_player.GetSession()->SendPacket(&packet2);- }- }-}--void-VisibleNotifier::Notify()-{- if( i_data.HasData() )- {- // send update to other players (except player updates that already sent using SendUpdateToPlayer)- for(UpdateDataMapType::iterator iter = i_updateDatas.begin(); iter != i_updateDatas.end(); ++iter)- {- if(iter->first==&i_player)- continue;-- WorldPacket packet;- iter->second.BuildPacket(&packet);- iter->first->GetSession()->SendPacket(&packet);- }-- // send create packet to player (except player create updates that already sent using SendUpdateToPlayer)- WorldPacket packet;- i_data.BuildPacket(&packet);- i_player.GetSession()->SendPacket(&packet);-- // all object visible to i_player is updated/(create updated)- }-}--template<class T>-void-VisibleNotifier::Visit(std::map<OBJECT_HANDLE, T *> &m)-{- for(typename std::map<OBJECT_HANDLE, T *>::iterator iter=m.begin(); iter != m.end(); ++iter)- {- iter->second->BuildUpdate(i_updateDatas);- iter->second->BuildCreateUpdateBlockForPlayer(&i_data, &i_player);- }-}--template<class T>-void-VisibleNotifier::Visit(std::map<OBJECT_HANDLE, CountedPtr<T> > &m)-{- for(typename std::map<OBJECT_HANDLE, CountedPtr<T> >::iterator iter=m.begin(); iter != m.end(); ++iter)- {- iter->second->BuildUpdate(i_updateDatas);- iter->second->BuildCreateUpdateBlockForPlayer(&i_data, &i_player);- }-}--void-VisibleNotifier::Visit(GameObjectMapType &m)-{- for(GameObjectMapType::iterator iter=m.begin(); iter != m.end(); ++iter)- {- if(iter->second->isSpawned()) // show only respawned GO- {- iter->second->BuildUpdate(i_updateDatas);- iter->second->BuildCreateUpdateBlockForPlayer(&i_data, &i_player);- }- }-}--void-MaNGOS::VisibleChangesNotifier::Visit(PlayerMapType &m)-{- for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)- {- // Invisibility for gms- if(iter->second != &i_player)- {- switch(i_player.GetUpdateVisibility())- {- case VISIBLE_SET_INVISIBLE:- {- i_player.DestroyForPlayer(iter->second);- iter->second->m_DetectInvTimer = 1;- }- break;- case VISIBLE_SET_INVISIBLE_FOR_GROUP:- if (!iter->second->IsGroupVisibleFor(&i_player))- {- i_player.DestroyForPlayer(iter->second);- iter->second->m_DetectInvTimer = 1;- }- break;- case VISIBLE_SET_VISIBLE:- i_player.SendUpdateToPlayer(iter->second);- break;- }-- // Detect invisible pjs- if (i_player.m_enableDetect && iter->second->GetVisibility() == VISIBILITY_GROUP && !iter->second->IsGroupVisibleFor(&i_player))- {- if(i_player.IsWithinDistInMap(iter->second, 20))- i_player.InvisiblePjsNear.push_back(iter->second);- }-- // Reveal Invisible Pjs- if (iter->second == i_player.m_DiscoveredPj)- iter->second->SendUpdateToPlayer(&i_player);- }- }-}--void-NotVisibleNotifier::Notify()-{- if( i_data.HasData() )- {- WorldPacket packet;- i_data.BuildPacket(&packet);- i_player.GetSession()->SendPacket(&packet);- }-}--template<class T>-void-NotVisibleNotifier::Visit(std::map<OBJECT_HANDLE, T *> &m)-{- for(typename std::map<OBJECT_HANDLE, T *>::iterator iter=m.begin(); iter != m.end(); ++iter)- iter->second->BuildOutOfRangeUpdateBlock(&i_data);-}--template<class T>-void-NotVisibleNotifier::Visit(std::map<OBJECT_HANDLE, CountedPtr<T> > &m)-{- for(typename std::map<OBJECT_HANDLE, CountedPtr<T> >::iterator iter=m.begin(); iter != m.end(); ++iter)- iter->second->BuildOutOfRangeUpdateBlock(&i_data);-}--void-NotVisibleNotifier::Visit(GameObjectMapType &m)-{- for(GameObjectMapType::iterator iter=m.begin(); iter != m.end(); ++iter)- // ignore transport gameobjects at same map- if(!i_player.IsInMap(iter->second) || !iter->second->IsTransport())- iter->second->BuildOutOfRangeUpdateBlock(&i_data);-}--void-MaNGOS::NotVisibleNotifier::Visit(PlayerMapType &m)-{- for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)- {- if( iter->second == &i_player )- continue;- if( (i_player.isAlive() && iter->second->isAlive()) ||- (i_player.isDead() && iter->second->isDead()) )- {- iter->second->BuildOutOfRangeUpdateBlock(&i_data);-- UpdateData his_data;- WorldPacket his_pk;- i_player.BuildOutOfRangeUpdateBlock(&his_data);- his_data.BuildPacket(&his_pk);- iter->second->GetSession()->SendPacket(&his_pk);- }- }-}--void-ObjectVisibleNotifier::Visit(PlayerMapType &m)-{- // ignore not respawned gameobjects- if(i_object.GetTypeId() == TYPEID_GAMEOBJECT && !((GameObject&)i_object).isSpawned())- return;-- for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)- {- UpdateData update_data;- WorldPacket packet;- i_object.BuildCreateUpdateBlockForPlayer(&update_data, iter->second);- update_data.BuildPacket(&packet);- iter->second->GetSession()->SendPacket(&packet);- }-}--void-ObjectNotVisibleNotifier::Visit(PlayerMapType &m)-{- // ignore transport gameobjects at same map- bool transport = (i_object.GetTypeId() == TYPEID_GAMEOBJECT && ((GameObject&)i_object).IsTransport());-- for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)- if(!i_object.IsInMap(iter->second) || !transport)- iter->second->SendOutOfRange(&i_object);-}--void MessageDeliverer::Visit(PlayerMapType &m) { for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)@@ -297,30 +49,6 @@ } } -void-CreatureVisibleMovementNotifier::Visit(PlayerMapType &m)-{- for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)- {- if( i_creature.IsVisibleInGridForPlayer(iter->second) )- {- UpdateData update_data;- WorldPacket packet;- i_creature.BuildCreateUpdateBlockForPlayer(&update_data, iter->second);- update_data.BuildPacket(&packet);- iter->second->GetSession()->SendPacket(&packet);- }- }-}--void-CreatureNotVisibleMovementNotifier::Visit(PlayerMapType &m)-{- for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)- if( iter->second->isAlive() )- iter->second->SendOutOfRange(&i_creature);-}- template<class T> void ObjectUpdater::Visit(std::map<OBJECT_HANDLE, T *> &m) {@@ -339,11 +67,5 @@ } } -template void VisibleNotifier::Visit<Corpse>(CorpseMapType &);-template void VisibleNotifier::Visit<DynamicObject>(DynamicObjectMapType &);--template void NotVisibleNotifier::Visit<Corpse>(CorpseMapType &);-template void NotVisibleNotifier::Visit<DynamicObject>(DynamicObjectMapType &);- template void ObjectUpdater::Visit<GameObject>(GameObjectMapType &); template void ObjectUpdater::Visit<DynamicObject>(DynamicObjectMapType &);Index: src/game/GridNotifiers.h===================================================================--- src/game/GridNotifiers.h (revision 3877)+++ src/game/GridNotifiers.h (working copy)@@ -36,78 +36,6 @@ namespace MaNGOS {-- struct MANGOS_DLL_DECL PlayerNotifier- {- explicit PlayerNotifier(Player &pl) : i_player(pl) {}- void Visit(PlayerMapType &);- template<class SKIP> void Visit(std::map<OBJECT_HANDLE, SKIP *> &) {}- template<class SKIP> void Visit(std::map<OBJECT_HANDLE, CountedPtr<SKIP> > &m) {}- void BuildForMySelf(void);- Player &i_player;- };-- struct MANGOS_DLL_DECL VisibleNotifier- {- Player &i_player;- UpdateData i_data;- UpdateDataMapType i_updateDatas;-- explicit VisibleNotifier(Player &player) : i_player(player) {}- template<class T> void Visit(std::map<OBJECT_HANDLE, T *> &m);- template<class T> void Visit(std::map<OBJECT_HANDLE, CountedPtr<T> > &m);- void Visit(GameObjectMapType &);- void Notify(void);-- #ifdef WIN32- template<> void VisibleNotifier::Visit(CreatureMapType &);- template<> void VisibleNotifier::Visit(PlayerMapType &);- #endif- };-- struct MANGOS_DLL_DECL VisibleChangesNotifier- {- Player &i_player;- explicit VisibleChangesNotifier(Player &player) : i_player(player) {}- void Visit(PlayerMapType &);- template<class SKIP> void Visit(std::map<OBJECT_HANDLE, SKIP *> &) {}- template<class SKIP> void Visit(std::map<OBJECT_HANDLE, CountedPtr<SKIP> > &m) {}- };-- struct MANGOS_DLL_DECL NotVisibleNotifier- {- Player &i_player;- UpdateData i_data;- explicit NotVisibleNotifier(Player &player) : i_player(player) {}- void Notify(void);- template<class T> void Visit(std::map<OBJECT_HANDLE, T *> &m);- template<class T> void Visit(std::map<OBJECT_HANDLE, CountedPtr<T> > &m);- void Visit(GameObjectMapType &);- void Visit(PlayerMapType &);-- #ifdef WIN32- template<> void NotVisibleNotifier::Visit(CreatureMapType &);- #endif- };-- struct MANGOS_DLL_DECL ObjectVisibleNotifier- {- WorldObject &i_object;- explicit ObjectVisibleNotifier(WorldObject &obj) : i_object(obj) {}- void Visit(PlayerMapType &);- template<class SKIP> void Visit(std::map<OBJECT_HANDLE, SKIP *> &) {}- template<class SKIP> void Visit(std::map<OBJECT_HANDLE, CountedPtr<SKIP> > &m) {}- };-- struct MANGOS_DLL_DECL ObjectNotVisibleNotifier- {- WorldObject &i_object;- explicit ObjectNotVisibleNotifier(WorldObject &obj) : i_object(obj) {}- void Visit(PlayerMapType &);- template<class SKIP> void Visit(std::map<OBJECT_HANDLE, SKIP *> &) {}- template<class SKIP> void Visit(std::map<OBJECT_HANDLE, CountedPtr<SKIP> > &m) {}- };- struct MANGOS_DLL_DECL GridUpdater { GridType &i_grid;@@ -154,24 +82,6 @@ template<class SKIP> void Visit(std::map<OBJECT_HANDLE, CountedPtr<SKIP> > &m) {} }; - struct MANGOS_DLL_DECL CreatureVisibleMovementNotifier- {- Creature &i_creature;- explicit CreatureVisibleMovementNotifier(Creature &creature) : i_creature(creature) {}- void Visit(PlayerMapType &m);- template<class SKIP> void Visit(std::map<OBJECT_HANDLE, SKIP *> &) {}- template<class SKIP> void Visit(std::map<OBJECT_HANDLE, CountedPtr<SKIP> > &m) {}- };-- struct MANGOS_DLL_DECL CreatureNotVisibleMovementNotifier- {- Creature &i_creature;- explicit CreatureNotVisibleMovementNotifier(Creature &creature) : i_creature(creature) {}- void Visit(PlayerMapType &m);- template<class SKIP> void Visit(std::map<OBJECT_HANDLE, SKIP *> &) {}- template<class SKIP> void Visit(std::map<OBJECT_HANDLE, CountedPtr<SKIP> > &m) {}- };- struct MANGOS_DLL_DECL ObjectUpdater { uint32 i_timeDiff;@@ -236,10 +146,8 @@ PlayerRelocationNotifier(Player &pl) : i_player(pl) {} template<class T> void Visit(std::map<OBJECT_HANDLE, T *> &m) {} template<class T> void Visit(std::map<OBJECT_HANDLE, CountedPtr<T> > &m) {}- #ifdef WIN32- template<> void Visit(PlayerMapType &);- template<> void Visit(CreatureMapType &);- #endif+ void Visit(PlayerMapType &);+ void Visit(CreatureMapType &); }; struct MANGOS_DLL_DECL CreatureRelocationNotifier@@ -528,17 +436,14 @@ float i_range; }; - class AnyDeadUnitCheck+ struct AnyDeadUnitCheck {- public:- AnyDeadUnitCheck() {}- bool operator()(Unit* u)- {- if(!u->isAlive())- return true;+ bool operator()(Unit* u) { return !u->isAlive(); }+ }; - return false;- }+ struct AnyDetectableInvisibleUnitCheck+ {+ bool operator()(Unit* u) { return u->GetVisibility()==VISIBILITY_GROUP; } }; class CannibalizeUnitCheck@@ -590,9 +495,6 @@ }; #ifndef WIN32- template<> void VisibleNotifier::Visit<Creature>(CreatureMapType &);- template<> void VisibleNotifier::Visit<Player>(PlayerMapType &);- template<> void NotVisibleNotifier::Visit<Creature>(CreatureMapType &); template<> void PlayerRelocationNotifier::Visit<Creature>(CreatureMapType &); template<> void PlayerRelocationNotifier::Visit<Player>(PlayerMapType &); template<> void CreatureRelocationNotifier::Visit<Player>(PlayerMapType &);Index: src/game/GridNotifiersImpl.h===================================================================--- src/game/GridNotifiersImpl.h (revision 3877)+++ src/game/GridNotifiersImpl.h (working copy)@@ -27,60 +27,7 @@ #include "CreatureAI.h" #include "SpellAuras.h" -template<> inline void-MaNGOS::NotVisibleNotifier::Visit(CreatureMapType &m)-{- for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)- if( ( i_player.isAlive() && iter->second->isAlive()) ||- (i_player.isDead() && iter->second->isDead()) )- iter->second->BuildOutOfRangeUpdateBlock(&i_data);-}--template<>-inline void-MaNGOS::VisibleNotifier::Visit(CreatureMapType &m)-{- for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)- {- if( iter->second->IsVisibleInGridForPlayer(&i_player) )- {- iter->second->BuildUpdate(i_updateDatas);- iter->second->BuildCreateUpdateBlockForPlayer(&i_data, &i_player);- }- else- {- iter->second->DestroyForPlayer(&i_player);- }- }-}--template<>-inline void-MaNGOS::VisibleNotifier::Visit(PlayerMapType &m)-{- for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)- {- if( iter->second == &i_player )- continue;-- if( (i_player.isAlive() && iter->second->isAlive()) ||- (i_player.isDead() && iter->second->isDead()) )- {- if (iter->second->isVisibleFor(&i_player,false))- iter->second->SendUpdateToPlayer(&i_player);- if (i_player.isVisibleFor(iter->second,false))- i_player.SendUpdateToPlayer(iter->second);- }- else- {- i_player.DestroyForPlayer(iter->second);- iter->second->DestroyForPlayer(&i_player);- }- }-}--inline void MaNGOS::ObjectUpdater::Visit(CreatureMapType &m) { for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)@@ -88,41 +35,27 @@ iter->second->Update(i_timeDiff); } -template<> inline void MaNGOS::PlayerRelocationNotifier::Visit(PlayerMapType &m) {- if(!i_player.isAlive() || i_player.isInFlight())- return;- for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) {- // Remove selection- if(i_player.GetSelection()==iter->second->GetGUID())- // visibility distance- if(!i_player.IsWithinDistInMap(iter->second, 160))- // valor under 160 can generate a bug of visibility, as a player- i_player.SendOutOfRange(iter->second); // can reach 158 yards until it disapears, without been selected+ if(&i_player==iter->second)+ continue; - if(iter->second->GetSelection()==i_player.GetGUID())- // visibility distance- if(!i_player.IsWithinDistInMap(iter->second, 160))- iter->second->SendOutOfRange(&i_player);+ // visibility for players updated by ObjectAccessor::UpdateVisibilityFor calls in appropriate places // Cancel Trade if(i_player.GetTrader()==iter->second) if(!i_player.IsWithinDistInMap(iter->second, 5)) // iteraction distance i_player.GetSession()->SendCancelTrade(); // will clode both side trade windows- } } inline void PlayerCreatureRelocationWorker(Player* pl, Creature* c) {- // Remove selection- if(pl->GetSelection()==c->GetGUID())- if(!pl->IsWithinDistInMap(c, 160)) // visibility distance- pl->SendOutOfRange(c);+ // update creature visibility at player/creature move+ pl->UpdateVisibilityOf(c); // Creature AI reaction if( c->AI() && c->AI()->IsVisible(pl) )@@ -138,7 +71,6 @@ c2->AI()->MoveInLineOfSight(c1); } -template<> inline void MaNGOS::PlayerRelocationNotifier::Visit(CreatureMapType &m) {@@ -146,7 +78,7 @@ return; for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)- if( iter->second->isAlive() && !iter->second->isInFlight())+ if( iter->second->isAlive()) PlayerCreatureRelocationWorker(&i_player,iter->second); } @@ -154,7 +86,7 @@ inline void MaNGOS::CreatureRelocationNotifier::Visit(PlayerMapType &m) {- if(!i_creature.isAlive() || i_creature.isInFlight())+ if(!i_creature.isAlive()) return; for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)@@ -166,11 +98,11 @@ inline void MaNGOS::CreatureRelocationNotifier::Visit(CreatureMapType &m) {- if(!i_creature.isAlive() || i_creature.isInFlight())+ if(!i_creature.isAlive()) return; for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)- if( iter->second->isAlive() && !iter->second->isInFlight())+ if( iter->second->isAlive()) CreatureCreatureRelocationWorker(iter->second, &i_creature); } Index: src/game/GuardAI.cpp===================================================================--- src/game/GuardAI.cpp (revision 3877)+++ src/game/GuardAI.cpp (working copy)@@ -150,7 +150,7 @@ assert((i_victimGuid != 0) == (i_creature.getVictim() != NULL) && "i_victimGuid and i_creature.getVictim() not synchronized."); - if( i_creature.IsWithinDistInMap(i_creature.getVictim(), ATTACK_DIST))+ if( i_creature.IsWithinDistInMap(i_creature.getVictim(), OBJECT_ATTACK_DIST)) { if( i_creature.isAttackReady() ) {Index: src/game/HomeMovementGenerator.cpp===================================================================--- src/game/HomeMovementGenerator.cpp (revision 3877)+++ src/game/HomeMovementGenerator.cpp (working copy)@@ -20,9 +20,7 @@ #include "Creature.h" #include "Traveller.h" #include "MapManager.h"-#include "RedZoneDistrict.h"-#include "CellImpl.h"-#include "GridNotifiersImpl.h"+#include "ObjectAccessor.h" #include "DestinationHolderImp.h" void@@ -63,15 +61,8 @@ if (owner.GetTypeId() == TYPEID_UNIT) {- sLog.outDebug("HomeMovementGenerator::_reLocate() called, where Unit.GetGUIDLow()=%d", owner.GetGUIDLow());- CellPair p = MaNGOS::ComputeCellPair(owner.GetPositionX(), owner.GetPositionY());- Cell cell = RedZone::GetZone(p);- cell.data.Part.reserved = ALL_DISTRICT;- MaNGOS::CreatureVisibleMovementNotifier notifier(owner);- TypeContainerVisitor<MaNGOS::CreatureVisibleMovementNotifier, WorldTypeMapContainer > player_notifier(notifier);- CellLock<GridReadGuard> cell_lock(cell, p);- cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(owner.GetMapId(), &owner));+ ObjectAccessor::UpdateObjectVisibility(&owner); } } Index: src/game/Map.cpp===================================================================--- src/game/Map.cpp (revision 3877)+++ src/game/Map.cpp (working copy)@@ -411,7 +411,7 @@ ObjectGridLoader loader(*grid, this, cell); loader.LoadN(); - // Add resurrectable corpses to world obect list in grid+ // Add resurrectable corpses to world object list in grid ObjectAccessor::Instance().AddCorpsesToGrid(GridPair(cell.GridX(),cell.GridY()),(*grid)(cell.CellX(), cell.CellY()), this); i_gridStatus[cell.GridX()] |= mask;@@ -422,22 +422,6 @@ } } -void-Map::NotifyPlayerVisibility(const Cell &cell, const CellPair &cell_pair, Player *player)-{- MaNGOS::PlayerNotifier pl_notifier(*player);- MaNGOS::VisibleNotifier obj_notifier(*player);- TypeContainerVisitor<MaNGOS::PlayerNotifier, WorldTypeMapContainer > player_notifier(pl_notifier);- TypeContainerVisitor<MaNGOS::VisibleNotifier, WorldTypeMapContainer > world_object_notifier(obj_notifier);- TypeContainerVisitor<MaNGOS::VisibleNotifier, GridTypeMapContainer > grid_object_notifier(obj_notifier);-- CellLock<ReadGuard> cell_lock(cell, cell_pair);- cell_lock->Visit(cell_lock, player_notifier, *this);- cell_lock->Visit(cell_lock, world_object_notifier, *this);- cell_lock->Visit(cell_lock, grid_object_notifier, *this);- obj_notifier.Notify();-}- bool Map::AddInstanced(Player *player) { if (!Instanceable())@@ -563,9 +547,41 @@ Cell cell = RedZone::GetZone(p); EnsureGridLoadedForPlayer(cell, player, true);- cell.data.Part.reserved = ALL_DISTRICT;- NotifyPlayerVisibility(cell, p, player); + // build data for self presence in world at own client+ WorldPacket packet;+ UpdateData data;++ Transport *t = player->GetTransport();+ if (t)+ {+ t->BuildCreateUpdateBlockForPlayer(&data, player);+ }++ sLog.outDetail("Creating player data for himself %u", player->GetGUIDLow());+ player->BuildCreateUpdateBlockForPlayer(&data, player);+ data.BuildPacket(&packet);+ player->GetSession()->SendPacket(&packet);++ player->AddToWorld();++ // Hack to send out transports+ WorldPacket packet2;+ UpdateData transData;+ if (MapManager::Instance().m_TransportsByMap.find(player->GetMapId()) != MapManager::Instance().m_TransportsByMap.end())+ {+ for (size_t i = 0; i < MapManager::Instance().m_TransportsByMap[player->GetMapId()].size(); ++i)+ {+ Transport *t = MapManager::Instance().m_TransportsByMap[player->GetMapId()][i];+ t->BuildCreateUpdateBlockForPlayer(&transData, player);+ }+ transData.BuildPacket(&packet2);+ player->GetSession()->SendPacket(&packet2);+ }++ // send data for other players who can see+ ObjectAccessor::UpdateVisibilityFor(player);+ // reinitialize reset time InitResetTime(); }@@ -592,14 +608,8 @@ AddToGrid(obj,grid,cell); DEBUG_LOG("Object %u enters grid[%u,%u]", GUID_LOPART(obj->GetGUID()), cell.GridX(), cell.GridY());- cell.data.Part.reserved = ALL_DISTRICT;- cell.SetNoCreate(); // not create cells at object add notifier (if player near then cell will already loaded) - MaNGOS::ObjectVisibleNotifier notifier(*static_cast<WorldObject *>(obj));- TypeContainerVisitor<MaNGOS::ObjectVisibleNotifier, WorldTypeMapContainer > player_notifier(notifier);-- CellLock<ReadGuard> cell_lock(cell, p);- cell_lock->Visit(cell_lock, player_notifier, *this);+ ObjectAccessor::UpdateObjectVisibility(obj); } template<class T>@@ -622,15 +632,10 @@ assert( grid != NULL ); AddToGrid(obj,grid,cell);+ obj->AddToWorld(); DEBUG_LOG("Object %u enters grid[%u,%u]", GUID_LOPART(obj->GetGUID()), cell.GridX(), cell.GridY());- cell.data.Part.reserved = ALL_DISTRICT;-- MaNGOS::ObjectVisibleNotifier notifier(*static_cast<WorldObject *>(&(*obj)));- TypeContainerVisitor<MaNGOS::ObjectVisibleNotifier, WorldTypeMapContainer > player_notifier(notifier);-- CellLock<ReadGuard> cell_lock(cell, p);- cell_lock->Visit(cell_lock, player_notifier, *this);+ ObjectAccessor::UpdateObjectVisibility(&*obj); } template<class T>@@ -856,12 +861,7 @@ RemoveFromGrid(player,grid,cell); player->RemoveFromWorld(); - cell.data.Part.reserved = ALL_DISTRICT;- MaNGOS::NotVisibleNotifier notifier(*player);- TypeContainerVisitor<MaNGOS::NotVisibleNotifier, WorldTypeMapContainer > player_notifier(notifier);- CellLock<ReadGuard> cell_lock(cell, p);- cell_lock->Visit(cell_lock, player_notifier, *this);- notifier.Notify();+ ObjectAccessor::UpdateVisibilityFor(player); if( remove ) DeleteFromWorld(player);@@ -903,16 +903,9 @@ assert( grid != NULL ); RemoveFromGrid(obj,grid,cell);+ obj->RemoveFromWorld(); - {- Cell cell = RedZone::GetZone(p);- cell.data.Part.reserved = ALL_DISTRICT;- cell.SetNoCreate(); // not create cells at object remove- MaNGOS::ObjectNotVisibleNotifier notifier(*static_cast<WorldObject *>(obj));- TypeContainerVisitor<MaNGOS::ObjectNotVisibleNotifier, WorldTypeMapContainer > player_notifier(notifier);- CellLock<ReadGuard> cell_lock(cell, p);- cell_lock->Visit(cell_lock, player_notifier, *this);- }+ ObjectAccessor::UpdateObjectVisibility(obj); if( remove ) {@@ -943,15 +936,9 @@ assert( grid != NULL ); RemoveFromGrid(obj,grid,cell);+ obj->RemoveFromWorld(); - {- Cell cell = RedZone::GetZone(p);- cell.data.Part.reserved = ALL_DISTRICT;- MaNGOS::ObjectNotVisibleNotifier notifier(*static_cast<WorldObject *>(&*obj));- TypeContainerVisitor<MaNGOS::ObjectNotVisibleNotifier, WorldTypeMapContainer > player_notifier(notifier);- CellLock<ReadGuard> cell_lock(cell, p);- cell_lock->Visit(cell_lock, player_notifier, *this);- }+ ObjectAccessor::UpdateObjectVisibility(&*obj); if( remove ) {@@ -963,7 +950,7 @@ } void-Map::PlayerRelocation(Player *player, float x, float y, float z, float orientation, bool visibilityChanges )+Map::PlayerRelocation(Player *player, float x, float y, float z, float orientation) { assert(player); @@ -973,7 +960,9 @@ Cell old_cell = RedZone::GetZone(old_val); Cell new_cell = RedZone::GetZone(new_val); new_cell |= old_cell;+ bool same_point = (x==player->GetPositionX() && y==player->GetPositionY() && z==player->GetPositionZ()); bool same_cell = (new_cell == old_cell);+ player->Relocate(x, y, z, orientation); if( old_cell.DiffGrid(new_cell) || old_cell.DiffCell(new_cell) )@@ -995,54 +984,24 @@ EnsureGridLoadedForPlayer(new_cell, player, true); } - CellLock<ReadGuard> cell_lock(new_cell, new_val);+ // if move then update what player see and who seen+ if(!same_point)+ ObjectAccessor::UpdateVisibilityFor(player); - MaNGOS::VisibleNotifier notifier(*player);-- if( !same_cell || player->IsBeingTeleported() ) {- if( player->IsBeingTeleported() )- new_cell.data.Part.reserved = ALL_DISTRICT;+ CellLock<ReadGuard> cell_lock(new_cell, new_val);+ MaNGOS::PlayerRelocationNotifier relocationNotifier(*player);+ new_cell.data.Part.reserved = ALL_DISTRICT; - TypeContainerVisitor<MaNGOS::VisibleNotifier, WorldTypeMapContainer > world_object_notifier(notifier);- TypeContainerVisitor<MaNGOS::VisibleNotifier, GridTypeMapContainer > grid_object_notifier(notifier);+ TypeContainerVisitor<MaNGOS::PlayerRelocationNotifier, GridTypeMapContainer > p2grid_relocation(relocationNotifier);+ TypeContainerVisitor<MaNGOS::PlayerRelocationNotifier, WorldTypeMapContainer > p2world_relocation(relocationNotifier); - cell_lock->Visit(cell_lock, world_object_notifier, *this);- cell_lock->Visit(cell_lock, grid_object_notifier, *this);-- notifier.Notify();+ cell_lock->Visit(cell_lock, p2grid_relocation, *this);+ cell_lock->Visit(cell_lock, p2world_relocation, *this); } - MaNGOS::PlayerRelocationNotifier relocationNotifier(*player);- new_cell.data.Part.reserved = ALL_DISTRICT;-- TypeContainerVisitor<MaNGOS::PlayerRelocationNotifier, GridTypeMapContainer > p2grid_relocation(relocationNotifier);- TypeContainerVisitor<MaNGOS::PlayerRelocationNotifier, WorldTypeMapContainer > p2world_relocation(relocationNotifier);-- cell_lock->Visit(cell_lock, p2grid_relocation, *this);- cell_lock->Visit(cell_lock, p2world_relocation, *this);-- if (visibilityChanges)- {- MaNGOS::VisibleChangesNotifier visualChangesNotifier(*player);- TypeContainerVisitor<MaNGOS::VisibleChangesNotifier, WorldTypeMapContainer > player_Vnotifier(visualChangesNotifier);- cell_lock->Visit(cell_lock, player_Vnotifier, *this);- }-- if( same_cell )- return;-- MaNGOS::NotVisibleNotifier notifier2(*player);- TypeContainerVisitor<MaNGOS::NotVisibleNotifier, WorldTypeMapContainer > world_object_notifier2(notifier2);- TypeContainerVisitor<MaNGOS::NotVisibleNotifier, GridTypeMapContainer > grid_object_notifier2(notifier2);-- cell_lock = CellLock<ReadGuard>(old_cell, old_val);-- cell_lock->Visit(cell_lock, world_object_notifier2, *this);- cell_lock->Visit(cell_lock, grid_object_notifier2, *this);-- i_grids[new_cell.GridX()][new_cell.GridY()]->SetGridState(GRID_STATE_ACTIVE);- notifier2.Notify();+ if( !same_cell )+ i_grids[new_cell.GridX()][new_cell.GridY()]->SetGridState(GRID_STATE_ACTIVE); } void@@ -1075,6 +1034,8 @@ void Map::CreatureRelocationNotifying(Creature *creature, Cell new_cell, CellPair new_val) {+ ObjectAccessor::UpdateObjectVisibility(creature);+ if( !creature->hasUnitState(UNIT_STAT_CHASE | UNIT_STAT_SEARCHING | UNIT_STAT_FLEEING)) { CellLock<ReadGuard> cell_lock(new_cell, new_val);Index: src/game/Map.h===================================================================--- src/game/Map.h (revision 3877)+++ src/game/Map.h (working copy)@@ -117,7 +117,7 @@ void MessageBoardcast(WorldObject *, WorldPacket *); - void PlayerRelocation(Player *, float x, float y, float z, float angl, bool visibilityChanges = false);+ void PlayerRelocation(Player *, float x, float y, float z, float angl); void CreatureRelocation(Creature *creature, float x, float y, float, float); @@ -215,7 +215,6 @@ bool loaded(const GridPair &) const; void EnsureGridLoadedForPlayer(const Cell&, Player*, bool add_player);- void NotifyPlayerVisibility(const Cell &, const CellPair &, Player *); uint64 EnsureGridCreated(const GridPair &); template<class T> void AddType(T *obj);Index: src/game/MovementHandler.cpp===================================================================--- src/game/MovementHandler.cpp (revision 3877)+++ src/game/MovementHandler.cpp (working copy)@@ -32,7 +32,7 @@ { sLog.outDebug( "WORLD: got MSG_MOVE_WORLDPORT_ACK." ); - GetPlayer()->RemoveFromWorld();+ MapManager::Instance().GetMap(GetPlayer()->GetMapId(), GetPlayer())->Remove(GetPlayer(),false); MapManager::Instance().GetMap(GetPlayer()->GetMapId(), GetPlayer())->Add(GetPlayer()); WorldPacket data(SMSG_SET_REST_START, 4); data << uint32(time(NULL));//getMSTime();Index: src/game/Object.h===================================================================--- src/game/Object.h (revision 3877)+++ src/game/Object.h (working copy)@@ -31,8 +31,12 @@ #define M_PI 3.14159265358979323846 #endif -#define OBJECT_CONTACT_DISTANCE 0.5+#define OBJECT_CONTACT_DISTANCE 0.5 #define OBJECT_ITERACTION_DISTANCE 5+#define OBJECT_ATTACK_DIST 5+#define OBJECT_DETECT_DISTANCE 20 // max distance to successful detect invisible unit+#define MAX_OBJECT_VISIBLE_DISTANCE (SIZE_OF_GRID_CELL) // max distance for visible object show, limited by active zone for player based at cell size+#define OBJECT_VISIBLE_DISTANCE (SIZE_OF_GRID_CELL) // default visible distance enum TYPE {@@ -296,6 +300,7 @@ uint32 GetInstanceId() const { return m_InstanceId; } void SetInstanceId(uint32 val) { m_InstanceId = val; } + virtual bool isVisibleFor(Player const* u) const =0; protected: WorldObject( WorldObject *instantiator ); Index: src/game/ObjectAccessor.cpp===================================================================--- src/game/ObjectAccessor.cpp (revision 3877)+++ src/game/ObjectAccessor.cpp (working copy)@@ -76,37 +76,6 @@ template<class SKIP> void Visit(std::map<OBJECT_HANDLE, SKIP *> &) {} template<class SKIP> void Visit(std::map<OBJECT_HANDLE, CountedPtr<SKIP> > &) {} };-- struct MANGOS_DLL_DECL CreatureCorpseViewRemover- {- Creature &i_creature;- CreatureCorpseViewRemover(Creature &c) : i_creature(c) {}-- void Visit(PlayerMapType &m)- {- for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)- i_creature.DestroyForPlayer(iter->second);- }-- template<class SKIP> void Visit(std::map<OBJECT_HANDLE, SKIP *> &) {}- template<class SKIP> void Visit(std::map<OBJECT_HANDLE, CountedPtr<SKIP> > &) {}- };-- struct MANGOS_DLL_DECL BonesViewRemover- {- CorpsePtr i_objects;-- BonesViewRemover(CorpsePtr& corpse) : i_objects(corpse) {}- - void Visit(PlayerMapType &m)- {- for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)- i_objects->DestroyForPlayer(iter->second);- }- - template<class SKIP> void Visit(std::map<OBJECT_HANDLE, SKIP *> &) {}- template<class SKIP> void Visit(std::map<OBJECT_HANDLE, CountedPtr<SKIP> > &) {}- }; } ObjectAccessor::ObjectAccessor() {}@@ -423,9 +392,6 @@ void ObjectAccessor::_buildPacket(Player *pl, Object *obj, UpdateDataMapType &update_players) {- if(obj->isType(TYPE_UNIT) && !((Unit*)obj)->isVisibleFor(pl,false))- return;- UpdateDataMapType::iterator iter = update_players.find(pl); if( iter == update_players.end() )@@ -445,8 +411,8 @@ Cell cell = RedZone::GetZone(p); cell.data.Part.reserved = ALL_DISTRICT; cell.SetNoCreate();- ObjectChangeAccumulator notifier(*obj, update_players);- TypeContainerVisitor<ObjectChangeAccumulator, WorldTypeMapContainer > player_notifier(notifier);+ WorldObjectChangeAccumulator notifier(*obj, update_players);+ TypeContainerVisitor<WorldObjectChangeAccumulator, WorldTypeMapContainer > player_notifier(notifier); CellLock<GridReadGuard> cell_lock(cell, p); cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(obj->GetMapId(), obj)); }@@ -662,34 +628,156 @@ } void-ObjectAccessor::ObjectChangeAccumulator::Visit(PlayerMapType &m)+ObjectAccessor::WorldObjectChangeAccumulator::Visit(PlayerMapType &m) { for(PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter)- ObjectAccessor::_buildPacket(iter->second, &i_object, i_updateDatas);+ if(i_object.isVisibleFor(iter->second))+ ObjectAccessor::_buildPacket(iter->second, &i_object, i_updateDatas); } +struct VisibleChangesNotifier+{+ WorldObject &i_object;++ explicit VisibleChangesNotifier(WorldObject &object) : i_object(object) {}+ template<class T> void Visit(std::map<OBJECT_HANDLE, T *> &m) {}+ template<class T> void Visit(std::map<OBJECT_HANDLE, CountedPtr<T> > &m) {}+ void Visit(PlayerMapType &);+};+ void-ObjectAccessor::RemoveCreatureCorpseFromPlayerView(Creature *c)+VisibleChangesNotifier::Visit(PlayerMapType &m) {- MaNGOS::CreatureCorpseViewRemover remover(*c);- TypeContainerVisitor<MaNGOS::CreatureCorpseViewRemover, WorldTypeMapContainer > player_notifier(remover);- CellPair p = MaNGOS::ComputeCellPair(c->GetPositionX(), c->GetPositionY());+ for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)+ {+ if(iter->second == &i_object)+ continue;++ iter->second->UpdateVisibilityOf(&i_object);+ }+}++void+ObjectAccessor::UpdateObjectVisibility(WorldObject *obj)+{+ CellPair p = MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); Cell cell = RedZone::GetZone(p);+ cell.data.Part.reserved = ALL_DISTRICT; cell.SetNoCreate();- cell.data.Part.reserved = ALL_DISTRICT;+ VisibleChangesNotifier notifier(*obj);+ TypeContainerVisitor<VisibleChangesNotifier, WorldTypeMapContainer > player_notifier(notifier); CellLock<GridReadGuard> cell_lock(cell, p);- cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(c->GetMapId(), c));+ cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(obj->GetMapId(), obj)); } +struct VisibleNotifier+{+ Player &i_player;+ UpdateData i_data;+ UpdateDataMapType i_data_updates;+ Player::ClientGUIDs i_clientGUIDs;++ explicit VisibleNotifier(Player &player) : i_player(player),i_clientGUIDs(player.m_clientGUIDs) {}+ template<class T> void Visit(std::map<OBJECT_HANDLE, T *> &m);+ template<class T> void Visit(std::map<OBJECT_HANDLE, CountedPtr<T> > &m);+ void Visit(PlayerMapType &);+ void Notify(void);+};++inline void+VisibleNotifier::Visit(PlayerMapType &m)+{+ for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)+ {+ if( iter->second == &i_player )+ continue;++ iter->second->UpdateVisibilityOf(&i_player);+ i_player.UpdateVisibilityOf(iter->second,i_data,i_data_updates);+ i_clientGUIDs.erase(iter->second->GetGUID());+ }+}++template<class T>+inline void+VisibleNotifier::Visit(std::map<OBJECT_HANDLE, T *> &m)+{+ for(typename std::map<OBJECT_HANDLE, T *>::iterator iter=m.begin(); iter != m.end(); ++iter)+ {+ i_player.UpdateVisibilityOf(iter->second,i_data,i_data_updates);+ i_clientGUIDs.erase(iter->second->GetGUID());+ }+}++template<class T>+inline void+VisibleNotifier::Visit(std::map<OBJECT_HANDLE, CountedPtr<T> > &m)+{+ for(typename std::map<OBJECT_HANDLE, CountedPtr<T> >::iterator iter=m.begin(); iter != m.end(); ++iter)+ {+ i_player.UpdateVisibilityOf(&*iter->second,i_data,i_data_updates);+ i_clientGUIDs.erase(iter->second->GetGUID());+ }+}+ void-ObjectAccessor::RemoveBonesFromPlayerView(CorpsePtr& corpse)+VisibleNotifier::Notify() {- MaNGOS::BonesViewRemover remover(corpse);- TypeContainerVisitor<MaNGOS::BonesViewRemover, WorldTypeMapContainer > player_notifier(remover);- CellPair p = MaNGOS::ComputeCellPair(corpse->GetPositionX(), corpse->GetPositionY());+ // generate outOfRange for not iterate objects+ i_data.AddOutOfRangeGUID(i_clientGUIDs);+ for(Player::ClientGUIDs::iterator itr = i_clientGUIDs.begin();itr!=i_clientGUIDs.end();++itr)+ i_player.m_clientGUIDs.erase(*itr);++ // send update to other players (except player updates that already sent using SendUpdateToPlayer)+ for(UpdateDataMapType::iterator iter = i_data_updates.begin(); iter != i_data_updates.end(); ++iter)+ {+ if(iter->first==&i_player)+ continue;++ WorldPacket packet;+ iter->second.BuildPacket(&packet);+ iter->first->GetSession()->SendPacket(&packet);+ }++ if( i_data.HasData() )+ {+ // send out of range to other players if need+ std::set<uint64> const& oor = i_data.GetOutOfRangeGUIDs();+ for(std::set<uint64>::const_iterator iter = oor.begin(); iter != oor.end(); ++iter)+ {+ if(GUID_HIPART(*iter)!=HIGHGUID_PLAYER)+ continue;++ Player* plr = ObjectAccessor::Instance().GetPlayer(i_player,*iter);+ if(plr)+ plr->UpdateVisibilityOf(&i_player);+ }++ // send create/outofrange packet to player (except player create updates that already sent using SendUpdateToPlayer)+ WorldPacket packet;+ i_data.BuildPacket(&packet);+ i_player.GetSession()->SendPacket(&packet);++ // all object visible to i_player is updated/(create updated)+ }+}++void+ObjectAccessor::UpdateVisibilityFor(Player *player)+{+ VisibleNotifier notifier(*player);++ // current position list+ CellPair p = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); Cell cell = RedZone::GetZone(p);+ cell.data.Part.reserved = ALL_DISTRICT; cell.SetNoCreate();- cell.data.Part.reserved = ALL_DISTRICT;+ TypeContainerVisitor<VisibleNotifier, WorldTypeMapContainer > world_notifier(notifier);+ TypeContainerVisitor<VisibleNotifier, GridTypeMapContainer > grid_notifier(notifier); CellLock<GridReadGuard> cell_lock(cell, p);- cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(corpse->GetMapId(), &(*corpse)));+ cell_lock->Visit(cell_lock, world_notifier, *MapManager::Instance().GetMap(player->GetMapId(), player));+ cell_lock->Visit(cell_lock, grid_notifier, *MapManager::Instance().GetMap(player->GetMapId(), player));++ // send data+ notifier.Notify(); }Index: src/game/ObjectAccessor.h===================================================================--- src/game/ObjectAccessor.h (revision 3877)+++ src/game/ObjectAccessor.h (working copy)@@ -81,9 +81,6 @@ void DoDelayedMovesAndRemoves(); - void RemoveCreatureCorpseFromPlayerView(Creature *);- void RemoveBonesFromPlayerView(CorpsePtr&);- void Update(const uint32 &diff); CorpsePtr& GetCorpseForPlayerGUID(uint64 guid);@@ -100,21 +97,23 @@ bool PlayersNearGrid(const uint32 &x, const uint32 &y, const uint32 &m_id, const uint32 &i_id) const; static void UpdateObject(Object* obj, Player* exceptPlayer);- static void _buildUpdateObject(Object *, UpdateDataMapType &);+ static void _buildUpdateObject(Object* obj, UpdateDataMapType &);+ static void UpdateObjectVisibility(WorldObject* obj);+ static void UpdateVisibilityFor(Player* player); private: void RemoveAllObjectsInRemoveList(); - struct ObjectChangeAccumulator+ struct WorldObjectChangeAccumulator { UpdateDataMapType &i_updateDatas;- Object &i_object;- ObjectChangeAccumulator(Object &obj, UpdateDataMapType &d) : i_updateDatas(d), i_object(obj) {}+ WorldObject &i_object;+ WorldObjectChangeAccumulator(WorldObject &obj, UpdateDataMapType &d) : i_updateDatas(d), i_object(obj) {} void Visit(PlayerMapType &); template<class SKIP> void Visit(std::map<OBJECT_HANDLE, SKIP *> &) {} template<class SKIP> void Visit(std::map<OBJECT_HANDLE, CountedPtr<SKIP> > &) {} }; - friend struct ObjectChangeAccumulator;+ friend struct WorldObjectChangeAccumulator; PlayersMapType i_players; PetsMapType i_pets; Player2CorpsesMapType i_player2corpse;Index: src/game/PetAI.cpp===================================================================--- src/game/PetAI.cpp (revision 3877)+++ src/game/PetAI.cpp (working copy)@@ -179,7 +179,7 @@ _stopAttack(); // i_victimGuid == 0 && i_pet.getVictim() == NULL now return; }- else if( i_pet.IsStopped() || i_pet.IsWithinDistInMap(i_pet.getVictim(), ATTACK_DIST))+ else if( i_pet.IsStopped() || i_pet.IsWithinDistInMap(i_pet.getVictim(), OBJECT_ATTACK_DIST)) { SpellEntry const* spellInfo; // required to be stopped casesIndex: src/game/Player.cpp===================================================================--- src/game/Player.cpp (revision 3877)+++ src/game/Player.cpp (working copy)@@ -36,6 +36,10 @@ #include "Chat.h" #include "MapManager.h" #include "MapInstanced.h"+#include "RedZoneDistrict.h"+#include "GridNotifiers.h"+#include "GridNotifiersImpl.h"+#include "CellImpl.h" #include "ObjectMgr.h" #include "ObjectAccessor.h" #include "CreatureAI.h"@@ -160,8 +164,6 @@ m_resurrectingSicknessExpire = 0; m_DetectInvTimer = 1000;- m_DiscoveredPj = 0;- m_enableDetect = true; m_bgBattleGroundID = 0; m_bgBattleGroundQueueID = 0;@@ -755,7 +757,7 @@ // default combat reach 10 // TODO add weapon,skill check - float pldistance = ATTACK_DIST;+ float pldistance = OBJECT_ATTACK_DIST; if (isAttackReady(BASE_ATTACK)) {@@ -908,7 +910,7 @@ if (p_time >= m_DetectInvTimer) { m_DetectInvTimer = 3000;- HandleInvisiblePjs();+ HandleInvisibleUnitsDetection(); } else m_DetectInvTimer -= p_time;@@ -1288,18 +1290,10 @@ if(!InBattleGround() && mEntry->map_type == MAP_BATTLEGROUND && !GetSession()->GetSecurity()) return; - QueryResult *result = loginDatabase.PQuery("SELECT `tbc` FROM `account` WHERE `id`='%u'", GetSession()->GetAccountId());-- if(!result)- return; // unknown client or error-- Field *fields = result->Fetch();- uint32 not_tbc_map = 0x10; // if any problems, then check 0x80000 also... // with 0x80000 we can teleport to Kharazan with normal client // with 0x10 we can't teleport to Kharazan with normal client- bool tbc = (fields[0].GetUInt8()) && sWorld.getConfig(CONFIG_EXPANSION);- delete result;+ bool tbc = GetSession()->IsTBC() && sWorld.getConfig(CONFIG_EXPANSION); if(!tbc && (mEntry->map_flag & not_tbc_map) == 0) // normal client and TBC map {@@ -1457,14 +1451,6 @@ { CombatStop(); - // remove selection- if(GetSelection())- {- Unit* unit = ObjectAccessor::Instance().GetUnit(*this, GetSelection());- if(unit)- SendOutOfRange(unit);- }- // unsummon pet if lost if(pet && !IsWithinDistInMap(pet, OWNER_MAX_DISTANCE)) RemovePet(pet, PET_SAVE_NOT_IN_SLOT);@@ -2059,6 +2045,13 @@ SetResistanceBuffMods(SpellSchools(i), false, 0); } + //clear mana draining field+ if (GetUInt32Value(UNIT_FIELD_POWER_COST_MODIFIER) != 0)+ {+ sLog.outError("Removing power cost draining/increasing for player : %u name : %s", GetGUIDLow(), m_name.c_str());+ SetUInt32Value(UNIT_FIELD_POWER_COST_MODIFIER,0);+ }+ InitDataForForm(); // save new stats@@ -2068,13 +2061,6 @@ SetMaxPower(POWER_FOCUS, 0 ); SetMaxPower(POWER_HAPPINESS, 0 ); - //clear power draining field- if (GetUInt32Value(UNIT_FIELD_POWER_COST_MODIFIER) != 0)- {- sLog.outError("Removing power cost draining/increasing for player : %u name : %s", GetGUIDLow(), m_name.c_str());- SetUInt32Value(UNIT_FIELD_POWER_COST_MODIFIER,0);- }- SetMaxHealth(info.health); // cleanup mounted state (it will set correctly at aura loading if player saved at mount.@@ -3301,6 +3287,9 @@ // dead player body showed at this moment, corpse will be show at Player ghost repop CreateCorpse();++ // update visibility+ ObjectAccessor::UpdateObjectVisibility(this); } void Player::CreateCorpse()@@ -4275,8 +4264,6 @@ if( old_x != x || old_y != y || old_r != orientation) {- m->PlayerRelocation(this, x, y, z, orientation);- // remove at movement non-move stealth aura if(HasFlag(UNIT_FIELD_BYTES_1,PLAYER_STATE_FLAG_STEALTH)) RemoveAurasDueToSpell(20580);@@ -4284,7 +4271,13 @@ // remove death simulation at move if(hasUnitState(UNIT_STAT_DIED)) RemoveSpellsCausingAura(SPELL_AURA_FEIGN_DEATH);++ // move and update visible state if need+ m->PlayerRelocation(this, x, y, z, orientation); }+ // or just update visibility for new place+ else+ ObjectAccessor::UpdateVisibilityFor(this); // reread after Map::Relocation m = MapManager::Instance().GetMap(GetMapId(), this);@@ -4840,7 +4833,7 @@ //How much honor Player gains from uVictim void Player::CalculateHonor(Unit *uVictim) {- if(!uVictim || uVictim->GetTypeId() == TYPEID_UNIT)+ if(!uVictim || uVictim == this || uVictim->GetTypeId() == TYPEID_UNIT) return; if(uVictim->GetAura(2479, 0)) return;@@ -12251,15 +12244,6 @@ /*** LOW LEVEL FUNCTIONS:Notifiers ***/ /*********************************************************/ -void Player::SendOutOfRange(Object* obj)-{- UpdateData his_data;- WorldPacket his_pk;- obj->BuildOutOfRangeUpdateBlock(&his_data);- his_data.BuildPacket(&his_pk);- GetSession()->SendPacket(&his_pk);-}- inline void Player::SendAttackSwingNotInRange() { WorldPacket data(SMSG_ATTACKSWING_NOTINRANGE, 0);@@ -12866,27 +12850,47 @@ SetUInt32Value(PLAYER_REST_STATE_EXPERIENCE, uint32(m_rest_bonus)); } -void Player::HandleInvisiblePjs()+void Player::HandleInvisibleUnitsDetection() {- Map *m = MapManager::Instance().GetMap(GetMapId(), this);+ std::list<Unit*> invisibleUnits; - //this is to be sure that InvisiblePjsNear vector has active pjs only.- m->PlayerRelocation(this, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation(), true);+ CellPair p(MaNGOS::ComputeCellPair(GetPositionX(),GetPositionY()));+ Cell cell = RedZone::GetZone(p);+ cell.data.Part.reserved = ALL_DISTRICT;+ cell.SetNoCreate(); - for (std::vector<Player *>::iterator i = InvisiblePjsNear.begin(); i != InvisiblePjsNear.end(); i++)+ MaNGOS::AnyDetectableInvisibleUnitCheck u_check;+ MaNGOS::UnitListSearcher<MaNGOS::AnyDetectableInvisibleUnitCheck > searcher(invisibleUnits, u_check);++ TypeContainerVisitor<MaNGOS::UnitListSearcher<MaNGOS::AnyDetectableInvisibleUnitCheck >, WorldTypeMapContainer > world_unit_searcher(searcher);+ TypeContainerVisitor<MaNGOS::UnitListSearcher<MaNGOS::AnyDetectableInvisibleUnitCheck >, GridTypeMapContainer > grid_unit_searcher(searcher);++ CellLock<GridReadGuard> cell_lock(cell, p);+ cell_lock->Visit(cell_lock, world_unit_searcher, *MapManager::Instance().GetMap(GetMapId(), this));+ cell_lock->Visit(cell_lock, grid_unit_searcher, *MapManager::Instance().GetMap(GetMapId(), this));++ for (std::list<Unit*>::iterator i = invisibleUnits.begin(); i != invisibleUnits.end();) {+ if((*i)==this)+ {+ i = invisibleUnits.erase(i);+ continue;+ }+ if ((*i)->isVisibleFor(this,true)) {- m_DiscoveredPj = *i;- m_enableDetect = false;- m->PlayerRelocation(this, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation(), true);- m_enableDetect = true;- m_DiscoveredPj = 0;++ (*i)->SendUpdateToPlayer(this);+ m_clientGUIDs.insert((*i)->GetGUID());+ i = invisibleUnits.erase(i);+ continue; }++ ++i; }- if (!InvisiblePjsNear.size())++ if(invisibleUnits.empty()) m_DetectInvTimer = 0;- InvisiblePjsNear.clear(); } bool Player::ActivateTaxiPathTo(std::vector<uint32> const& nodes)@@ -13639,3 +13643,81 @@ } return false; }++bool Player::IsVisibleInGridForPlayer( Player* pl ) const+{+ // Live player see live player or dead player with not realised corpse+ if(pl->isAlive() || pl->m_deathTimer > 0)+ {+ return isAlive() || m_deathTimer > 0;+ }++ // Dead player see live players near own corpse+ if(isAlive())+ {+ CorpsePtr &corpse = pl->GetCorpse();+ if(corpse)+ {+ // 20 - aggro distance for same level, 25 - max additional distance if player level less that creature level+ if(corpse->IsWithinDistInMap(this,(20+25)*sWorld.getRate(RATE_CREATURE_AGGRO)))+ return true;+ }+ }++ // and not see any other+ return false;+}++void Player::UpdateVisibilityOf(WorldObject* target)+{+ if(HaveAtClient(target))+ {+ if(!target->isVisibleFor(this))+ {+ target->DestroyForPlayer(this);+ m_clientGUIDs.erase(target->GetGUID());++ // activate invisibility detection system+ if(m_DetectInvTimer==0 && target->isType(TYPE_UNIT) && (+ ((Unit*)target)->GetVisibility()==VISIBILITY_GROUP || + ((Unit*)target)->GetVisibility()==VISIBILITY_GROUP_NO_DETECT ) )+ m_DetectInvTimer = 1;+ }+ }+ else+ {+ if(target->isVisibleFor(this))+ {+ target->SendUpdateToPlayer(this);+ m_clientGUIDs.insert(target->GetGUID());++ }+ }+}++void Player::UpdateVisibilityOf(WorldObject* target, UpdateData& data, UpdateDataMapType& data_updates)+{+ if(HaveAtClient(target))+ {+ if(!target->isVisibleFor(this))+ {+ target->BuildOutOfRangeUpdateBlock(&data);+ m_clientGUIDs.erase(target->GetGUID());++ // activate invisibility detection system+ if(m_DetectInvTimer==0 && target->isType(TYPE_UNIT) && (+ ((Unit*)target)->GetVisibility()==VISIBILITY_GROUP || + ((Unit*)target)->GetVisibility()==VISIBILITY_GROUP_NO_DETECT ) )+ m_DetectInvTimer = 1;+ }+ }+ else+ {+ if(target->isVisibleFor(this))+ {+ target->BuildUpdate(data_updates);+ target->BuildCreateUpdateBlockForPlayer(&data, this);+ m_clientGUIDs.insert(target->GetGUID());+ }+ }+}Index: src/game/Player.h===================================================================--- src/game/Player.h (revision 3877)+++ src/game/Player.h (working copy)@@ -1138,7 +1138,6 @@ void DestroyForPlayer( Player *target ) const; void SendDelayResponse(const uint32); void SendLogXPGain(uint32 GivenXP,Unit* victim,uint32 RestXP);- void SendOutOfRange(Object* obj); //Low Level Packets void PlaySound(uint32 Sound, bool OnlySelf);@@ -1369,12 +1368,20 @@ float m_homebindY; float m_homebindZ; + // currently visible objects at player client + typedef std::set<uint64> ClientGUIDs;+ ClientGUIDs m_clientGUIDs;++ bool HaveAtClient(WorldObject const* u) { return m_clientGUIDs.find(u->GetGUID())!=m_clientGUIDs.end(); }++ bool IsVisibleInGridForPlayer(Player* pl) const;++ void UpdateVisibilityOf(WorldObject* target);+ void UpdateVisibilityOf(WorldObject* target, UpdateData& data, UpdateDataMapType& data_updates);+ // Invisibility and detection system- std::vector<Player *> InvisiblePjsNear;- Player* m_DiscoveredPj; uint32 m_DetectInvTimer;- void HandleInvisiblePjs();- bool m_enableDetect;+ void HandleInvisibleUnitsDetection(); void ApplySpeedMod(UnitMoveType mtype, float rate, bool forced, bool apply); // overwrite Unit versionIndex: src/game/ReactorAI.cpp===================================================================--- src/game/ReactorAI.cpp (revision 3877)+++ src/game/ReactorAI.cpp (working copy)@@ -99,7 +99,7 @@ return; } - if( i_creature.IsWithinDistInMap(i_creature.getVictim(), ATTACK_DIST))+ if( i_creature.IsWithinDistInMap(i_creature.getVictim(), OBJECT_ATTACK_DIST)) { if( i_creature.isAttackReady() ) {Index: src/game/SpellAuras.cpp===================================================================--- src/game/SpellAuras.cpp (revision 3877)+++ src/game/SpellAuras.cpp (working copy)@@ -35,8 +35,6 @@ #include "UpdateData.h" #include "MapManager.h" #include "ObjectAccessor.h"-#include "RedZoneDistrict.h"-#include "CellImpl.h" #include "Policies/SingletonImp.h" #include "Totem.h" #include "Creature.h"@@ -2017,10 +2015,16 @@ // only at real aura add if(Real) {- m_target->SetVisibility(VISIBILITY_GROUP);+ m_target->SetVisibility(VISIBILITY_GROUP_NO_DETECT); if(m_target->GetTypeId() == TYPEID_PLAYER)+ { m_target->SendUpdateToPlayer((Player*)m_target); + // notify other players+ ObjectAccessor::UpdateObjectVisibility(m_target);+ }+ m_target->SetVisibility(VISIBILITY_GROUP);+ // for RACE_NIGHTELF stealth if(m_target->GetTypeId()==TYPEID_PLAYER && GetId()==20580) {@@ -2075,9 +2079,15 @@ // only at real aura add if(Real) {- m_target->SetVisibility(VISIBILITY_GROUP);+ m_target->SetVisibility(VISIBILITY_GROUP_NO_DETECT); if(m_target->GetTypeId() == TYPEID_PLAYER)+ { m_target->SendUpdateToPlayer((Player*)m_target);++ // notify other players+ ObjectAccessor::UpdateObjectVisibility(m_target);+ }+ m_target->SetVisibility(VISIBILITY_GROUP); } } elseIndex: src/game/SpellEffects.cpp===================================================================--- src/game/SpellEffects.cpp (revision 3879)+++ src/game/SpellEffects.cpp (working copy)@@ -1932,8 +1932,8 @@ pet->AddToWorld(); MapManager::Instance().GetMap(pet->GetMapId(), pet)->Add((Creature*)pet); - ObjectAccessor::Instance().RemoveCreatureCorpseFromPlayerView(creatureTarget); creatureTarget->setDeathState(JUST_DIED);+ ObjectAccessor::UpdateObjectVisibility(creatureTarget); if(m_caster->GetTypeId() == TYPEID_PLAYER) {Index: src/game/TargetedMovementGenerator.cpp===================================================================--- src/game/TargetedMovementGenerator.cpp (revision 3877)+++ src/game/TargetedMovementGenerator.cpp (working copy)@@ -144,72 +144,6 @@ owner.Attack(&i_target); } }- /*-- //SpellEntry* spellInfo;- if( reach )- {- if( owner.GetDistance2dSq( &i_target ) > 0.0f )- {- DEBUG_LOG("MOVEMENT : Distance = %f",owner.GetDistance2dSq( &i_target ));- owner.addUnitState(UNIT_STAT_CHASE);- _setTargetLocation(owner, 0);- }- else if ( !owner.HasInArc( 0.0f, &i_target ) )- {- DEBUG_LOG("MOVEMENT : Orientation = %f",owner.GetAngle(&i_target));- owner.SetInFront(&i_target);- if( i_target.GetTypeId() == TYPEID_PLAYER )- owner.SendUpdateToPlayer( (Player*)&i_target );- }- if( !owner.isInCombat() )- {- owner.AIM_Initialize();- return;- }- }- else if( i_target.isAlive() )- {- if( !owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.isInCombat() )- {- if( spellInfo = owner.reachWithSpellAttack( &i_target ) )- {- _spellAtack(owner, spellInfo);- return;- }- }- if( owner.GetDistance2dSq( &i_target ) > 0.0f )- {- DEBUG_LOG("MOVEMENT : Distance = %f",owner.GetDistance2dSq( &i_target ));- owner.addUnitState(UNIT_STAT_CHASE);- _setTargetLocation(owner, 0);- }- }- else if( !i_targetedHome )- {- if( !owner.hasUnitState(UNIT_STAT_FOLLOW) && owner.isInCombat() && (spellInfo = owner.reachWithSpellAttack(&i_target)) )- {- _spellAtack(owner, spellInfo);- return;- }- _setTargetLocation(owner, 0);- if(reach)- {- if( reach && owner.canReachWithAttack(&i_target) )- {- owner.StopMoving();- if(!owner.hasUnitState(UNIT_STAT_FOLLOW))- owner.Attack(&i_target);- owner.clearUnitState(UNIT_STAT_CHASE);- DEBUG_LOG("UNIT IS THERE");- }- else- {- _setTargetLocation(owner, 0);- DEBUG_LOG("Continue to chase");- }- }- }*/ return true; } Index: src/game/Unit.cpp===================================================================--- src/game/Unit.cpp (revision 3877)+++ src/game/Unit.cpp (working copy)@@ -82,7 +82,6 @@ waterbreath = false; m_Visibility = VISIBILITY_ON;- m_UpdateVisibility = VISIBLE_NOCHANGES; m_detectStealth = 0; m_stealthvalue = 0;@@ -448,9 +447,12 @@ // self or owner of pet if(player) {- player->CalculateHonor(pVictim);+ if(player!=pVictim)+ {+ player->CalculateHonor(pVictim); - player->CalculateReputation(pVictim);+ player->CalculateReputation(pVictim);+ } if(!PvP) {@@ -2124,7 +2126,7 @@ } } -bool Unit::isInFront(Unit const* target, float radius)+bool Unit::isInFront(Unit const* target, float radius) const { return IsWithinDistInMap(target, radius) && HasInArc( M_PI, target ); }@@ -4931,19 +4933,61 @@ return gain; } -bool Unit::isVisibleFor(Unit* u, bool detect)+bool Unit::isVisibleFor(Unit const* u, bool detect) const { if(!u) return false; + // Always can see self+ if (u==this)+ return true;++ // not in world+ if(!IsInWorld() || !u->IsInWorld())+ return false;++ // different visible distance check+ if(!isAlive())+ {+ if (!this->IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()))+ return false;+ }+ if(GetTypeId()==TYPEID_PLAYER)+ {+ // Units far than MAX_DIST_INVISIBLE or not in our map are not visible too+ if (!this->IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()))+ return false;+ }+ else+ {+ // Units far than MAX_DIST_INVISIBLE or not in our map are not visible too+ if (!this->IsWithinDistInMap(u,World::GetMaxVisibleDistanceForCreature()))+ return false;+ }+++ // Grid dead/alive checks+ if( u->GetTypeId()==TYPEID_PLAYER)+ {+ // non visible at grid for any stealth state+ if(!IsVisibleInGridForPlayer((Player *)u))+ return false;++ // if player is dead then he can't detect anyone in anycases+ if(!u->isAlive())+ detect = false;+ }+ else+ {+ // all dead creatures/players not visible for any creatures+ if(!u->isAlive() || !isAlive())+ return false;+ }+ // Visible units, always are visible for all pjs if (m_Visibility == VISIBILITY_ON) return true; - // Always can see self- if (u==this)- return true;- // GMs are visible for higher gms (or players are visible for gms) if (u->GetTypeId() == TYPEID_PLAYER && ((Player *)u)->isGameMaster()) return (GetTypeId() == TYPEID_PLAYER && ((Player *)this)->GetSession()->GetSecurity() <= ((Player *)u)->GetSession()->GetSecurity());@@ -4952,10 +4996,6 @@ if (m_Visibility == VISIBILITY_OFF) return false; - // Units far than MAX_DIST_INVISIBLE or not in our map, that are not gms and are stealth, are not visibles too- if (!this->IsWithinDistInMap(u,MAX_DIST_INVISIBLE_UNIT))- return false;- // Stealth not hostile units, not visibles (except Player-with-Player case) if (!u->IsHostileTo(this)) {@@ -4971,12 +5011,20 @@ return true; } + // unit got in stealth in this moment and must ignore old detected state+ if (m_Visibility == VISIBILITY_GROUP_NO_DETECT)+ return false;++ // invisible and detected+ if (u->GetTypeId() == TYPEID_PLAYER && ((Player*)u)->HaveAtClient(this) )+ return true;+ // if in non-detect mode then invisible for unit if(!detect) return false; bool IsVisible = true;- bool notInFront = u->isInFront(this, MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT) ? 0 : 1;+ bool notInFront = u->isInFront(this, OBJECT_DETECT_DISTANCE * OBJECT_DETECT_DISTANCE) ? 0 : 1; float Distance = sqrt(GetDistanceSq(u)); float prob = 0; @@ -4999,33 +5047,23 @@ IsVisible = roll_chance_f(prob); - return IsVisible && ( Distance <= MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT) ;+ return IsVisible && ( Distance <= OBJECT_DETECT_DISTANCE * OBJECT_DETECT_DISTANCE) ; } +bool Unit::isVisibleFor(Player const* u) const+{+ return isVisibleFor(u,false);+}+ void Unit::SetVisibility(UnitVisibility x) { m_Visibility = x; - switch (x)- {- case VISIBILITY_ON:- m_UpdateVisibility = VISIBLE_SET_VISIBLE;- break;- case VISIBILITY_OFF:- m_UpdateVisibility = VISIBLE_SET_INVISIBLE;- break;- case VISIBILITY_GROUP:- m_UpdateVisibility = VISIBLE_SET_INVISIBLE_FOR_GROUP;- break;- } if(GetTypeId() == TYPEID_PLAYER && IsInWorld()) { Map *m = MapManager::Instance().GetMap(GetMapId(), this);- m->PlayerRelocation((Player *)this,GetPositionX(),GetPositionY(),- GetPositionZ(),GetOrientation(), true);+ m->PlayerRelocation((Player *)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); }-- m_UpdateVisibility = VISIBLE_NOCHANGES; } float Unit::GetSpeed( UnitMoveType mtype ) const@@ -5443,7 +5481,7 @@ Map* map = MapManager::Instance().GetMap(GetMapId(), this); if((map->Instanceable() || (!((Creature*)this)->IsOutOfThreatArea(target))) && target->isInAccessablePlaceFor( ((Creature*)this) )) {- if((IsWithinDistInMap(target, ATTACK_DIST) && (iter->Threat > 1.1f * threat)) || (iter->Threat > 1.3f * threat))+ if((IsWithinDistInMap(target, OBJECT_ATTACK_DIST) && (iter->Threat > 1.1f * threat)) || (iter->Threat > 1.3f * threat)) { //implement 110% threat rule for targets in melee range SetCurrentVictimThreat(iter->Threat); //and 130% rule for targets in ranged distances return target; //for selecting alive targetsIndex: src/game/Unit.h===================================================================--- src/game/Unit.h (revision 3877)+++ src/game/Unit.h (working copy)@@ -125,12 +125,6 @@ NULL_SLOT = 255 }; -enum Dist-{- MAX_DIST_INVISIBLE_UNIT = 20, // Max distance to be able to detect an invisible unit- ATTACK_DIST = 5-};- struct FactionTemplateEntry; struct Modifier; struct SpellEntry;@@ -221,19 +215,12 @@ SELF_DAMAGE = 5 }; -enum UnitVisibilityUpdate-{- VISIBLE_NOCHANGES = 0,- VISIBLE_SET_VISIBLE = 1,- VISIBLE_SET_INVISIBLE = 2,- VISIBLE_SET_INVISIBLE_FOR_GROUP = 3-};- enum UnitVisibility {- VISIBILITY_OFF = 0,- VISIBILITY_ON = 1,- VISIBILITY_GROUP = 2+ VISIBILITY_OFF = 0,+ VISIBILITY_ON = 1,+ VISIBILITY_GROUP = 2, // only detectable case+ VISIBILITY_GROUP_NO_DETECT = 3 // state just at invisibility apply for update Grid state }; // Value masks for UNIT_FIELD_FLAGS@@ -810,15 +797,15 @@ float m_threatModifier[MAX_SPELL_SCHOOL]; float m_modAttackSpeedPct[3]; - bool isInFront(Unit const* target,float distance);+ bool isInFront(Unit const* target,float distance) const; void SetInFront(Unit const* target); // Invisibility and detection system- UnitVisibility GetVisibility() {return m_Visibility;}- UnitVisibilityUpdate GetUpdateVisibility() { return m_UpdateVisibility; }+ UnitVisibility GetVisibility() const {return m_Visibility;} void SetVisibility(UnitVisibility x);- void SetUpdateVisibility(UnitVisibilityUpdate x) { m_UpdateVisibility = x; }- bool isVisibleFor(Unit* u, bool detect);+ bool isVisibleFor(Unit const* u, bool detect) const;+ bool isVisibleFor(Player const* u) const;+ virtual bool IsVisibleInGridForPlayer(Player* pl) const = 0; bool m_silenced; bool waterbreath;@@ -954,7 +941,6 @@ uint32 m_state; // Even derived shouldn't modify uint32 m_CombatTimer; - UnitVisibilityUpdate m_UpdateVisibility; UnitVisibility m_Visibility; Diminishing m_Diminishing;Index: src/game/UpdateData.cpp===================================================================--- src/game/UpdateData.cpp (revision 3877)+++ src/game/UpdateData.cpp (working copy)@@ -29,6 +29,11 @@ { } +void UpdateData::AddOutOfRangeGUID(std::set<uint64>& guids)+{+ m_outOfRangeGUIDs.insert(guids.begin(),guids.end());+}+ void UpdateData::AddOutOfRangeGUID(const uint64 &guid) { m_outOfRangeGUIDs.insert(guid);Index: src/game/UpdateData.h===================================================================--- src/game/UpdateData.h (revision 3877)+++ src/game/UpdateData.h (working copy)@@ -47,12 +47,15 @@ public: UpdateData(); + void AddOutOfRangeGUID(std::set<uint64>& guids); void AddOutOfRangeGUID(const uint64 &guid); void AddUpdateBlock(const ByteBuffer &block); bool BuildPacket(WorldPacket *packet); bool HasData() { return m_blockCount > 0 || m_outOfRangeGUIDs.size() > 0; } void Clear(); + std::set<uint64> const& GetOutOfRangeGUIDs() const { return m_outOfRangeGUIDs; }+ protected: uint32 m_blockCount; std::set<uint64> m_outOfRangeGUIDs;Index: src/game/WaypointMovementGenerator.h===================================================================--- src/game/WaypointMovementGenerator.h (revision 3877)+++ src/game/WaypointMovementGenerator.h (working copy)@@ -132,7 +132,7 @@ { float x, y, z; i_destinationHolder.GetLocationNow(x, y, z);- i_player.SetPosition(x, y, z, true);+ i_player.SetPosition(x, y, z, i_player.GetOrientation()); i_player.FlightComplete(); return true; }Index: src/game/World.cpp===================================================================--- src/game/World.cpp (revision 3877)+++ src/game/World.cpp (working copy)@@ -51,6 +51,10 @@ volatile bool World::m_stopEvent = false; +uint32 World::m_MaxVisibleDistanceForCreature = OBJECT_VISIBLE_DISTANCE;+uint32 World::m_MaxVisibleDistanceForPlayer = OBJECT_VISIBLE_DISTANCE;+uint32 World::m_MaxVisibleDistanceForObject = OBJECT_VISIBLE_DISTANCE;+ // ServerMessages.dbc enum ServerMessageType {@@ -119,7 +123,7 @@ continue; if( player->IsInWorld() && player->GetZoneId() == zone ) {- // Used by the weather system. We return the player to brodcast the change weather message to him and all players in the zone.+ // Used by the weather system. We return the player to broadcast the change weather message to him and all players in the zone. return player; } }@@ -162,7 +166,7 @@ m_sessions[s->GetAccountId()] = s; m_maxSessionsCount = max(m_maxSessionsCount,uint32(m_sessions.size())); - // if session already exist, prepere to it deleting at next world update+ // if session already exist, prepare to it deleting at next world update if(old) m_kicked_sessions.insert(old); }@@ -324,7 +328,7 @@ m_configs[CONFIG_GM_LOGIN_STATE] = sConfig.GetIntDefault("GM.LoginState",2); m_configs[CONFIG_GM_LOG_TRADE] = sConfig.GetIntDefault("GM.LogTrade", 1); - m_configs[CONFIG_GROUP_VISIBILITY] = sConfig.GetIntDefault("GroupVisibility",0);+ m_configs[CONFIG_GROUP_VISIBILITY] = sConfig.GetIntDefault("Visibility.GroupMode",0); m_configs[CONFIG_MAIL_DELIVERY_DELAY] = sConfig.GetIntDefault("MailDeliveryDelay",HOUR); @@ -348,6 +352,40 @@ m_configs[CONFIG_CHATFLOOD_MESSAGE_DELAY] = sConfig.GetIntDefault("ChatFlood.MessageDelay",1); m_configs[CONFIG_CHATFLOOD_MUTE_TIME] = sConfig.GetIntDefault("ChatFlood.MuteTime",10); + m_MaxVisibleDistanceForCreature = sConfig.GetIntDefault("Visibility.Distance.Creature", OBJECT_VISIBLE_DISTANCE);+ if(m_MaxVisibleDistanceForCreature < uint32(45*sWorld.getRate(RATE_CREATURE_AGGRO)))+ {+ sLog.outError("Visibility.Distance.Creature can't be less max aggro radius %u",uint32(45*sWorld.getRate(RATE_CREATURE_AGGRO)));+ m_MaxVisibleDistanceForCreature = uint32(45*sWorld.getRate(RATE_CREATURE_AGGRO));+ }+ else if(m_MaxVisibleDistanceForCreature > MAX_OBJECT_VISIBLE_DISTANCE)+ {+ sLog.outError("Visibility. Distance .Creature can't be greater %u",MAX_OBJECT_VISIBLE_DISTANCE);+ m_MaxVisibleDistanceForCreature = MAX_OBJECT_VISIBLE_DISTANCE;+ }+ m_MaxVisibleDistanceForPlayer = sConfig.GetIntDefault("Visibility.Distance.Player", OBJECT_VISIBLE_DISTANCE);+ if(m_MaxVisibleDistanceForPlayer < uint32(45*sWorld.getRate(RATE_CREATURE_AGGRO)))+ {+ sLog.outError("Visibility.Distance.Player can't be less max aggro radius %u",uint32(45*sWorld.getRate(RATE_CREATURE_AGGRO)));+ m_MaxVisibleDistanceForPlayer = uint32(45*sWorld.getRate(RATE_CREATURE_AGGRO));+ }+ else if(m_MaxVisibleDistanceForPlayer > MAX_OBJECT_VISIBLE_DISTANCE)+ {+ sLog.outError("Visibility.Distance.Player can't be greater %u",MAX_OBJECT_VISIBLE_DISTANCE);+ m_MaxVisibleDistanceForPlayer = MAX_OBJECT_VISIBLE_DISTANCE;+ }+ m_MaxVisibleDistanceForObject = sConfig.GetIntDefault("Visibility.Distance.Gameobject", OBJECT_VISIBLE_DISTANCE);+ if(m_MaxVisibleDistanceForObject < OBJECT_ITERACTION_DISTANCE)+ {+ sLog.outError("Visibility.Distance.Object can't be less max aggro radius %u",OBJECT_ITERACTION_DISTANCE);+ m_MaxVisibleDistanceForObject = OBJECT_ITERACTION_DISTANCE;+ }+ else if(m_MaxVisibleDistanceForObject > MAX_OBJECT_VISIBLE_DISTANCE)+ {+ sLog.outError("Visibility.Distance.Object can't be greater %u",MAX_OBJECT_VISIBLE_DISTANCE);+ m_MaxVisibleDistanceForObject = MAX_OBJECT_VISIBLE_DISTANCE;+ }+ ///- Read the "Data" directory from the config file m_dataPath = sConfig.GetStringDefault("DataDir","./"); if((m_dataPath.at(m_dataPath.length()-1)!='/') && (m_dataPath.at(m_dataPath.length()-1)!='\\'))@@ -916,7 +954,7 @@ return; } -/// Send a packet to all players (except self if mentionned)+/// Send a packet to all players (except self if mentioned) void World::SendGlobalMessage(WorldPacket *packet, WorldSession *self, uint32 team) { SessionMap::iterator itr;@@ -959,7 +997,7 @@ } } -/// Send a System Message to all players in the zone (except self if mentionned)+/// Send a System Message to all players in the zone (except self if mentioned) void World::SendZoneText(uint32 zone, const char* text, WorldSession *self, uint32 team) { WorldPacket data;Index: src/game/World.h===================================================================--- src/game/World.h (revision 3877)+++ src/game/World.h (working copy)@@ -250,6 +250,10 @@ void ScriptsStart(map<uint32, multimap<uint32, ScriptInfo> > const& scripts, uint32 id, Object* source, Object* target); + // for max speed access+ static uint32 GetMaxVisibleDistanceForCreature() { return m_MaxVisibleDistanceForCreature; }+ static uint32 GetMaxVisibleDistanceForPlayer() { return m_MaxVisibleDistanceForPlayer; }+ static uint32 GetMaxVisibleDistanceForObject() { return m_MaxVisibleDistanceForObject; } protected: void _UpdateGameTime();@@ -283,6 +287,11 @@ uint32 m_ShutdownIdleMode; uint32 m_ShutdownTimer;++ // for max speed access+ static uint32 m_MaxVisibleDistanceForCreature;+ static uint32 m_MaxVisibleDistanceForPlayer;+ static uint32 m_MaxVisibleDistanceForObject; }; extern uint32 realmID;Index: src/game/WorldSession.cpp===================================================================--- src/game/WorldSession.cpp (revision 3877)+++ src/game/WorldSession.cpp (working copy)@@ -39,8 +39,8 @@ #include "Language.h" // for CMSG_DISMOUNT handler /// WorldSession constructor-WorldSession::WorldSession(uint32 id, WorldSocket *sock, uint32 sec, time_t mute_time) : _player(NULL), _socket(sock),-_security(sec), _accountId(id), _logoutTime(0), m_playerLoading(false), m_playerRecentlyLogout(false),+WorldSession::WorldSession(uint32 id, WorldSocket *sock, uint32 sec, bool tbc, time_t mute_time) : _player(NULL), _socket(sock),+_security(sec), _accountId(id), m_isTBC(tbc), _logoutTime(0), m_playerLoading(false), m_playerRecentlyLogout(false), LookingForGroup_auto_join(false), LookingForGroup_auto_add(false), m_muteTime(mute_time) { FillOpcodeHandlerHashTable();@@ -540,8 +540,13 @@ { ///- If the player just died before logging out, make him appear as a ghost //FIXME: logout must be delayed in case lost connection with client in time of combat- if (_player->GetDeathTimer() || _player->isAttacked())+ if (_player->GetDeathTimer()) {+ _player->DeleteInHateListOf();+ _player->BuildPlayerRepop();+ }+ else if (_player->isAttacked())+ { _player->CombatStop(true); _player->DeleteInHateListOf(); _player->KillPlayer();@@ -602,7 +607,6 @@ ///- Release charmed creatures and unsummon totems _player->Uncharm(); _player->UnsummonAllTotems();- _player->InvisiblePjsNear.clear(); ///- empty buyback items and save the player in the database // some save parts only correctly work in case player present in map/player_lists (pets, etc)Index: src/game/WorldSession.h===================================================================--- src/game/WorldSession.h (revision 3877)+++ src/game/WorldSession.h (working copy)@@ -40,7 +40,7 @@ class MANGOS_DLL_SPEC WorldSession { public:- WorldSession(uint32 id, WorldSocket *sock, uint32 sec, time_t mute_time);+ WorldSession(uint32 id, WorldSocket *sock, uint32 sec, bool tbc, time_t mute_time); ~WorldSession(); bool PlayerLoading() { return m_playerLoading; }@@ -60,6 +60,7 @@ void SetSecurity(uint32 security) { _security = security; } void SetSocket(WorldSocket *sock); void SetPlayer(Player *plr) { _player = plr; }+ bool IsTBC() const { return m_isTBC; } /// Is the user engaged in a log out process? bool isLogingOut() const@@ -520,6 +521,7 @@ uint32 _security; uint32 _accountId;+ bool m_isTBC; time_t _logoutTime; bool m_playerLoading;Index: src/game/WorldSocket.cpp===================================================================--- src/game/WorldSocket.cpp (revision 3877)+++ src/game/WorldSocket.cpp (working copy)@@ -384,7 +384,7 @@ SendPacket(&packet); ///- Create a new WorldSession for the player and add it to the World- _session = new WorldSession(id, this,security,mutetime);+ _session = new WorldSession(id, this,security,tbc,mutetime); sWorld.AddSession(_session); sLog.outDebug( "SOCKET: Client '%s' authenticated successfully.", account.c_str() );Index: src/mangosd/CliRunnable.cpp===================================================================--- src/mangosd/CliRunnable.cpp (revision 3877)+++ src/mangosd/CliRunnable.cpp (working copy)@@ -182,7 +182,7 @@ if(Player* p = objmgr.GetPlayer(MAKE_GUID(guidlo,HIGHGUID_PLAYER))) p->GetSession()->KickPlayer(); - WorldSession acc_s(account_id,NULL,0,0); // some invalid session+ WorldSession acc_s(account_id,NULL,0,true,0); // some invalid session Player acc_player(&acc_s); acc_player.LoadFromDB(guidlo);Index: src/mangosd/mangosd.conf.in===================================================================--- src/mangosd/mangosd.conf.in (revision 3877)+++ src/mangosd/mangosd.conf.in (working copy)@@ -205,8 +205,16 @@ # Default: 0 (standard setting: only members from same group can 100% auto detect invisible player) # 1 (raid members 100% auto detect invisible player from same raid) # 2 (players from same team can 100% auto detect invisible player)-GroupVisibility = 0+Visibility.GroupMode = 0 +# Visibility distance for different in game object (max limited by active player zone, min limited by interaction distance for objects and max aggro radius for creatures/players )+# Default: 64 (standard setting)+Visibility.Distance.Creature = 64+Visibility.Distance.Player = 64++# gameobject/dynobject/creature's bodies+Visibility.Distance.Object = 64+ # Mail delivery delay time in case sending item # Default: 3600 sec (1 hour) MailDeliveryDelay = 3600