Index: src/game/AggressorAI.cpp =================================================================== --- src/game/AggressorAI.cpp (revision 3914) +++ 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() ) { @@ -181,7 +181,7 @@ AggressorAI::IsVisible(Unit *pl) const { return i_creature.GetDistanceSq(pl) < sWorld.getConfig(CONFIG_SIGHT_MONSTER) - && pl->isVisibleFor(&i_creature,true); + && pl->isVisibleForOrDetect(&i_creature,true); } void Index: src/game/Corpse.cpp =================================================================== --- src/game/Corpse.cpp (revision 3914) +++ src/game/Corpse.cpp (working copy) @@ -27,7 +27,6 @@ #include "WorldSession.h" #include "WorldPacket.h" #include "GossipDef.h" -#include "RedZoneDistrict.h" Corpse::Corpse( WorldObject *instantiator, CorpseType type ) : WorldObject( instantiator ) { @@ -102,10 +101,7 @@ sLog.outError("Bones %u not found in world.", GetGUIDLow()); } else - { - ObjectAccessor::Instance().RemoveBonesFromPlayerView(corpse); ObjectAccessor::Instance().AddObjectToRemoveList(this); - } RemoveFromWorld(); } @@ -265,3 +261,8 @@ else bones->DeleteBonesFromWorld(); } + +bool Corpse::isVisibleForInState(Player const* u, bool inVisibleList) const +{ + return IsInWorld() && u->IsInWorld() && IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleGrayDistance() : 0)); +} Index: src/game/Corpse.h =================================================================== --- src/game/Corpse.h (revision 3914) +++ src/game/Corpse.h (working copy) @@ -57,6 +57,8 @@ GridPair const& GetGrid() const { return m_grid; } + bool isVisibleForInState(Player const* u, bool inVisibleList) const; + void _ConvertCorpseToBones(); // only call from ObjectAccessor::ConvertCorpseForPlayer private: CorpseType m_type; Index: src/game/Creature.cpp =================================================================== --- src/game/Creature.cpp (revision 3914) +++ src/game/Creature.cpp (working copy) @@ -186,7 +186,7 @@ { m_deathTimer = 0; DEBUG_LOG("Removing corpse... %u ", GetUInt32Value(OBJECT_FIELD_ENTRY)); - ObjectAccessor::Instance().RemoveCreatureCorpseFromPlayerView(this); + ObjectAccessor::UpdateObjectVisibility(this); lootForPickPocketed = false; lootForBody = false; loot.clear(); Index: src/game/CreatureAIRegistry.cpp =================================================================== --- src/game/CreatureAIRegistry.cpp (revision 3914) +++ src/game/CreatureAIRegistry.cpp (working copy) @@ -28,7 +28,6 @@ #include "MovementGeneratorImpl.h" #include "MapManager.h" #include "WaypointMovementGenerator.h" -#include "RedZoneDistrict.h" #include "CreatureAIRegistry.h" #include "WaypointMovementGenerator.h" Index: src/game/DynamicObject.cpp =================================================================== --- src/game/DynamicObject.cpp (revision 3914) +++ src/game/DynamicObject.cpp (working copy) @@ -127,3 +127,8 @@ if (*iunit) (*iunit)->DelayAura(m_spellId, m_effIndex, delaytime); } + +bool DynamicObject::isVisibleForInState(Player const* u, bool inVisibleList) const +{ + return IsInWorld() && u->IsInWorld() && IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleGrayDistance() : 0)); +} Index: src/game/DynamicObject.h =================================================================== --- src/game/DynamicObject.h (revision 3914) +++ 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 isVisibleForInState(Player const* u, bool inVisibleList) const; protected: uint64 m_casterGuid; uint32 m_spellId; Index: src/game/GameObject.cpp =================================================================== --- src/game/GameObject.cpp (revision 3914) +++ 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::isVisibleForInState(Player const* u, bool inVisibleList) const +{ + return IsInWorld() && u->IsInWorld() && ( IsTransport() && IsInMap(u) || + isSpawned() && IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleGrayDistance() : 0)) ); +} Index: src/game/GameObject.h =================================================================== --- src/game/GameObject.h (revision 3914) +++ src/game/GameObject.h (working copy) @@ -166,6 +166,8 @@ bool hasQuest(uint32 quest_id) const; bool hasInvolvedQuest(uint32 quest_id) const; + + bool isVisibleForInState(Player const* u, bool inVisibleList) 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 3914) +++ src/game/GridNotifiers.cpp (working copy) @@ -24,258 +24,90 @@ #include "Map.h" #include "MapManager.h" #include "Transports.h" +#include "ObjectAccessor.h" using namespace MaNGOS; -void PlayerNotifier::Visit(PlayerMapType &m) +void +MaNGOS::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); - } + iter->second->UpdateVisibilityOf(&i_player); + i_player.UpdateVisibilityOf(iter->second); } } void -PlayerNotifier::BuildForMySelf() +VisibleChangesNotifier::Visit(PlayerMapType &m) { - if( !i_player.IsInWorld() ) + for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) { - WorldPacket packet; - UpdateData data; + if(iter->second == &i_object) + continue; - 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); - } + iter->second->UpdateVisibilityOf(&i_object); } } void -VisibleNotifier::Notify() +VisibleNotifier::Visit(PlayerMapType &m) { - if( i_data.HasData() ) + for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) { - // 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; + if( iter->second == &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) + iter->second->UpdateVisibilityOf(&i_player); + i_player.UpdateVisibilityOf(iter->second,i_data,i_data_updates); + i_clientGUIDs.erase(iter->second->GetGUID()); } } -template void -VisibleNotifier::Visit(std::map &m) +VisibleNotifier::Notify() { - for(typename std::map::iterator iter=m.begin(); iter != m.end(); ++iter) - { - iter->second->BuildUpdate(i_updateDatas); - iter->second->BuildCreateUpdateBlockForPlayer(&i_data, &i_player); - } -} + // 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); -template -void -VisibleNotifier::Visit(std::map > &m) -{ - for(typename std::map >::iterator iter=m.begin(); iter != m.end(); ++iter) + // 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) { - iter->second->BuildUpdate(i_updateDatas); - iter->second->BuildCreateUpdateBlockForPlayer(&i_data, &i_player); - } -} + if(iter->first==&i_player) + continue; -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); - } + WorldPacket packet; + iter->second.BuildPacket(&packet); + iter->first->GetSession()->SendPacket(&packet); } -} -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() ) { + // 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); - } -} -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()) ) + // 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) { - iter->second->BuildOutOfRangeUpdateBlock(&i_data); + if(GUID_HIPART(*iter)!=HIGHGUID_PLAYER) + continue; - UpdateData his_data; - WorldPacket his_pk; - i_player.BuildOutOfRangeUpdateBlock(&his_data); - his_data.BuildPacket(&his_pk); - iter->second->GetSession()->SendPacket(&his_pk); + Player* plr = ObjectAccessor::Instance().GetPlayer(i_player,*iter); + if(plr) + plr->UpdateVisibilityOf(&i_player); } } } 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) @@ -283,7 +115,8 @@ if( (iter->second != &i_player || i_toSelf) && (!i_ownTeamOnly || iter->second->GetTeam() == i_player.GetTeam()) ) { - iter->second->GetSession()->SendPacket(i_message); + if(WorldSession* session = iter->second->GetSession()) + session->SendPacket(i_message); } } } @@ -293,34 +126,11 @@ { for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) { - iter->second->GetSession()->SendPacket(i_message); + if(WorldSession* session = iter->second->GetSession()) + session->SendPacket(i_message); } } -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 +149,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 3914) +++ src/game/GridNotifiers.h (working copy) @@ -43,7 +43,6 @@ void Visit(PlayerMapType &); template void Visit(std::map &) {} template void Visit(std::map > &m) {} - void BuildForMySelf(void); Player &i_player; }; @@ -51,61 +50,24 @@ { Player &i_player; UpdateData i_data; - UpdateDataMapType i_updateDatas; + UpdateDataMapType i_data_updates; + Player::ClientGUIDs i_clientGUIDs; - explicit VisibleNotifier(Player &player) : i_player(player) {} + 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(GameObjectMapType &); + void Visit(PlayerMapType &); 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) {} + explicit VisibleChangesNotifier(WorldObject &object) : i_object(object) {} + template void Visit(std::map &m) {} + template void Visit(std::map > &m) {} void Visit(PlayerMapType &); - template void Visit(std::map &) {} - template void Visit(std::map > &m) {} }; struct MANGOS_DLL_DECL GridUpdater @@ -154,24 +116,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 +180,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 +470,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 AnyStealthedCheck + { + bool operator()(Unit* u) { return u->GetVisibility()==VISIBILITY_GROUP_STEALTH; } }; class CannibalizeUnitCheck @@ -590,9 +529,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 3914) +++ src/game/GridNotifiersImpl.h (working copy) @@ -27,56 +27,25 @@ #include "CreatureAI.h" #include "SpellAuras.h" -template<> +template inline void -MaNGOS::NotVisibleNotifier::Visit(CreatureMapType &m) +MaNGOS::VisibleNotifier::Visit(std::map &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) + for(typename std::map::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); - } + i_player.UpdateVisibilityOf(iter->second,i_data,i_data_updates); + i_clientGUIDs.erase(iter->second->GetGUID()); } } -template<> +template inline void -MaNGOS::VisibleNotifier::Visit(PlayerMapType &m) +MaNGOS::VisibleNotifier::Visit(std::map > &m) { - for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter) + for(typename std::map >::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); - } + i_player.UpdateVisibilityOf(&*iter->second,i_data,i_data_updates); + i_clientGUIDs.erase(iter->second->GetGUID()); } } @@ -88,41 +57,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 +93,6 @@ c2->AI()->MoveInLineOfSight(c1); } -template<> inline void MaNGOS::PlayerRelocationNotifier::Visit(CreatureMapType &m) { @@ -146,7 +100,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 +108,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 +120,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 3914) +++ 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() ) { @@ -164,7 +164,7 @@ bool GuardAI::IsVisible(Unit *pl) const { return i_creature.GetDistanceSq(pl) < sWorld.getConfig(CONFIG_SIGHT_GUARDER) - && pl->isVisibleFor(&i_creature,true); + && pl->isVisibleForOrDetect(&i_creature,true); } void GuardAI::AttackStart(Unit *u) Index: src/game/HomeMovementGenerator.cpp =================================================================== --- src/game/HomeMovementGenerator.cpp (revision 3914) +++ 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/Level0.cpp =================================================================== --- src/game/Level0.cpp (revision 3914) +++ src/game/Level0.cpp (working copy) @@ -186,7 +186,7 @@ for(ObjectAccessor::PlayersMapType::iterator itr = m.begin(); itr != m.end(); ++itr) { if( itr->second->GetSession()->GetSecurity() && (itr->second->isGameMaster() || sWorld.getConfig(CONFIG_GM_IN_GM_LIST) ) && - itr->second->isVisibleFor(m_session->GetPlayer(),false) ) + itr->second->isVisibleFor(m_session->GetPlayer()) ) { if(first) { Index: src/game/Level1.cpp =================================================================== --- src/game/Level1.cpp (revision 3914) +++ src/game/Level1.cpp (working copy) @@ -247,7 +247,7 @@ PSendSysMessage(LANG_SUMMONING, chr->GetName(),""); - if (m_session->GetPlayer()->isVisibleFor(chr,false)) + if (m_session->GetPlayer()->isVisibleFor(chr)) { char buf0[256]; snprintf((char*)buf0,256,LANG_SUMMONED_BY, m_session->GetPlayer()->GetName()); @@ -342,7 +342,7 @@ PSendSysMessage(LANG_APPEARING_AT, chr->GetName()); - if (_player->isVisibleFor(chr,false)) + if (_player->isVisibleFor(chr)) { char buf0[256]; sprintf((char*)buf0,LANG_APPEARING_TO, _player->GetName()); @@ -1663,7 +1663,7 @@ PSendSysMessage(LANG_TELEPORTING_TO, chr->GetName(),"", location.c_str()); - if (m_session->GetPlayer()->isVisibleFor(chr,false)) + if (m_session->GetPlayer()->isVisibleFor(chr)) { WorldPacket data; char buf0[256]; Index: src/game/Map.cpp =================================================================== --- src/game/Map.cpp (revision 3914) +++ src/game/Map.cpp (working copy) @@ -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()) @@ -553,19 +537,23 @@ void Map::Add(Player *player) { - CellPair p = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); - - assert( player && p.x_coord >= 0 && p.x_coord < TOTAL_NUMBER_OF_CELLS_PER_MAP && - p.y_coord >= 0 && p.y_coord < TOTAL_NUMBER_OF_CELLS_PER_MAP ); - if (player->GetPet()) player->GetPet()->SetInstanceId(this->GetInstanceId()); player->SetInstanceId(this->GetInstanceId()); + SendInitSelf(player); + + player->AddToWorld(); + + SendInitTransports(player); + + // update player state for other player and visa-versa + CellPair p = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); Cell cell = RedZone::GetZone(p); EnsureGridLoadedForPlayer(cell, player, true); - cell.data.Part.reserved = ALL_DISTRICT; - NotifyPlayerVisibility(cell, p, player); + UpdatePlayerVisibility(player,cell,p); + UpdateObjectsVisibilityFor(player,cell,p); + // reinitialize reset time InitResetTime(); } @@ -592,14 +580,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); + UpdateObjectVisibility(obj,cell,p); } template @@ -622,15 +604,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); + UpdateObjectVisibility(&*obj,cell,p); } template @@ -856,12 +833,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(); + UpdateObjectsVisibilityFor(player,cell,p); if( remove ) DeleteFromWorld(player); @@ -903,16 +875,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); - } + UpdateObjectVisibility(obj,cell,p); if( remove ) { @@ -943,15 +908,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); - } + UpdateObjectVisibility(&*obj,cell,p); if( remove ) { @@ -963,7 +922,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); @@ -974,6 +933,7 @@ Cell new_cell = RedZone::GetZone(new_val); new_cell |= old_cell; 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 +955,13 @@ EnsureGridLoadedForPlayer(new_cell, player, true); } - CellLock cell_lock(new_cell, new_val); + // if move then update what player see and who seen + UpdatePlayerVisibility(player,new_cell,new_val); + UpdateObjectsVisibilityFor(player,new_cell,new_val); + PlayerRelocationNotify(player,new_cell,new_val); - MaNGOS::VisibleNotifier notifier(*player); - - if( !same_cell || player->IsBeingTeleported() ) - { - if( player->IsBeingTeleported() ) - new_cell.data.Part.reserved = ALL_DISTRICT; - - TypeContainerVisitor world_object_notifier(notifier); - TypeContainerVisitor grid_object_notifier(notifier); - - cell_lock->Visit(cell_lock, world_object_notifier, *this); - cell_lock->Visit(cell_lock, grid_object_notifier, *this); - - notifier.Notify(); - } - - 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 @@ -1068,28 +987,11 @@ else { creature->Relocate(x, y, z, ang); - CreatureRelocationNotifying(creature,new_cell,new_val); + CreatureRelocationNotify(creature,new_cell,new_val); } assert(CheckGridIntegrity(creature,true)); } -void Map::CreatureRelocationNotifying(Creature *creature, Cell new_cell, CellPair new_val) -{ - if( !creature->hasUnitState(UNIT_STAT_CHASE | UNIT_STAT_SEARCHING | UNIT_STAT_FLEEING)) - { - CellLock cell_lock(new_cell, new_val); - MaNGOS::CreatureRelocationNotifier relocationNotifier(*creature); - new_cell.data.Part.reserved = ALL_DISTRICT; - new_cell.SetNoCreate(); // not trigger load unloaded grids at notifier call - - TypeContainerVisitor c2world_relocation(relocationNotifier); - TypeContainerVisitor c2grid_relocation(relocationNotifier); - - cell_lock->Visit(cell_lock, c2world_relocation, *this); - cell_lock->Visit(cell_lock, c2grid_relocation, *this); - } -} - void Map::AddCreatureToMoveList(Creature *c, float x, float y, float z, float ang) { if(!c) return; @@ -1116,7 +1018,7 @@ { // update pos c->Relocate(cm.x, cm.y, cm.z, cm.ang); - CreatureRelocationNotifying(c,new_cell,new_cell.cellPair()); + CreatureRelocationNotify(c,new_cell,new_cell.cellPair()); } else { @@ -1212,7 +1114,7 @@ { c->Relocate(resp_x, resp_y, resp_z, c->GetOrientation()); (*c)->Initialize(); // prevent possible problems with default move generators - CreatureRelocationNotifying(c,resp_cell,resp_cell.cellPair()); + CreatureRelocationNotify(c,resp_cell,resp_cell.cellPair()); return true; } else @@ -1496,6 +1398,112 @@ return i_mapEntry ? i_mapEntry->name[sWorld.GetDBClang()] : "UNNAMEDMAP\x0"; } +void Map::UpdateObjectVisibility( WorldObject* obj, Cell cell, CellPair cellpair) +{ + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + MaNGOS::VisibleChangesNotifier notifier(*obj); + TypeContainerVisitor player_notifier(notifier); + CellLock cell_lock(cell, cellpair); + cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(obj->GetMapId(), obj)); +} + +void Map::UpdatePlayerVisibility( Player* player, Cell cell, CellPair cellpair ) +{ + cell.data.Part.reserved = ALL_DISTRICT; + + + MaNGOS::PlayerNotifier pl_notifier(*player); + TypeContainerVisitor player_notifier(pl_notifier); + + CellLock cell_lock(cell, cellpair); + cell_lock->Visit(cell_lock, player_notifier, *this); +} + +void Map::UpdateObjectsVisibilityFor( Player* player, Cell cell, CellPair cellpair ) +{ + MaNGOS::VisibleNotifier notifier(*player); + + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); + TypeContainerVisitor world_notifier(notifier); + TypeContainerVisitor grid_notifier(notifier); + CellLock cell_lock(cell, cellpair); + 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(); +} + +void Map::PlayerRelocationNotify( Player* player, Cell cell, CellPair cellpair ) +{ + CellLock cell_lock(cell, cellpair); + MaNGOS::PlayerRelocationNotifier relocationNotifier(*player); + 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); +} + +void Map::CreatureRelocationNotify(Creature *creature, Cell cell, CellPair cellpair) +{ + if(creature->hasUnitState(UNIT_STAT_CHASE | UNIT_STAT_SEARCHING | UNIT_STAT_FLEEING)) + return; + + CellLock cell_lock(cell, cellpair); + MaNGOS::CreatureRelocationNotifier relocationNotifier(*creature); + cell.data.Part.reserved = ALL_DISTRICT; + cell.SetNoCreate(); // not trigger load unloaded grids at notifier call + + TypeContainerVisitor c2world_relocation(relocationNotifier); + TypeContainerVisitor c2grid_relocation(relocationNotifier); + + cell_lock->Visit(cell_lock, c2world_relocation, *this); + cell_lock->Visit(cell_lock, c2grid_relocation, *this); +} + +void Map::SendInitSelf( Player * player ) +{ + // build data for self presence in world at own client (one time for map) + 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); + + WorldPacket packet; + data.BuildPacket(&packet); + player->GetSession()->SendPacket(&packet); +} + +void Map::SendInitTransports( Player * player ) +{ + // Hack to send out transports + if (MapManager::Instance().m_TransportsByMap.find(player->GetMapId()) == MapManager::Instance().m_TransportsByMap.end()) + return; + + UpdateData transData; + + 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); + } + + WorldPacket packet; + transData.BuildPacket(&packet); + player->GetSession()->SendPacket(&packet); +} + template void Map::Add(CorpsePtr&); template void Map::Add(Creature *); template void Map::Add(GameObject *); Index: src/game/Map.h =================================================================== --- src/game/Map.h (revision 3914) +++ src/game/Map.h (working copy) @@ -105,6 +105,7 @@ template T* GetObjectNear(float x, float y, OBJECT_HANDLE hdl, T*); template void Add(CountedPtr&); + template void Remove(CountedPtr&, bool); template bool Find(CountedPtr&) const; @@ -117,7 +118,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); @@ -203,19 +204,26 @@ std::bitset marked_cells; + void UpdateObjectVisibility(WorldObject* obj, Cell cell, CellPair cellpair); + void UpdatePlayerVisibility(Player* player, Cell cell, CellPair cellpair); + void UpdateObjectsVisibilityFor(Player* player, Cell cell, CellPair cellpair); private: void SetTimer(uint32 t) { i_gridExpiry = t < MIN_GRID_DELAY ? MIN_GRID_DELAY : t; } uint64 CalculateGridMask(const uint32 &y) const; + void SendInitSelf( Player * player ); + void SendInitTransports( Player * player ); + + void PlayerRelocationNotify(Player* player, Cell cell, CellPair cellpair); + bool CreatureCellRelocation(Creature *creature, Cell new_cell); - void CreatureRelocationNotifying(Creature *creature, Cell newcell, CellPair newval); + void CreatureRelocationNotify(Creature *creature, Cell newcell, CellPair newval); void AddCreatureToMoveList(Creature *c, float x, float y, float z, float ang); CreatureMoveList i_creaturesToMove; 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/MiscHandler.cpp =================================================================== --- src/game/MiscHandler.cpp (revision 3914) +++ src/game/MiscHandler.cpp (working copy) @@ -166,7 +166,7 @@ (guild_name.length()?strstr(gname.c_str(), guild_name.c_str())!=0 : true) && (player_name.length()?strstr(pname, player_name.c_str())!=0 : true) && z_show && s_show && - (itr->second->GetSession()->GetSecurity() == 0 || gmInWhoList && itr->second->isVisibleFor(_player,false) ))) + (itr->second->GetSession()->GetSecurity() == 0 || gmInWhoList && itr->second->isVisibleFor(_player) ))) { clientcount++; @@ -569,7 +569,7 @@ if (friendGuid && friendResult==FRIEND_NOT_FOUND) { - if( pfriend && pfriend->IsInWorld() && pfriend->isVisibleFor(GetPlayer(),false)) + if( pfriend && pfriend->IsInWorld() && pfriend->isVisibleFor(GetPlayer())) { friendResult = FRIEND_ADDED_ONLINE; friendArea = pfriend->GetZoneId(); Index: src/game/MovementHandler.cpp =================================================================== --- src/game/MovementHandler.cpp (revision 3914) +++ 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 3914) +++ 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 stealthed unit +#define MAX_OBJECT_VISIBLE_DISTANCE (5*SIZE_OF_GRID_CELL/2) // max distance for visible object show, limited by active zone for player based at cell size (active zone = 5x5 cells) +#define OBJECT_VISIBLE_DISTANCE (SIZE_OF_GRID_CELL) // default visible distance enum TYPE { @@ -296,6 +300,11 @@ uint32 GetInstanceId() const { return m_InstanceId; } void SetInstanceId(uint32 val) { m_InstanceId = val; } + // main visibility check function in normal case (ignore grey zone distance check) + bool isVisibleFor(Player const* u) const { return isVisibleForInState(u,false); } + + // low level function for visibility change code, must be define in all main world object subclasses + virtual bool isVisibleForInState(Player const* u, bool inVisibleList) const = 0; protected: WorldObject( WorldObject *instantiator ); Index: src/game/ObjectAccessor.cpp =================================================================== --- src/game/ObjectAccessor.cpp (revision 3914) +++ 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() {} @@ -242,8 +211,6 @@ ObjectAccessor::InsertPlayer(Player *pl) { i_players[pl->GetGUID()] = pl; - _update(); - } void @@ -423,9 +390,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 +409,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 +626,28 @@ } 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(iter->second->HaveAtClient(&i_object)) + ObjectAccessor::_buildPacket(iter->second, &i_object, i_updateDatas); } void -ObjectAccessor::RemoveCreatureCorpseFromPlayerView(Creature *c) +ObjectAccessor::UpdateObjectVisibility(WorldObject *obj) { - MaNGOS::CreatureCorpseViewRemover remover(*c); - TypeContainerVisitor player_notifier(remover); - CellPair p = MaNGOS::ComputeCellPair(c->GetPositionX(), c->GetPositionY()); + CellPair p = MaNGOS::ComputeCellPair(obj->GetPositionX(), obj->GetPositionY()); Cell cell = RedZone::GetZone(p); - cell.SetNoCreate(); - cell.data.Part.reserved = ALL_DISTRICT; - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(c->GetMapId(), c)); + + MapManager::Instance().GetMap(obj->GetMapId(), obj)->UpdateObjectVisibility(obj,cell,p); } -void -ObjectAccessor::RemoveBonesFromPlayerView(CorpsePtr& corpse) +void ObjectAccessor::UpdateVisibilityForPlayer( Player* player ) { - MaNGOS::BonesViewRemover remover(corpse); - TypeContainerVisitor player_notifier(remover); - CellPair p = MaNGOS::ComputeCellPair(corpse->GetPositionX(), corpse->GetPositionY()); + CellPair p = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY()); Cell cell = RedZone::GetZone(p); - cell.SetNoCreate(); - cell.data.Part.reserved = ALL_DISTRICT; - CellLock cell_lock(cell, p); - cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(corpse->GetMapId(), &(*corpse))); + Map* m = MapManager::Instance().GetMap(player->GetMapId(),player); + + m->UpdatePlayerVisibility(player,cell,p); + m->UpdateObjectsVisibilityFor(player,cell,p); } Index: src/game/ObjectAccessor.h =================================================================== --- src/game/ObjectAccessor.h (revision 3914) +++ 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,24 @@ 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 UpdateVisibilityForPlayer(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 3914) +++ 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 3914) +++ 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)) { @@ -902,13 +904,13 @@ //Handle lava HandleLava(); - //Handle detect invisible players + //Handle detect stealth players if (m_DetectInvTimer > 0) { if (p_time >= m_DetectInvTimer) { m_DetectInvTimer = 3000; - HandleInvisiblePjs(); + HandleStealthedUnitsDetection(); } else m_DetectInvTimer -= p_time; @@ -1174,7 +1176,7 @@ if( pObj && pObj->GetName() && ( security > 0 || ( pObj->GetTeam() == team || allowTwoSideWhoList ) && - (pObj->GetSession()->GetSecurity() == 0 || gmInWhoList && pObj->isVisibleFor(this,false) ))) + (pObj->GetSession()->GetSecurity() == 0 || gmInWhoList && pObj->isVisibleFor(this) ))) { if(pObj->isAFK()) friendstr[i].Status = 2; @@ -1352,7 +1354,7 @@ WorldPacket data; BuildTeleportAckMsg(&data, x, y, z, orientation); GetSession()->SendPacket(&data); - SetPosition( x, y, z, orientation ); + SetPosition( x, y, z, orientation, true); BuildHeartBeatMsg(&data); SendMessageToSet(&data, true); } @@ -1403,20 +1405,27 @@ data << uint32(0); GetSession()->SendPacket( &data ); - SetMapId(mapid); + // new final coordinates + float final_x = x; + float final_y = y; + float final_z = z; + float final_o = orientation; - // orientation+0.1 used to pressure SetPosition send notifiers at teleportaion like in normal move case if(m_transport) { - Relocate(x + m_transX, y + m_transY, z + m_transZ, orientation + m_transO+0.1); - SetPosition(x + m_transX, y + m_transY, z + m_transZ, orientation + m_transO); + final_x += m_transX; + final_y += m_transY; + final_z += m_transZ; + final_o += m_transO; } - else - { - Relocate(x, y, z, orientation+0.1); - SetPosition(x, y, z, orientation); - } + // set position + SetMapId(mapid); + Relocate(final_x, final_y, final_z,final_o); + + // move packet sent by client always after far teleport + // SetPosition(final_x, final_y, final_z, final_o, true); + // resurrect character at enter into instance where his corpse exist CorpsePtr corpse = GetCorpse(); if (corpse && corpse->GetType() == CORPSE_RESURRECTABLE && corpse->GetMapId() == mapid) @@ -1450,14 +1459,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); @@ -3294,6 +3295,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() @@ -3606,7 +3610,7 @@ if( pfriend && pfriend->IsInWorld() && ( pfriend->GetSession()->GetSecurity() > 0 || ( pfriend->GetTeam() == team || allowTwoSideWhoList ) && - (security == 0 || gmInWhoList && isVisibleFor(pfriend,false) ))) + (security == 0 || gmInWhoList && isVisibleFor(pfriend) ))) { pfriend->GetSession()->SendPacket(packet); } @@ -4258,7 +4262,7 @@ m_dontMove = dontMove; } -bool Player::SetPosition(float x, float y, float z, float orientation) +bool Player::SetPosition(float x, float y, float z, float orientation, bool teleport) { Map *m = MapManager::Instance().GetMap(GetMapId(), this); @@ -4266,10 +4270,8 @@ const float old_y = GetPositionY(); const float old_r = GetOrientation(); - if( old_x != x || old_y != y || old_r != orientation) + if( teleport || 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); @@ -4277,14 +4279,17 @@ // 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); + + // reread after Map::Relocation + m = MapManager::Instance().GetMap(GetMapId(), this); + x = GetPositionX(); + y = GetPositionY(); + z = GetPositionZ(); } - // reread after Map::Relocation - m = MapManager::Instance().GetMap(GetMapId(), this); - x = GetPositionX(); - y = GetPositionY(); - z = GetPositionZ(); - float water_z = m->GetWaterLevel(x,y); uint8 flag1 = m->GetTerrainType(x,y); @@ -12331,15 +12336,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); @@ -12939,27 +12935,47 @@ SetUInt32Value(PLAYER_REST_STATE_EXPERIENCE, uint32(m_rest_bonus)); } -void Player::HandleInvisiblePjs() +void Player::HandleStealthedUnitsDetection() { - Map *m = MapManager::Instance().GetMap(GetMapId(), this); + std::list stealthedUnits; - //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::AnyStealthedCheck u_check; + MaNGOS::UnitListSearcher searcher(stealthedUnits, 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 = stealthedUnits.begin(); i != stealthedUnits.end();) { - if ((*i)->isVisibleFor(this,true)) + if((*i)==this) { - m_DiscoveredPj = *i; - m_enableDetect = false; - m->PlayerRelocation(this, GetPositionX(), GetPositionY(), GetPositionZ(), GetOrientation(), true); - m_enableDetect = true; - m_DiscoveredPj = 0; + i = stealthedUnits.erase(i); + continue; } + + if ((*i)->isVisibleForOrDetect(this,true)) + { + + (*i)->SendUpdateToPlayer(this); + m_clientGUIDs.insert((*i)->GetGUID()); + i = stealthedUnits.erase(i); + continue; + } + + ++i; } - if (!InvisiblePjsNear.size()) + + if(stealthedUnits.empty()) m_DetectInvTimer = 0; - InvisiblePjsNear.clear(); } bool Player::ActivateTaxiPathTo(std::vector const& nodes) @@ -13712,3 +13728,101 @@ } 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->isVisibleForInState(this,true)) + { + target->DestroyForPlayer(this); + m_clientGUIDs.erase(target->GetGUID()); + + // activate stealth detection system + if(m_DetectInvTimer==0 && target->isType(TYPE_UNIT) && ( + ((Unit*)target)->GetVisibility()==VISIBILITY_GROUP_STEALTH || + ((Unit*)target)->GetVisibility()==VISIBILITY_GROUP_NO_DETECT ) ) + m_DetectInvTimer = 1; + } + } + else + { + if(target->isVisibleForInState(this,false)) + { + target->SendUpdateToPlayer(this); + if(target->GetTypeId()!=TYPEID_GAMEOBJECT||!((GameObject*)target)->IsTransport()) + m_clientGUIDs.insert(target->GetGUID()); + } + } +} + +template +inline void UpdateVisibilityOf_helper(std::set& s64, T* target) +{ + s64.insert(target->GetGUID()); +} + +template<> +inline void UpdateVisibilityOf_helper(std::set& s64, GameObject* target) +{ + if(!target->IsTransport()) + s64.insert(target->GetGUID()); +} + +template +void Player::UpdateVisibilityOf(T* target, UpdateData& data, UpdateDataMapType& data_updates) +{ + if(HaveAtClient(target)) + { + if(!target->isVisibleForInState(this,true)) + { + 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_STEALTH || + ((Unit*)target)->GetVisibility()==VISIBILITY_GROUP_NO_DETECT ) ) + m_DetectInvTimer = 1; + } + } + else + { + if(target->isVisibleForInState(this,false)) + { + target->BuildUpdate(data_updates); + target->BuildCreateUpdateBlockForPlayer(&data, this); + UpdateVisibilityOf_helper(m_clientGUIDs,target); + } + } +} + +template void Player::UpdateVisibilityOf(Player* target, UpdateData& data, UpdateDataMapType& data_updates); +template void Player::UpdateVisibilityOf(Creature* target, UpdateData& data, UpdateDataMapType& data_updates); +template void Player::UpdateVisibilityOf(Corpse* target, UpdateData& data, UpdateDataMapType& data_updates); +template void Player::UpdateVisibilityOf(GameObject* target, UpdateData& data, UpdateDataMapType& data_updates); +template void Player::UpdateVisibilityOf(DynamicObject* target, UpdateData& data, UpdateDataMapType& data_updates); Index: src/game/Player.h =================================================================== --- src/game/Player.h (revision 3914) +++ src/game/Player.h (working copy) @@ -1140,7 +1140,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); @@ -1156,7 +1155,7 @@ void SendDungeonDifficulty(); void SendAllowMove(); - bool SetPosition(float x, float y, float z, float orientation); + bool SetPosition(float x, float y, float z, float orientation, bool teleport = false); void SendMessageToSet(WorldPacket *data, bool self);// overwrite Object::SendMessageToSet void SendMessageToOwnTeamSet(WorldPacket *data, bool self); @@ -1341,7 +1340,7 @@ bool IsFlying() const { return HasMovementFlags(MOVEMENTFLAG_FLYING); } // Transports - Transport * GetTransport() { return m_transport; } + Transport * GetTransport() const { return m_transport; } void SetTransport(Transport * t) { m_transport = t; } void SetTransOffset(float x, float y, float z, float orientation) @@ -1371,12 +1370,22 @@ float m_homebindY; float m_homebindZ; - // Invisibility and detection system - std::vector InvisiblePjsNear; - Player* m_DiscoveredPj; + // currently visible objects at player client + typedef std::set ClientGUIDs; + ClientGUIDs m_clientGUIDs; + + bool HaveAtClient(WorldObject const* u) { return u==this || m_clientGUIDs.find(u->GetGUID())!=m_clientGUIDs.end(); } + + bool IsVisibleInGridForPlayer(Player* pl) const; + + void UpdateVisibilityOf(WorldObject* target); + + template + void UpdateVisibilityOf(T* target, UpdateData& data, UpdateDataMapType& data_updates); + + // Stealth detection system uint32 m_DetectInvTimer; - void HandleInvisiblePjs(); - bool m_enableDetect; + void HandleStealthedUnitsDetection(); void ApplySpeedMod(UnitMoveType mtype, float rate, bool forced, bool apply); // overwrite Unit version Index: src/game/ReactorAI.cpp =================================================================== --- src/game/ReactorAI.cpp (revision 3914) +++ 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 3914) +++ 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" @@ -69,7 +67,7 @@ &Aura::HandleNoImmediateEffect, // 14 SPELL_AURA_MOD_DAMAGE_TAKEN &Aura::HandleAuraDamageShield, // 15 SPELL_AURA_DAMAGE_SHIELD &Aura::HandleModStealth, // 16 SPELL_AURA_MOD_STEALTH - &Aura::HandleModDetect, // 17 SPELL_AURA_MOD_DETECT + &Aura::HandleModStealthDetect, // 17 SPELL_AURA_MOD_STEALTH_DETECT &Aura::HandleInvisibility, // 18 SPELL_AURA_MOD_INVISIBILITY &Aura::HandleInvisibilityDetect, // 19 SPELL_AURA_MOD_INVISIBILITY_DETECTION &Aura::HandleAuraModTotalHealthPercentRegen, // 20 SPELL_AURA_OBS_MOD_HEALTH @@ -2017,9 +2015,10 @@ // 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); + m_target->SetVisibility(VISIBILITY_GROUP_STEALTH); // for RACE_NIGHTELF stealth if(m_target->GetTypeId()==TYPEID_PLAYER && GetId()==20580) @@ -2053,7 +2052,7 @@ } } -void Aura::HandleModDetect(bool apply, bool Real) +void Aura::HandleModStealthDetect(bool apply, bool Real) { if(apply) { @@ -2069,20 +2068,21 @@ { if(Apply) { - m_target->m_stealthvalue = CalculateDamage(); + m_target->m_invisibilityvalue = CalculateDamage(); m_target->SetFlag(UNIT_FIELD_BYTES_1, PLAYER_STATE_FLAG_STEALTH ); // 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); + m_target->SetVisibility(VISIBILITY_GROUP_INVISIBILITY); } } else { - m_target->m_stealthvalue = 0; + m_target->m_invisibilityvalue = 0; m_target->RemoveFlag(UNIT_FIELD_BYTES_1, PLAYER_STATE_FLAG_STEALTH ); // only at real aura remove @@ -2099,12 +2099,15 @@ { if(Apply) { - m_target->m_detectStealth = CalculateDamage(); + m_target->m_detectInvisibility = CalculateDamage(); } else { - m_target->m_detectStealth = 0; + m_target->m_detectInvisibility = 0; } + + if(Real && m_target->GetTypeId()==TYPEID_PLAYER) + ObjectAccessor::UpdateVisibilityForPlayer((Player*)m_target); } void Aura::HandleAuraModRoot(bool apply, bool Real) Index: src/game/SpellAuras.h =================================================================== --- src/game/SpellAuras.h (revision 3914) +++ src/game/SpellAuras.h (working copy) @@ -103,7 +103,7 @@ void HandleAuraSafeFall(bool Apply, bool Real); void HandleAuraDamageShield(bool Apply, bool Real); void HandleModStealth(bool Apply, bool Real); - void HandleModDetect(bool Apply, bool Real); + void HandleModStealthDetect(bool Apply, bool Real); void HandleInvisibility(bool Apply, bool Real); void HandleInvisibilityDetect(bool Apply, bool Real); void HandleAuraModTotalHealthPercentRegen(bool Apply, bool Real); Index: src/game/SpellEffects.cpp =================================================================== --- src/game/SpellEffects.cpp (revision 3914) +++ src/game/SpellEffects.cpp (working copy) @@ -1957,8 +1957,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/Unit.cpp =================================================================== --- src/game/Unit.cpp (revision 3914) +++ src/game/Unit.cpp (working copy) @@ -82,10 +82,11 @@ waterbreath = false; m_Visibility = VISIBILITY_ON; - m_UpdateVisibility = VISIBLE_NOCHANGES; m_detectStealth = 0; + m_detectInvisibility = 0; m_stealthvalue = 0; + m_invisibilityvalue = 0; m_transform = 0; m_ShapeShiftForm = 0; @@ -4934,7 +4935,7 @@ return gain; } -bool Unit::isVisibleFor(Unit const* u, bool detect) const +bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList) const { if(!u) return false; @@ -4943,26 +4944,92 @@ if (u==this) return true; - // Visible units, always are visible for all pjs - if (m_Visibility == VISIBILITY_ON) + // not in world + if(!IsInWorld() || !u->IsInWorld()) + 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; + } + + // different visible distance checks + if(u->isInFlight()) // what see player in flight + { + if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceInFlight()+(inVisibleList ? World::GetVisibleGrayDistance() : 0))) + return false; + } + else if(!isAlive()) // distance for show body + { + if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleGrayDistance() : 0))) + return false; + } + else if(GetTypeId()==TYPEID_PLAYER) // distance for show player + { + // in case two player at same transport ignore distance checks + if(!((Player*)this)->GetTransport() || u->GetTypeId()!=TYPEID_PLAYER || ((Player*)this)->GetTransport() != ((Player*)u)->GetTransport()) + { + // Players far than max visible distance for player or not in our map are not visible too + if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleGrayDistance() : 0))) + return false; + } + } + else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed + { + // Pet/charmed far than max visible distance for player or not in our map are not visible too + if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleGrayDistance() : 0))) + return false; + } + else // distance for show creature + { + // Units far than max visible distance for creature or not in our map are not visible too + if (!IsWithinDistInMap(u,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleGrayDistance() : 0))) + return false; + } + + // Visible units, always are visible for all units, except for units under invisibility + if (m_Visibility == VISIBILITY_ON && u->GetVisibility()!= VISIBILITY_GROUP_INVISIBILITY) 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()); - // non faction visibility non-breakable for non-GMs + // non faction visibility non-breakable for non-GMs 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; + // Invisible units, always are visible for units under invisibility or unit that can detect this invisibility + if (m_Visibility == VISIBILITY_GROUP_INVISIBILITY) + { + if(u->GetVisibility()== VISIBILITY_GROUP_INVISIBILITY || m_invisibilityvalue <= u->m_detectInvisibility) + return true; + } - // Stealth not hostile units, not visibles (except Player-with-Player case) + // Units that can detect invisibility always are visible for units that can be detected + if (u->GetVisibility()== VISIBILITY_GROUP_INVISIBILITY) + { + if(m_detectInvisibility >= u->m_invisibilityvalue) + return true; + } + + // Stealth/invisible not hostile units, not visible (except Player-with-Player case) if (!u->IsHostileTo(this)) { - // player auto-detect other player with stealth only if he in same group or raid or same team (raid/team case dependent from conf setting) + // player see other player with stealth/invisibility only if he in same group or raid or same team (raid/team case dependent from conf setting) if(GetTypeId()==TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER) { if(((Player*)this)->IsGroupVisibleFor(((Player*)u))) @@ -4970,16 +5037,34 @@ // else apply same rules as for hostile case (detecting check) } - else - return true; } + else + { + // Hunter mark functionality + AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_STALKED); + for(AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter) + if((*iter)->GetCasterGUID()==u->GetGUID()) + return true; + } - // if in non-detect mode then invisible for unit + // unit got in stealth in this moment and must ignore old detected state + // invisibility not have chance for detection + if (m_Visibility == VISIBILITY_ON || m_Visibility == VISIBILITY_GROUP_NO_DETECT || m_Visibility == VISIBILITY_GROUP_INVISIBILITY) + return false; + + // NOW ONLY STEALTH CASE + + // stealth and detected + if (u->GetTypeId() == TYPEID_PLAYER && ((Player*)u)->HaveAtClient(this) ) + return true; + + // if in non-detect mode then stealthed for unit if(!detect) return false; + // STEALTH DETECTION CODE 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; @@ -5002,33 +5087,22 @@ 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) ; } void Unit::SetVisibility(UnitVisibility x) { m_Visibility = x; - switch (x) + if(IsInWorld()) { - 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); + + if(GetTypeId()==TYPEID_PLAYER) + m->PlayerRelocation((Player*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); + else + m->CreatureRelocation((Creature*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); } - - m_UpdateVisibility = VISIBLE_NOCHANGES; } float Unit::GetSpeed( UnitMoveType mtype ) const @@ -5474,7 +5548,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 @@ -5840,3 +5914,8 @@ { return ObjectAccessor::Instance().GetUnit(object,guid); } + +bool Unit::isVisibleForInState( Player const* u, bool inVisibleList ) const +{ + return isVisibleForOrDetect(u,false,inVisibleList); +} \ No newline at end of file Index: src/game/Unit.h =================================================================== --- src/game/Unit.h (revision 3914) +++ 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,13 @@ 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, // absolute, not detectable, GM-like, can see all other + VISIBILITY_ON = 1, + VISIBILITY_GROUP_STEALTH = 2, // detect chance, seen and can see group members + VISIBILITY_GROUP_INVISIBILITY = 3, // invisibility, can see and can be seen only another invisible unit or invisible detection unit + VISIBILITY_GROUP_NO_DETECT = 4 // state just at stealth apply for update Grid state }; // Value masks for UNIT_FIELD_FLAGS @@ -799,7 +787,9 @@ uint64 m_ObjectSlot[4]; uint32 m_canMove; uint32 m_detectStealth; + uint32 m_detectInvisibility; uint32 m_stealthvalue; + uint32 m_invisibilityvalue; uint32 m_ShapeShiftForm; uint32 m_form; int32 m_modHitChance; @@ -813,13 +803,18 @@ bool isInFront(Unit const* target,float distance) const; void SetInFront(Unit const* target); - // Invisibility and detection system + // Visibility system UnitVisibility GetVisibility() const { return m_Visibility; } - UnitVisibilityUpdate GetUpdateVisibility() const { return m_UpdateVisibility; } void SetVisibility(UnitVisibility x); - void SetUpdateVisibility(UnitVisibilityUpdate x) { m_UpdateVisibility = x; } - bool isVisibleFor(Unit const* u, bool detect) const; + // common function for visibility checks for player/creatures with detection code + bool isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList = false) const; + + // virtual functions for all world objects types + bool isVisibleForInState(Player const* u, bool inVisibleList) const; + // function for low level grid visibility checks in player/creature cases + virtual bool IsVisibleInGridForPlayer(Player* pl) const = 0; + bool m_silenced; bool waterbreath; AuraList & GetSingleCastAuras() { return m_scAuras; } @@ -955,7 +950,6 @@ uint32 m_state; // Even derived shouldn't modify uint32 m_CombatTimer; - UnitVisibilityUpdate m_UpdateVisibility; UnitVisibility m_Visibility; Diminishing m_Diminishing; Index: src/game/World.cpp =================================================================== --- src/game/World.cpp (revision 3914) +++ src/game/World.cpp (working copy) @@ -51,6 +51,12 @@ 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; +uint32 World::m_MaxVisibleDistanceInFlight = OBJECT_VISIBLE_DISTANCE; +uint32 World::m_VisibleGreyDistance = 0; + // ServerMessages.dbc enum ServerMessageType { @@ -324,7 +330,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 +354,48 @@ 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; + } + m_MaxVisibleDistanceInFlight = sConfig.GetIntDefault("Visibility.Distance.InFlight", OBJECT_VISIBLE_DISTANCE); + if(m_MaxVisibleDistanceInFlight > MAX_OBJECT_VISIBLE_DISTANCE) + { + sLog.outError("Visibility.Distance.InFlight can't be greater %u",MAX_OBJECT_VISIBLE_DISTANCE); + m_MaxVisibleDistanceInFlight = MAX_OBJECT_VISIBLE_DISTANCE; + } + + m_VisibleGreyDistance = sConfig.GetIntDefault("Visibility.Distance.Grey", 1); + ///- 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)!='\\')) Index: src/game/World.h =================================================================== --- src/game/World.h (revision 3914) +++ src/game/World.h (working copy) @@ -255,6 +255,13 @@ 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; } + static uint32 GetMaxVisibleDistanceInFlight() { return m_MaxVisibleDistanceInFlight; } + static uint32 GetVisibleGrayDistance() { return m_VisibleGreyDistance; } + protected: void _UpdateGameTime(); void ScriptsProcess(); @@ -286,6 +293,13 @@ uint32 m_ShutdownIdleMode; uint32 m_ShutdownTimer; + + // for max speed access + static uint32 m_MaxVisibleDistanceForCreature; + static uint32 m_MaxVisibleDistanceForPlayer; + static uint32 m_MaxVisibleDistanceForObject; + static uint32 m_MaxVisibleDistanceInFlight; + static uint32 m_VisibleGreyDistance; }; extern uint32 realmID; Index: src/game/WorldSession.cpp =================================================================== --- src/game/WorldSession.cpp (revision 3914) +++ src/game/WorldSession.cpp (working copy) @@ -489,7 +489,7 @@ { uint64 minTime = uint64(cur_time - lastTime); uint64 fullTime = uint64(lastTime - firstTime); - sLog.outDetail("Send all time packets count: " I64FMTD " bytes: " I64FMTD " avr.count/sec: %f avr.bytes/sec: %f",sendPacketCount,sendPacketBytes,float(sendPacketCount)/fullTime,float(sendPacketBytes)/fullTime); + sLog.outDetail("Send all time packets count: " I64FMTD " bytes: " I64FMTD " avr.count/sec: %f avr.bytes/sec: %f time: %u",sendPacketCount,sendPacketBytes,float(sendPacketCount)/fullTime,float(sendPacketBytes)/fullTime,uint32(fullTime)); sLog.outDetail("Send last min packets count: " I64FMTD " bytes: " I64FMTD " avr.count/sec: %f avr.bytes/sec: %f",sendLastPacketCount,sendLastPacketBytes,float(sendLastPacketCount)/minTime,float(sendLastPacketBytes)/minTime); lastTime = cur_time; Index: src/mangosd/mangosd.conf.in =================================================================== --- src/mangosd/mangosd.conf.in (revision 3914) +++ src/mangosd/mangosd.conf.in (working copy) @@ -219,8 +219,32 @@ # 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: ~ 166 +# Min limit dependent from objects +# Default: 66 (cell size) + +# Min limit is max aggro radius (45) * Rate.Creature.Aggro +Visibility.Distance.Creature = 66 +Visibility.Distance.Player = 66 + +# gameobject, dynobject, bodies, corpses, bones +# Min limit is iteraction distance (5) +Visibility.Distance.Object = 66 + +# visible distance for player in flight +# Min limit is 0 (not show any objects) +Visibility.Distance.InFlight = 66 + +# Visibility grey distance +# addition to appropriate object type Visibility.Distance.* use in case visibility removing to object (except corpse around distences) +# If В is distance and G is grey distance then object make visible if distance to it <= D but make non visible if distance > D+G +# Default: 1 yard +Visibility.Distance.Grey = 1 + # Mail delivery delay time in case sending item # Default: 3600 sec (1 hour) MailDeliveryDelay = 3600