From b4f744d0005cce49cee5ed9fdc515fe984424de6 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Mon, 9 Mar 2026 21:34:02 -0700 Subject: [PATCH] tbc: fix combat damage parsing for TBC 2.4.3 TBC 2.4.3 SMSG_ATTACKERSTATEUPDATE and SMSG_SPELLNONMELEEDAMAGELOG send full uint64 GUIDs for attacker/target, while WotLK 3.3.5a uses packed (variable-length) GUIDs. Using the WotLK reader on TBC packets consumes 1-8 bytes where a fixed 8 are expected, shifting all subsequent reads and producing completely wrong damage/absorbed/resisted values. Add TbcPacketParsers overrides that read plain uint64 GUIDs. Also note that TBC SMSG_SPELLNONMELEEDAMAGELOG lacks the WotLK overkill field. --- include/game/packet_parsers.hpp | 4 ++ src/game/packet_parsers_tbc.cpp | 70 +++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) diff --git a/include/game/packet_parsers.hpp b/include/game/packet_parsers.hpp index 4c7edb11..6fb9b8ae 100644 --- a/include/game/packet_parsers.hpp +++ b/include/game/packet_parsers.hpp @@ -298,6 +298,10 @@ public: // TBC 2.4.3 SMSG_MAIL_LIST_RESULT: uint8 count (not uint32+uint8), no body field, // attachment uses uint64 itemGuid (not uint32), enchants are 7×u32 id-only (not 7×{id+dur+charges}) bool parseMailList(network::Packet& packet, std::vector& inbox) override; + // TBC 2.4.3 SMSG_ATTACKERSTATEUPDATE uses full uint64 GUIDs (WotLK uses packed GUIDs) + bool parseAttackerStateUpdate(network::Packet& packet, AttackerStateUpdateData& data) override; + // TBC 2.4.3 SMSG_SPELLNONMELEEDAMAGELOG uses full uint64 GUIDs (WotLK uses packed GUIDs) + bool parseSpellDamageLog(network::Packet& packet, SpellDamageLogData& data) override; }; /** diff --git a/src/game/packet_parsers_tbc.cpp b/src/game/packet_parsers_tbc.cpp index 55ad50fa..bef4b411 100644 --- a/src/game/packet_parsers_tbc.cpp +++ b/src/game/packet_parsers_tbc.cpp @@ -977,5 +977,75 @@ bool TbcPacketParsers::parseMailList(network::Packet& packet, std::vector(packet.readUInt32()); + data.subDamageCount = packet.readUInt8(); + + for (uint8_t i = 0; i < data.subDamageCount; ++i) { + SubDamage sub; + sub.schoolMask = packet.readUInt32(); + sub.damage = packet.readFloat(); + sub.intDamage = packet.readUInt32(); + sub.absorbed = packet.readUInt32(); + sub.resisted = packet.readUInt32(); + data.subDamages.push_back(sub); + } + + data.victimState = packet.readUInt32(); + data.overkill = static_cast(packet.readUInt32()); + + if (packet.getReadPos() < packet.getSize()) { + data.blocked = packet.readUInt32(); + } + + LOG_INFO("[TBC] Melee hit: ", data.totalDamage, " damage", + data.isCrit() ? " (CRIT)" : "", + data.isMiss() ? " (MISS)" : ""); + return true; +} + +// ============================================================================ +// TbcPacketParsers::parseSpellDamageLog — TBC 2.4.3 SMSG_SPELLNONMELEEDAMAGELOG +// +// TBC uses full uint64 GUIDs; WotLK uses packed GUIDs. +// ============================================================================ +bool TbcPacketParsers::parseSpellDamageLog(network::Packet& packet, SpellDamageLogData& data) { + if (packet.getSize() - packet.getReadPos() < 29) return false; + + data.targetGuid = packet.readUInt64(); // full GUID in TBC + data.attackerGuid = packet.readUInt64(); // full GUID in TBC + data.spellId = packet.readUInt32(); + data.damage = packet.readUInt32(); + data.schoolMask = packet.readUInt8(); + data.absorbed = packet.readUInt32(); + data.resisted = packet.readUInt32(); + + uint8_t periodicLog = packet.readUInt8(); + (void)periodicLog; + packet.readUInt8(); // unused + packet.readUInt32(); // blocked + uint32_t flags = packet.readUInt32(); + data.isCrit = (flags & 0x02) != 0; + + // TBC does not have an overkill field here + data.overkill = 0; + + LOG_INFO("[TBC] Spell damage: spellId=", data.spellId, " dmg=", data.damage, + data.isCrit ? " CRIT" : ""); + return true; +} + } // namespace game } // namespace wowee