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.
This commit is contained in:
Kelsi 2026-02-17 01:05:15 -08:00
parent a1457ee801
commit 67fdd7809a
3 changed files with 21 additions and 6 deletions

View file

@ -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<MailMessage>& 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;
};

View file

@ -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);
}

View file

@ -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<int32_t>(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<int32_t>(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