From a9ce22f31558c6646e337d48d38f53a351369537 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Mon, 30 Mar 2026 13:56:45 -0700 Subject: [PATCH] refactor: extract findOnUseSpellId helper, add warden hash comment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - spell_handler: extract duplicated item on-use spell lookup into findOnUseSpellId() — was copy-pasted in useItemBySlot and useItemInBag - warden_handler: add why-comment explaining the door model HMAC-SHA1 hash table (wall-hack detection for unmodified 3.3.5a client data) --- include/game/spell_handler.hpp | 3 +++ src/game/spell_handler.cpp | 34 ++++++++++++++-------------------- src/game/warden_handler.cpp | 3 +++ 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/include/game/spell_handler.hpp b/include/game/spell_handler.hpp index e93e58ed..e93f6281 100644 --- a/include/game/spell_handler.hpp +++ b/include/game/spell_handler.hpp @@ -249,6 +249,9 @@ private: void handleChannelUpdate(network::Packet& packet); // --- Internal helpers --- + // Find the on-use spell for an item (trigger=0 Use or trigger=5 NoDelay). + // CMSG_USE_ITEM requires a valid spellId or the server silently ignores it. + uint32_t findOnUseSpellId(uint32_t itemId) const; void loadSpellNameCache() const; void loadSkillLineAbilityDbc(); void categorizeTrainerSpells(); diff --git a/src/game/spell_handler.cpp b/src/game/spell_handler.cpp index fa3ea356..0502f84e 100644 --- a/src/game/spell_handler.cpp +++ b/src/game/spell_handler.cpp @@ -446,6 +446,18 @@ void SpellHandler::confirmPetUnlearn() { petUnlearnCost_ = 0; } +uint32_t SpellHandler::findOnUseSpellId(uint32_t itemId) const { + if (auto* info = owner_.getItemInfo(itemId)) { + for (const auto& sp : info->spells) { + // spellTrigger 0 = "Use", 5 = "No Delay" — both are player-activated on-use effects + if (sp.spellId != 0 && (sp.spellTrigger == 0 || sp.spellTrigger == 5)) { + return sp.spellId; + } + } + } + return 0; +} + void SpellHandler::useItemBySlot(int backpackIndex) { if (backpackIndex < 0 || backpackIndex >= owner_.inventory.getBackpackSize()) return; const auto& slot = owner_.inventory.getBackpackSlot(backpackIndex); @@ -457,16 +469,7 @@ void SpellHandler::useItemBySlot(int backpackIndex) { } if (itemGuid != 0 && owner_.state == WorldState::IN_WORLD && owner_.socket) { - uint32_t useSpellId = 0; - if (auto* info = owner_.getItemInfo(slot.item.itemId)) { - for (const auto& sp : info->spells) { - if (sp.spellId != 0 && (sp.spellTrigger == 0 || sp.spellTrigger == 5)) { - useSpellId = sp.spellId; - break; - } - } - } - + uint32_t useSpellId = findOnUseSpellId(slot.item.itemId); auto packet = owner_.packetParsers_ ? owner_.packetParsers_->buildUseItem(0xFF, static_cast(23 + backpackIndex), itemGuid, useSpellId) : UseItemPacket::build(0xFF, static_cast(23 + backpackIndex), itemGuid, useSpellId); @@ -498,16 +501,7 @@ void SpellHandler::useItemInBag(int bagIndex, int slotIndex) { " itemGuid=0x", std::hex, itemGuid, std::dec); if (itemGuid != 0 && owner_.state == WorldState::IN_WORLD && owner_.socket) { - uint32_t useSpellId = 0; - if (auto* info = owner_.getItemInfo(slot.item.itemId)) { - for (const auto& sp : info->spells) { - if (sp.spellId != 0 && (sp.spellTrigger == 0 || sp.spellTrigger == 5)) { - useSpellId = sp.spellId; - break; - } - } - } - + uint32_t useSpellId = findOnUseSpellId(slot.item.itemId); uint8_t wowBag = static_cast(19 + bagIndex); auto packet = owner_.packetParsers_ ? owner_.packetParsers_->buildUseItem(wowBag, static_cast(slotIndex), itemGuid, useSpellId) diff --git a/src/game/warden_handler.cpp b/src/game/warden_handler.cpp index 3c2c463c..8b999a51 100644 --- a/src/game/warden_handler.cpp +++ b/src/game/warden_handler.cpp @@ -116,6 +116,9 @@ bool hmacSha1Matches(const uint8_t seedBytes[4], const std::string& text, const return outLen == SHA_DIGEST_LENGTH && std::memcmp(out, expected, SHA_DIGEST_LENGTH) == 0; } +// Pre-computed HMAC-SHA1 hashes of known door M2 models that Warden checks +// to verify the client hasn't modified collision geometry (wall-hack detection). +// These hashes match the unmodified 3.3.5a client data files. const std::unordered_map>& knownDoorHashes() { static const std::unordered_map> k = { {"world\\lordaeron\\stratholme\\activedoodads\\doors\\nox_door_plague.m2",