diff options
| author | ariel- <ariel-@users.noreply.github.com> | 2018-03-10 03:55:14 -0300 |
|---|---|---|
| committer | ariel- <ariel-@users.noreply.github.com> | 2018-03-10 03:55:14 -0300 |
| commit | 0c2a6dee0781be56bdee81e4d155431d7e7634f1 (patch) | |
| tree | 44c95a57f51536f513f7a17b1d47602c99b9bbde /src/server/game/Spells/Spell.cpp | |
| parent | 4ca9d6469da435cb818e3b56840669775627e050 (diff) | |
Core/Spell: fix spell visual for other players
- Ported SMSG_SPELL_GO and SMSG_SPELL_START to new packet system
Diffstat (limited to 'src/server/game/Spells/Spell.cpp')
| -rw-r--r-- | src/server/game/Spells/Spell.cpp | 191 |
1 files changed, 91 insertions, 100 deletions
diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 6f8322332b8..bbd290df5a4 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -47,6 +47,7 @@ #include "SpellHistory.h" #include "SpellInfo.h" #include "SpellMgr.h" +#include "SpellPackets.h" #include "SpellScript.h" #include "TemporarySummon.h" #include "TradeData.h" @@ -175,41 +176,42 @@ void SpellCastTargets::Read(ByteBuffer& data, Unit* caster) Update(caster); } -void SpellCastTargets::Write(ByteBuffer& data) +void SpellCastTargets::Write(WorldPackets::Spells::SpellTargetData& data) { - data << uint32(m_targetMask); + data.Flags = m_targetMask; if (m_targetMask & (TARGET_FLAG_UNIT | TARGET_FLAG_CORPSE_ALLY | TARGET_FLAG_GAMEOBJECT | TARGET_FLAG_CORPSE_ENEMY | TARGET_FLAG_UNIT_MINIPET)) - data << m_objectTargetGUID.WriteAsPacked(); + data.Unit = m_objectTargetGUID; if (m_targetMask & (TARGET_FLAG_ITEM | TARGET_FLAG_TRADE_ITEM)) { + data.Item = boost::in_place(); if (m_itemTarget) - data << m_itemTarget->GetPackGUID(); - else - data << uint8(0); + data.Item = m_itemTarget->GetGUID(); } if (m_targetMask & TARGET_FLAG_SOURCE_LOCATION) { - data << m_src._transportGUID.WriteAsPacked(); // relative position guid here - transport for example - if (m_src._transportGUID) - data << m_src._transportOffset.PositionXYZStream(); + data.SrcLocation = boost::in_place(); + data.SrcLocation->Transport = m_src._transportGUID; + if (!m_src._transportGUID.IsEmpty()) + data.SrcLocation->Location = m_src._transportOffset; else - data << m_src._position.PositionXYZStream(); + data.SrcLocation->Location = m_src._position; } if (m_targetMask & TARGET_FLAG_DEST_LOCATION) { - data << m_dst._transportGUID.WriteAsPacked(); // relative position guid here - transport for example + data.DstLocation = boost::in_place(); + data.DstLocation->Transport = m_dst._transportGUID; if (m_dst._transportGUID) - data << m_dst._transportOffset.PositionXYZStream(); + data.DstLocation->Location = m_dst._transportOffset; else - data << m_dst._position.PositionXYZStream(); + data.DstLocation->Location = m_dst._position; } if (m_targetMask & TARGET_FLAG_STRING) - data << m_strTarget; + data.Name = m_strTarget; } ObjectGuid SpellCastTargets::GetOrigUnitTargetGUID() const @@ -4082,33 +4084,39 @@ void Spell::SendSpellStart() if (m_spellInfo->RuneCostID && m_spellInfo->PowerType == POWER_RUNE) castFlags |= CAST_FLAG_NO_GCD; // not needed, but Blizzard sends it - WorldPacket data(SMSG_SPELL_START, (8+8+4+4+2)); + WorldPackets::Spells::SpellStart packet; + WorldPackets::Spells::SpellCastData& castData = packet.Cast; + if (m_CastItem) - data << m_CastItem->GetPackGUID(); + castData.CasterGUID = m_CastItem->GetGUID(); else - data << m_caster->GetPackGUID(); + castData.CasterGUID = m_caster->GetGUID(); - data << m_caster->GetPackGUID(); - data << uint8(m_cast_count); // pending spell cast? - data << uint32(m_spellInfo->Id); // spellId - data << uint32(castFlags); // cast flags - data << int32(m_timer); // delay? + castData.CasterUnit = m_caster->GetGUID(); + castData.CastID = m_cast_count; + castData.SpellID = m_spellInfo->Id; + castData.CastFlags = castFlags; + castData.CastTime = m_timer; - m_targets.Write(data); + m_targets.Write(castData.Target); if (castFlags & CAST_FLAG_POWER_LEFT_SELF) - data << uint32(ASSERT_NOTNULL(m_caster->ToUnit())->GetPower((Powers)m_spellInfo->PowerType)); + castData.RemainingPower = ASSERT_NOTNULL(m_caster->ToUnit())->GetPower(static_cast<Powers>(m_spellInfo->PowerType)); if (castFlags & CAST_FLAG_AMMO) - WriteAmmoToPacket(&data); + { + castData.Ammo = boost::in_place(); + UpdateSpellCastDataAmmo(*castData.Ammo); + } if (castFlags & CAST_FLAG_IMMUNITY) { - data << uint32(schoolImmunityMask); - data << uint32(mechanicImmunityMask); + castData.Immunities = boost::in_place(); + castData.Immunities->School = schoolImmunityMask; + castData.Immunities->Value = mechanicImmunityMask; } - m_caster->SendMessageToSet(&data, true); + m_caster->SendMessageToSet(packet.Write(), true); } void Spell::SendSpellGo() @@ -4117,8 +4125,6 @@ void Spell::SendSpellGo() if (!IsNeedSendToClient()) return; - //TC_LOG_DEBUG("spells", "Sending SMSG_SPELL_GO id=%u", m_spellInfo->Id); - uint32 castFlags = CAST_FLAG_UNKNOWN_9; // triggered spells with spell visual != 0 @@ -4152,78 +4158,82 @@ void Spell::SendSpellGo() if (!m_spellInfo->StartRecoveryTime) castFlags |= CAST_FLAG_NO_GCD; - WorldPacket data(SMSG_SPELL_GO, 50); // guess size + WorldPackets::Spells::SpellGo packet; + WorldPackets::Spells::SpellCastData& castData = packet.Cast; + if (m_CastItem) - data << m_CastItem->GetPackGUID(); + castData.CasterGUID = m_CastItem->GetGUID(); else - data << m_caster->GetPackGUID(); + castData.CasterGUID = m_caster->GetGUID(); - data << m_caster->GetPackGUID(); - data << uint8(m_cast_count); // pending spell cast? - data << uint32(m_spellInfo->Id); // spellId - data << uint32(castFlags); // cast flags - data << uint32(GameTime::GetGameTimeMS()); // timestamp + castData.CasterUnit = m_caster->GetGUID(); + castData.CastID = m_cast_count; + castData.SpellID = m_spellInfo->Id; + castData.CastFlags = castFlags; + castData.CastTime = GameTime::GetGameTimeMS(); - WriteSpellGoTargets(&data); + UpdateSpellCastDataTargets(castData); - m_targets.Write(data); + m_targets.Write(castData.Target); if (castFlags & CAST_FLAG_POWER_LEFT_SELF) - data << uint32(ASSERT_NOTNULL(m_caster->ToUnit())->GetPower((Powers)m_spellInfo->PowerType)); + castData.RemainingPower = ASSERT_NOTNULL(m_caster->ToUnit())->GetPower(static_cast<Powers>(m_spellInfo->PowerType)); if (castFlags & CAST_FLAG_RUNE_LIST) // rune cooldowns list { + castData.RemainingRunes = boost::in_place(); + /// @todo There is a crash caused by a spell with CAST_FLAG_RUNE_LIST cast by a creature //The creature is the mover of a player, so HandleCastSpellOpcode uses it as the caster if (Player* player = m_caster->ToPlayer()) { uint8 runeMaskInitial = m_runesState; uint8 runeMaskAfterCast = player->GetRunesState(); - data << uint8(runeMaskInitial); // runes state before - data << uint8(runeMaskAfterCast); // runes state after + castData.RemainingRunes->Start = runeMaskInitial; // runes state before + castData.RemainingRunes->Count = runeMaskAfterCast; // runes state after + for (uint8 i = 0; i < MAX_RUNES; ++i) { uint8 mask = (1 << i); - if (mask & runeMaskInitial && !(mask & runeMaskAfterCast)) // usable before andon cooldown now... + if ((mask & runeMaskInitial) && !(mask & runeMaskAfterCast)) // usable before and on cooldown now... { // float casts ensure the division is performed on floats as we need float result float baseCd = float(player->GetRuneBaseCooldown(i)); - data << uint8((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255); // rune cooldown passed + castData.RemainingRunes->Cooldowns.push_back(uint8((baseCd - float(player->GetRuneCooldown(i))) / baseCd * 255)); } } } } + if (castFlags & CAST_FLAG_ADJUST_MISSILE) { - data << m_targets.GetElevation(); - data << uint32(m_delayMoment); + castData.MissileTrajectory = boost::in_place(); + castData.MissileTrajectory->Pitch = m_targets.GetElevation(); + castData.MissileTrajectory->TravelTime = m_delayMoment; } if (castFlags & CAST_FLAG_AMMO) - WriteAmmoToPacket(&data); - - if (castFlags & CAST_FLAG_VISUAL_CHAIN) { - data << uint32(0); - data << uint32(0); - } - - if (m_targets.GetTargetMask() & TARGET_FLAG_DEST_LOCATION) - { - data << uint8(0); + castData.Ammo = boost::in_place(); + UpdateSpellCastDataAmmo(*castData.Ammo); } // should be sent to self only if (castFlags & CAST_FLAG_POWER_LEFT_SELF) { if (Player* player = m_caster->GetAffectingPlayer()) - player->SendDirectMessage(&data); + player->SendDirectMessage(packet.Write()); + + // update nearby players (remove flag) + castData.CastFlags &= ~CAST_FLAG_POWER_LEFT_SELF; + castData.RemainingPower = boost::none; + m_caster->SendMessageToSet(packet.Write(), false); } else - m_caster->SendMessageToSet(&data, true); + m_caster->SendMessageToSet(packet.Write(), true); } -void Spell::WriteAmmoToPacket(WorldPacket* data) +void Spell::UpdateSpellCastDataAmmo(WorldPackets::Spells::SpellAmmo& ammo) { uint32 ammoInventoryType = 0; uint32 ammoDisplayID = 0; @@ -4291,13 +4301,16 @@ void Spell::WriteAmmoToPacket(WorldPacket* data) } } - *data << uint32(ammoDisplayID); - *data << uint32(ammoInventoryType); + ammo.DisplayID = ammoDisplayID; + ammo.InventoryType = ammoInventoryType; } /// Writes miss and hit targets for a SMSG_SPELL_GO packet -void Spell::WriteSpellGoTargets(WorldPacket* data) +void Spell::UpdateSpellCastDataTargets(WorldPackets::Spells::SpellCastData& data) { + data.HitTargets = boost::in_place(); + data.MissStatus = boost::in_place(); + // This function also fill data for channeled spells: // m_needAliveTargetMask req for stop channelig if one target die for (TargetInfo& targetInfo : m_UniqueTargetInfo) @@ -4305,53 +4318,31 @@ void Spell::WriteSpellGoTargets(WorldPacket* data) if (targetInfo.EffectMask == 0) // No effect apply - all immuned add state // possibly SPELL_MISS_IMMUNE2 for this?? targetInfo.MissCondition = SPELL_MISS_IMMUNE2; - } - // Hit and miss target counts are both uint8, that limits us to 255 targets for each - // sending more than 255 targets crashes the client (since count sent would be wrong) - // Spells like 40647 (with a huge radius) can easily reach this limit (spell might need - // target conditions but we still need to limit the number of targets sent and keeping - // correct count for both hit and miss). + if (targetInfo.MissCondition == SPELL_MISS_NONE) // Add only hits + { + data.HitTargets->push_back(targetInfo.TargetGUID); - uint32 hit = 0; - size_t hitPos = data->wpos(); - *data << (uint8)0; // placeholder - for (auto ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end() && hit < 255; ++ihit) - { - if (ihit->MissCondition == SPELL_MISS_NONE) // Add only hits + m_channelTargetEffectMask |= targetInfo.EffectMask; + } + else // misses { - *data << uint64(ihit->TargetGUID); - m_channelTargetEffectMask |= ihit->EffectMask; - ++hit; + WorldPackets::Spells::SpellMissStatus missStatus; + missStatus.TargetGUID = targetInfo.TargetGUID; + missStatus.Reason = targetInfo.MissCondition; + if (targetInfo.MissCondition == SPELL_MISS_REFLECT) + missStatus.ReflectStatus = targetInfo.ReflectResult; + + data.MissStatus->push_back(missStatus); } } - for (auto ighit = m_UniqueGOTargetInfo.begin(); ighit != m_UniqueGOTargetInfo.end() && hit < 255; ++ighit) - { - *data << uint64(ighit->TargetGUID); // Always hits - ++hit; - } + for (GOTargetInfo const& targetInfo : m_UniqueGOTargetInfo) + data.HitTargets->push_back(targetInfo.TargetGUID); // Always hits - uint32 miss = 0; - size_t missPos = data->wpos(); - *data << (uint8)0; // placeholder - for (auto ihit = m_UniqueTargetInfo.begin(); ihit != m_UniqueTargetInfo.end() && miss < 255; ++ihit) - { - if (ihit->MissCondition != SPELL_MISS_NONE) // Add only miss - { - *data << uint64(ihit->TargetGUID); - *data << uint8(ihit->MissCondition); - if (ihit->MissCondition == SPELL_MISS_REFLECT) - *data << uint8(ihit->ReflectResult); - ++miss; - } - } // Reset m_needAliveTargetMask for non channeled spell if (!m_spellInfo->IsChanneled()) m_channelTargetEffectMask = 0; - - data->put<uint8>(hitPos, (uint8)hit); - data->put<uint8>(missPos, (uint8)miss); } void Spell::SendLogExecute() |
