From 63c09163dc2efe9f3fae97149183fb80a4498d6b Mon Sep 17 00:00:00 2001 From: Kelsi Date: Tue, 10 Mar 2026 17:28:20 -0700 Subject: [PATCH] fix: correct SMSG_ACTION_BUTTONS parsing for Classic and TBC expansions Classic 1.12 sends 120 action button slots with no leading mode byte (480 bytes total). TBC 2.4.3 sends 132 slots with no mode byte (528 bytes). WotLK 3.3.5a sends a uint8 mode byte followed by 144 slots (577 bytes total). The previous code always consumed a mode byte and assumed 144 slots. On Classic servers this would misparse the first action button (reading one byte as the mode, shifting all subsequent entries), causing the action bar to load garbage spells/items from the server. Fixed by detecting expansion type at runtime and selecting the appropriate slot count and presence of mode byte accordingly. --- src/game/game_handler.cpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 7f4425f9..79071a51 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -3403,15 +3403,28 @@ void GameHandler::handlePacket(network::Packet& packet) { } case Opcode::SMSG_ACTION_BUTTONS: { - // uint8 mode (0=initial, 1=update) + 144 × uint32 packed buttons // packed: bits 0-23 = actionId, bits 24-31 = type // 0x00 = spell (when id != 0), 0x80 = item, 0x40 = macro (skip) + // Format differences: + // Classic 1.12: no mode byte, 120 slots (480 bytes) + // TBC 2.4.3: no mode byte, 132 slots (528 bytes) + // WotLK 3.3.5a: uint8 mode + 144 slots (577 bytes) size_t rem = packet.getSize() - packet.getReadPos(); - if (rem < 1) break; - /*uint8_t mode =*/ packet.readUInt8(); - rem--; - constexpr int SERVER_BAR_SLOTS = 144; - for (int i = 0; i < SERVER_BAR_SLOTS; ++i) { + const bool hasModeByteExp = isActiveExpansion("wotlk"); + int serverBarSlots; + if (isClassicLikeExpansion()) { + serverBarSlots = 120; + } else if (isActiveExpansion("tbc")) { + serverBarSlots = 132; + } else { + serverBarSlots = 144; + } + if (hasModeByteExp) { + if (rem < 1) break; + /*uint8_t mode =*/ packet.readUInt8(); + rem--; + } + for (int i = 0; i < serverBarSlots; ++i) { if (rem < 4) break; uint32_t packed = packet.readUInt32(); rem -= 4;