From 3667ff4998ebb29f8f8901cd25f2834d3dd3977b Mon Sep 17 00:00:00 2001 From: Kelsi Date: Tue, 17 Mar 2026 09:04:40 -0700 Subject: [PATCH] fix: use uniform 22-byte loot item size for Classic/TBC/Turtle SMSG_LOOT_RESPONSE items include randomSuffix and randomPropertyId fields across all expansions, not just WotLK. Using 14-byte size for Classic/TBC caused item data to be read at wrong offsets. --- include/game/world_packets.hpp | 5 +++-- src/game/world_packets.cpp | 33 +++++++++++++-------------------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/include/game/world_packets.hpp b/include/game/world_packets.hpp index 293953ea..c2e92f06 100644 --- a/include/game/world_packets.hpp +++ b/include/game/world_packets.hpp @@ -2060,8 +2060,9 @@ public: /** SMSG_LOOT_RESPONSE parser */ class LootResponseParser { public: - // isWotlkFormat: true for WotLK 3.3.5a (22 bytes/item with randomSuffix+randomProp), - // false for Classic 1.12 and TBC 2.4.3 (14 bytes/item). + // isWotlkFormat: true for WotLK (has trailing quest item section), + // false for Classic/TBC (no quest item section). + // Per-item size is 22 bytes across all expansions. static bool parse(network::Packet& packet, LootResponseData& data, bool isWotlkFormat = true); }; diff --git a/src/game/world_packets.cpp b/src/game/world_packets.cpp index 5a9804a1..5d322ff1 100644 --- a/src/game/world_packets.cpp +++ b/src/game/world_packets.cpp @@ -4257,10 +4257,9 @@ bool LootResponseParser::parse(network::Packet& packet, LootResponseData& data, data.gold = packet.readUInt32(); uint8_t itemCount = packet.readUInt8(); - // Item wire size: - // WotLK 3.3.5a: slot(1)+itemId(4)+count(4)+displayInfo(4)+randSuffix(4)+randProp(4)+slotType(1) = 22 - // Classic/TBC: slot(1)+itemId(4)+count(4)+displayInfo(4)+slotType(1) = 14 - const size_t kItemSize = isWotlkFormat ? 22u : 14u; + // Per-item wire size is 22 bytes across all expansions: + // slot(1)+itemId(4)+count(4)+displayInfo(4)+randSuffix(4)+randProp(4)+slotType(1) = 22 + constexpr size_t kItemSize = 22u; auto parseLootItemList = [&](uint8_t listCount, bool markQuestItems) -> bool { for (uint8_t i = 0; i < listCount; ++i) { @@ -4270,21 +4269,14 @@ bool LootResponseParser::parse(network::Packet& packet, LootResponseData& data, } LootItem item; - item.slotIndex = packet.readUInt8(); - item.itemId = packet.readUInt32(); - item.count = packet.readUInt32(); - item.displayInfoId = packet.readUInt32(); - - if (isWotlkFormat) { - item.randomSuffix = packet.readUInt32(); - item.randomPropertyId = packet.readUInt32(); - } else { - item.randomSuffix = 0; - item.randomPropertyId = 0; - } - - item.lootSlotType = packet.readUInt8(); - item.isQuestItem = markQuestItems; + item.slotIndex = packet.readUInt8(); + item.itemId = packet.readUInt32(); + item.count = packet.readUInt32(); + item.displayInfoId = packet.readUInt32(); + item.randomSuffix = packet.readUInt32(); + item.randomPropertyId = packet.readUInt32(); + item.lootSlotType = packet.readUInt8(); + item.isQuestItem = markQuestItems; data.items.push_back(item); } return true; @@ -4296,8 +4288,9 @@ bool LootResponseParser::parse(network::Packet& packet, LootResponseData& data, return false; } + // Quest item section only present in WotLK 3.3.5a uint8_t questItemCount = 0; - if (packet.getSize() - packet.getReadPos() >= 1) { + if (isWotlkFormat && packet.getSize() - packet.getReadPos() >= 1) { questItemCount = packet.readUInt8(); data.items.reserve(data.items.size() + questItemCount); if (!parseLootItemList(questItemCount, true)) {