From 67fdd7809a9188924a4848c1e2da314ea8c0f6dd Mon Sep 17 00:00:00 2001 From: Kelsi Date: Tue, 17 Feb 2026 01:05:15 -0800 Subject: [PATCH] Fix Classic item query packet format for auction house item names Vanilla CMSG_ITEM_QUERY_SINGLE has no GUID field (just uint32 entry), causing servers to reject the oversized WotLK-format packets. Also fix response parser: remove nonexistent statsCount field and use 5 damage types instead of 2 to match Vanilla protocol. --- include/game/packet_parsers.hpp | 6 ++++++ src/game/game_handler.cpp | 4 +++- src/game/packet_parsers_classic.cpp | 17 ++++++++++++----- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/include/game/packet_parsers.hpp b/include/game/packet_parsers.hpp index 9bc6b72a..2d0c1b2e 100644 --- a/include/game/packet_parsers.hpp +++ b/include/game/packet_parsers.hpp @@ -124,6 +124,11 @@ public: // --- Item Query --- + /** Build CMSG_ITEM_QUERY_SINGLE */ + virtual network::Packet buildItemQuery(uint32_t entry, uint64_t guid) { + return ItemQueryPacket::build(entry, guid); + } + /** Parse SMSG_ITEM_QUERY_SINGLE_RESPONSE */ virtual bool parseItemQueryResponse(network::Packet& packet, ItemQueryResponseData& data) { return ItemQueryResponseParser::parse(packet, data); @@ -287,6 +292,7 @@ public: bool parseMailList(network::Packet& packet, std::vector& inbox) override; network::Packet buildMailTakeItem(uint64_t mailboxGuid, uint32_t mailId, uint32_t itemSlot) override; network::Packet buildMailDelete(uint64_t mailboxGuid, uint32_t mailId, uint32_t mailTemplateId) override; + network::Packet buildItemQuery(uint32_t entry, uint64_t guid) override; bool parseItemQueryResponse(network::Packet& packet, ItemQueryResponseData& data) override; }; diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 0a61e1e0..96e0df66 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -5547,7 +5547,9 @@ void GameHandler::queryItemInfo(uint32_t entry, uint64_t guid) { // If we don't have the item object's GUID (e.g. visible equipment decoding), // fall back to the player's GUID to keep the request non-zero. uint64_t queryGuid = (guid != 0) ? guid : playerGuid; - auto packet = ItemQueryPacket::build(entry, queryGuid); + auto packet = packetParsers_ + ? packetParsers_->buildItemQuery(entry, queryGuid) + : ItemQueryPacket::build(entry, queryGuid); socket->send(packet); } diff --git a/src/game/packet_parsers_classic.cpp b/src/game/packet_parsers_classic.cpp index 086a4863..acaf0629 100644 --- a/src/game/packet_parsers_classic.cpp +++ b/src/game/packet_parsers_classic.cpp @@ -846,6 +846,14 @@ network::Packet ClassicPacketParsers::buildMailDelete(uint64_t mailboxGuid, // Vanilla has NO SoundOverrideSubclass, NO Flags2, NO ScalingStatDistribution, // NO ScalingStatValue, and only 2 damage types (not 5). // ============================================================================ +network::Packet ClassicPacketParsers::buildItemQuery(uint32_t entry, uint64_t /*guid*/) { + // Vanilla CMSG_ITEM_QUERY_SINGLE: just uint32 entry (no GUID field) + network::Packet packet(wireOpcode(Opcode::CMSG_ITEM_QUERY_SINGLE)); + packet.writeUInt32(entry); + LOG_DEBUG("[Classic] Built CMSG_ITEM_QUERY_SINGLE: entry=", entry); + return packet; +} + bool ClassicPacketParsers::parseItemQueryResponse(network::Packet& packet, ItemQueryResponseData& data) { data.entry = packet.readUInt32(); @@ -893,12 +901,11 @@ bool ClassicPacketParsers::parseItemQueryResponse(network::Packet& packet, ItemQ data.maxStack = static_cast(packet.readUInt32()); // Stackable data.containerSlots = packet.readUInt32(); - // Vanilla: 10 stat pairs (same as WotLK) - uint32_t statsCount = packet.readUInt32(); + // Vanilla: 10 stat pairs, NO statsCount prefix for (uint32_t i = 0; i < 10; i++) { uint32_t statType = packet.readUInt32(); int32_t statValue = static_cast(packet.readUInt32()); - if (i < statsCount) { + if (statType != 0) { switch (statType) { case 3: data.agility = statValue; break; case 4: data.strength = statValue; break; @@ -912,8 +919,8 @@ bool ClassicPacketParsers::parseItemQueryResponse(network::Packet& packet, ItemQ // Vanilla: NO ScalingStatDistribution, NO ScalingStatValue - // Vanilla: only 2 damage types (not 5) - for (int i = 0; i < 2; i++) { + // Vanilla: 5 damage types (same count as WotLK) + for (int i = 0; i < 5; i++) { packet.readFloat(); // DamageMin packet.readFloat(); // DamageMax packet.readUInt32(); // DamageType