Skip to content

Commit

Permalink
Aura/Spell: Rework aura protocol more closely based on discovered new…
Browse files Browse the repository at this point in the history
… info
  • Loading branch information
killerwife committed Aug 16, 2023
1 parent 0c08098 commit f963617
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 54 deletions.
50 changes: 39 additions & 11 deletions src/game/Entities/Player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19532,17 +19532,18 @@ void Player::SendInitialPacketsAfterAddToMap()
auraList.front()->ApplyModifier(true, true);
}

SendAuraDurationsOnLogin();

if (IsImmobilizedState()) // TODO: Figure out if this protocol is correct
SendMoveRoot(true);

SendAuraDurationsOnLogin(true);

SendEnchantmentDurations(); // must be after add to map
SendItemDurations(); // must be after add to map

CastSpell(this, 836, TRIGGERED_OLD_TRIGGERED); // LOGINEFFECT
CastSpell(this, 836, TRIGGERED_IGNORE_CURRENT_CASTED_SPELL); // LOGINEFFECT

SendAuraDurationsOnLogin(false);
SendExtraAuraDurationsOnLogin(true);
SendExtraAuraDurationsOnLogin(false);
}

void Player::SendUpdateToOutOfRangeGroupMembers()
Expand Down Expand Up @@ -19782,18 +19783,25 @@ void Player::SendAuraDurationsForTarget(Unit* target)
if (holder->GetAuraSlot() >= MAX_AURAS || holder->IsPassive() || holder->GetCasterGuid() != GetObjectGuid())
continue;

holder->SendAuraDurationForCaster(this);
holder->SendAuraDurationToCaster(this);
}
}

void Player::SendAuraDurationsOnLogin(bool visible)
void Player::SendAuraDurationsOnLogin()
{
if (!visible)
for (auto& data : GetSpellAuraHolderMap())
{
WorldPacket data(SMSG_SET_EXTRA_AURA_INFO, 8);
data << GetPackGUID();
SendDirectMessage(data);
SpellAuraHolder* holder = data.second;
if (holder->GetAuraSlot() >= MAX_AURAS)
continue;

holder->LoginAuraDuration();
}
}

void Player::SendExtraAuraDurationsOnLogin(bool visible)
{
std::vector<SpellAuraHolder*> holders;

uint32 counter = MAX_AURAS;
SpellAuraHolderMap const& auraHolders = GetSpellAuraHolderMap();
Expand All @@ -19813,9 +19821,29 @@ void Player::SendAuraDurationsOnLogin(bool visible)
continue;
}

holder->SendAuraDurationForTarget(!visible ? counter : MAX_AURAS);
holders.push_back(holder);
++counter;
}

if (!visible) // slots >= 56 are sent as singles
{
std::sort(holders.begin(), holders.end(), [](SpellAuraHolder* left, SpellAuraHolder* right) { return left->GetAuraSlot() < right->GetAuraSlot(); });
for (SpellAuraHolder* holder : holders)
holder->SendAuraDurationToCaster(this);
}
else // visible slots (<= 56) are sent in a single packet
{
WorldPacket data(SMSG_INIT_EXTRA_AURA_INFO, (8 + (1 + 4 + 4 + 4) * holders.size()));
data << GetPackGUID();
for (SpellAuraHolder* holder : holders)
{
data << uint8(holder->GetAuraSlot());
data << uint32(holder->GetId());
data << int32(holder->GetAuraMaxDuration());
data << uint32(holder->GetAuraMaxDuration() == -1 ? 0 : holder->GetAuraDuration());
}
SendDirectMessage(data);
}
}

ItemSetEffect* Player::GetItemSetEffect(uint32 setId)
Expand Down
3 changes: 2 additions & 1 deletion src/game/Entities/Player.h
Original file line number Diff line number Diff line change
Expand Up @@ -1942,7 +1942,8 @@ class Player : public Unit
void SendDirectMessage(WorldPacket const& data) const;

void SendAuraDurationsForTarget(Unit* target);
void SendAuraDurationsOnLogin(bool visible); // uses different packets
void SendAuraDurationsOnLogin(); // sends own durations
void SendExtraAuraDurationsOnLogin(bool visible); // sends init and non visible slot auras

PlayerMenu* GetPlayerMenu() const { return m_playerMenu.get(); }

Expand Down
2 changes: 1 addition & 1 deletion src/game/Entities/Unit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5771,7 +5771,7 @@ void Unit::DelaySpellAuraHolder(uint32 spellId, int32 delaytime, ObjectGuid cast
else
holder->SetAuraDuration(holder->GetAuraDuration() - delaytime);

holder->UpdateAuraDuration();
holder->ForceUpdateAuraDuration();

DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Spell %u partially interrupted on %s, new duration: %u ms", spellId, GetGuidStr().c_str(), holder->GetAuraDuration());
}
Expand Down
27 changes: 15 additions & 12 deletions src/game/Spells/Spell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7168,23 +7168,26 @@ void Spell::DelayedChannel()

DEBUG_FILTER_LOG(LOG_FILTER_SPELL_CAST, "Spell %u partially interrupted for %i ms, new duration: %u ms", m_spellInfo->Id, delaytime, m_timer);

for (TargetList::const_iterator ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end(); ++ihit)
SendChannelUpdate(m_timer);

if (m_timer != 0) // must be after channel update
{
if ((*ihit).missCondition == SPELL_MISS_NONE)
for (auto& target : m_UniqueTargetInfo)
{
if (Unit* unit = m_caster->GetObjectGuid() == ihit->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID))
unit->DelaySpellAuraHolder(m_spellInfo->Id, delaytime, m_caster->GetObjectGuid());
if (target.missCondition == SPELL_MISS_NONE)
{
if (Unit* unit = m_caster->GetObjectGuid() == target.targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, target.targetGUID))
unit->DelaySpellAuraHolder(m_spellInfo->Id, delaytime, m_caster->GetObjectGuid());
}
}
}

for (int j = 0; j < MAX_EFFECT_INDEX; ++j)
{
// partially interrupt persistent area auras
if (DynamicObject* dynObj = m_caster->GetDynObject(m_spellInfo->Id, SpellEffectIndex(j)))
dynObj->Delay(delaytime);
for (int j = 0; j < MAX_EFFECT_INDEX; ++j)
{
// partially interrupt persistent area auras
if (DynamicObject* dynObj = m_caster->GetDynObject(m_spellInfo->Id, SpellEffectIndex(j)))
dynObj->Delay(delaytime);
}
}

SendChannelUpdate(m_timer);
}

void Spell::UpdateOriginalCasterPointer()
Expand Down
101 changes: 74 additions & 27 deletions src/game/Spells/SpellAuras.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7913,10 +7913,34 @@ void SpellAuraHolder::_AddSpellAuraHolder()
}
}

if (slot >= MAX_AURAS)
{
uint32 theoreticalSlot = MAX_AURAS;
std::set<uint32> freeSlot;
for (auto& data : m_target->GetSpellAuraHolderMap())
{
SpellAuraHolder* holder = data.second;
if (holder->GetAuraSlot() >= MAX_AURAS)
freeSlot.insert(holder->GetAuraSlot());
}
for (uint32 slot : freeSlot)
{
// set is sorted so this should yield first empty
if (theoreticalSlot == slot)
theoreticalSlot++;
else
break;
}
// slot is uint8 - avoid shenanigans - 56 max visible auras - 255 max all auras
if (theoreticalSlot > NULL_AURA_SLOT)
theoreticalSlot = NULL_AURA_SLOT;
slot = theoreticalSlot;
}

SetAuraSlot(slot);

// Not update fields for not first spell's aura, all data already in fields
if (slot < MAX_AURAS) // slot found
if (slot < MAX_AURAS) // slot found
{
SetAura(slot, false);
SetAuraFlag(slot, true);
Expand All @@ -7925,10 +7949,10 @@ void SpellAuraHolder::_AddSpellAuraHolder()

// update for out of range group members
m_target->UpdateAuraForGroup(slot);

UpdateAuraDuration();
}

UpdateAuraDuration();

//*****************************************************
// Update target aura state flag (at 1 aura apply)
// TODO: Make it easer
Expand Down Expand Up @@ -8736,55 +8760,78 @@ void SpellAuraHolder::ClearExtraAuraInfo(Unit* caster)

void SpellAuraHolder::UpdateAuraDuration()
{
if (GetAuraSlot() >= MAX_AURAS || m_isPassive)
// not send in case player loading - on load is sent differently
if (m_target->IsPlayer() && static_cast<Player*>(m_target)->GetSession()->PlayerLoading())
return;

if (m_target->IsPlayer())
Unit* caster = GetCaster();

if (!GetSpellProto()->HasAttribute(SPELL_ATTR_EX5_DO_NOT_DISPLAY_DURATION))
{
if (!GetSpellProto()->HasAttribute(SPELL_ATTR_EX5_DO_NOT_DISPLAY_DURATION))
{
WorldPacket data(SMSG_UPDATE_AURA_DURATION, 5);
data << uint8(GetAuraSlot());
data << uint32(GetAuraDuration());
static_cast<Player*>(m_target)->SendDirectMessage(data);
// if caster == target and player, meant to get both
if (GetAuraSlot() < MAX_AURAS) // only visible auras
SendAuraDuration();

SendAuraDurationForTarget();
}
if (caster && caster->IsPlayer())
SendAuraDurationToCaster(static_cast<Player*>(caster));
}
}

// not send in case player loading (will not work anyway until player not added to map), sent in visibility change code
if (m_target->GetTypeId() == TYPEID_PLAYER && static_cast<Player*>(m_target)->GetSession()->PlayerLoading())
void SpellAuraHolder::LoginAuraDuration()
{
// target is currently logging in player and only send what he needs
SendAuraDuration();
if (m_casterGuid == m_target->GetObjectGuid()) // no need to fetch caster - must only send if they are the same anyway
SendAuraDurationToCaster(static_cast<Player*>(m_target));
}

void SpellAuraHolder::ForceUpdateAuraDuration()
{
if (GetAuraSlot() >= MAX_AURAS)
return;

Unit* caster = GetCaster();
if (!GetSpellProto()->HasAttribute(SPELL_ATTR_EX5_DO_NOT_DISPLAY_DURATION))
{
// if caster == target and player, meant to get both
SendAuraDuration();

if (caster && caster->IsPlayer())
SendAuraDurationToCasterNeedUpdate(static_cast<Player*>(caster));
}
}

if (caster && caster->GetTypeId() == TYPEID_PLAYER && caster != m_target)
SendAuraDurationForCaster(static_cast<Player*>(caster));
void SpellAuraHolder::SendAuraDuration()
{
if (!m_target->IsPlayer())
return;

WorldPacket data(SMSG_UPDATE_AURA_DURATION, 5);
data << uint8(GetAuraSlot());
data << uint32(GetAuraMaxDuration() == -1 ? 0 : GetAuraDuration());
static_cast<Player*>(m_target)->SendDirectMessage(data);
}

void SpellAuraHolder::SendAuraDurationForTarget(uint32 slot)
void SpellAuraHolder::SendAuraDurationToCaster(Player* caster, uint32 slot)
{
WorldPacket data(SMSG_SET_EXTRA_AURA_INFO, (8 + 1 + 4 + 4 + 4));
data << m_target->GetPackGUID();
data << uint8(slot == MAX_AURAS ? GetAuraSlot() : slot);
data << uint32(GetId());
data << uint32(GetAuraMaxDuration());
data << uint32(GetAuraDuration());
data << int32(GetAuraMaxDuration());
data << uint32(GetAuraMaxDuration() == -1 ? 0 : GetAuraDuration());

static_cast<Player*>(m_target)->SendDirectMessage(data);
caster->SendDirectMessage(data);
}

void SpellAuraHolder::SendAuraDurationForCaster(Player* caster)
void SpellAuraHolder::SendAuraDurationToCasterNeedUpdate(Player* caster)
{
WorldPacket data(SMSG_SET_EXTRA_AURA_INFO_NEED_UPDATE, (8 + 1 + 4 + 4 + 4));
data << m_target->GetPackGUID();
data << uint8(GetAuraSlot());
data << uint32(GetId());
if (!GetSpellProto()->HasAttribute(SPELL_ATTR_EX5_DO_NOT_DISPLAY_DURATION))
{
data << uint32(GetAuraMaxDuration()); // full
data << uint32(GetAuraDuration()); // remain
}
data << int32(GetAuraMaxDuration()); // full
data << uint32(GetAuraMaxDuration() == -1 ? 0 : GetAuraDuration()); // remain
caster->GetSession()->SendPacket(data);
}

Expand Down
7 changes: 5 additions & 2 deletions src/game/Spells/SpellAuras.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,11 @@ class SpellAuraHolder
bool IsDispellableByMask(uint32 dispelMask, Unit const* caster, SpellEntry const* spellInfo) const;

void UpdateAuraDuration();
void SendAuraDurationForTarget(uint32 slot = MAX_AURAS);
void SendAuraDurationForCaster(Player* caster);
void LoginAuraDuration();
void ForceUpdateAuraDuration();
void SendAuraDuration();
void SendAuraDurationToCaster(Player* caster, uint32 slot = MAX_AURAS);
void SendAuraDurationToCasterNeedUpdate(Player* caster);

void SetAura(uint32 slot, bool remove) { m_target->SetUInt32Value(UNIT_FIELD_AURA + slot, remove ? 0 : GetId()); }
void SetAuraFlag(uint32 slot, bool add);
Expand Down

2 comments on commit f963617

@Eonfluxx
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got random crashes after this update on
void AddUpdateObject(Object* obj) { i_objectsToClientUpdate.insert(obj); }
Can't reproduce. There's a crashlog

Thread 13 "mangos" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffb77fe6c0 (LWP 1037867)]
std::_Rb_tree<Object*, Object*, std::_Identity<Object*>, std::less<Object*>, std::allocator<Object*> >::_M_get_insert_unique_pos (__k=<synthetic pointer>: 0x7fff78d13300, this=0x7fff5e045a60) at /usr/include/c++/12/bits/stl_tree.h:2117
2117		  __comp = _M_impl._M_key_compare(__k, _S_key(__x));

------------- CRASHLOG BEGIN -------------
	Using the running image of child Thread 0x7fffb77fe6c0 (LWP 1037867).
Program stopped at 0x555555d19833.
It stopped with signal SIGSEGV, Segmentation fault.

------------- BACKTRACE -------------
#0  std::_Rb_tree<Object*, Object*, std::_Identity<Object*>, std::less<Object*>, std::allocator<Object*> >::_M_get_insert_unique_pos (__k=<synthetic pointer>: 0x7fff78d13300, this=0x7fff5e045a60) at /usr/include/c++/12/bits/stl_tree.h:2117
#1  std::_Rb_tree<Object*, Object*, std::_Identity<Object*>, std::less<Object*>, std::allocator<Object*> >::_M_insert_unique<Object* const&> (__v=<synthetic pointer>: 0x7fff78d13300, this=0x7fff5e045a60) at /usr/include/c++/12/bits/stl_tree.h:2170
#2  std::set<Object*, std::less<Object*>, std::allocator<Object*> >::insert (__x=<synthetic pointer>: 0x7fff78d13300, this=0x7fff5e045a60) at /usr/include/c++/12/bits/stl_set.h:512
#3  Map::AddUpdateObject (obj=0x7fff78d13300, this=0x7fff5e045a00) at /mangos/src/game/Maps/Map.h:314
#4  WorldObject::AddToClientUpdateList (this=0x7fff78d13300) at /mangos/src/game/Entities/Object.cpp:2609
#5  0x0000555555d1a073 in Object::ForceValuesUpdateAtIndex (this=0x7fff78d13300, index=<optimized out>) at /mangos/src/game/Entities/Object.cpp:1252
#6  0x0000555555cd4e82 in WorldSession::HandlePlayerLogin (this=0x7fff9886c6b0, holder=<optimized out>) at /mangos/src/game/Entities/CharacterHandler.cpp:797
#7  0x0000555555c028c2 in SqlResultQueue::Update (this=0x555556a25490) at /mangos/src/shared/Database/SqlOperations.cpp:110
#8  0x0000555555bfb9ee in Database::ProcessResultQueue (this=<optimized out>) at /mangos/src/shared/Database/Database.cpp:201
#9  0x000055555604549e in World::UpdateResultQueue (this=0x555556a49d70) at /mangos/src/game/World/World.cpp:2304
#10 World::Update (this=0x555556a49d70, diff=diff@entry=50) at /mangos/src/game/World/World.cpp:1694
#11 0x0000555555bf1377 in WorldRunnable::run (this=<optimized out>) at /mangos/src/mangosd/WorldRunnable.cpp:55
#12 0x00007ffff76d44a3 in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6
#13 0x00007ffff74a8044 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#14 0x00007ffff75285fc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

@killerwife
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is my CharacterHandler 797

image

As you can see, an empty line. Hence you are not running a stock cmangos, hence I cannot help you.

Please sign in to comment.