fix: add TBC chat message parser to prevent 12-byte misalignment

TBC 2.4.3 SMSG_MESSAGECHAT has no senderGuid(u64) or unknown(u32)
prefix before type-specific data. The WotLK base parser reads these
12 bytes unconditionally, causing complete misalignment of all chat
message fields — every chat message on a TBC server would parse
garbage for sender, channel, and message content.
This commit is contained in:
Kelsi 2026-03-17 11:23:37 -07:00
parent e1be8667ed
commit ef5532cf15
2 changed files with 102 additions and 0 deletions

View file

@ -370,6 +370,8 @@ public:
bool parseGuildRoster(network::Packet& packet, GuildRosterData& data) override;
// TBC 2.4.3 SMSG_QUESTGIVER_STATUS: uint32 status (WotLK uses uint8)
uint8_t readQuestGiverStatus(network::Packet& packet) override;
// TBC 2.4.3 SMSG_MESSAGECHAT: no senderGuid/unknown prefix before type-specific data
bool parseMessageChat(network::Packet& packet, MessageChatData& data) override;
// TBC 2.4.3 SMSG_GAMEOBJECT_QUERY_RESPONSE: 2 extra strings after names
// (iconName + castBarCaption); WotLK has 3 (adds unk1)
bool parseGameObjectQueryResponse(network::Packet& packet, GameObjectQueryResponseData& data) override;

View file

@ -1537,6 +1537,106 @@ bool TbcPacketParsers::parseSpellHealLog(network::Packet& packet, SpellHealLogDa
return true;
}
// ============================================================================
// TBC 2.4.3 SMSG_MESSAGECHAT
// TBC format: type(u8) + language(u32) + [type-specific data] + msgLen(u32) + msg + tag(u8)
// WotLK adds senderGuid(u64) + unknown(u32) before type-specific data.
// ============================================================================
bool TbcPacketParsers::parseMessageChat(network::Packet& packet, MessageChatData& data) {
if (packet.getSize() < 10) {
LOG_ERROR("[TBC] SMSG_MESSAGECHAT packet too small: ", packet.getSize(), " bytes");
return false;
}
uint8_t typeVal = packet.readUInt8();
data.type = static_cast<ChatType>(typeVal);
uint32_t langVal = packet.readUInt32();
data.language = static_cast<ChatLanguage>(langVal);
// TBC: NO senderGuid or unknown field here (WotLK has senderGuid(u64) + unk(u32))
switch (data.type) {
case ChatType::MONSTER_SAY:
case ChatType::MONSTER_YELL:
case ChatType::MONSTER_EMOTE:
case ChatType::MONSTER_WHISPER:
case ChatType::MONSTER_PARTY:
case ChatType::RAID_BOSS_EMOTE: {
// senderGuid(u64) + nameLen(u32) + name + targetGuid(u64)
data.senderGuid = packet.readUInt64();
uint32_t nameLen = packet.readUInt32();
if (nameLen > 0 && nameLen < 256) {
data.senderName.resize(nameLen);
for (uint32_t i = 0; i < nameLen; ++i) {
data.senderName[i] = static_cast<char>(packet.readUInt8());
}
if (!data.senderName.empty() && data.senderName.back() == '\0') {
data.senderName.pop_back();
}
}
data.receiverGuid = packet.readUInt64();
break;
}
case ChatType::SAY:
case ChatType::PARTY:
case ChatType::YELL:
case ChatType::WHISPER:
case ChatType::WHISPER_INFORM:
case ChatType::GUILD:
case ChatType::OFFICER:
case ChatType::RAID:
case ChatType::RAID_LEADER:
case ChatType::RAID_WARNING:
case ChatType::EMOTE:
case ChatType::TEXT_EMOTE: {
// senderGuid(u64) + senderGuid(u64) — written twice by server
data.senderGuid = packet.readUInt64();
/*duplicateGuid*/ packet.readUInt64();
break;
}
case ChatType::CHANNEL: {
// channelName(string) + rank(u32) + senderGuid(u64)
data.channelName = packet.readString();
/*uint32_t rank =*/ packet.readUInt32();
data.senderGuid = packet.readUInt64();
break;
}
default: {
// All other types: senderGuid(u64) + senderGuid(u64) — written twice
data.senderGuid = packet.readUInt64();
/*duplicateGuid*/ packet.readUInt64();
break;
}
}
// Read message length + message
uint32_t messageLen = packet.readUInt32();
if (messageLen > 0 && messageLen < 8192) {
data.message.resize(messageLen);
for (uint32_t i = 0; i < messageLen; ++i) {
data.message[i] = static_cast<char>(packet.readUInt8());
}
if (!data.message.empty() && data.message.back() == '\0') {
data.message.pop_back();
}
}
// Read chat tag
if (packet.getReadPos() < packet.getSize()) {
data.chatTag = packet.readUInt8();
}
LOG_DEBUG("[TBC] SMSG_MESSAGECHAT: type=", getChatTypeString(data.type),
" sender=", data.senderName.empty() ? std::to_string(data.senderGuid) : data.senderName);
return true;
}
// ============================================================================
// TBC 2.4.3 quest giver status
// TBC sends uint32 (like Classic), WotLK changed to uint8.