From e92bea747a6398f961377c5ea4a81dd147aa69ae Mon Sep 17 00:00:00 2001 From: Kelsi Date: Thu, 19 Feb 2026 17:54:32 -0800 Subject: [PATCH] Fix item tooltip armor: auto-detect BuyCount in WotLK item query parser The WotLK item query parser assumed BuyCount is always present as a separate field (Flags + Flags2 + BuyCount + BuyPrice + SellPrice = 5 fields). Some server variants omit BuyCount, shifting every subsequent field by 4 bytes and causing armor to be read from the wrong offset. Now read 5 fields and validate InventoryType (must be 0-28). If it falls outside that range, rewind and re-parse with 4 fields (no BuyCount), which recovers correct alignment. Elevated item query log from DEBUG to INFO so the parsed armor value is visible in output. --- src/game/world_packets.cpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/game/world_packets.cpp b/src/game/world_packets.cpp index 1fa34986..c05f694a 100644 --- a/src/game/world_packets.cpp +++ b/src/game/world_packets.cpp @@ -2084,14 +2084,27 @@ bool ItemQueryResponseParser::parse(network::Packet& packet, ItemQueryResponseDa data.displayInfoId = packet.readUInt32(); data.quality = packet.readUInt32(); + // WotLK 3.3.5a (TrinityCore/AzerothCore): Flags, Flags2, BuyCount, BuyPrice, SellPrice + // Some server variants omit BuyCount (4 fields instead of 5). + // Read 5 fields and validate InventoryType; if it looks implausible, rewind and try 4. + const size_t postQualityPos = packet.getReadPos(); packet.readUInt32(); // Flags packet.readUInt32(); // Flags2 - packet.readUInt32(); // BuyCount (WotLK: separate from BuyPrice) + packet.readUInt32(); // BuyCount packet.readUInt32(); // BuyPrice data.sellPrice = packet.readUInt32(); // SellPrice - data.inventoryType = packet.readUInt32(); + if (data.inventoryType > 28) { + // inventoryType out of range — BuyCount probably not present; rewind and try 4 fields + packet.setReadPos(postQualityPos); + packet.readUInt32(); // Flags + packet.readUInt32(); // Flags2 + packet.readUInt32(); // BuyPrice + data.sellPrice = packet.readUInt32(); // SellPrice + data.inventoryType = packet.readUInt32(); + } + packet.readUInt32(); // AllowableClass packet.readUInt32(); // AllowableRace packet.readUInt32(); // ItemLevel @@ -2193,10 +2206,10 @@ bool ItemQueryResponseParser::parse(network::Packet& packet, ItemQueryResponseDa data.delayMs = chosen->delayMs; data.valid = !data.name.empty(); - LOG_DEBUG("Item query response: ", data.name, " (quality=", data.quality, - " invType=", data.inventoryType, " stack=", data.maxStack, - " class=", data.itemClass, " armor=", data.armor, - " dmgEntries=", chosenDamageEntries, ")"); + LOG_INFO("Item query: '", data.name, "' class=", data.itemClass, + " invType=", data.inventoryType, " quality=", data.quality, + " armor=", data.armor, " dmgEntries=", chosenDamageEntries, + " statsCount=", statsCount, " sellPrice=", data.sellPrice); return true; }