Index: 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 other Index: 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::iterator i = m_SkillupList.begin(); i != m_SkillupList.end(); ++i) + for (std::list::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 -void -VisibleNotifier::Visit(std::map &m) -{ - for(typename std::map::iterator iter=m.begin(); iter != m.end(); ++iter) - { - iter->second->BuildUpdate(i_updateDatas); - iter->second->BuildCreateUpdateBlockForPlayer(&i_data, &i_player); - } -} - -template -void -VisibleNotifier::Visit(std::map > &m) -{ - for(typename std::map >::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 -void -NotVisibleNotifier::Visit(std::map &m) -{ - for(typename std::map::iterator iter=m.begin(); iter != m.end(); ++iter) - iter->second->BuildOutOfRangeUpdateBlock(&i_data); -} - -template -void -NotVisibleNotifier::Visit(std::map > &m) -{ - for(typename std::map >::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 void ObjectUpdater::Visit(std::map &m) { @@ -339,11 +67,5 @@ } } -template void VisibleNotifier::Visit(CorpseMapType &); -template void VisibleNotifier::Visit(DynamicObjectMapType &); - -template void NotVisibleNotifier::Visit(CorpseMapType &); -template void NotVisibleNotifier::Visit(DynamicObjectMapType &); - template void ObjectUpdater::Visit(GameObjectMapType &); template void ObjectUpdater::Visit(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 void Visit(std::map &) {} - template void Visit(std::map > &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 void Visit(std::map &m); - template void Visit(std::map > &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 void Visit(std::map &) {} - template void Visit(std::map > &m) {} - }; - - struct MANGOS_DLL_DECL NotVisibleNotifier - { - Player &i_player; - UpdateData i_data; - explicit NotVisibleNotifier(Player &player) : i_player(player) {} - void Notify(void); - template void Visit(std::map &m); - template void Visit(std::map > &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 void Visit(std::map &) {} - template void Visit(std::map > &m) {} - }; - - struct MANGOS_DLL_DECL ObjectNotVisibleNotifier - { - WorldObject &i_object; - explicit ObjectNotVisibleNotifier(WorldObject &obj) : i_object(obj) {} - void Visit(PlayerMapType &); - template void Visit(std::map &) {} - template void Visit(std::map > &m) {} - }; - struct MANGOS_DLL_DECL GridUpdater { GridType &i_grid; @@ -154,24 +82,6 @@ template void Visit(std::map > &m) {} }; - struct MANGOS_DLL_DECL CreatureVisibleMovementNotifier - { - Creature &i_creature; - explicit CreatureVisibleMovementNotifier(Creature &creature) : i_creature(creature) {} - void Visit(PlayerMapType &m); - template void Visit(std::map &) {} - template void Visit(std::map > &m) {} - }; - - struct MANGOS_DLL_DECL CreatureNotVisibleMovementNotifier - { - Creature &i_creature; - explicit CreatureNotVisibleMovementNotifier(Creature &creature) : i_creature(creature) {} - void Visit(PlayerMapType &m); - template void Visit(std::map &) {} - template void Visit(std::map > &m) {} - }; - struct MANGOS_DLL_DECL ObjectUpdater { uint32 i_timeDiff; @@ -236,10 +146,8 @@ PlayerRelocationNotifier(Player &pl) : i_player(pl) {} template void Visit(std::map &m) {} template void Visit(std::map > &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(CreatureMapType &); - template<> void VisibleNotifier::Visit(PlayerMapType &); - template<> void NotVisibleNotifier::Visit(CreatureMapType &); template<> void PlayerRelocationNotifier::Visit(CreatureMapType &); template<> void PlayerRelocationNotifier::Visit(PlayerMapType &); template<> void CreatureRelocationNotifier::Visit(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 player_notifier(notifier); - CellLock 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 player_notifier(pl_notifier); - TypeContainerVisitor world_object_notifier(obj_notifier); - TypeContainerVisitor grid_object_notifier(obj_notifier); - - CellLock 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(obj)); - TypeContainerVisitor player_notifier(notifier); - - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, player_notifier, *this); + ObjectAccessor::UpdateObjectVisibility(obj); } template @@ -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(&(*obj))); - TypeContainerVisitor player_notifier(notifier); - - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, player_notifier, *this); + ObjectAccessor::UpdateObjectVisibility(&*obj); } template @@ -856,12 +861,7 @@ RemoveFromGrid(player,grid,cell); player->RemoveFromWorld(); - cell.data.Part.reserved = ALL_DISTRICT; - MaNGOS::NotVisibleNotifier notifier(*player); - TypeContainerVisitor player_notifier(notifier); - CellLock 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(obj)); - TypeContainerVisitor player_notifier(notifier); - CellLock 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(&*obj)); - TypeContainerVisitor player_notifier(notifier); - CellLock 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 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 cell_lock(new_cell, new_val); + MaNGOS::PlayerRelocationNotifier relocationNotifier(*player); + new_cell.data.Part.reserved = ALL_DISTRICT; - TypeContainerVisitor world_object_notifier(notifier); - TypeContainerVisitor grid_object_notifier(notifier); + TypeContainerVisitor p2grid_relocation(relocationNotifier); + TypeContainerVisitor 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 p2grid_relocation(relocationNotifier); - TypeContainerVisitor 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 player_Vnotifier(visualChangesNotifier); - cell_lock->Visit(cell_lock, player_Vnotifier, *this); - } - - if( same_cell ) - return; - - MaNGOS::NotVisibleNotifier notifier2(*player); - TypeContainerVisitor world_object_notifier2(notifier2); - TypeContainerVisitor grid_object_notifier2(notifier2); - - cell_lock = CellLock(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 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 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 void Visit(std::map &) {} template void Visit(std::map > &) {} }; - - 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 void Visit(std::map &) {} - template void Visit(std::map > &) {} - }; - - 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 void Visit(std::map &) {} - template void Visit(std::map > &) {} - }; } 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 player_notifier(notifier); + WorldObjectChangeAccumulator notifier(*obj, update_players); + TypeContainerVisitor player_notifier(notifier); CellLock 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 void Visit(std::map &m) {} + template void Visit(std::map > &m) {} + void Visit(PlayerMapType &); +}; + void -ObjectAccessor::RemoveCreatureCorpseFromPlayerView(Creature *c) +VisibleChangesNotifier::Visit(PlayerMapType &m) { - MaNGOS::CreatureCorpseViewRemover remover(*c); - TypeContainerVisitor 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 player_notifier(notifier); CellLock 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 void Visit(std::map &m); + template void Visit(std::map > &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 +inline void +VisibleNotifier::Visit(std::map &m) +{ + for(typename std::map::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 +inline void +VisibleNotifier::Visit(std::map > &m) +{ + for(typename std::map >::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 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 const& oor = i_data.GetOutOfRangeGUIDs(); + for(std::set::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 world_notifier(notifier); + TypeContainerVisitor grid_notifier(notifier); CellLock 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 void Visit(std::map &) {} template void Visit(std::map > &) {} }; - 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 cases Index: 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 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::iterator i = InvisiblePjsNear.begin(); i != InvisiblePjsNear.end(); i++) + MaNGOS::AnyDetectableInvisibleUnitCheck u_check; + MaNGOS::UnitListSearcher searcher(invisibleUnits, u_check); + + TypeContainerVisitor, WorldTypeMapContainer > world_unit_searcher(searcher); + TypeContainerVisitor, GridTypeMapContainer > grid_unit_searcher(searcher); + + CellLock 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::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 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 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 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 version Index: 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); } } else Index: 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 targets Index: 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& 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& 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 const& GetOutOfRangeGUIDs() const { return m_outOfRangeGUIDs; } + protected: uint32 m_blockCount; std::set 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 > 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