From 9cd7e7978d774b36339085b89b0b1fce3705f399 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 11 Mar 2026 02:49:37 -0700 Subject: [PATCH] fix: correct SMSG_DISPEL_FAILED packet format and improve message WotLK sends spellId(4) + packed_guid caster + packed_guid victim, while TBC/Classic sends full uint64 caster + uint64 victim + spellId(4). The previous handler assumed TBC format unconditionally, causing incorrect reads in WotLK mode. Also use the spell name cache to display "Purge failed to dispel." rather than a raw "Dispel failed! (spell N)" message. --- src/game/game_handler.cpp | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 071a6e72..d7867113 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -2864,13 +2864,33 @@ void GameHandler::handlePacket(network::Packet& packet) { handleAuraUpdate(packet, true); break; case Opcode::SMSG_DISPEL_FAILED: { - // casterGuid(8) + victimGuid(8) + spellId(4) [+ failing spellId(4)...] - if (packet.getSize() - packet.getReadPos() >= 20) { - /*uint64_t casterGuid =*/ packet.readUInt64(); - /*uint64_t victimGuid =*/ packet.readUInt64(); - uint32_t spellId = packet.readUInt32(); + // WotLK: uint32 dispelSpellId + packed_guid caster + packed_guid victim + // [+ count × uint32 failedSpellId] + // TBC/Classic: uint64 caster + uint64 victim + uint32 spellId + // [+ count × uint32 failedSpellId] + const bool dispelTbcLike = isClassicLikeExpansion() || isActiveExpansion("tbc"); + uint32_t dispelSpellId = 0; + if (dispelTbcLike) { + if (packet.getSize() - packet.getReadPos() < 20) break; + /*uint64_t caster =*/ packet.readUInt64(); + /*uint64_t victim =*/ packet.readUInt64(); + dispelSpellId = packet.readUInt32(); + } else { + if (packet.getSize() - packet.getReadPos() < 4) break; + dispelSpellId = packet.readUInt32(); + if (packet.getSize() - packet.getReadPos() < 1) break; + /*uint64_t caster =*/ UpdateObjectParser::readPackedGuid(packet); + if (packet.getSize() - packet.getReadPos() < 1) break; + /*uint64_t victim =*/ UpdateObjectParser::readPackedGuid(packet); + } + { + loadSpellNameCache(); + auto it = spellNameCache_.find(dispelSpellId); char buf[128]; - std::snprintf(buf, sizeof(buf), "Dispel failed! (spell %u)", spellId); + if (it != spellNameCache_.end() && !it->second.name.empty()) + std::snprintf(buf, sizeof(buf), "%s failed to dispel.", it->second.name.c_str()); + else + std::snprintf(buf, sizeof(buf), "Dispel failed! (spell %u)", dispelSpellId); addSystemChatMessage(buf); } break;