Skip to content

Commit

Permalink
Map: Optimize low priority objects to not update every time
Browse files Browse the repository at this point in the history
  • Loading branch information
Laizerox authored and killerwife committed Feb 12, 2025
1 parent 39a1196 commit b7e9688
Show file tree
Hide file tree
Showing 16 changed files with 163 additions and 17 deletions.
1 change: 1 addition & 0 deletions src/framework/Utilities/EventProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class EventProcessor
void ModifyEventTime(BasicEvent* event, uint64 msTime);
uint64 CalculateTime(uint64 t_offset) const;
EventList& GetEvents() { return m_events; }
bool IsEmpty() const { return m_events.empty(); }

protected:

Expand Down
1 change: 1 addition & 0 deletions src/game/Chat/Level3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4132,6 +4132,7 @@ bool ChatHandler::HandleNpcInfoCommand(char* /*args*/)
PSendSysMessage("Spell Lists %s ID %u", spellList.Disabled ? "disabled" : "enabled", spellList.Id);

PSendSysMessage("Combat Timer: %u Leashing disabled: %s", target->GetCombatManager().GetCombatTimer(), target->GetCombatManager().IsLeashingDisabled() ? "true" : "false");
PSendSysMessage("Accumulated diff: %u NextUpdateTime: %u", target->GetAccumulatedUpdateDiff(), target->GetNextUpdateTime());

PSendSysMessage("Combat Script: %s", target->AI()->GetCombatScriptStatus() ? "true" : "false");
PSendSysMessage("Movementflags: %u", target->m_movementInfo.moveFlags);
Expand Down
8 changes: 8 additions & 0 deletions src/game/Entities/Creature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3128,6 +3128,14 @@ void Creature::ResetSpellHitCounter()
m_hitBySpells.clear();
}

uint32 Creature::GetNextUpdateTime()
{
if (!HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED) && m_deathState != ALIVE)
return 500;

return WorldObject::GetNextUpdateTime();
}

void Creature::Heartbeat()
{
Unit::Heartbeat();
Expand Down
2 changes: 2 additions & 0 deletions src/game/Entities/Creature.h
Original file line number Diff line number Diff line change
Expand Up @@ -883,6 +883,8 @@ class Creature : public Unit
void UnregisterHitBySpell(uint32 spellId);
void ResetSpellHitCounter();

uint32 GetNextUpdateTime() override;

HighGuid GetParentHigh() const override { return HIGHGUID_UNIT; }

void Heartbeat() override;
Expand Down
17 changes: 16 additions & 1 deletion src/game/Entities/Object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1370,7 +1370,7 @@ bool WorldObject::HasStringId(uint32 stringId) const

WorldObject::WorldObject() :
m_transport(nullptr), m_transportInfo(nullptr), m_isOnEventNotified(false),
m_visibilityData(this), m_currMap(nullptr),
m_visibilityData(this), m_nextUpdateTime(0), m_accumulatedUpdateDiff(0), m_currMap(nullptr),
m_mapId(0), m_InstanceId(0), m_phaseMask(PHASEMASK_NORMAL),
m_isActiveObject(false), m_debugFlags(0), m_destLocCounter(0), m_castCounter(0)
{
Expand Down Expand Up @@ -3334,6 +3334,21 @@ int32 WorldObject::CalculateSpellEffectValue(Unit const* target, SpellEntry cons
return value;
}

uint32 WorldObject::ShouldPerformObjectUpdate(uint32 const diff)
{
// For objects that don't have next update time return diff immediately
if (!m_nextUpdateTime)
return diff;

m_accumulatedUpdateDiff += diff;

// Once accumulated time reaches and goes over update time lets use it
if (m_accumulatedUpdateDiff >= GetNextUpdateTime())
return m_accumulatedUpdateDiff;

return 0;
}

float Position::GetAngle(const float x, const float y) const
{
float dx = x - GetPositionX();
Expand Down
11 changes: 11 additions & 0 deletions src/game/Entities/Object.h
Original file line number Diff line number Diff line change
Expand Up @@ -1222,6 +1222,14 @@ class WorldObject : public Object
VisibilityData const& GetVisibilityData() const { return m_visibilityData; }
VisibilityData& GetVisibilityData() { return m_visibilityData; }

virtual uint32 GetNextUpdateTime() { return m_nextUpdateTime; }
virtual void SetNextUpdateTime(uint32 time) { m_nextUpdateTime = time; }
virtual void UpdateNextUpdateTime() {}
uint32 GetAccumulatedUpdateDiff() { return m_accumulatedUpdateDiff; }
void ResetAccumulatedUpdateDiff() { m_accumulatedUpdateDiff = 0; }

virtual uint32 ShouldPerformObjectUpdate(uint32 const diff);

bool HaveDebugFlag(CMDebugFlags flag) const { return (uint64(m_debugFlags) & flag) != 0; }
void SetDebugFlag(CMDebugFlags flag) { m_debugFlags |= uint64(flag); }
void ClearDebugFlag(CMDebugFlags flag) { m_debugFlags &= ~(uint64(flag)); }
Expand Down Expand Up @@ -1305,6 +1313,9 @@ class WorldObject : public Object

VisibilityData m_visibilityData;

uint32 m_nextUpdateTime;
uint32 m_accumulatedUpdateDiff;

ShortTimeTracker m_heartBeatTimer;
private:
Map* m_currMap; // current object's Map location
Expand Down
51 changes: 50 additions & 1 deletion src/game/Entities/Unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,8 @@ Unit::Unit() :
m_ignoreRangedTargets(false),
m_auraUpdateMask(0),
m_combatManager(this),
m_isMountOverriden(false), m_overridenMountId(0)
m_isMountOverriden(false), m_overridenMountId(0),
m_hasPeriodicAura(false)
{
m_objectType |= TYPEMASK_UNIT;
m_objectTypeId = TYPEID_UNIT;
Expand Down Expand Up @@ -5483,6 +5484,11 @@ bool Unit::AddSpellAuraHolder(SpellAuraHolder* holder)
if (!holder->IsDeleted())
{
holder->HandleSpellSpecificBoosts(true);
m_hasPeriodicAura = m_hasPeriodicAura || holder->HasPeriodicAura();
if (m_hasPeriodicAura)
SetNextUpdateTime(1);
else
SetNextUpdateTime(0);
SpellProcEventEntry const* procEntry = sSpellMgr.GetSpellProcEvent(aurSpellInfo->Id);
if (aurSpellInfo->procFlags & PROC_FLAG_HEARTBEAT || (procEntry && procEntry->procFlags & PROC_FLAG_HEARTBEAT))
++m_hasHeartbeatProcCounter;
Expand Down Expand Up @@ -6107,6 +6113,9 @@ void Unit::RemoveSpellAuraHolder(SpellAuraHolder* holder, AuraRemoveMode mode)
if (itr->second == holder)
{
m_spellAuraHolders.erase(itr);
m_hasPeriodicAura = HasPeriodicAura();
if (!m_hasPeriodicAura)
SetNextUpdateTime(0);
break;
}
}
Expand Down Expand Up @@ -6418,6 +6427,19 @@ bool Unit::HasAuraTypeWithCaster(AuraType auratype, ObjectGuid caster) const
return false;
}

bool Unit::HasPeriodicAura() const
{
for (auto holder : m_spellAuraHolders)
{
for (auto aura : holder.second->m_auras)
{
if (aura && aura->IsPeriodic())
return true;
}
}
return false;
}

bool Unit::HasMechanicMaskOrDispelMaskAura(uint32 dispelMask, uint32 mechanicMask, Unit const* caster) const
{
Unit::SpellAuraHolderMap const& Auras = GetSpellAuraHolderMap();
Expand Down Expand Up @@ -13616,6 +13638,33 @@ uint32 Unit::GetModifierXpBasedOnDamageReceived(uint32 xp)
return xp;
}

void Unit::UpdateNextUpdateTime()
{
// If we already have next update time don't reset it (movement mutation should do it)
if (m_nextUpdateTime)
return;

if (!m_events.IsEmpty() || m_hasPeriodicAura)
SetNextUpdateTime(1);
// If motion type is idle and there is no nextUpdateTime force it
else if (GetMotionMaster()->GetCurrentMovementGeneratorType() == IDLE_MOTION_TYPE)
SetNextUpdateTime(urand(500, 1000));
// If motion type is random and there is no nextUpdateTime force it
else if (GetMotionMaster()->GetCurrentMovementGeneratorType() == RANDOM_MOTION_TYPE)
SetNextUpdateTime(urand(250, 500));
}

uint32 Unit::ShouldPerformObjectUpdate(uint32 const diff)
{
if (HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED))
return diff;

if (IsInCombat())
return diff + m_accumulatedUpdateDiff;

return WorldObject::ShouldPerformObjectUpdate(diff);
}

void Unit::OverrideMountDisplayId(uint32 newDisplayId)
{
if (newDisplayId)
Expand Down
5 changes: 5 additions & 0 deletions src/game/Entities/Unit.h
Original file line number Diff line number Diff line change
Expand Up @@ -1756,6 +1756,7 @@ class Unit : public WorldObject
}
bool HasAuraOfDifficulty(uint32 spellId) const;
bool HasAuraTypeWithCaster(AuraType auratype, ObjectGuid caster) const;
bool HasPeriodicAura() const;
bool HasMechanicMaskOrDispelMaskAura(uint32 dispelMask, uint32 mechanicMask, Unit const* caster) const;
bool HasNegativeAuraWithInterruptFlag(SpellAuraInterruptFlags flag) const;
template<typename Func>
Expand Down Expand Up @@ -2623,6 +2624,9 @@ class Unit : public WorldObject

uint32 GetDamageDoneByOthers() { return m_damageByOthers; }
uint32 GetModifierXpBasedOnDamageReceived(uint32 xp);

void UpdateNextUpdateTime() override;
uint32 ShouldPerformObjectUpdate(uint32 const diff) override;

void OverrideMountDisplayId(uint32 newDisplayId);

Expand Down Expand Up @@ -2823,6 +2827,7 @@ class Unit : public WorldObject
Position m_last_notified_position;
BasicEvent* m_AINotifyEvent;
ShortTimeTracker m_movesplineTimer;
bool m_hasPeriodicAura;

Diminishing m_Diminishing;

Expand Down
27 changes: 19 additions & 8 deletions src/game/Maps/Map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -784,8 +784,6 @@ void Map::Update(const uint32& t_diff)
localtime_r(&m_curTime, &m_curTimeTm);
#endif

uint64 count = 0;

m_dyn_tree.update(t_diff);

GetMessager().Execute(this);
Expand Down Expand Up @@ -1099,12 +1097,7 @@ void Map::Update(const uint32& t_diff)
}
}

// update all objects
for (auto wObj : objToUpdate)
{
wObj->Update(t_diff);
++count;
}
uint64 count = PerformObjectUpdate(t_diff, objToUpdate);

#ifdef BUILD_METRICS
meas.add_field("count", std::to_string(static_cast<int32>(count)));
Expand Down Expand Up @@ -1147,6 +1140,24 @@ void Map::Update(const uint32& t_diff)
sLog.outError("Map Id %u took %u miliseconds", GetId(), ms_int.count());
}

uint64 Map::PerformObjectUpdate(uint32 t_diff, WorldObjectUnSet& objToUpdate)
{
uint64 count = 0;
// update all objects
for (WorldObject* object : objToUpdate)
{
if (uint32 accumulatedDiff = object->ShouldPerformObjectUpdate(t_diff))
{
object->Update(accumulatedDiff);
object->ResetAccumulatedUpdateDiff();
object->UpdateNextUpdateTime();

++count;
}
}
return count;
}

void Map::Remove(Player* player, bool remove)
{
if (i_data)
Expand Down
2 changes: 2 additions & 0 deletions src/game/Maps/Map.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ class Map : public GridRefManager<NGridType>
void VisitNearbyCellsOf(WorldObject* obj, TypeContainerVisitor<MaNGOS::ObjectUpdater, GridTypeMapContainer> &gridVisitor, TypeContainerVisitor<MaNGOS::ObjectUpdater, WorldTypeMapContainer> &worldVisitor);
virtual void Update(const uint32&);

uint64 PerformObjectUpdate(uint32 t_diff, WorldObjectUnSet& objToUpdate);

void MessageBroadcast(Player const*, WorldPacket const&, bool to_self);
void MessageBroadcast(WorldObject const*, WorldPacket const&);
void MessageDistBroadcast(Player const*, WorldPacket const&, float dist, bool to_self, bool own_team_only = false);
Expand Down
27 changes: 27 additions & 0 deletions src/game/MotionGenerators/MotionMaster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ void MotionMaster::Initialize()
auto creature = static_cast<Creature*>(m_owner);
m_currentPathId = m_defaultPathId;
MovementGenerator* movement = FactorySelector::selectMovementGenerator(creature);
// Initialize update timers
InitializeObjectUpdateTimer(movement ? movement->GetMovementGeneratorType() : IDLE_MOTION_TYPE);
push(movement == nullptr ? &si_idleMovement : movement);
top()->Initialize(*m_owner);

Expand Down Expand Up @@ -800,3 +802,28 @@ bool MotionMaster::GetDestination(float& x, float& y, float& z) const
z = dest.z;
return true;
}

void MotionMaster::InitializeObjectUpdateTimer(const MovementGeneratorType type)
{
if (m_owner->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_PLAYER_CONTROLLED))
{
if (m_owner->GetNextUpdateTime())
m_owner->SetNextUpdateTime(0);

return;
}

switch (type)
{
case IDLE_MOTION_TYPE:
m_owner->SetNextUpdateTime(urand(500, 1000));
return;
case RANDOM_MOTION_TYPE:
m_owner->SetNextUpdateTime(urand(250, 500));
return;
default:
if (m_owner->GetNextUpdateTime())
m_owner->SetNextUpdateTime(0);
return;
}
}
1 change: 1 addition & 0 deletions src/game/MotionGenerators/MotionMaster.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ class MotionMaster : private std::stack<MovementGenerator*>

private:
void Mutate(MovementGenerator* m); // use Move* functions instead
void InitializeObjectUpdateTimer(const MovementGeneratorType type);

void DirectClean(bool reset, bool all);
void DelayedClean(bool reset, bool all);
Expand Down
4 changes: 4 additions & 0 deletions src/game/Spells/Spell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3318,6 +3318,7 @@ SpellCastResult Spell::SpellStart(SpellCastTargets const* targets, Aura* trigger
// create and add update event for this spell
m_spellEvent = new SpellEvent(this);
m_trueCaster->m_events.AddEvent(m_spellEvent, m_trueCaster->m_events.CalculateTime(1));
m_trueCaster->SetNextUpdateTime(1);

if (m_trueCaster->IsUnit()) // gameobjects dont have a sense of already casting a spell
{
Expand Down Expand Up @@ -5024,7 +5025,10 @@ void Spell::SendChannelStart(uint32 duration)
}

if (target)
{
target->SetNextUpdateTime(1);
m_caster->SetChannelObject(target);
}

m_caster->SetUInt32Value(UNIT_FIELD_CHANNEL_SPELL, m_spellInfo->Id);
m_caster->addUnitState(UNIT_STAT_CHANNELING);
Expand Down
10 changes: 10 additions & 0 deletions src/game/Spells/SpellAuras.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include "Entities/TemporarySpawn.h"
#include "Maps/InstanceData.h"
#include "AI/ScriptDevAI/include/sc_grid_searchers.h"
#include "SpellAuras.h"

#define NULL_AURA_SLOT 0xFF

Expand Down Expand Up @@ -11014,6 +11015,15 @@ bool SpellAuraHolder::IsDispellableByMask(uint32 dispelMask, Unit const* caster,
return false;
}

bool SpellAuraHolder::HasPeriodicAura() const
{
for (Aura* aura : m_auras)
if (aura && aura->IsPeriodic())
return true;

return false;
}

bool SpellAuraHolder::IsPersistent() const
{
for (auto aur : m_auras)
Expand Down
2 changes: 2 additions & 0 deletions src/game/Spells/SpellAuras.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ class SpellAuraHolder
bool HasMechanicMask(uint32 mechanicMask) const;
bool IsDispellableByMask(uint32 dispelMask, Unit const* caster, SpellEntry const* spellInfo) const;

bool HasPeriodicAura() const;

void SetCreationDelayFlag();

bool IsProcReady(TimePoint const& now) const;
Expand Down
11 changes: 4 additions & 7 deletions src/shared/Util/Timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,17 +148,14 @@ struct ShortTimeTracker
ShortTimeTracker(uint32 expiry = 0) : i_expiryTime(expiry) {}
void Update(uint32 diff)
{
if (i_expiryTime <= diff)
i_expiryTime = 0;
else
i_expiryTime -= diff;
i_expiryTime -= diff;
}
bool Passed() const { return (i_expiryTime <= 0); }
void Reset(uint32 interval) { i_expiryTime = interval; }
uint32 GetExpiry() const { return i_expiryTime; }
void Reset(int32 interval) { i_expiryTime = interval; }
int32 GetExpiry() const { return i_expiryTime; }

private:
uint32 i_expiryTime;
int32 i_expiryTime;
};

#endif

0 comments on commit b7e9688

Please sign in to comment.