[11193] Optimize visibility update and AI notification code. Optimization decreases amount of visibility and AI notification operations in 8-10 times, and as a result, lowers CPU usage by 30-40%

You need to update your config file, new "Visibility.RelocationLowerLimit" and "Visibility.AIRelocationNotifyDelay' options added

Special thanks to Ambal for code hints and advices
Thanks to Undergarun and kero99 for making tests
This commit is contained in:
SilverIce 2011-02-22 02:32:49 +02:00
parent 60b2e2c8ba
commit 724092d9e5
10 changed files with 117 additions and 62 deletions

View file

@ -125,7 +125,7 @@ m_lootMoney(0), m_lootGroupRecipientId(0),
m_corpseDecayTimer(0), m_respawnTime(0), m_respawnDelay(25), m_corpseDelay(60), m_respawnradius(5.0f),
m_subtype(subtype), m_defaultMovementType(IDLE_MOTION_TYPE), m_equipmentId(0),
m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false),
m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false), m_needNotify(false),
m_regenHealth(true), m_AI_locked(false), m_isDeadByDefault(false),
m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL),
m_creatureInfo(NULL), m_splineFlags(SPLINEFLAG_WALKMODE)
{
@ -426,15 +426,6 @@ uint32 Creature::ChooseDisplayId(const CreatureInfo *cinfo, const CreatureData *
void Creature::Update(uint32 update_diff, uint32 diff)
{
if (m_needNotify)
{
m_needNotify = false;
RelocationNotify();
if (!IsInWorld())
return;
}
switch( m_deathState )
{
case JUST_ALIVED:
@ -2352,13 +2343,6 @@ void Creature::SendAreaSpiritHealerQueryOpcode(Player *pl)
pl->SendDirectMessage(&data);
}
void Creature::RelocationNotify()
{
MaNGOS::CreatureRelocationNotifier relocationNotifier(*this);
float radius = MAX_CREATURE_ATTACK_RADIUS * sWorld.getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO);
Cell::VisitAllObjects(this, relocationNotifier, radius);
}
void Creature::ApplyGameEventSpells(GameEventCreatureData const* eventData, bool activated)
{
uint32 cast_spell = activated ? eventData->spell_id_start : eventData->spell_id_end;

View file

@ -647,14 +647,11 @@ class MANGOS_DLL_SPEC Creature : public Unit
void SetActiveObjectState(bool on);
void SetNeedNotify() { m_needNotify = true; }
void SendAreaSpiritHealerQueryOpcode(Player *pl);
protected:
bool CreateFromProto(uint32 guidlow,uint32 Entry, Team team, const CreatureData *data = NULL, GameEventCreatureData const* eventData =NULL);
bool InitEntry(uint32 entry, const CreatureData* data = NULL, GameEventCreatureData const* eventData = NULL);
void RelocationNotify();
uint32 m_groupLootTimer; // (msecs)timer used for group loot
uint32 m_groupLootId; // used to find group which is looting corpse
@ -691,7 +688,6 @@ class MANGOS_DLL_SPEC Creature : public Unit
bool m_regenHealth;
bool m_AI_locked;
bool m_isDeadByDefault;
bool m_needNotify;
SpellSchoolMask m_meleeDamageSchoolMask;
uint32 m_originalEntry;

View file

@ -47,11 +47,8 @@ inline void MaNGOS::ObjectUpdater::Visit(CreatureMapType &m)
}
}
inline void PlayerCreatureRelocationWorker(Player* pl, WorldObject const* viewPoint, Creature* c)
inline void PlayerCreatureRelocationWorker(Player* pl, Creature* c)
{
// update creature visibility at player/creature move
pl->UpdateVisibilityOf(viewPoint,c);
// Creature AI reaction
if (!c->hasUnitState(UNIT_STAT_LOST_CONTROL))
{
@ -80,11 +77,12 @@ inline void MaNGOS::PlayerRelocationNotifier::Visit(CreatureMapType &m)
if (!i_player.isAlive() || i_player.IsTaxiFlying())
return;
WorldObject const* viewPoint = i_player.GetCamera().GetBody();
for(CreatureMapType::iterator iter = m.begin(); iter != m.end(); ++iter)
if (iter->getSource()->isAlive())
PlayerCreatureRelocationWorker(&i_player, viewPoint, iter->getSource());
{
Creature* c = iter->getSource();
if (c->isAlive())
PlayerCreatureRelocationWorker(&i_player, c);
}
}
template<>
@ -94,9 +92,11 @@ inline void MaNGOS::CreatureRelocationNotifier::Visit(PlayerMapType &m)
return;
for(PlayerMapType::iterator iter=m.begin(); iter != m.end(); ++iter)
if (Player* player = iter->getSource())
{
Player* player = iter->getSource();
if (player->isAlive() && !player->IsTaxiFlying())
PlayerCreatureRelocationWorker(player, player->GetCamera().GetBody(), &i_creature);
PlayerCreatureRelocationWorker(player, &i_creature);
}
}
template<>

View file

@ -207,13 +207,13 @@ void Map::AddNotifier(T* , Cell const& , CellPair const& )
template<>
void Map::AddNotifier(Player* obj, Cell const& cell, CellPair const& cellpair)
{
PlayerRelocationNotify(obj,cell,cellpair);
obj->SheduleAINotify(0);
}
template<>
void Map::AddNotifier(Creature* obj, Cell const&, CellPair const&)
{
obj->SetNeedNotify();
obj->SheduleAINotify(0);
}
void
@ -708,10 +708,7 @@ Map::PlayerRelocation(Player *player, float x, float y, float z, float orientati
player->GetViewPoint().Event_GridChanged(&(*newGrid)(new_cell.CellX(),new_cell.CellY()));
}
player->GetViewPoint().Call_UpdateVisibilityForOwner();
// if move then update what player see and who seen
UpdateObjectVisibility(player, new_cell, new_val);
PlayerRelocationNotify(player,new_cell,new_val);
player->OnRelocated();
NGridType* newGrid = getNGrid(new_cell.GridX(), new_cell.GridY());
if( !same_cell && newGrid->GetGridState()!= GRID_STATE_ACTIVE )
@ -731,7 +728,6 @@ Map::CreatureRelocation(Creature *creature, float x, float y, float z, float ang
CellPair new_val = MaNGOS::ComputeCellPair(x, y);
Cell new_cell(new_val);
// delay creature move for grid/cell to grid/cell moves
if (old_cell.DiffCell(new_cell) || old_cell.DiffGrid(new_cell))
{
DEBUG_FILTER_LOG(LOG_FILTER_CREATURE_MOVES, "Creature (GUID: %u Entry: %u) added to moving list from grid[%u,%u]cell[%u,%u] to grid[%u,%u]cell[%u,%u].", creature->GetGUIDLow(), creature->GetEntry(), old_cell.GridX(), old_cell.GridY(), old_cell.CellX(), old_cell.CellY(), new_cell.GridX(), new_cell.GridY(), new_cell.CellX(), new_cell.CellY());
@ -741,29 +737,22 @@ Map::CreatureRelocation(Creature *creature, float x, float y, float z, float ang
{
// update pos
creature->Relocate(x, y, z, ang);
// in diffcell/diffgrid case notifiers called in Creature::Update
creature->SetNeedNotify();
creature->OnRelocated();
}
else
{
// if creature can't be move in new cell/grid (not loaded) move it to repawn cell/grid
// creature coordinates will be updated and notifiers send
if(!CreatureRespawnRelocation(creature))
else if (!CreatureRespawnRelocation(creature))
{
// ... or unload (if respawn grid also not loaded)
DEBUG_FILTER_LOG(LOG_FILTER_CREATURE_MOVES, "Creature (GUID: %u Entry: %u ) can't be move to unloaded respawn grid.",creature->GetGUIDLow(),creature->GetEntry());
creature->SetNeedNotify();
}
}
}
else
{
creature->Relocate(x, y, z, ang);
creature->SetNeedNotify();
creature->OnRelocated();
}
creature->GetViewPoint().Call_UpdateVisibilityForOwner();
MANGOS_ASSERT(CheckGridIntegrity(creature,true));
}
@ -847,7 +836,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
c->SetNeedNotify();
c->OnRelocated();
return true;
}
else

View file

@ -218,6 +218,7 @@ Unit::Unit()
m_AuraFlags = 0;
m_Visibility = VISIBILITY_ON;
m_AINotifySheduled = false;
m_detectInvisibilityMask = 0;
m_invisibilityMask = 0;
@ -8089,12 +8090,9 @@ void Unit::SetVisibility(UnitVisibility x)
}
}
Map *m = GetMap();
if(GetTypeId()==TYPEID_PLAYER)
m->PlayerRelocation((Player*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
else
m->CreatureRelocation((Creature*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation());
GetViewPoint().Call_UpdateVisibilityForOwner();
UpdateObjectVisibility();
SheduleAINotify(0);
GetViewPoint().Event_ViewPointVisibilityChanged();
}
@ -10827,3 +10825,62 @@ bool Unit::IsAllowedDamageInArea(Unit* pVictim) const
return true;
}
class RelocationNotifyEvent : public BasicEvent
{
public:
RelocationNotifyEvent(Unit& owner) : BasicEvent(), m_owner(owner)
{
m_owner._SetAINotifySheduled(true);
}
bool Execute(uint64 /*e_time*/, uint32 /*p_time*/)
{
float radius = MAX_CREATURE_ATTACK_RADIUS * sWorld.getConfig(CONFIG_FLOAT_RATE_CREATURE_AGGRO);
if (m_owner.GetTypeId() == TYPEID_PLAYER)
{
MaNGOS::PlayerRelocationNotifier notify((Player&)m_owner);
Cell::VisitAllObjects(&m_owner,notify,radius);
}
else //if(m_owner.GetTypeId() == TYPEID_UNIT)
{
MaNGOS::CreatureRelocationNotifier notify((Creature&)m_owner);
Cell::VisitAllObjects(&m_owner,notify,radius);
}
m_owner._SetAINotifySheduled(false);
return true;
}
void Abort(uint64)
{
m_owner._SetAINotifySheduled(false);
}
private:
Unit& m_owner;
};
void Unit::SheduleAINotify(uint32 delay)
{
if (!IsAINotifySheduled())
m_Events.AddEvent(new RelocationNotifyEvent(*this), m_Events.CalculateTime(delay));
}
void Unit::OnRelocated()
{
// switch to use G3D::Vector3 is good idea, maybe
float dx = m_last_notified_position.x - GetPositionX();
float dy = m_last_notified_position.y - GetPositionY();
float dz = m_last_notified_position.z - GetPositionZ();
float distsq = dx*dx+dy*dy+dz*dz;
if (distsq > World::GetRelocationLowerLimitSq())
{
m_last_notified_position.x = GetPositionX();
m_last_notified_position.y = GetPositionY();
m_last_notified_position.z = GetPositionZ();
GetViewPoint().Call_UpdateVisibilityForOwner();
UpdateObjectVisibility();
}
SheduleAINotify(World::GetRelocationAINotifyDelay());
}

View file

@ -1954,6 +1954,11 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
// Movement info
MovementInfo m_movementInfo;
void SheduleAINotify(uint32 delay);
bool IsAINotifySheduled() const { return m_AINotifySheduled;}
void _SetAINotifySheduled(bool on) { m_AINotifySheduled = on;} // only for call from RelocationNotifyEvent class code
void OnRelocated();
protected:
explicit Unit ();
@ -2020,6 +2025,8 @@ class MANGOS_DLL_SPEC Unit : public WorldObject
uint32 m_castCounter; // count casts chain of triggered spells for prevent infinity cast crashes
UnitVisibility m_Visibility;
Position m_last_notified_position;
bool m_AINotifySheduled;
Diminishing m_Diminishing;
// Manage all Units threatening us

View file

@ -77,6 +77,9 @@ float World::m_MaxVisibleDistanceInFlight = DEFAULT_VISIBILITY_DISTANCE;
float World::m_VisibleUnitGreyDistance = 0;
float World::m_VisibleObjectGreyDistance = 0;
float World::m_relocation_lower_limit_sq = 10.f * 10.f;
uint32 World::m_relocation_ai_notify_delay = 1000u;
/// World constructor
World::World()
{
@ -768,6 +771,9 @@ void World::LoadConfigSettings(bool reload)
setConfig(CONFIG_BOOL_PET_UNSUMMON_AT_MOUNT, "PetUnsummonAtMount", true);
m_relocation_ai_notify_delay = sConfig.GetIntDefault("Visibility.AIRelocationNotifyDelay", 1000u);
m_relocation_lower_limit_sq = pow(sConfig.GetFloatDefault("Visibility.RelocationLowerLimit",10), 2);
m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1);
if(m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE)
{

View file

@ -565,6 +565,9 @@ class World
static float GetVisibleUnitGreyDistance() { return m_VisibleUnitGreyDistance; }
static float GetVisibleObjectGreyDistance() { return m_VisibleObjectGreyDistance; }
static float GetRelocationLowerLimitSq() { return m_relocation_lower_limit_sq; }
static uint32 GetRelocationAINotifyDelay() { return m_relocation_ai_notify_delay; }
void ProcessCliCommands();
void QueueCliCommand(CliCommandHolder* commandHolder) { cliCmdQueue.add(commandHolder); }
@ -654,6 +657,9 @@ class World
static float m_VisibleUnitGreyDistance;
static float m_VisibleObjectGreyDistance;
static float m_relocation_lower_limit_sq;
static uint32 m_relocation_ai_notify_delay;
// CLI command holder to be thread safe
ACE_Based::LockedQueue<CliCommandHolder*,ACE_Thread_Mutex> cliCmdQueue;

View file

@ -1138,6 +1138,14 @@ GM.AllowAchievementGain = 1
# Visibility grey distance for dynobjects/gameobjects/corpses/creature bodies
# Default: 10 (yards)
#
# Visibility.RelocationLowerLimit
# Object's visibility update called, when distance between current object's position and position,
# where visiblity was updated last time, reaches RelocationLoverLimit value
# Default: 10 (yards)
#
# Visibility.AIRelocationNotifyDelay
# Delay time between creature AI reactions on nearby movements
# Default: 1000 (milliseconds)
#
###################################################################################################################
@ -1148,6 +1156,8 @@ Visibility.Distance.BGArenas = 180
Visibility.Distance.InFlight = 100
Visibility.Distance.Grey.Unit = 1
Visibility.Distance.Grey.Object = 10
Visibility.RelocationLowerLimit = 10
Visibility.AIRelocationNotifyDelay = 1000
###################################################################################################################
# SERVER RATES

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__
#define __REVISION_NR_H__
#define REVISION_NR "11192"
#define REVISION_NR "11193"
#endif // __REVISION_NR_H__