From 1b2c7f595ee69809e0a9518f95e1c8fc14d1d4fa Mon Sep 17 00:00:00 2001 From: Kelsi Date: Mon, 9 Mar 2026 21:44:07 -0700 Subject: [PATCH] =?UTF-8?q?classic:=20fix=20SMSG=5FCREATURE=5FQUERY=5FRESP?= =?UTF-8?q?ONSE=20=E2=80=94=20no=20iconName=20field=20in=201.12?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Classic 1.12 SMSG_CREATURE_QUERY_RESPONSE has no iconName CString between subName and typeFlags. The TBC/WotLK parser was reading the typeFlags uint32 bytes as the iconName string, then reading the remaining bytes as typeFlags — producing garbage creature type/family/rank values and corrupting target frame display for all creatures on Classic servers. Add ClassicPacketParsers::parseCreatureQueryResponse without the iconName read, and route the game handler through virtual dispatch so the override is called. --- include/game/packet_parsers.hpp | 9 +++++++ src/game/game_handler.cpp | 2 +- src/game/packet_parsers_classic.cpp | 37 +++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/include/game/packet_parsers.hpp b/include/game/packet_parsers.hpp index 4dd25170..03da989d 100644 --- a/include/game/packet_parsers.hpp +++ b/include/game/packet_parsers.hpp @@ -127,6 +127,13 @@ public: return NameQueryResponseParser::parse(packet, data); } + // --- Creature Query --- + + /** Parse SMSG_CREATURE_QUERY_RESPONSE */ + virtual bool parseCreatureQueryResponse(network::Packet& packet, CreatureQueryResponseData& data) { + return CreatureQueryResponseParser::parse(packet, data); + } + // --- Item Query --- /** Build CMSG_ITEM_QUERY_SINGLE */ @@ -339,6 +346,8 @@ public: bool parseCastFailed(network::Packet& packet, CastFailedData& data) override; bool parseMessageChat(network::Packet& packet, MessageChatData& data) override; bool parseGameObjectQueryResponse(network::Packet& packet, GameObjectQueryResponseData& data) override; + // Classic 1.12 SMSG_CREATURE_QUERY_RESPONSE lacks the iconName string that TBC/WotLK include + bool parseCreatureQueryResponse(network::Packet& packet, CreatureQueryResponseData& data) override; bool parseGossipMessage(network::Packet& packet, GossipMessageData& data) override; bool parseGuildRoster(network::Packet& packet, GuildRosterData& data) override; bool parseGuildQueryResponse(network::Packet& packet, GuildQueryResponseData& data) override; diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 0e167f97..0dfe66b7 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -9578,7 +9578,7 @@ void GameHandler::handleNameQueryResponse(network::Packet& packet) { void GameHandler::handleCreatureQueryResponse(network::Packet& packet) { CreatureQueryResponseData data; - if (!CreatureQueryResponseParser::parse(packet, data)) return; + if (!packetParsers_->parseCreatureQueryResponse(packet, data)) return; pendingCreatureQueries.erase(data.entry); diff --git a/src/game/packet_parsers_classic.cpp b/src/game/packet_parsers_classic.cpp index 2e335af1..60a282dc 100644 --- a/src/game/packet_parsers_classic.cpp +++ b/src/game/packet_parsers_classic.cpp @@ -1309,5 +1309,42 @@ bool ClassicPacketParsers::parseQuestDetails(network::Packet& packet, QuestDetai return true; } +// ============================================================================ +// ClassicPacketParsers::parseCreatureQueryResponse +// +// Classic 1.12 SMSG_CREATURE_QUERY_RESPONSE lacks the iconName CString field +// that TBC 2.4.3 and WotLK 3.3.5a include between subName and typeFlags. +// Without this override, the TBC/WotLK parser reads typeFlags bytes as the +// iconName string, shifting typeFlags/creatureType/family/rank by 1-4 bytes. +// ============================================================================ +bool ClassicPacketParsers::parseCreatureQueryResponse(network::Packet& packet, + CreatureQueryResponseData& data) { + data.entry = packet.readUInt32(); + if (data.entry & 0x80000000) { + data.entry &= ~0x80000000; + data.name = ""; + return true; + } + + data.name = packet.readString(); + packet.readString(); // name2 + packet.readString(); // name3 + packet.readString(); // name4 + data.subName = packet.readString(); + // NOTE: NO iconName field in Classic 1.12 — goes straight to typeFlags + if (packet.getReadPos() + 16 > packet.getSize()) { + LOG_WARNING("[Classic] Creature query: truncated at typeFlags (entry=", data.entry, ")"); + return true; + } + data.typeFlags = packet.readUInt32(); + data.creatureType = packet.readUInt32(); + data.family = packet.readUInt32(); + data.rank = packet.readUInt32(); + + LOG_DEBUG("[Classic] Creature query: ", data.name, " type=", data.creatureType, + " rank=", data.rank); + return true; +} + } // namespace game } // namespace wowee