commit 66e5a9630687dd387da35bbd38e82d7d9c1e1c2f
Author: SilveIce <Slv_89@mail.ru>
Date:   Sun Jun 7 11:39:59 2009 +0300

    rel&vis demo

diff --git a/src/game/GridNotifiers.cpp b/src/game/GridNotifiers.cpp
index 1aefbcb..58dfa2c 100644
--- a/src/game/GridNotifiers.cpp
+++ b/src/game/GridNotifiers.cpp
@@ -28,19 +28,6 @@
 using namespace MaNGOS;
 
 void
-MaNGOS::PlayerNotifier::Visit(PlayerMapType &m)
-{
-    for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
-    {
-        if( iter->getSource() == &i_player )
-            continue;
-
-        iter->getSource()->UpdateVisibilityOf(&i_player);
-        i_player.UpdateVisibilityOf(iter->getSource());
-    }
-}
-
-void
 VisibleChangesNotifier::Visit(PlayerMapType &m)
 {
     for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
@@ -57,89 +44,51 @@ VisibleNotifier::Visit(PlayerMapType &m)
 {
     for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
     {
-        if( iter->getSource() == &i_player )
+        if(iter->getSource() == &i_player)
             continue;
 
-        iter->getSource()->UpdateVisibilityOf(&i_player);
-        i_player.UpdateVisibilityOf(iter->getSource(),i_data,i_data_updates,i_visibleNow);
-        i_clientGUIDs.erase(iter->getSource()->GetGUID());
+        if(!iter->getSource()->isNotified(NOTIFY_VISIBILITY))
+            i_player.UpdateVisibilityOf(iter->getSource(),i_data,i_visibleNow);
+
+        vis_guids.erase(iter->getSource()->GetGUID());
     }
 }
 
 void
-VisibleNotifier::Notify()
+VisibleNotifier::SendToSelf()
 {
     // at this moment i_clientGUIDs have guids that not iterate at grid level checks
     // but exist one case when this possible and object not out of range: transports
-    if(Transport* transport = i_player.GetTransport())
+    if(Transport* transport = i_player.GetTransport())	// ONTRANSPORT_VISIBILITY
     {
         for(Transport::PlayerSet::const_iterator itr = transport->GetPassengers().begin();itr!=transport->GetPassengers().end();++itr)
         {
-            if(i_clientGUIDs.find((*itr)->GetGUID())!=i_clientGUIDs.end())
+            if(vis_guids.find((*itr)->GetGUID()) != vis_guids.end())
             {
-                (*itr)->UpdateVisibilityOf(&i_player);
-                i_player.UpdateVisibilityOf((*itr),i_data,i_data_updates,i_visibleNow);
-                i_clientGUIDs.erase((*itr)->GetGUID());
-            }
-        }
-    }
+                if(!i_player.isNotified(NOTIFY_VISIBILITY))
+                    (*itr)->UpdateVisibilityOf(&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);
+                if(!(*itr)->isNotified(NOTIFY_VISIBILITY))
+                    i_player.UpdateVisibilityOf((*itr), i_data, i_visibleNow);
 
-        #ifdef MANGOS_DEBUG
-        if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0)
-            sLog.outDebug("Object %u (Type: %u) is out of range (no in active cells set) now for player %u",GUID_LOPART(*itr),GuidHigh2TypeId(GUID_HIPART(*itr)),i_player.GetGUIDLow());
-        #endif
-    }
-
-    // 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 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);
-
-        // send out of range to other players if need
-        std::set<uint64> const& oor = i_data.GetOutOfRangeGUIDs();
-        for(std::set<uint64>::const_iterator iter = oor.begin(); iter != oor.end(); ++iter)
-        {
-            if(!IS_PLAYER_GUID(*iter))
-                continue;
-
-            Player* plr = ObjectAccessor::GetPlayer(i_player,*iter);
-            if(plr)
-                plr->UpdateVisibilityOf(&i_player);
+                vis_guids.erase((*itr)->GetGUID());
+            }
         }
     }
 
-    // Now do operations that required done at object visibility change to visible
+    i_data.AddOutOfRangeGUID(vis_guids);
+    for(Player::ClientGUIDs::const_iterator it = vis_guids.begin();it != vis_guids.end(); ++it)
+        i_player.m_clientGUIDs.erase(*it);
 
-    // send data at target visibility change (adding to client)
-    for(std::set<WorldObject*>::const_iterator vItr = i_visibleNow.begin(); vItr != i_visibleNow.end(); ++vItr)
-    {
-        // target aura duration for caster show only if target exist at caster client
-        if((*vItr)!=&i_player && (*vItr)->isType(TYPEMASK_UNIT))
-            i_player.SendAurasForTarget((Unit*)(*vItr));
+    if(!i_data.HasData())
+        return;
 
-        // non finished movements show to player
-        if((*vItr)->GetTypeId()==TYPEID_UNIT && ((Creature*)(*vItr))->isAlive())
-            ((Creature*)(*vItr))->SendMonsterMoveWithSpeedToCurrentDestination(&i_player);
-    }
+    WorldPacket packet;
+    i_data.BuildPacket(&packet);
+    i_player.GetSession()->SendPacket(&packet);
+
+    for(std::set<Unit*>::const_iterator it = i_visibleNow.begin(); it != i_visibleNow.end(); ++it)
+        (*it)->SendInitialVisiblePackets(&i_player);
 }
 
 void
diff --git a/src/game/GridNotifiers.h b/src/game/GridNotifiers.h
index ae34ed7..d4e929a 100644
--- a/src/game/GridNotifiers.h
+++ b/src/game/GridNotifiers.h
@@ -37,29 +37,21 @@ class Player;
 
 namespace MaNGOS
 {
-
-    struct MANGOS_DLL_DECL PlayerNotifier
-    {
-        explicit PlayerNotifier(Player &pl) : i_player(pl) {}
-        void Visit(PlayerMapType &);
-        template<class SKIP> void Visit(GridRefManager<SKIP> &) {}
-        Player &i_player;
-    };
-
+    // creates UpdateData for i_player
     struct MANGOS_DLL_DECL VisibleNotifier
     {
         Player &i_player;
         UpdateData i_data;
-        UpdateDataMapType i_data_updates;
-        Player::ClientGUIDs i_clientGUIDs;
-        std::set<WorldObject*> i_visibleNow;
+        std::set<Unit*> i_visibleNow;
+        Player::ClientGUIDs vis_guids;
 
-        explicit VisibleNotifier(Player &player) : i_player(player),i_clientGUIDs(player.m_clientGUIDs) {}
+        explicit VisibleNotifier(Player &player) : i_player(player), vis_guids(player.m_clientGUIDs) {}
         template<class T> void Visit(GridRefManager<T> &m);
-        void Visit(PlayerMapType &);
-        void Notify(void);
+        void Visit(PlayerMapType &m);
+        void SendToSelf(void);
     };
 
+    // send object's update to every player in cell
     struct MANGOS_DLL_DECL VisibleChangesNotifier
     {
         WorldObject &i_object;
@@ -188,6 +180,43 @@ namespace MaNGOS
         #endif
     };
 
+    // mass creature relocation
+    struct MANGOS_DLL_DECL DelayedUnitRelocation
+    {
+        typedef GridReadGuard ReadGuard;
+        Map &i_map;
+        CellLock<ReadGuard> &i_lock;
+        //const float i_radius;
+        DelayedUnitRelocation(CellLock<ReadGuard> &lock, Map &map/*, float radius*/) :
+            i_lock(lock), i_map(map)/*, i_radius(radius)*/ {}
+        template<class T> void Visit(GridRefManager<T> &) {}
+        void Visit(CreatureMapType &);
+        void Visit(PlayerMapType &);
+    };
+
+    // mass update player/creature objects (that was added to visibility notify) to nearby players
+    struct MANGOS_DLL_DECL ObjectVisibilityUpdater
+    {
+        typedef GridReadGuard ReadGuard;
+        Map &i_map;
+        CellLock<ReadGuard>& i_lock;
+        //const float i_radius;
+        ObjectVisibilityUpdater(CellLock<ReadGuard>& lock, Map &map/*, float radius*/) : 
+            i_lock(lock), i_map(map)/*, i_radius(radius)*/ {}
+        template<class T> void Visit(GridRefManager<T> &) {}
+        void Visit(CreatureMapType &);
+        void Visit(PlayerMapType &);
+   };
+
+    struct MANGOS_DLL_DECL ResetNotifier
+    {
+        uint16 reset_mask;
+        ResetNotifier(uint16 notifies) : reset_mask(notifies) {}
+        template<class T> void Visit(GridRefManager<T> &) {}
+        void Visit(CreatureMapType &);
+        void Visit(PlayerMapType &);
+    };
+
     struct MANGOS_DLL_DECL DynamicObjectUpdater
     {
         DynamicObject &i_dynobject;
diff --git a/src/game/GridNotifiersImpl.h b/src/game/GridNotifiersImpl.h
index 583732a..f6cfac4 100644
--- a/src/game/GridNotifiersImpl.h
+++ b/src/game/GridNotifiersImpl.h
@@ -33,8 +33,10 @@ MaNGOS::VisibleNotifier::Visit(GridRefManager<T> &m)
 {
     for(typename GridRefManager<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
     {
-        i_player.UpdateVisibilityOf(iter->getSource(),i_data,i_data_updates,i_visibleNow);
-        i_clientGUIDs.erase(iter->getSource()->GetGUID());
+        if(!iter->getSource()->isNotified(NOTIFY_VISIBILITY))
+            i_player.UpdateVisibilityOf(iter->getSource(),i_data,i_visibleNow);
+
+        vis_guids.erase(iter->getSource()->GetGUID());
     }
 }
 
@@ -49,26 +51,14 @@ MaNGOS::ObjectUpdater::Visit(CreatureMapType &m)
 inline void
 MaNGOS::PlayerRelocationNotifier::Visit(PlayerMapType &m)
 {
-    for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
-    {
-        if(&i_player==iter->getSource())
-            continue;
-
-        // visibility for players updated by ObjectAccessor::UpdateVisibilityFor calls in appropriate places
-
-        // Cancel Trade
-        if(i_player.GetTrader()==iter->getSource())
-                                                            // iteraction distance
-            if(!i_player.IsWithinDistInMap(iter->getSource(), 5))
-                i_player.GetSession()->SendCancelTrade();   // will clode both side trade windows
-    }
+    // Cancel Trade
+    if(i_player.GetTrader())
+        if(!i_player.IsWithinDistInMap(i_player.GetTrader(), 5))
+            i_player.GetSession()->SendCancelTrade();   // will clode both side trade windows
 }
 
 inline void PlayerCreatureRelocationWorker(Player* pl, Creature* c)
 {
-    // update creature visibility at player/creature move
-    pl->UpdateVisibilityOf(c);
-
     // Creature AI reaction
     if(!c->hasUnitState(UNIT_STAT_SEARCHING | UNIT_STAT_FLEEING))
     {
@@ -99,8 +89,11 @@ MaNGOS::PlayerRelocationNotifier::Visit(CreatureMapType &m)
         return;
 
     for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
-        if( iter->getSource()->isAlive())
-            PlayerCreatureRelocationWorker(&i_player,iter->getSource());
+    {
+        Creature * c = iter->getSource();
+        if(c->isAlive() && !c->isNotified(NOTIFY_RELOCATION))
+            PlayerCreatureRelocationWorker(&i_player, c);
+    }
 }
 
 template<>
@@ -111,8 +104,11 @@ MaNGOS::CreatureRelocationNotifier::Visit(PlayerMapType &m)
         return;
 
     for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
-        if( iter->getSource()->isAlive() && !iter->getSource()->isInFlight())
-            PlayerCreatureRelocationWorker(iter->getSource(), &i_creature);
+    {
+        Player * pl = iter->getSource();
+        if( pl->isAlive() && !pl->isInFlight() && !pl->isNotified(NOTIFY_RELOCATION))
+            PlayerCreatureRelocationWorker(pl, &i_creature);
+    }
 }
 
 template<>
@@ -125,11 +121,105 @@ MaNGOS::CreatureRelocationNotifier::Visit(CreatureMapType &m)
     for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
     {
         Creature* c = iter->getSource();
-        if( c != &i_creature && c->isAlive())
+        if( c != &i_creature && c->isAlive() && !c->isNotified(NOTIFY_RELOCATION))
             CreatureCreatureRelocationWorker(c, &i_creature);
     }
 }
 
+inline void
+MaNGOS::DelayedUnitRelocation::Visit(CreatureMapType &m)
+{
+    for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
+    {
+        Creature * i_creature = iter->getSource();
+        if(!i_creature->isAlive() || !i_creature->isNeedNotify(NOTIFY_RELOCATION) || i_creature->isNotified(NOTIFY_RELOCATION))
+            continue;
+
+        CreatureRelocationNotifier relocate(*i_creature);
+        TypeContainerVisitor<MaNGOS::CreatureRelocationNotifier, WorldTypeMapContainer > c2world_relocation(relocate);
+        TypeContainerVisitor<MaNGOS::CreatureRelocationNotifier, GridTypeMapContainer >  c2grid_relocation(relocate);
+
+        i_lock->Visit(i_lock, c2world_relocation, i_map/*, *i_creature, i_radius*/);
+        i_lock->Visit(i_lock, c2grid_relocation, i_map/*, *i_creature, i_radius*/);
+
+        i_creature->SetNotified(NOTIFY_RELOCATION);
+        i_creature->RemoveFromNotify(NOTIFY_RELOCATION);
+    }
+}
+
+inline void
+MaNGOS::DelayedUnitRelocation::Visit(PlayerMapType &m)
+{
+    for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
+    {
+        Player * i_player = iter->getSource();
+        if(!i_player->isAlive() || !i_player->isNeedNotify(NOTIFY_RELOCATION) || i_player->isNotified(NOTIFY_RELOCATION))
+            continue;
+
+        PlayerRelocationNotifier relocate(*i_player);
+        TypeContainerVisitor<MaNGOS::PlayerRelocationNotifier, WorldTypeMapContainer > c2world_relocation(relocate);
+        TypeContainerVisitor<MaNGOS::PlayerRelocationNotifier, GridTypeMapContainer >  c2grid_relocation(relocate);
+
+        i_lock->Visit(i_lock, c2world_relocation, i_map/*, *i_player, i_radius*/);
+        i_lock->Visit(i_lock, c2grid_relocation, i_map/*, *i_player, i_radius*/);
+
+        i_player->SetNotified(NOTIFY_RELOCATION);
+        i_player->RemoveFromNotify(NOTIFY_RELOCATION);
+    }
+}
+
+inline void		// i_object data to all nearby players
+MaNGOS::ObjectVisibilityUpdater::Visit(CreatureMapType &m)
+{
+    for(CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
+    {
+        if(!iter->getSource()->isNeedNotify(NOTIFY_VISIBILITY) || iter->getSource()->isNotified(NOTIFY_VISIBILITY))
+            continue;
+
+        Creature * obj = iter->getSource();
+        VisibleChangesNotifier notify(*obj);
+
+        TypeContainerVisitor<VisibleChangesNotifier, WorldTypeMapContainer > world_notifier(notify);
+        i_lock->Visit(i_lock, world_notifier, i_map/*, *obj, i_radius*/);
+
+        obj->SetNotified(NOTIFY_VISIBILITY);
+        obj->RemoveFromNotify(NOTIFY_VISIBILITY);
+    }
+}
+
+inline void		// i_object data to all nearby players
+MaNGOS::ObjectVisibilityUpdater::Visit(PlayerMapType &m)
+{
+    for(PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
+    {
+        if(!iter->getSource()->isNeedNotify(NOTIFY_VISIBILITY) || iter->getSource()->isNotified(NOTIFY_VISIBILITY))
+            continue;
+
+        Player * obj = iter->getSource();
+        VisibleChangesNotifier notify(*obj);
+
+        TypeContainerVisitor<VisibleChangesNotifier, WorldTypeMapContainer > world_notifier(notify);
+        i_lock->Visit(i_lock, world_notifier, i_map/*, *obj, i_radius*/);
+
+        obj->SetNotified(NOTIFY_VISIBILITY);
+        obj->RemoveFromNotify(NOTIFY_VISIBILITY);
+    }
+}
+
+inline void
+MaNGOS::ResetNotifier::Visit(CreatureMapType &m)
+{
+    for(CreatureMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
+        iter->getSource()->ResetAllNotifiesbyMask(reset_mask);
+}
+
+inline void
+MaNGOS::ResetNotifier::Visit(PlayerMapType &m)
+{
+    for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
+        iter->getSource()->ResetAllNotifiesbyMask(reset_mask);
+}
+
 inline void MaNGOS::DynamicObjectUpdater::VisitHelper(Unit* target)
 {
     if(!target->isAlive() || target->isInFlight() )
diff --git a/src/game/Map.cpp b/src/game/Map.cpp
index 35b6c53..8ff5662 100644
--- a/src/game/Map.cpp
+++ b/src/game/Map.cpp
@@ -40,6 +40,7 @@
 
 #define DEFAULT_GRID_EXPIRY     300
 #define MAX_GRID_LOAD_TIME      50
+#define MAP_NOTIFY_DELAY      600                          // lets update player/mob relocation and visibility every n msec
 
 GridState* si_GridStates[MAX_GRID_STATE];
 
@@ -187,7 +188,9 @@ void Map::DeleteStateMachine()
 Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode)
   : i_mapEntry (sMapStore.LookupEntry(id)), i_spawnMode(SpawnMode),
   i_id(id), i_InstanceId(InstanceId), m_unloadTimer(0),
-  m_activeNonPlayersIter(m_activeNonPlayers.end()),
+  m_VisibilityNotifyTimer(MAP_NOTIFY_DELAY, (int32)0.3333f*MAP_NOTIFY_DELAY),
+  m_SelfVisibilityNotifyTimer(MAP_NOTIFY_DELAY, (int32)0.6666f*MAP_NOTIFY_DELAY),
+  m_RelocationNotifyTimer(MAP_NOTIFY_DELAY, (int32)MAP_NOTIFY_DELAY),
   i_gridExpiry(expiry)
 {
     for(unsigned int idx=0; idx < MAX_NUMBER_OF_GRIDS; ++idx)
@@ -406,12 +409,13 @@ bool Map::Add(Player *player)
     CellPair p = MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
     Cell cell(p);
     EnsureGridLoadedAtEnter(cell, player);
+    player->ResetAllNotifies();
     player->AddToWorld();
 
     SendInitSelf(player);
     SendInitTransports(player);
 
-    UpdatePlayerVisibility(player,cell,p);
+    UpdateObjectVisibility(player,cell,p);
     UpdateObjectsVisibilityFor(player,cell,p);
 
     AddNotifier(player,cell,p);
@@ -441,6 +445,7 @@ Map::Add(T *obj)
     assert( grid != NULL );
 
     AddToGrid(obj,grid,cell);
+    obj->ResetAllNotifies();
     obj->AddToWorld();
 
     if(obj->isActiveObject())
@@ -662,16 +667,190 @@ void Map::Update(const uint32 &t_diff)
 
     // Don't unload grids if it's battleground, since we may have manually added GOs,creatures, those doesn't load from DB at grid re-load !
     // This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended
-    if (IsBattleGroundOrArena())
+    if (IsBattleGroundOrArena() == false)
+    {
+        for (GridRefManager<NGridType>::iterator i = GridRefManager<NGridType>::begin(); i != GridRefManager<NGridType>::end(); )
+        {
+            NGridType *grid = i->getSource();
+            GridInfo *info = i->getSource()->getGridInfoRef();
+            ++i;                                                // The update might delete the map and we need the next map before the iterator gets invalid
+            assert(grid->GetGridState() >= 0 && grid->GetGridState() < MAX_GRID_STATE);
+            si_GridStates[grid->GetGridState()]->Update(*this, *grid, *info, grid->getX(), grid->getY(), t_diff);
+        }
+    }
+
+    if(m_mapRefManager.isEmpty() && m_activeNonPlayers.empty())
         return;
 
-    for (GridRefManager<NGridType>::iterator i = GridRefManager<NGridType>::begin(); i != GridRefManager<NGridType>::end(); )
+    //lets update visibility and object reactions with some delay
+    if(m_VisibilityNotifyTimer.Update(t_diff))
+        ProcessVisibilityNotifies();
+
+    if(m_SelfVisibilityNotifyTimer.Update(t_diff))
+    {
+        ProcessSelfVisibility();
+        ResetNotifies(NOTIFY_VISIBILITY | NOTIFY_VISIBILITY_SELF);
+    }
+
+    //relocation notifiers
+    if(m_RelocationNotifyTimer.Update(t_diff))
+    {
+        ProcessRelocationNotifies();
+        ResetNotifies(NOTIFY_RELOCATION);
+    }
+}
+
+void Map::ProcessVisibilityNotifies()
+{
+    for(GridRefManager<NGridType>::iterator i = GridRefManager<NGridType>::begin(); i != GridRefManager<NGridType>::end(); ++i)
+    {
+        NGridType *grid = i->getSource();
+
+        if(!grid || grid->GetGridState() != GRID_STATE_ACTIVE)
+            continue;
+
+        uint32 gx = grid->getX(), gy = grid->getY();
+
+        CellPair cell_min(gx*MAX_NUMBER_OF_CELLS, gy*MAX_NUMBER_OF_CELLS);
+        CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS);
+
+        for(uint32 x = cell_min.x_coord; x <= cell_max.x_coord; ++x)
+        {
+            for(uint32 y = cell_min.y_coord; y <= cell_max.y_coord; ++y)
+            {
+                uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
+                if(!isCellMarked(cell_id))
+                    continue;
+
+                CellPair pair(x, y);
+                Cell cell(pair);
+                cell.data.Part.reserved = CENTER_DISTRICT;
+                cell.SetNoCreate();
+
+                Cell notify_cell(cell);
+                notify_cell.data.Part.reserved = ALL_DISTRICT;
+                CellLock<ReadGuard> notify_lock(notify_cell, pair);
+
+                CellLock<NullGuard> cell_lock(cell, pair);
+                MaNGOS::ObjectVisibilityUpdater cell_relocation(notify_lock, *this/*, sWorld.GetMaxVisibleDistanceForPlayer()*/);
+                TypeContainerVisitor<MaNGOS::ObjectVisibilityUpdater, GridTypeMapContainer  > grid_object_relocation(cell_relocation);
+                TypeContainerVisitor<MaNGOS::ObjectVisibilityUpdater, WorldTypeMapContainer > world_object_relocation(cell_relocation);
+                cell_lock->Visit(cell_lock, grid_object_relocation,  *this);
+                cell_lock->Visit(cell_lock, world_object_relocation,  *this);
+            }
+        }
+    }
+}
+
+void Map::ProcessSelfVisibility()
+{
+    for(m_mapRefIter = m_mapRefManager.begin(); m_mapRefIter != m_mapRefManager.end(); ++m_mapRefIter)
+    {
+        Player* player = m_mapRefIter->getSource();
+
+        if(!player->IsInWorld() || !player->isNeedNotify(NOTIFY_VISIBILITY_SELF) || player->isNotified(NOTIFY_VISIBILITY_SELF))
+            continue;
+
+        CellPair cellpair(MaNGOS::ComputeCellPair(player->GetPositionX(), player->GetPositionY()));
+
+        if (cellpair.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || cellpair.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
+            continue;
+
+        MaNGOS::VisibleNotifier notifier(*player);
+
+        Cell cell(cellpair);
+        cell.data.Part.reserved = ALL_DISTRICT;
+        cell.SetNoCreate();
+        TypeContainerVisitor<MaNGOS::VisibleNotifier, WorldTypeMapContainer > world_notifier(notifier);
+        TypeContainerVisitor<MaNGOS::VisibleNotifier, GridTypeMapContainer  > grid_notifier(notifier);
+        CellLock<GridReadGuard> cell_lock(cell, cellpair);
+        cell_lock->Visit(cell_lock, world_notifier, *this/*, *player, sWorld.GetMaxVisibleDistanceForPlayer()*/);
+        cell_lock->Visit(cell_lock, grid_notifier,  *this/*, *player, sWorld.GetMaxVisibleDistanceForPlayer()*/);
+
+        // send data
+        notifier.SendToSelf();
+        player->SetNotified(NOTIFY_VISIBILITY_SELF);
+        player->RemoveFromNotify(NOTIFY_VISIBILITY_SELF);
+    }
+}
+
+void Map::ProcessRelocationNotifies()
+{
+    for(GridRefManager<NGridType>::iterator i = GridRefManager<NGridType>::begin(); i != GridRefManager<NGridType>::end(); ++i)
+    {
+        NGridType *grid = i->getSource();
+
+        if(!grid || grid->GetGridState() != GRID_STATE_ACTIVE)
+            continue;
+
+        uint32 gx = grid->getX(), gy = grid->getY();
+
+        CellPair cell_min(gx*MAX_NUMBER_OF_CELLS, gy*MAX_NUMBER_OF_CELLS);
+        CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS);
+
+        for(uint32 x = cell_min.x_coord; x <= cell_max.x_coord; ++x)
+        {
+            for(uint32 y = cell_min.y_coord; y <= cell_max.y_coord; ++y)
+            {
+                uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
+                if(!isCellMarked(cell_id))
+                    continue;
+
+                CellPair pair(x,y);
+                Cell cell(pair);
+                cell.data.Part.reserved = CENTER_DISTRICT;
+                cell.SetNoCreate();
+
+                Cell notify_cell(cell);
+                notify_cell.data.Part.reserved = ALL_DISTRICT;
+                CellLock<ReadGuard> notify_lock(notify_cell, pair);
+
+                CellLock<NullGuard> cell_lock(cell, pair);
+                MaNGOS::DelayedUnitRelocation cell_relocation(notify_lock, *this/*, CREATURE_MAX_AGGRO_RANGE*/);
+                TypeContainerVisitor<MaNGOS::DelayedUnitRelocation, GridTypeMapContainer  > grid_object_relocation(cell_relocation);
+                TypeContainerVisitor<MaNGOS::DelayedUnitRelocation, WorldTypeMapContainer > world_object_relocation(cell_relocation);
+                cell_lock->Visit(cell_lock, grid_object_relocation,  *this);
+                cell_lock->Visit(cell_lock, world_object_relocation,  *this);
+            }
+        }
+    }
+}
+
+void Map::ResetNotifies(uint16 notify_mask)
+{
+    MaNGOS::ResetNotifier reset(notify_mask);
+    TypeContainerVisitor<MaNGOS::ResetNotifier, GridTypeMapContainer >  grid_notifier(reset);
+    TypeContainerVisitor<MaNGOS::ResetNotifier, WorldTypeMapContainer > world_notifier(reset);
+
+    for(GridRefManager<NGridType>::iterator i = GridRefManager<NGridType>::begin(); i != GridRefManager<NGridType>::end(); ++i)
     {
         NGridType *grid = i->getSource();
-        GridInfo *info = i->getSource()->getGridInfoRef();
-        ++i;                                                // The update might delete the map and we need the next map before the iterator gets invalid
-        assert(grid->GetGridState() >= 0 && grid->GetGridState() < MAX_GRID_STATE);
-        si_GridStates[grid->GetGridState()]->Update(*this, *grid, *info, grid->getX(), grid->getY(), t_diff);
+
+        if(!grid || grid->GetGridState() != GRID_STATE_ACTIVE)
+            continue;
+
+        uint32 gx = grid->getX(), gy = grid->getY();
+
+        CellPair cell_min(gx*MAX_NUMBER_OF_CELLS, gy*MAX_NUMBER_OF_CELLS);
+        CellPair cell_max(cell_min.x_coord + MAX_NUMBER_OF_CELLS, cell_min.y_coord+MAX_NUMBER_OF_CELLS);
+
+        for(uint32 x = cell_min.x_coord; x <= cell_max.x_coord; ++x)
+        {
+            for(uint32 y = cell_min.y_coord; y <= cell_max.y_coord; ++y)
+            {
+                uint32 cell_id = (y * TOTAL_NUMBER_OF_CELLS_PER_MAP) + x;
+                if(!isCellMarked(cell_id))
+                    continue;
+
+                CellPair pair(x,y);
+                Cell cell(pair);
+                cell.data.Part.reserved = CENTER_DISTRICT;
+                cell.SetNoCreate();
+                CellLock<NullGuard> cell_lock(cell, pair);
+                cell_lock->Visit(cell_lock, grid_notifier,  *this);
+                cell_lock->Visit(cell_lock, world_notifier,  *this);
+            }
+        }
     }
 }
 
@@ -709,11 +888,13 @@ void Map::Remove(Player *player, bool remove)
     NGridType *grid = getNGrid(cell.GridX(), cell.GridY());
     assert(grid != NULL);
 
+    player->ResetAllNotifies();
     player->RemoveFromWorld();
     RemoveFromGrid(player,grid,cell);
 
     SendRemoveTransports(player);
 
+    UpdateObjectVisibility(player,cell,p);
     UpdateObjectsVisibilityFor(player,cell,p);
 
     if( remove )
@@ -755,6 +936,7 @@ Map::Remove(T *obj, bool remove)
     if(obj->isActiveObject())
         RemoveFromActive(obj);
 
+    //obj->RemoveAllNotifies();
     obj->RemoveFromWorld();
     RemoveFromGrid(obj,grid,cell);
 
@@ -801,9 +983,12 @@ Map::PlayerRelocation(Player *player, float x, float y, float z, float orientati
     }
 
     // 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);
+    //UpdatePlayerVisibility(player,new_cell,new_val);
+    //UpdateObjectsVisibilityFor(player,new_cell,new_val);
+
+    //PlayerRelocationNotify(player,new_cell,new_val);
+    player->AddToNotify(NOTIFY_VISIBILITY | NOTIFY_VISIBILITY_SELF | NOTIFY_RELOCATION);
+
     NGridType* newGrid = getNGrid(new_cell.GridX(), new_cell.GridY());
     if( !same_cell && newGrid->GetGridState()!= GRID_STATE_ACTIVE )
     {
@@ -835,7 +1020,8 @@ Map::CreatureRelocation(Creature *creature, float x, float y, float z, float ang
     else
     {
         creature->Relocate(x, y, z, ang);
-        CreatureRelocationNotify(creature,new_cell,new_val);
+        creature->AddToNotify(NOTIFY_VISIBILITY | NOTIFY_RELOCATION);
+        //CreatureRelocationNotify(creature,new_cell,new_val);
     }
     assert(CheckGridIntegrity(creature,true));
 }
@@ -867,7 +1053,8 @@ void Map::MoveAllCreaturesInMoveList()
         {
             // update pos
             c->Relocate(cm.x, cm.y, cm.z, cm.ang);
-            CreatureRelocationNotify(c,new_cell,new_cell.cellPair());
+            c->AddToNotify(NOTIFY_RELOCATION | NOTIFY_VISIBILITY);
+            //CreatureRelocationNotify(c,new_cell,new_cell.cellPair());
         }
         else
         {
@@ -979,7 +1166,8 @@ bool Map::CreatureRespawnRelocation(Creature *c)
     {
         c->Relocate(resp_x, resp_y, resp_z, resp_o);
         c->GetMotionMaster()->Initialize();                 // prevent possible problems with default move generators
-        CreatureRelocationNotify(c,resp_cell,resp_cell.cellPair());
+        c->AddToNotify(NOTIFY_RELOCATION | NOTIFY_VISIBILITY);
+        //CreatureRelocationNotify(c,resp_cell,resp_cell.cellPair());
         return true;
     }
     else
@@ -1893,13 +2081,14 @@ void Map::UpdateObjectVisibility( WorldObject* obj, Cell cell, CellPair cellpair
 
 void Map::UpdatePlayerVisibility( Player* player, Cell cell, CellPair cellpair )
 {
-    cell.data.Part.reserved = ALL_DISTRICT;
+ //   cell.data.Part.reserved = ALL_DISTRICT;
 
-    MaNGOS::PlayerNotifier pl_notifier(*player);
-    TypeContainerVisitor<MaNGOS::PlayerNotifier, WorldTypeMapContainer > player_notifier(pl_notifier);
+ //   MaNGOS::PlayerNotifier pl_notifier(*player);
+ //   TypeContainerVisitor<MaNGOS::VisibleChangesNotifier, WorldTypeMapContainer > player_notifier(pl_notifier);
 
-    CellLock<ReadGuard> cell_lock(cell, cellpair);
-    cell_lock->Visit(cell_lock, player_notifier, *this);
+ //   CellLock<ReadGuard> cell_lock(cell, cellpair);
+ //   cell_lock->Visit(cell_lock, player_notifier, *this, *player, sWorld.GetMaxVisibleDistanceForPlayer());
+    //player->SetNotified(NOTIFY_OBJECT_VISIBILITY);
 }
 
 void Map::UpdateObjectsVisibilityFor( Player* player, Cell cell, CellPair cellpair )
@@ -1915,7 +2104,7 @@ void Map::UpdateObjectsVisibilityFor( Player* player, Cell cell, CellPair cellpa
     cell_lock->Visit(cell_lock, grid_notifier,  *this);
 
     // send data
-    notifier.Notify();
+    notifier.SendToSelf();
 }
 
 void Map::PlayerRelocationNotify( Player* player, Cell cell, CellPair cellpair )
@@ -1923,6 +2112,7 @@ void Map::PlayerRelocationNotify( Player* player, Cell cell, CellPair cellpair )
     CellLock<ReadGuard> cell_lock(cell, cellpair);
     MaNGOS::PlayerRelocationNotifier relocationNotifier(*player);
     cell.data.Part.reserved = ALL_DISTRICT;
+    //cell.SetNoCreate();
 
     TypeContainerVisitor<MaNGOS::PlayerRelocationNotifier, GridTypeMapContainer >  p2grid_relocation(relocationNotifier);
     TypeContainerVisitor<MaNGOS::PlayerRelocationNotifier, WorldTypeMapContainer > p2world_relocation(relocationNotifier);
diff --git a/src/game/Map.h b/src/game/Map.h
index a075531..542125d 100644
--- a/src/game/Map.h
+++ b/src/game/Map.h
@@ -373,6 +373,9 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
         void UpdatePlayerVisibility(Player* player, Cell cell, CellPair cellpair);
         void UpdateObjectsVisibilityFor(Player* player, Cell cell, CellPair cellpair);
 
+        void PlayerRelocationNotify(Player* player, Cell cell, CellPair cellpair);
+        void CreatureRelocationNotify(Creature *creature, Cell newcell, CellPair newval);
+
         void resetMarkedCells() { marked_cells.reset(); }
         bool isCellMarked(uint32 pCellId) { return marked_cells.test(pCellId); }
         void markCell(uint32 pCellId) { marked_cells.set(pCellId); }
@@ -407,6 +410,13 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
         void LoadMap(int gx,int gy, bool reload = false);
         GridMap *GetGrid(float x, float y);
 
+        //these functions used to process player/mob aggro reactions and
+        //visibility calculations. Highly optimized for massive calculations
+        void ProcessVisibilityNotifies();
+        void ProcessSelfVisibility();
+        void ProcessRelocationNotifies();
+        void ResetNotifies(uint16 notify_mask);
+
         void SetTimer(uint32 t) { i_gridExpiry = t < MIN_GRID_DELAY ? MIN_GRID_DELAY : t; }
         //uint64 CalculateGridMask(const uint32 &y) const;
 
@@ -415,9 +425,6 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
         void SendInitTransports( Player * player );
         void SendRemoveTransports( Player * player );
 
-        void PlayerRelocationNotify(Player* player, Cell cell, CellPair cellpair);
-        void CreatureRelocationNotify(Creature *creature, Cell newcell, CellPair newval);
-
         bool CreatureCellRelocation(Creature *creature, Cell new_cell);
 
         void AddCreatureToMoveList(Creature *c, float x, float y, float z, float ang);
@@ -448,11 +455,14 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
 
         typedef MaNGOS::ObjectLevelLockable<Map, ACE_Thread_Mutex>::Lock Guard;
 
-        MapEntry const* i_mapEntry;
+        MapEntry const* i_mapEntry;  
         uint8 i_spawnMode;
         uint32 i_id;
         uint32 i_InstanceId;
         uint32 m_unloadTimer;
+        PeriodicTimer m_VisibilityNotifyTimer;
+        PeriodicTimer m_SelfVisibilityNotifyTimer;
+        PeriodicTimer m_RelocationNotifyTimer;
 
         MapRefManager m_mapRefManager;
         MapRefManager::iterator m_mapRefIter;
diff --git a/src/game/Object.cpp b/src/game/Object.cpp
index fc7826a..943675a 100644
--- a/src/game/Object.cpp
+++ b/src/game/Object.cpp
@@ -1051,6 +1051,8 @@ WorldObject::WorldObject()
     : m_mapId(0), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL),
     m_positionX(0.0f), m_positionY(0.0f), m_positionZ(0.0f), m_orientation(0.0f)
 {
+    m_notifyflags = 0;
+    m_executed_notifies = 0;
 }
 
 void WorldObject::CleanupsBeforeDelete()
diff --git a/src/game/Object.h b/src/game/Object.h
index aa53d62..5ce64fd 100644
--- a/src/game/Object.h
+++ b/src/game/Object.h
@@ -83,6 +83,15 @@ enum PhaseMasks
     PHASEMASK_ANYWHERE = 0xFFFFFFFF
 };
 
+enum NotifyFlags
+{
+    NOTIFY_NONE                     = 0x00,
+    NOTIFY_RELOCATION               = 0x01,
+    NOTIFY_VISIBILITY               = 0x02,
+    NOTIFY_VISIBILITY_SELF          = 0x04,
+    NOTIFY_ALL                      = 0xFF
+};
+
 class WorldPacket;
 class UpdateData;
 class ByteBuffer;
@@ -481,6 +490,17 @@ class MANGOS_DLL_SPEC WorldObject : public Object
         // 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;
 
+        //new relocation and visibility system functions
+        void AddToNotify(uint16 f) { m_notifyflags |= f;}
+        void RemoveFromNotify(uint16 f) { m_notifyflags &= ~f;}
+        bool isNeedNotify(uint16 f) const { return m_notifyflags & f;}
+
+        bool isNotified(uint16 f) const { return m_executed_notifies & f;}
+        void SetNotified(uint16 f) { m_executed_notifies |= f;}
+        void ResetNotifies(uint16 f) { m_executed_notifies |= ~f;}
+        void ResetAllNotifies() { m_notifyflags = 0; m_executed_notifies = 0; }
+        void ResetAllNotifiesbyMask(uint16 f) { m_notifyflags &= ~f; m_executed_notifies &= ~f; }
+
         Map      * GetMap() const;
         Map const* GetBaseMap() const;
         Creature* SummonCreature(uint32 id, float x, float y, float z, float ang,TempSummonType spwtype,uint32 despwtime);
@@ -498,5 +518,8 @@ class MANGOS_DLL_SPEC WorldObject : public Object
         float m_positionY;
         float m_positionZ;
         float m_orientation;
+
+        uint16 m_notifyflags;
+        uint16 m_executed_notifies;
 };
 #endif
diff --git a/src/game/ObjectAccessor.cpp b/src/game/ObjectAccessor.cpp
index 43eb02a..1097423 100644
--- a/src/game/ObjectAccessor.cpp
+++ b/src/game/ObjectAccessor.cpp
@@ -435,7 +435,7 @@ void ObjectAccessor::UpdateVisibilityForPlayer( Player* player )
     Cell cell(p);
     Map* m = player->GetMap();
 
-    m->UpdatePlayerVisibility(player, cell, p);
+    m->UpdateObjectVisibility(player, cell, p);
     m->UpdateObjectsVisibilityFor(player, cell, p);
 }
 
diff --git a/src/game/Player.cpp b/src/game/Player.cpp
index 77bf6c2..d96b39c 100644
--- a/src/game/Player.cpp
+++ b/src/game/Player.cpp
@@ -369,6 +369,7 @@ Player::Player (WorldSession *session): Unit(), m_achievementMgr(this), m_reputa
     m_swingErrorMsg = 0;
 
     m_DetectInvTimer = 1*IN_MILISECONDS;
+    undetected = false;
 
     m_bgBattleGroundID = 0;
     m_bgTypeID = BATTLEGROUND_TYPE_NONE;
@@ -1272,11 +1273,17 @@ void Player::Update( uint32 p_time )
     {
         if (p_time >= m_DetectInvTimer)
         {
+            undetected = false;
             m_DetectInvTimer = 3000;
             HandleStealthedUnitsDetection();
-        }
-        else
+        }else
             m_DetectInvTimer -= p_time;
+
+        if(!undetected && m_DetectInvTimer <= 300)
+        {
+            undetected = true;
+            HandleStealthedUnitsUndetection();
+        }
     }
 
     // Played time
@@ -16831,7 +16838,7 @@ void Player::HandleStealthedUnitsDetection()
             continue;
         }
 
-        if ((*i)->isVisibleForOrDetect(this,true))
+        if (!HaveAtClient(*i) && (*i)->isVisibleForOrDetect(this,true))
         {
 
             (*i)->SendUpdateToPlayer(this);
@@ -16844,8 +16851,53 @@ void Player::HandleStealthedUnitsDetection()
 
             // target aura duration for caster show only if target exist at caster client
             // send data at target visibility change (adding to client)
-            if((*i)!=this && (*i)->isType(TYPEMASK_UNIT))
-                SendAurasForTarget(*i);
+            if((*i)->isType(TYPEMASK_UNIT))
+                (*i)->SendInitialVisiblePackets(this);
+
+            i = stealthedUnits.erase(i);
+            continue;
+        }
+
+        ++i;
+    }
+}
+
+void Player::HandleStealthedUnitsUndetection()
+{
+    std::list<Unit*> stealthedUnits;
+
+    CellPair p(MaNGOS::ComputeCellPair(GetPositionX(),GetPositionY()));
+    Cell cell(p);
+    cell.data.Part.reserved = ALL_DISTRICT;
+    cell.SetNoCreate();
+
+    MaNGOS::AnyStealthedCheck u_check;
+    MaNGOS::UnitListSearcher<MaNGOS::AnyStealthedCheck > searcher(this,stealthedUnits, u_check);
+
+    TypeContainerVisitor<MaNGOS::UnitListSearcher<MaNGOS::AnyStealthedCheck >, WorldTypeMapContainer > world_unit_searcher(searcher);
+    TypeContainerVisitor<MaNGOS::UnitListSearcher<MaNGOS::AnyStealthedCheck >, GridTypeMapContainer >  grid_unit_searcher(searcher);
+
+    CellLock<GridReadGuard> cell_lock(cell, p);
+    cell_lock->Visit(cell_lock, world_unit_searcher, *GetMap());
+    cell_lock->Visit(cell_lock, grid_unit_searcher, *GetMap());
+
+    for (std::list<Unit*>::iterator i = stealthedUnits.begin(); i != stealthedUnits.end();)
+    {
+        if((*i)==this)
+        {
+            i = stealthedUnits.erase(i);
+            continue;
+        }
+
+        if (HaveAtClient(*i) && !(*i)->isVisibleForOrDetect(this,false))
+        {
+            (*i)->DestroyForPlayer(this);
+            m_clientGUIDs.erase((*i)->GetGUID());
+
+            #ifdef MANGOS_DEBUG
+            if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0)
+                sLog.outDebug("Object %u (Type: %u) is undetected in stealth by player %u. Distance = %f",(*i)->GetGUIDLow(),(*i)->GetTypeId(),GetGUIDLow(),GetDistance(*i));
+            #endif
 
             i = stealthedUnits.erase(i);
             continue;
@@ -17868,6 +17920,19 @@ bool Player::IsVisibleGloballyFor( Player* u ) const
     return true;
 }
 
+template<class T>
+inline void UpdateVisibilityOf_helper(std::set<uint64>& s64, T* target)
+{
+    s64.insert(target->GetGUID());
+}
+
+template<>
+inline void UpdateVisibilityOf_helper(std::set<uint64>& s64, GameObject* target)
+{
+    if(!target->IsTransport())
+        s64.insert(target->GetGUID());
+}
+
 void Player::UpdateVisibilityOf(WorldObject* target)
 {
     if(HaveAtClient(target))
@@ -17887,41 +17952,27 @@ void Player::UpdateVisibilityOf(WorldObject* target)
     {
         if(target->isVisibleForInState(this,false))
         {
-            target->SendUpdateToPlayer(this);
-            if(target->GetTypeId()!=TYPEID_GAMEOBJECT||!((GameObject*)target)->IsTransport())
-                m_clientGUIDs.insert(target->GetGUID());
+            UpdateData upd;
+            target->BuildCreateUpdateBlockForPlayer(&upd, this);
+
+            WorldPacket packet;
+            upd.BuildPacket(&packet);
+            GetSession()->SendPacket(&packet);
+
+            UpdateVisibilityOf_helper(m_clientGUIDs, target);
+            if(target->isType(TYPEMASK_UNIT) && target != this)
+                ((Unit*)target)->SendInitialVisiblePackets(this);
 
             #ifdef MANGOS_DEBUG
             if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0)
                 sLog.outDebug("Object %u (Type: %u) is visible now for player %u. Distance = %f",target->GetGUIDLow(),target->GetTypeId(),GetGUIDLow(),GetDistance(target));
             #endif
-
-            // target aura duration for caster show only if target exist at caster client
-            // send data at target visibility change (adding to client)
-            if(target!=this && target->isType(TYPEMASK_UNIT))
-                SendAurasForTarget((Unit*)target);
-
-            if(target->GetTypeId()==TYPEID_UNIT && ((Creature*)target)->isAlive())
-                ((Creature*)target)->SendMonsterMoveWithSpeedToCurrentDestination(this);
         }
     }
 }
 
 template<class T>
-inline void UpdateVisibilityOf_helper(std::set<uint64>& s64, T* target)
-{
-    s64.insert(target->GetGUID());
-}
-
-template<>
-inline void UpdateVisibilityOf_helper(std::set<uint64>& s64, GameObject* target)
-{
-    if(!target->IsTransport())
-        s64.insert(target->GetGUID());
-}
-
-template<class T>
-void Player::UpdateVisibilityOf(T* target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow)
+void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& visibleNow)
 {
     if(HaveAtClient(target))
     {
@@ -17940,11 +17991,11 @@ void Player::UpdateVisibilityOf(T* target, UpdateData& data, UpdateDataMapType&
     {
         if(target->isVisibleForInState(this,false))
         {
-            visibleNow.insert(target);
-            target->BuildUpdate(data_updates);
             target->BuildCreateUpdateBlockForPlayer(&data, this);
             UpdateVisibilityOf_helper(m_clientGUIDs,target);
 
+            if(target->isType(TYPEMASK_UNIT) && ((Unit*)target) != this)
+                visibleNow.insert((Unit*)target);
             #ifdef MANGOS_DEBUG
             if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0)
                 sLog.outDebug("Object %u (Type: %u, Entry: %u) is visible now for player %u. Distance = %f",target->GetGUIDLow(),target->GetTypeId(),target->GetEntry(),GetGUIDLow(),GetDistance(target));
@@ -17953,11 +18004,11 @@ void Player::UpdateVisibilityOf(T* target, UpdateData& data, UpdateDataMapType&
     }
 }
 
-template void Player::UpdateVisibilityOf(Player*        target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow);
-template void Player::UpdateVisibilityOf(Creature*      target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow);
-template void Player::UpdateVisibilityOf(Corpse*        target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow);
-template void Player::UpdateVisibilityOf(GameObject*    target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow);
-template void Player::UpdateVisibilityOf(DynamicObject* target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow);
+template void Player::UpdateVisibilityOf(Player*        target, UpdateData& data, std::set<Unit*>& visibleNow);
+template void Player::UpdateVisibilityOf(Creature*      target, UpdateData& data, std::set<Unit*>& visibleNow);
+template void Player::UpdateVisibilityOf(Corpse*        target, UpdateData& data, std::set<Unit*>& visibleNow);
+template void Player::UpdateVisibilityOf(GameObject*    target, UpdateData& data, std::set<Unit*>& visibleNow);
+template void Player::UpdateVisibilityOf(DynamicObject* target, UpdateData& data, std::set<Unit*>& visibleNow);
 
 void Player::InitPrimaryProfessions()
 {
@@ -18122,7 +18173,7 @@ void Player::SendInitialPacketsAfterAddToMap()
         SendMessageToSet(&data2,true);
     }
 
-    SendAurasForTarget(this);
+    SendAuras(this);
     SendEnchantmentDurations();                             // must be after add to map
     SendItemDurations();                                    // must be after add to map
 }
@@ -18355,53 +18406,6 @@ void Player::learnSkillRewardedSpells(uint32 skill_id, uint32 skill_value )
     }
 }
 
-void Player::SendAurasForTarget(Unit *target)
-{
-    if(target->GetVisibleAuras()->empty())                  // speedup things
-        return;
-
-    WorldPacket data(SMSG_AURA_UPDATE_ALL);
-    data.append(target->GetPackGUID());
-
-    Unit::VisibleAuraMap const *visibleAuras = target->GetVisibleAuras();
-    for(Unit::VisibleAuraMap::const_iterator itr = visibleAuras->begin(); itr != visibleAuras->end(); ++itr)
-    {
-        for(uint32 j = 0; j < 3; ++j)
-        {
-            if(Aura *aura = target->GetAura(itr->second, j))
-            {
-                data << uint8(aura->GetAuraSlot());
-                data << uint32(aura->GetId());
-
-                if(aura->GetId())
-                {
-                    uint8 auraFlags = aura->GetAuraFlags();
-                    // flags
-                    data << uint8(auraFlags);
-                    // level
-                    data << uint8(aura->GetAuraLevel());
-                    // charges
-                    data << uint8(aura->GetAuraCharges());
-
-                    if(!(auraFlags & AFLAG_NOT_CASTER))
-                    {
-                        data << uint8(0);                   // packed GUID of someone (caster?)
-                    }
-
-                    if(auraFlags & AFLAG_DURATION)          // include aura duration
-                    {
-                        data << uint32(aura->GetAuraMaxDuration());
-                        data << uint32(aura->GetAuraDuration());
-                    }
-                }
-                break;
-            }
-        }
-    }
-
-    GetSession()->SendPacket(&data);
-}
-
 void Player::SetDailyQuestStatus( uint32 quest_id )
 {
     for(uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx)
diff --git a/src/game/Player.h b/src/game/Player.h
index f7a656f..c8956b6 100644
--- a/src/game/Player.h
+++ b/src/game/Player.h
@@ -1865,8 +1865,6 @@ class MANGOS_DLL_SPEC Player : public Unit
         void SendUpdateWorldState(uint32 Field, uint32 Value);
         void SendDirectMessage(WorldPacket *data);
 
-        void SendAurasForTarget(Unit *target);
-
         PlayerMenu* PlayerTalkClass;
         std::vector<ItemSetEffect *> ItemSetEff;
 
@@ -2083,7 +2081,7 @@ class MANGOS_DLL_SPEC Player : public Unit
         void UpdateVisibilityOf(WorldObject* target);
 
         template<class T>
-            void UpdateVisibilityOf(T* target, UpdateData& data, UpdateDataMapType& data_updates, std::set<WorldObject*>& visibleNow);
+            void UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& visibleNow);
 
         // Stealth detection system
         uint32 m_DetectInvTimer;
@@ -2416,6 +2414,8 @@ class MANGOS_DLL_SPEC Player : public Unit
         void SetCanDelayTeleport(bool setting) { m_bCanDelayTeleport = setting; }
         bool IsHasDelayedTeleport() const { return m_bHasDelayedTeleport; }
         void SetDelayedTeleportFlag(bool setting) { m_bHasDelayedTeleport = setting; }
+        void HandleStealthedUnitsUndetection();
+        bool undetected;
 
         void ScheduleDelayedOperation(uint32 operation);
 
diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp
index f0ff6b6..ff909f0 100644
--- a/src/game/Unit.cpp
+++ b/src/game/Unit.cpp
@@ -2343,6 +2343,69 @@ void Unit::SendMeleeAttackStop(Unit* victim)
     ((Creature*)victim)->AI().EnterEvadeMode(this);*/
 }
 
+void Unit::SendInitialVisiblePackets(Player *player)
+{
+    SendAuras(player);
+    if(isAlive())
+    {
+        if(GetTypeId() == TYPEID_UNIT)
+            ((Creature*)this)->SendMonsterMoveWithSpeedToCurrentDestination(player);
+
+        if(hasUnitState(UNIT_STAT_MELEE_ATTACKING) && getVictim())
+            SendMeleeAttackStart(getVictim());
+    }
+}
+
+void Unit::SendAuras(Player *player)
+{
+    if(GetVisibleAuras()->empty())                  // speedup things
+        return;
+
+    WorldPacket data(SMSG_AURA_UPDATE_ALL);
+    data.append(GetPackGUID());
+
+    Unit::VisibleAuraMap const *visibleAuras = GetVisibleAuras();
+    for(Unit::VisibleAuraMap::const_iterator itr = visibleAuras->begin(); itr != visibleAuras->end(); ++itr)
+    {
+        for(uint32 j = 0; j < 3; ++j)
+        {
+            if(Aura *aura = GetAura(itr->second, j))
+            {
+                data << uint8(aura->GetAuraSlot());
+                data << uint32(aura->GetId());
+
+                if(aura->GetId())
+                {
+                    uint8 auraFlags = aura->GetAuraFlags();
+                    // flags
+                    data << uint8(auraFlags);
+                    // level
+                    data << uint8(aura->GetAuraLevel());
+                    // charges
+                    data << uint8(aura->GetAuraCharges());
+
+                    if(!(auraFlags & AFLAG_NOT_CASTER))
+                    {
+                        data << uint8(0);                   // packed GUID of someone (caster?)
+                    }
+
+                    if(auraFlags & AFLAG_DURATION)          // include aura duration
+                    {
+                        data << uint32(aura->GetAuraMaxDuration());
+                        data << uint32(aura->GetAuraDuration());
+                    }
+                }
+                break;
+            }
+        }
+    }
+
+    if (player)
+        player->GetSession()->SendPacket(&data);
+    else
+        SendMessageToSet(&data,true);
+}
+
 bool Unit::isSpellBlocked(Unit *pVictim, SpellEntry const * /*spellProto*/, WeaponAttackType attackType)
 {
     if (pVictim->HasInArc(M_PI,this))
@@ -9265,12 +9328,17 @@ void Unit::SetVisibility(UnitVisibility x)
 
     if(IsInWorld())
     {
-        Map *m = GetMap();
+        CellPair p = MaNGOS::ComputeCellPair(GetPositionX(), GetPositionY());
+        Cell cell(p);
 
-        if(GetTypeId()==TYPEID_PLAYER)
-            m->PlayerRelocation((Player*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
-        else
-            m->CreatureRelocation((Creature*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
+        GetMap()->UpdateObjectVisibility(this, cell, p);
+
+        if(GetTypeId() == TYPEID_PLAYER)
+        {
+            GetMap()->UpdateObjectsVisibilityFor((Player*)this, cell, p);
+            GetMap()->PlayerRelocationNotify((Player*)this, cell, p);
+        }else
+            GetMap()->CreatureRelocationNotify((Creature*)this, cell, p);
     }
 }
 
diff --git a/src/game/Unit.h b/src/game/Unit.h
index faefbef..b347ab3 100644
--- a/src/game/Unit.h
+++ b/src/game/Unit.h
@@ -921,6 +921,8 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
         bool hasNegativeAuraWithInterruptFlag(uint32 flag);
         void SendMeleeAttackStop(Unit* victim);
         void SendMeleeAttackStart(Unit* pVictim);
+        void SendInitialVisiblePackets(Player *player = 0);
+        void SendAuras(Player *player = 0);
 
         void addUnitState(uint32 f) { m_state |= f; }
         bool hasUnitState(const uint32 f) const { return (m_state & f); }
diff --git a/src/shared/Timer.h b/src/shared/Timer.h
index c258fdc..79470a8 100644
--- a/src/shared/Timer.h
+++ b/src/shared/Timer.h
@@ -93,4 +93,21 @@ struct TimeTrackerSmall
     int32 i_expiryTime;
 };
 
+struct PeriodicTimer
+{
+    PeriodicTimer(int32 period, int32 start_time) :
+        i_expirity(start_time), i_period(period) {}
+        
+    bool Update(const uint32 &diff)
+    {
+        if((i_expirity -= diff) > 0)
+            return false;
+
+        i_expirity += i_period;
+        return true;
+    }
+    const int32 i_period;
+    int32 i_expirity;
+};
+
 #endif
