classic: fix SMSG_CREATURE_QUERY_RESPONSE — no iconName field in 1.12

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.
This commit is contained in:
Kelsi 2026-03-09 21:44:07 -07:00
parent 6d21f77d32
commit 1b2c7f595e
3 changed files with 47 additions and 1 deletions

View file

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

View file

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

View file

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