From e0346c85df4f532cd7c1bdb9ad48c7824cbcb6e3 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 18 Mar 2026 06:23:03 -0700 Subject: [PATCH] fix: salvage spell-go hit data when miss targets are truncated SMSG_SPELL_GO packets with unreasonably high miss counts (48, 118, 241) were causing the entire packet to be discarded, losing all combat hit data. Now salvage the successfully-parsed hit targets (needed for combat text, health bars, animations) instead of discarding everything. Also add spellId/hitCount to truncation warnings for easier diagnosis. --- src/game/world_packets.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/game/world_packets.cpp b/src/game/world_packets.cpp index a4562067..e6f6d872 100644 --- a/src/game/world_packets.cpp +++ b/src/game/world_packets.cpp @@ -3891,23 +3891,27 @@ bool SpellGoParser::parse(network::Packet& packet, SpellGoData& data) { const uint8_t rawMissCount = packet.readUInt8(); if (rawMissCount > 128) { - LOG_WARNING("Spell go: missCount capped (requested=", (int)rawMissCount, ")"); + LOG_WARNING("Spell go: missCount capped (requested=", (int)rawMissCount, + ") spell=", data.spellId, " hits=", (int)data.hitCount, + " remaining=", packet.getSize() - packet.getReadPos()); } const uint8_t storedMissLimit = std::min(rawMissCount, 128); data.missTargets.reserve(storedMissLimit); for (uint16_t i = 0; i < rawMissCount; ++i) { // Each miss entry: packed GUID(1-8 bytes) + missType(1 byte). - // REFLECT additionally appends uint32 reflectSpellId + uint8 reflectResult. + // REFLECT additionally appends uint8 reflectResult. if (!hasFullPackedGuid(packet)) { - LOG_WARNING("Spell go: truncated miss targets at index ", i, "/", (int)rawMissCount); + LOG_WARNING("Spell go: truncated miss targets at index ", i, "/", (int)rawMissCount, + " spell=", data.spellId, " hits=", (int)data.hitCount); truncatedTargets = true; break; } SpellGoMissEntry m; m.targetGuid = UpdateObjectParser::readPackedGuid(packet); // packed GUID in WotLK if (packet.getSize() - packet.getReadPos() < 1) { - LOG_WARNING("Spell go: missing missType at miss index ", i, "/", (int)rawMissCount); + LOG_WARNING("Spell go: missing missType at miss index ", i, "/", (int)rawMissCount, + " spell=", data.spellId); truncatedTargets = true; break; } @@ -3924,12 +3928,17 @@ bool SpellGoParser::parse(network::Packet& packet, SpellGoData& data) { data.missTargets.push_back(m); } } - if (truncatedTargets) { - packet.setReadPos(startPos); - return false; - } data.missCount = static_cast(data.missTargets.size()); + // If miss targets were truncated, salvage the successfully-parsed hit data + // rather than discarding the entire spell. The server already applied effects; + // we just need the hit list for UI feedback (combat text, health bars). + if (truncatedTargets) { + LOG_DEBUG("Spell go: salvaging ", (int)data.hitCount, " hits despite miss truncation"); + packet.setReadPos(packet.getSize()); // consume remaining bytes + return true; + } + // WotLK 3.3.5a SpellCastTargets — consume ALL target payload bytes so that // any trailing fields after the target section are not misaligned for // ground-targeted or AoE spells. Same layout as SpellStartParser.