Implement new visibility system, based on Silverice patch for mangos

--HG--
branch : trunk
This commit is contained in:
n0n4m3
2009-12-19 10:12:40 +01:00
parent 7a3e524df2
commit 243f33b5ea
15 changed files with 553 additions and 165 deletions

View File

@@ -29,6 +29,92 @@
using namespace Trinity;
void
Player2PlayerNotifier::Visit(PlayerMapType &m)
{
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
{
Player* plr = iter->getSource();
if(plr == &i_player)
continue;
vis_guids.erase(plr->GetGUID());
i_player.UpdateVisibilityOf(plr,i_data,i_visibleNow);
// force == true - update i_player visibility for all player in cell, ignore optimization flags.
if(!force && (plr->NotifyExecuted(NOTIFY_PLAYER_VISIBILITY) || plr->isNeedNotify(NOTIFY_PLAYER_VISIBILITY)))
continue;
plr->UpdateVisibilityOf(&i_player);
}
}
void
VisibleNotifier::SendToSelf()
{
for(Player::ClientGUIDs::const_iterator it = vis_guids.begin();it != vis_guids.end();++it)
{ //player guids processed in Player2PlayerNotifier
if(IS_PLAYER_GUID(*it))
continue;
i_player.m_clientGUIDs.erase(*it);
i_data.AddOutOfRangeGUID(*it);
}
if(!i_data.HasData())
return;
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)
i_player.SendInitialVisiblePackets(*it);
}
void
Player2PlayerNotifier::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())
for(Transport::PlayerSet::const_iterator itr = transport->GetPassengers().begin();itr!=transport->GetPassengers().end();++itr)
{
if(vis_guids.find((*itr)->GetGUID()) != vis_guids.end())
{
vis_guids.erase((*itr)->GetGUID());
i_player.UpdateVisibilityOf((*itr), i_data, i_visibleNow);
if(!(*itr)->isNeedNotify(NOTIFY_PLAYER_VISIBILITY))
(*itr)->UpdateVisibilityOf(&i_player);
}
}
for(Player::ClientGUIDs::const_iterator it = vis_guids.begin();it != vis_guids.end(); ++it)
{
//since its player-player notifier we work only with player guids
if(!IS_PLAYER_GUID(*it))
continue;
i_player.m_clientGUIDs.erase(*it);
i_data.AddOutOfRangeGUID(*it);
Player* plr = ObjectAccessor::FindPlayer(*it);
if(plr && plr->IsInWorld() && !plr->NotifyExecuted(NOTIFY_PLAYER_VISIBILITY) && !plr->isNeedNotify(NOTIFY_PLAYER_VISIBILITY))
plr->UpdateVisibilityOf(&i_player);
}
if(!i_data.HasData())
return;
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)
i_player.SendInitialVisiblePackets(*it);
}
void
VisibleChangesNotifier::Visit(PlayerMapType &m)
{
@@ -71,74 +157,6 @@ VisibleChangesNotifier::Visit(DynamicObjectMapType &m)
void
PlayerVisibilityNotifier::Notify()
{
// 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())
{
for (Transport::PlayerSet::const_iterator itr = transport->GetPassengers().begin(); itr!=transport->GetPassengers().end(); ++itr)
{
if(i_clientGUIDs.find((*itr)->GetGUID())!=i_clientGUIDs.end())
{
(*itr)->UpdateVisibilityOf(&i_player);
i_player.UpdateVisibilityOf((*itr),i_data,i_visibleNow);
i_clientGUIDs.erase((*itr)->GetGUID());
}
}
}
// 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);
#ifdef TRINITY_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
}
if( i_data.HasData() )
{
/*uint32 entry = 0, map;
float x,y;
if(!i_visibleNow.empty())
{
entry = (*i_visibleNow.begin())->GetEntry();
map = (*i_visibleNow.begin())->GetMapId();
x = (*i_visibleNow.begin())->GetPositionX();
y = (*i_visibleNow.begin())->GetPositionY();
sLog.outError("notify %u %u %f %f", entry, map, x, y);
}*/
// 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);
}
}
// Now do operations that required done at object visibility change to visible
// 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.SendInitialVisiblePackets((Unit*)(*vItr));
if(i_visibleNow.size() >= 30)
i_player.SetToNotify();
}
void

View File

@@ -38,6 +38,35 @@ class Player;
namespace Trinity
{
struct MANGOS_DLL_DECL VisibleNotifier
{
bool force;
Player &i_player;
UpdateData i_data;
std::set<Unit*> i_visibleNow;
Player::ClientGUIDs vis_guids;
explicit VisibleNotifier(Player &player, bool forced) :
i_player(player), vis_guids(player.m_clientGUIDs), force(forced) {}
explicit VisibleNotifier(Player &player) :
i_player(player), vis_guids(player.m_clientGUIDs),
force(player.isNeedNotify(NOTIFY_VISIBILITY_CHANGED)) {}
template<class T> void Visit(GridRefManager<T> &m);
void Visit(CreatureMapType &m);
void Visit(PlayerMapType &m) {}
void SendToSelf(void);
};
struct MANGOS_DLL_DECL Player2PlayerNotifier : public VisibleNotifier
{
Player2PlayerNotifier(Player &player, bool forced = false) :
VisibleNotifier(player, forced) {}
template<class T> void Visit(GridRefManager<T> &) {}
void Visit(PlayerMapType &);
void SendToSelf(void);
};
struct TRINITY_DLL_DECL PlayerVisibilityNotifier
{
Player &i_player;
@@ -52,12 +81,12 @@ namespace Trinity
void Notify(void);
};
struct TRINITY_DLL_DECL PlayerRelocationNotifier : public PlayerVisibilityNotifier
struct MANGOS_DLL_DECL PlayerRelocationNotifier
{
PlayerRelocationNotifier(Player &player) : PlayerVisibilityNotifier(player) {}
template<class T> inline void Visit(GridRefManager<T> &m) { PlayerVisibilityNotifier::Visit(m); }
Player &i_player;
PlayerRelocationNotifier(Player &pl) : i_player(pl) {}
template<class T> void Visit(GridRefManager<T> &) {}
#ifdef WIN32
template<> inline void Visit(PlayerMapType &);
template<> inline void Visit(CreatureMapType &);
#endif
};
@@ -84,6 +113,31 @@ namespace Trinity
void Visit(DynamicObjectMapType &);
};
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 &m) { Notify<Creature,CreatureRelocationNotifier >(m); }
void Visit(PlayerMapType &m) { Notify<Player,PlayerRelocationNotifier >(m); }
template<class T, class VISITOR>
void Notify(GridRefManager<T> &);
};
struct MANGOS_DLL_DECL ResetNotifier
{
uint16 reset_mask;
ResetNotifier(uint16 notifies) : reset_mask(notifies) {}
template<class T> void Visit(GridRefManager<T> &m) { /*resetNotify(m);*/}
template<class T> void resetNotify(GridRefManager<T> &);
void Visit(CreatureMapType &m) { resetNotify<Creature>(m);}
void Visit(PlayerMapType &m) { resetNotify<Player>(m);}
};
struct TRINITY_DLL_DECL GridUpdater
{
GridType &i_grid;
@@ -1236,7 +1290,6 @@ namespace Trinity
#ifndef WIN32
template<> inline void PlayerRelocationNotifier::Visit<Creature>(CreatureMapType &);
template<> inline void PlayerRelocationNotifier::Visit<Player>(PlayerMapType &);
template<> inline void CreatureRelocationNotifier::Visit<Player>(PlayerMapType &);
template<> inline void CreatureRelocationNotifier::Visit<Creature>(CreatureMapType &);
template<> inline void DynamicObjectUpdater::Visit<Creature>(CreatureMapType &);

View File

@@ -29,6 +29,32 @@
#include "CreatureAI.h"
#include "SpellAuras.h"
template<class T>
inline void
Trinity::VisibleNotifier::Visit(GridRefManager<T> &m)
{
for(typename GridRefManager<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
{
vis_guids.erase(iter->getSource()->GetGUID());
if(force/* || iter->getSource()->isNeedNotify(NOTIFY_VISIBILITY_CHANGED)*/)
i_player.UpdateVisibilityOf(iter->getSource(),i_data,i_visibleNow);
}
}
inline void
Trinity::VisibleNotifier::Visit(CreatureMapType &m)
{
for(CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
{
vis_guids.erase(iter->getSource()->GetGUID());
if(force || iter->getSource()->isNeedNotify(NOTIFY_VISIBILITY_CHANGED))
i_player.UpdateVisibilityOf(iter->getSource(),i_data,i_visibleNow);
}
}
inline void
Trinity::ObjectUpdater::Visit(CreatureMapType &m)
{
@@ -70,45 +96,47 @@ Trinity::PlayerVisibilityNotifier::Visit(GridRefManager<T> &m)
}
}
template<>
template<class T, class VISITOR>
inline void
Trinity::PlayerRelocationNotifier::Visit(PlayerMapType &m)
MaNGOS::DelayedUnitRelocation::Notify(GridRefManager<T> &m)
{
for (PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
for(typename GridRefManager<T>::iterator iter = m.begin(); iter != m.end(); ++iter)
{
i_clientGUIDs.erase(iter->getSource()->GetGUID());
if(iter->getSource()->m_Notified) //self is also skipped in this check
T * unit = iter->getSource();
if(!unit->isAlive() || !unit->isNeedNotify(NOTIFY_AI_RELOCATION))
continue;
i_player.UpdateVisibilityOf(iter->getSource(),i_data,i_visibleNow);
iter->getSource()->UpdateVisibilityOf(&i_player);
VISITOR relocate(*unit);
TypeContainerVisitor<VISITOR, WorldTypeMapContainer > c2world_relocation(relocate);
TypeContainerVisitor<VISITOR, GridTypeMapContainer > c2grid_relocation(relocate);
//if (!i_player.GetSharedVisionList().empty())
// for (SharedVisionList::const_iterator it = i_player.GetSharedVisionList().begin(); it != i_player.GetSharedVisionList().end(); ++it)
// (*it)->UpdateVisibilityOf(iter->getSource());
i_lock->Visit(i_lock, c2world_relocation, i_map, *unit, i_radius);
i_lock->Visit(i_lock, c2grid_relocation, i_map, *unit, i_radius);
// Cancel Trade
if(i_player.GetTrader()==iter->getSource())
if(!i_player.IsWithinDistInMap(iter->getSource(), 5)) // iteraction distance
i_player.GetSession()->SendCancelTrade(); // will clode both side trade windows
unit->SetNotified(NOTIFY_AI_RELOCATION);
}
}
template<class T>
inline void
MaNGOS::ResetNotifier::resetNotify(GridRefManager<T> &m)
{
for(typename GridRefManager<T>::iterator iter=m.begin(); iter != m.end(); ++iter)
iter->getSource()->ResetAllNotifiesbyMask(reset_mask);
}
template<>
inline void
Trinity::PlayerRelocationNotifier::Visit(CreatureMapType &m)
{
if(!i_player.isAlive() || i_player.isInFlight())
return;
for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
{
i_clientGUIDs.erase(iter->getSource()->GetGUID());
if(iter->getSource()->m_Notified)
continue;
i_player.UpdateVisibilityOf(iter->getSource(),i_data,i_visibleNow);
PlayerCreatureRelocationWorker(&i_player, iter->getSource());
Creature * c = iter->getSource();
if(c->isAlive() && !c->NotifyExecuted(NOTIFY_AI_RELOCATION))
PlayerCreatureRelocationWorker(&i_player, c);
}
}
@@ -116,14 +144,14 @@ template<>
inline void
Trinity::CreatureRelocationNotifier::Visit(PlayerMapType &m)
{
for (PlayerMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
if(!i_creature.isAlive())
return;
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
{
if(iter->getSource()->m_Notified)
continue;
iter->getSource()->UpdateVisibilityOf(&i_creature);
PlayerCreatureRelocationWorker(iter->getSource(), &i_creature);
Player * pl = iter->getSource();
if( pl->isAlive() && !pl->isInFlight() && !pl->NotifyExecuted(NOTIFY_AI_RELOCATION))
PlayerCreatureRelocationWorker(pl, &i_creature);
}
}
@@ -136,13 +164,9 @@ Trinity::CreatureRelocationNotifier::Visit(CreatureMapType &m)
for (CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
{
if(iter->getSource()->m_Notified)
continue;
if(!iter->getSource()->isAlive())
continue;
CreatureCreatureRelocationWorker(iter->getSource(), &i_creature);
Creature* c = iter->getSource();
if( c != &i_creature && c->isAlive() && !c->NotifyExecuted(NOTIFY_AI_RELOCATION))
CreatureCreatureRelocationWorker(c, &i_creature);
}
}

View File

@@ -214,7 +214,10 @@ Map::Map(uint32 id, time_t expiry, uint32 InstanceId, uint8 SpawnMode, Map* _par
m_activeNonPlayersIter(m_activeNonPlayers.end()),
i_gridExpiry(expiry), m_parentMap(_parent ? _parent : this),
m_VisibleDistance(DEFAULT_VISIBILITY_DISTANCE)
, i_notifyLock(false), i_scriptLock(false)
, i_notifyLock(false), i_scriptLock(false),
m_PlayerVisibilityNotifyTimer(0.75*DEFAULT_VISIBILITY_NOTIFY_PERIOD, 0.25*DEFAULT_VISIBILITY_NOTIFY_PERIOD),
m_ObjectVisibilityNotifyTimer(DEFAULT_VISIBILITY_NOTIFY_PERIOD, 0 * DEFAULT_VISIBILITY_NOTIFY_PERIOD),
m_RelocationNotifyTimer(DEFAULT_VISIBILITY_NOTIFY_PERIOD,0.5*DEFAULT_VISIBILITY_NOTIFY_PERIOD)
{
m_notifyTimer.SetInterval(IN_MILISECONDS/2);
@@ -236,6 +239,10 @@ void Map::InitVisibilityDistance()
{
//init visibility for continents
m_VisibleDistance = World::GetMaxVisibleDistanceOnContinents();
m_PlayerVisibilityNotifyTimer.SetPeriodic(0.75*sWorld.GetVisibilityNotifyPeriodOnContinents(), 0.25*sWorld.GetVisibilityNotifyPeriodOnContinents());
m_ObjectVisibilityNotifyTimer.SetPeriodic(sWorld.GetVisibilityNotifyPeriodOnContinents(), 0 * sWorld.GetVisibilityNotifyPeriodOnContinents());
m_RelocationNotifyTimer.SetPeriodic(sWorld.GetVisibilityNotifyPeriodOnContinents(),0.5*sWorld.GetVisibilityNotifyPeriodOnContinents());
}
// Template specialization of utility methods
@@ -336,17 +343,13 @@ void Map::AddNotifier(T*)
template<>
void Map::AddNotifier(Player* obj)
{
//obj->m_Notified = false;
//obj->m_IsInNotifyList = false;
AddUnitToNotify(obj);
obj->AddToNotify(NOTIFY_VISIBILITY_CHANGED | NOTIFY_AI_RELOCATION | NOTIFY_PLAYER_VISIBILITY);
}
template<>
void Map::AddNotifier(Creature* obj)
{
//obj->m_Notified = false;
//obj->m_IsInNotifyList = false;
AddUnitToNotify(obj);
obj->AddToNotify(NOTIFY_VISIBILITY_CHANGED | NOTIFY_AI_RELOCATION);
}
void
@@ -444,13 +447,14 @@ bool Map::Add(Player *player)
CellPair p = Trinity::ComputeCellPair(player->GetPositionX(), player->GetPositionY());
Cell cell(p);
EnsureGridLoadedAtEnter(cell, player);
player->ResetAllNotifies();
player->AddToWorld();
SendInitSelf(player);
SendInitTransports(player);
player->m_clientGUIDs.clear();
//AddNotifier(player);
AddNotifier<Player>(player);
return true;
}
@@ -494,8 +498,8 @@ Map::Add(T *obj)
//something, such as vehicle, needs to be update immediately
//also, trigger needs to cast spell, if not update, cannot see visual
//if(obj->GetTypeId() != TYPEID_UNIT)
UpdateObjectVisibility(obj,cell,p);
AddNotifier(obj);
UpdateObjectVisibility(obj,cell,p);
AddNotifier<T>(obj);
}
/*
@@ -601,7 +605,7 @@ bool Map::loaded(const GridPair &p) const
void Map::RelocationNotify()
{
i_notifyLock = true;
/* i_notifyLock = true;
//Notify
for (std::vector<Unit*>::iterator iter = i_unitsToNotify.begin(); iter != i_unitsToNotify.end(); ++iter)
@@ -651,12 +655,12 @@ void Map::RelocationNotify()
{
i_unitsToNotify.insert(i_unitsToNotify.end(), i_unitsToNotifyBacklog.begin(), i_unitsToNotifyBacklog.end());
i_unitsToNotifyBacklog.clear();
}
}*/
}
void Map::AddUnitToNotify(Unit* u)
{
if(u->m_NotifyListPos < 0 && u->IsInWorld())
/* if(u->m_NotifyListPos < 0 && u->IsInWorld())
{
u->oldX = u->GetPositionX();
u->oldY = u->GetPositionY();
@@ -671,7 +675,7 @@ void Map::AddUnitToNotify(Unit* u)
u->m_NotifyListPos = i_unitsToNotify.size();
i_unitsToNotify.push_back(u);
}
}
}*/
}
void Map::RemoveUnitFromNotify(Unit *unit)
@@ -714,13 +718,6 @@ void Map::Update(const uint32 &t_diff)
plr->Update(t_diff);
}
m_notifyTimer.Update(t_diff);
if (m_notifyTimer.Passed())
{
m_notifyTimer.Reset();
RelocationNotify();
}
/// update active cells around players and active objects
resetMarkedCells();
@@ -772,9 +769,6 @@ void Map::Update(const uint32 &t_diff)
}
}
}
if (plr->m_seer != plr && !plr->GetVehicle())
AddUnitToNotify(plr);
}
// non-player active objects
@@ -836,10 +830,191 @@ void Map::Update(const uint32 &t_diff)
}
MoveAllCreaturesInMoveList();
{
bool hasPlayers = !m_mapRefManager.isEmpty();
bool hasActiveObjects = !m_activeNonPlayers.empty();
if(hasPlayers)
{
if(m_PlayerVisibilityNotifyTimer.Update(t_diff))
{ // process player-player visibility
ProcesssPlayersVisibility();
ResetNotifies(NOTIFY_PLAYER_VISIBILITY);
}
if(m_ObjectVisibilityNotifyTimer.Update(t_diff))
{
ProcessObjectsVisibility();
ResetNotifies(NOTIFY_VISIBILITY_CHANGED);
}
}
if(hasActiveObjects || hasPlayers)
if(m_RelocationNotifyTimer.Update(t_diff))
{
ProcessRelocationNotifies();
ResetNotifies(NOTIFY_AI_RELOCATION);
}
}
}
void Map::ProcesssPlayersVisibility()
{
for(m_mapRefIter = m_mapRefManager.begin(); m_mapRefIter != m_mapRefManager.end(); ++m_mapRefIter)
{
Player* player = m_mapRefIter->getSource();
if (player->m_seer != player && !player->GetVehicle())
AddNotifier<Player>(player);
if(!player->IsInWorld() || !player->isNeedNotify(NOTIFY_PLAYER_VISIBILITY))
continue;
WorldObject const *viewPoint = player->m_seer;
CellPair cellpair(Trinity::ComputeCellPair(viewPoint->GetPositionX(), viewPoint->GetPositionY()));
if (cellpair.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || cellpair.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
continue;
Trinity::Player2PlayerNotifier notifier(*player);
Cell cell(cellpair);
cell.data.Part.reserved = ALL_DISTRICT;
//cell.SetNoCreate();
TypeContainerVisitor<Trinity::Player2PlayerNotifier, WorldTypeMapContainer > world_notifier(notifier);
CellLock<ReadGuard> cell_lock(cell, cellpair);
cell_lock->Visit(cell_lock, world_notifier, *this, *viewPoint, GetVisibilityDistance());
// send data
notifier.SendToSelf();
player->RemoveFromNotify(NOTIFY_PLAYER_VISIBILITY);
player->SetNotified(NOTIFY_PLAYER_VISIBILITY);
}
}
void Map::ProcessObjectsVisibility()
{
for(m_mapRefIter = m_mapRefManager.begin(); m_mapRefIter != m_mapRefManager.end(); ++m_mapRefIter)
{
Player* player = m_mapRefIter->getSource();
if (player->m_seer != player && !player->GetVehicle())
AddNotifier<Player>(player);
if(!player->IsInWorld())
continue;
WorldObject const *viewPoint = player->m_seer;
CellPair cellpair(Trinity::ComputeCellPair(viewPoint->GetPositionX(), viewPoint->GetPositionY()));
if (cellpair.x_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP || cellpair.y_coord >= TOTAL_NUMBER_OF_CELLS_PER_MAP)
continue;
Cell cell(cellpair);
cell.data.Part.reserved = ALL_DISTRICT;
cell.SetNoCreate();
Trinity::VisibleNotifier notifier(*player);
TypeContainerVisitor<Trinity::VisibleNotifier, WorldTypeMapContainer > world_notifier(notifier);
TypeContainerVisitor<Trinity::VisibleNotifier, GridTypeMapContainer > grid_notifier(notifier);
CellLock<ReadGuard> cell_lock(cell, cellpair);
cell_lock->Visit(cell_lock, world_notifier, *this, *viewPoint, GetVisibilityDistance());
cell_lock->Visit(cell_lock, grid_notifier, *this, *viewPoint, GetVisibilityDistance());
// send data
notifier.SendToSelf();
player->SetNotified(NOTIFY_VISIBILITY_CHANGED);
}
}
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();
CellLock<ReadGuard> cell_lock(cell, pair);
Trinity::DelayedUnitRelocation cell_relocation(cell_lock, *this, GetVisibilityDistance());
TypeContainerVisitor<Trinity::DelayedUnitRelocation, GridTypeMapContainer > grid_object_relocation(cell_relocation);
TypeContainerVisitor<Trinity::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)
{
if(notify_mask == NOTIFY_PLAYER_VISIBILITY)
{
for(m_mapRefIter = m_mapRefManager.begin(); m_mapRefIter != m_mapRefManager.end(); ++m_mapRefIter)
m_mapRefIter->getSource()->ResetAllNotifiesbyMask(notify_mask);
return;
}
Trinity::ResetNotifier reset(notify_mask);
TypeContainerVisitor<Trinity::ResetNotifier, GridTypeMapContainer > grid_notifier(reset);
TypeContainerVisitor<Trinity::ResetNotifier, WorldTypeMapContainer > world_notifier(reset);
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();
CellLock<NullGuard> cell_lock(cell, pair);
cell_lock->Visit(cell_lock, grid_notifier, *this);
cell_lock->Visit(cell_lock, world_notifier, *this);
}
}
}
}
void Map::Remove(Player *player, bool remove)
{
player->ResetAllNotifies();
player->RemoveFromWorld();
SendRemoveTransports(player);
@@ -883,6 +1058,7 @@ template<class T>
void
Map::Remove(T *obj, bool remove)
{
obj->ResetAllNotifies();
obj->RemoveFromWorld();
if (obj->isActiveObject())
RemoveFromActive(obj);
@@ -946,7 +1122,7 @@ Map::PlayerRelocation(Player *player, float x, float y, float z, float orientati
EnsureGridLoadedAtEnter(new_cell, player);
}
AddUnitToNotify(player);
AddNotifier<Player>(player);
NGridType* newGrid = getNGrid(new_cell.GridX(), new_cell.GridY());
if (!same_cell && newGrid->GetGridState()!= GRID_STATE_ACTIVE)
@@ -979,7 +1155,7 @@ Map::CreatureRelocation(Creature *creature, float x, float y, float z, float ang
else
{
creature->Relocate(x, y, z, ang);
AddUnitToNotify(creature);
AddNotifier<Creature>(creature);
}
if (creature->IsVehicle())
@@ -1033,7 +1209,7 @@ void Map::MoveAllCreaturesInMoveList()
// update pos
c->Relocate(cm.x, cm.y, cm.z, cm.ang);
//CreatureRelocationNotify(c,new_cell,new_cell.cellPair());
AddUnitToNotify(c);
AddNotifier<Creature>(c);
}
else
{
@@ -1140,7 +1316,7 @@ 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());
AddUnitToNotify(c);
AddNotifier<Creature>(c);
return true;
}
else
@@ -2141,34 +2317,35 @@ void Map::UpdateObjectVisibility( WorldObject* obj, Cell cell, CellPair cellpair
cell_lock->Visit(cell_lock, player_notifier, *this, *obj, GetVisibilityDistance());
}
/*
void Map::UpdatePlayerVisibility( Player* player, Cell cell, CellPair cellpair )
{
cell.data.Part.reserved = ALL_DISTRICT;
MaNGOS::PlayerNotifier pl_notifier(*player);
TypeContainerVisitor<MaNGOS::PlayerNotifier, WorldTypeMapContainer > player_notifier(pl_notifier);
Trinity::Player2PlayerNotifier pl_notifier(*player);
TypeContainerVisitor<Trinity::Player2PlayerNotifier, WorldTypeMapContainer > player_notifier(pl_notifier);
CellLock<ReadGuard> cell_lock(cell, cellpair);
cell_lock->Visit(cell_lock, player_notifier, *this, *player, GetVisibilityDistance());
pl_notifier.SendToSelf();
}
void Map::UpdateObjectsVisibilityFor( Player* player, Cell cell, CellPair cellpair )
{
MaNGOS::VisibleNotifier notifier(*player);
Trinity::VisibleNotifier notifier(*player, true);
cell.data.Part.reserved = ALL_DISTRICT;
cell.SetNoCreate();
TypeContainerVisitor<MaNGOS::VisibleNotifier, WorldTypeMapContainer > world_notifier(notifier);
TypeContainerVisitor<MaNGOS::VisibleNotifier, GridTypeMapContainer > grid_notifier(notifier);
TypeContainerVisitor<Trinity::VisibleNotifier, WorldTypeMapContainer > world_notifier(notifier);
TypeContainerVisitor<Trinity::VisibleNotifier, GridTypeMapContainer > grid_notifier(notifier);
CellLock<GridReadGuard> cell_lock(cell, cellpair);
cell_lock->Visit(cell_lock, world_notifier, *this, *player, GetVisibilityDistance());
cell_lock->Visit(cell_lock, grid_notifier, *this, *player, GetVisibilityDistance());
// send data
notifier.Notify();
notifier.SendToSelf();
}
/*
void Map::PlayerRelocationNotify( Player* player, Cell cell, CellPair cellpair )
{
CellLock<ReadGuard> cell_lock(cell, cellpair);
@@ -2524,6 +2701,10 @@ void InstanceMap::InitVisibilityDistance()
{
//init visibility distance for instances
m_VisibleDistance = World::GetMaxVisibleDistanceInInstances();
m_PlayerVisibilityNotifyTimer.SetPeriodic(0.75*sWorld.GetVisibilityNotifyPeriodInInstances(), 0.25*sWorld.GetVisibilityNotifyPeriodInInstances());
m_ObjectVisibilityNotifyTimer.SetPeriodic(sWorld.GetVisibilityNotifyPeriodInInstances(), 0 * sWorld.GetVisibilityNotifyPeriodInInstances());
m_RelocationNotifyTimer.SetPeriodic(sWorld.GetVisibilityNotifyPeriodInInstances(),0.5*sWorld.GetVisibilityNotifyPeriodInInstances());
}
/*
@@ -2873,6 +3054,10 @@ void BattleGroundMap::InitVisibilityDistance()
{
//init visibility distance for BG/Arenas
m_VisibleDistance = World::GetMaxVisibleDistanceInBGArenas();
m_PlayerVisibilityNotifyTimer.SetPeriodic(0.75*sWorld.GetVisibilityNotifyPeriodInBGArenas(), 0.25*sWorld.GetVisibilityNotifyPeriodInBGArenas());
m_ObjectVisibilityNotifyTimer.SetPeriodic(sWorld.GetVisibilityNotifyPeriodInBGArenas(), 0 * sWorld.GetVisibilityNotifyPeriodInBGArenas());
m_RelocationNotifyTimer.SetPeriodic(sWorld.GetVisibilityNotifyPeriodInBGArenas(),0.5*sWorld.GetVisibilityNotifyPeriodInBGArenas());
}
bool BattleGroundMap::CanEnter(Player * player)

View File

@@ -405,6 +405,8 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
virtual bool RemoveBones(uint64 guid, float x, float y);
void UpdateObjectVisibility(WorldObject* obj, Cell cell, CellPair cellpair);
void UpdatePlayerVisibility( Player* player, Cell cell, CellPair cellpair );
void UpdateObjectsVisibilityFor(Player* player, Cell cell, CellPair cellpair );
void resetMarkedCells() { marked_cells.reset(); }
bool isCellMarked(uint32 pCellId) { return marked_cells.test(pCellId); }
@@ -517,6 +519,10 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
MapRefManager m_mapRefManager;
MapRefManager::iterator m_mapRefIter;
PeriodicTimer m_ObjectVisibilityNotifyTimer;
PeriodicTimer m_PlayerVisibilityNotifyTimer;
PeriodicTimer m_RelocationNotifyTimer;
typedef std::set<WorldObject*> ActiveNonPlayers;
ActiveNonPlayers m_activeNonPlayers;
ActiveNonPlayers::iterator m_activeNonPlayersIter;
@@ -537,6 +543,11 @@ class MANGOS_DLL_SPEC Map : public GridRefManager<NGridType>, public MaNGOS::Obj
IntervalTimer m_notifyTimer;
void ProcessObjectsVisibility();
void ProcesssPlayersVisibility();
void ProcessRelocationNotifies();
void ResetNotifies(uint16 notify_mask);
bool i_notifyLock, i_scriptLock;
std::vector<Unit*> i_unitsToNotifyBacklog;
std::vector<Unit*> i_unitsToNotify;

View File

@@ -31,6 +31,8 @@
class Transport;
#define DEFAULT_VISIBILITY_NOTIFY_PERIOD 1000
class MANGOS_DLL_DECL MapManager : public MaNGOS::Singleton<MapManager, MaNGOS::ClassLevelLockable<MapManager, ACE_Thread_Mutex> >
{

View File

@@ -240,9 +240,6 @@ void Object::BuildUpdate(UpdateDataMapType &update_players)
void Object::SendUpdateToPlayer(Player* player)
{
// send update to another players
SendUpdateObjectToAllExcept(player);
// send create update to player
UpdateData upd;
WorldPacket packet;
@@ -1108,6 +1105,7 @@ WorldObject::WorldObject()
, m_zoneScript(NULL)
, m_isActive(false), m_isWorldObject(false)
, m_name("")
, m_notifyflags(0), m_executed_notifies(0)
{
}

View File

@@ -93,6 +93,15 @@ enum PhaseMasks
PHASEMASK_ANYWHERE = 0xFFFFFFFF
};
enum NotifyFlags
{
NOTIFY_NONE = 0x00,
NOTIFY_AI_RELOCATION = 0x01,
NOTIFY_VISIBILITY_CHANGED = 0x02,
NOTIFY_PLAYER_VISIBILITY = 0x04,
NOTIFY_ALL = 0xFF
};
class WorldPacket;
class UpdateData;
class ByteBuffer;
@@ -620,6 +629,17 @@ class TRINITY_DLL_SPEC WorldObject : public Object, public WorldLocation
void DestroyForNearbyPlayers();
//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 NotifyExecuted(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; }
bool isActiveObject() const { return m_isActive; }
void setActive(bool isActiveObject);
void SetWorldObject(bool apply);
@@ -654,5 +674,8 @@ class TRINITY_DLL_SPEC WorldObject : public Object, public WorldLocation
//uint32 m_mapId; // object at map with map_id
uint32 m_InstanceId; // in map copy with instance id
uint32 m_phaseMask; // in area phase state
uint16 m_notifyflags;
uint16 m_executed_notifies;
};
#endif

View File

@@ -6015,6 +6015,9 @@ bool Player::SetPosition(float x, float y, float z, float orientation, bool tele
// code block for underwater state update
UpdateUnderwaterState(GetMap(), x, y, z);
if(GetTrader() && !IsWithinDistInMap(GetTrader(), 5))
GetSession()->SendCancelTrade();
CheckExploreSystem();
}
else if(turn)
@@ -19292,18 +19295,32 @@ bool Player::IsVisibleGloballyFor( Player* u ) const
}
template<class T>
inline void UpdateVisibilityOf_helper(std::set<uint64>& s64, T* target)
inline void UpdateVisibilityOf_helper(std::set<uint64>& s64, T* target, std::set<Unit*>& v)
{
s64.insert(target->GetGUID());
}
template<>
inline void UpdateVisibilityOf_helper(std::set<uint64>& s64, GameObject* target)
inline void UpdateVisibilityOf_helper(std::set<uint64>& s64, GameObject* target, std::set<Unit*>& v)
{
if(!target->IsTransport())
s64.insert(target->GetGUID());
}
template<>
inline void UpdateVisibilityOf_helper(std::set<uint64>& s64, Creature* target, std::set<Unit*>& v)
{
s64.insert(target->GetGUID());
v.insert(target);
}
template<>
inline void UpdateVisibilityOf_helper(std::set<uint64>& s64, Player* target, std::set<Unit*>& v)
{
s64.insert(target->GetGUID());
v.insert(target);
}
void Player::UpdateVisibilityOf(WorldObject* target)
{
if(HaveAtClient(target))
@@ -19327,7 +19344,7 @@ void Player::UpdateVisibilityOf(WorldObject* target)
// UpdateVisibilityOf(((Unit*)target)->m_Vehicle);
target->SendUpdateToPlayer(this);
UpdateVisibilityOf_helper(m_clientGUIDs, target);
m_clientGUIDs.insert(target->GetGUID());
#ifdef TRINITY_DEBUG
if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0)
@@ -19355,7 +19372,7 @@ void Player::SendInitialVisiblePackets(Unit* target)
}
template<class T>
void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::set<WorldObject*>& visibleNow)
void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& visibleNow)
{
if(HaveAtClient(target))
{
@@ -19377,9 +19394,8 @@ void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::set<WorldObjec
//if(target->isType(TYPEMASK_UNIT) && ((Unit*)target)->m_Vehicle)
// UpdateVisibilityOf(((Unit*)target)->m_Vehicle, data, visibleNow);
visibleNow.insert(target);
target->BuildCreateUpdateBlockForPlayer(&data, this);
UpdateVisibilityOf_helper(m_clientGUIDs,target);
UpdateVisibilityOf_helper(m_clientGUIDs,target,visibleNow);
#ifdef TRINITY_DEBUG
if((sLog.getLogFilter() & LOG_FILTER_VISIBILITY_CHANGES)==0)
@@ -19389,11 +19405,11 @@ void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::set<WorldObjec
}
}
template void Player::UpdateVisibilityOf(Player* target, UpdateData& data, std::set<WorldObject*>& visibleNow);
template void Player::UpdateVisibilityOf(Creature* target, UpdateData& data, std::set<WorldObject*>& visibleNow);
template void Player::UpdateVisibilityOf(Corpse* target, UpdateData& data, std::set<WorldObject*>& visibleNow);
template void Player::UpdateVisibilityOf(GameObject* target, UpdateData& data, std::set<WorldObject*>& visibleNow);
template void Player::UpdateVisibilityOf(DynamicObject* target, UpdateData& data, 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()
{

View File

@@ -2154,7 +2154,7 @@ class MANGOS_DLL_SPEC Player : public Unit
void SendInitialVisiblePackets(Unit* target);
template<class T>
void UpdateVisibilityOf(T* target, UpdateData& data, std::set<WorldObject*>& visibleNow);
void UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& visibleNow);
// Stealth detection system
void HandleStealthedUnitsDetection();

View File

@@ -11220,7 +11220,22 @@ void Unit::SetVisibility(UnitVisibility x)
{
m_Visibility = x;
SetToNotify();
if(IsInWorld())
{
Map *m = GetMap();
CellPair p(Trinity::ComputeCellPair(GetPositionX(), GetPositionY()));
Cell cell(p);
if(GetTypeId() == TYPEID_PLAYER)
{
m->UpdatePlayerVisibility((Player*)this, cell, p);
m->UpdateObjectsVisibilityFor((Player*)this, cell, p);
}
else
m->UpdateObjectVisibility(this, cell, p);
AddToNotify(NOTIFY_AI_RELOCATION);
}
if (x == VISIBILITY_GROUP_STEALTH)
DestroyForNearbyPlayers();
@@ -14034,9 +14049,10 @@ bool Unit::HandleAuraRaidProcFromCharge(AuraEffect* triggeredByAura)
void Unit::SetToNotify()
{
// it is called somewhere when obj is not in world (crash when log in instance)
if (m_NotifyListPos < 0)
GetMap()->AddUnitToNotify(this);
if (GetTypeId() == TYPEID_PLAYER)
AddToNotify(NOTIFY_VISIBILITY_CHANGED | NOTIFY_AI_RELOCATION | NOTIFY_PLAYER_VISIBILITY);
else
AddToNotify(NOTIFY_VISIBILITY_CHANGED | NOTIFY_AI_RELOCATION);
}
void Unit::Kill(Unit *pVictim, bool durabilityLoss)

View File

@@ -84,6 +84,10 @@ float World::m_MaxVisibleDistanceInFlight = DEFAULT_VISIBILITY_DISTANCE;
float World::m_VisibleUnitGreyDistance = 0;
float World::m_VisibleObjectGreyDistance = 0;
int32 World::m_visibility_notify_periodOnContinents = DEFAULT_VISIBILITY_NOTIFY_PERIOD;
int32 World::m_visibility_notify_periodInInstances = DEFAULT_VISIBILITY_NOTIFY_PERIOD;
int32 World::m_visibility_notify_periodInBGArenas = DEFAULT_VISIBILITY_NOTIFY_PERIOD;
/// World constructor
World::World()
{
@@ -1132,6 +1136,10 @@ void World::LoadConfigSettings(bool reload)
m_MaxVisibleDistanceInFlight = MAX_VISIBILITY_DISTANCE - m_VisibleObjectGreyDistance;
}
m_visibility_notify_periodOnContinents = sConfig.GetIntDefault("Visibility.Notify.Period.OnContinents", DEFAULT_VISIBILITY_NOTIFY_PERIOD);
m_visibility_notify_periodInInstances = sConfig.GetIntDefault("Visibility.Notify.Period.InInstances", DEFAULT_VISIBILITY_NOTIFY_PERIOD);
m_visibility_notify_periodInBGArenas = sConfig.GetIntDefault("Visibility.Notify.Period.InBGArenas", DEFAULT_VISIBILITY_NOTIFY_PERIOD);
///- Read the "Data" directory from the config file
std::string dataPath = sConfig.GetStringDefault("DataDir","./");
if (dataPath.at(dataPath.length()-1)!='/' && dataPath.at(dataPath.length()-1)!='\\')

View File

@@ -613,6 +613,9 @@ class World
static float GetVisibleUnitGreyDistance() { return m_VisibleUnitGreyDistance; }
static float GetVisibleObjectGreyDistance() { return m_VisibleObjectGreyDistance; }
static int32 GetVisibilityNotifyPeriodOnContinents(){ return m_visibility_notify_periodOnContinents; }
static int32 GetVisibilityNotifyPeriodInInstances() { return m_visibility_notify_periodInInstances; }
static int32 GetVisibilityNotifyPeriodInBGArenas() { return m_visibility_notify_periodInBGArenas; }
void SetWintergrapsTimer(uint32 timer, uint32 state)
{
@@ -723,6 +726,10 @@ class World
static float m_VisibleUnitGreyDistance;
static float m_VisibleObjectGreyDistance;
static int32 m_visibility_notify_periodOnContinents;
static int32 m_visibility_notify_periodInInstances;
static int32 m_visibility_notify_periodInBGArenas;
// CLI command holder to be thread safe
ACE_Based::LockedQueue<CliCommandHolder*,ACE_Thread_Mutex> cliCmdQueue;
SqlResultQueue *m_resultQueue;

View File

@@ -95,5 +95,28 @@ struct TimeTrackerSmall
int32 i_expiryTime;
};
struct PeriodicTimer
{
PeriodicTimer(int32 period, int32 start_time) :
i_expireTime(start_time), i_period(period) {}
bool Update(const uint32 &diff)
{
if((i_expireTime -= diff) > 0)
return false;
i_expireTime += i_period > diff ? i_period : diff;
return true;
}
void SetPeriodic(int32 period, int32 start_time)
{
i_expireTime=start_time, i_period=period;
}
int32 i_period;
int32 i_expireTime;
};
#endif

View File

@@ -1181,6 +1181,10 @@ Visibility.Distance.InFlight = 100
Visibility.Distance.Grey.Unit = 1
Visibility.Distance.Grey.Object = 10
Visibility.Notify.Period.OnContinents = 1000
Visibility.Notify.Period.InInstances = 1000
Visibility.Notify.Period.InBGArenas = 1000
###################################################################################################################
# SERVER RATES
#