From f4a2a631ab6f649aee4742d587e1207af14d41dd Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sat, 28 Mar 2026 10:49:00 -0700 Subject: [PATCH] =?UTF-8?q?fix:=20visible=20item=20field=20base=20284?= =?UTF-8?q?=E2=86=92408=20(was=20reading=20quest=20log,=20not=20equipment)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PLAYER_VISIBLE_ITEM_1_ENTRYID for WotLK 3.3.5a is at UNIT_END(148) + 260 = field index 408 with stride 2. The previous default of 284 (UNIT_END+136) was in the quest log field range, causing item IDs like "Lesser Invisibility Potion" and "Deathstalker Report" to be read as equipment entries. This was the root cause of other players appearing naked — item queries returned valid responses but for the WRONG items (quest log entries instead of equipment), so displayInfoIds were consumable/quest item appearances. The heuristic auto-detection still overrides for Classic/TBC (different stride per expansion), so this only affects the WotLK default before detection runs. Also filter addon whispers (GearScore GS_*, DBM, oRA, BigWigs, tab-prefixed) from chat display — these are invisible in the real WoW client. --- include/game/game_handler.hpp | 5 +++-- src/game/chat_handler.cpp | 16 ++++++++++++++++ src/game/inventory_handler.cpp | 9 +++++---- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index cdc210cd..e2977b77 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -2568,9 +2568,10 @@ private: // Visible equipment for other players: detect the update-field layout (base + stride) // using the local player's own equipped items, then decode other players by index. - // Default to known WotLK 3.3.5a layout: UNIT_END(148) + 0x0088 = 284, stride 2. + // WotLK 3.3.5a: PLAYER_VISIBLE_ITEM_1_ENTRYID = UNIT_END(148) + 0x0104 = 408, stride 2. + // Previous value 284 (UNIT_END+136) was wrong — landed in quest log fields. // The heuristic in maybeDetectVisibleItemLayout() can still override if needed. - int visibleItemEntryBase_ = 284; + int visibleItemEntryBase_ = 408; int visibleItemStride_ = 2; bool visibleItemLayoutVerified_ = false; // true once heuristic confirms/overrides default std::unordered_map> otherPlayerVisibleItemEntries_; diff --git a/src/game/chat_handler.cpp b/src/game/chat_handler.cpp index abe38578..8d2308d9 100644 --- a/src/game/chat_handler.cpp +++ b/src/game/chat_handler.cpp @@ -196,6 +196,22 @@ void ChatHandler::handleMessageChat(network::Packet& packet) { } } + // Filter addon-to-addon whispers (GearScore, DBM, oRA, etc.) from player chat. + // These are invisible in the real WoW client. + if (data.type == ChatType::WHISPER || data.type == ChatType::WHISPER_INFORM) { + const auto& msg = data.message; + if (msg.size() >= 3 && ( + msg.rfind("GS_", 0) == 0 || // GearScore + msg.rfind("DVNE", 0) == 0 || // DBM (DeadlyBossMods) + msg.rfind("oRA", 0) == 0 || // oRA raid addon + msg.rfind("BWVQ", 0) == 0 || // BigWigs + msg.rfind("AVR", 0) == 0 || // AVR (Augmented Virtual Reality) + msg.rfind("\t", 0) == 0 || // Tab-prefixed addon messages + (msg.size() > 4 && static_cast(msg[0]) > 127))) { // Binary data + return; // Silently discard addon whisper + } + } + // Add to chat history chatHistory_.push_back(data); if (chatHistory_.size() > maxChatHistory_) { diff --git a/src/game/inventory_handler.cpp b/src/game/inventory_handler.cpp index 1838e232..4a73fb76 100644 --- a/src/game/inventory_handler.cpp +++ b/src/game/inventory_handler.cpp @@ -2341,8 +2341,9 @@ void InventoryHandler::handleItemQueryResponse(network::Packet& packet) { } owner_.pendingItemQueries_.erase(data.entry); - LOG_DEBUG("handleItemQueryResponse: entry=", data.entry, " name='", data.name, - "' displayInfoId=", data.displayInfoId, " pending=", owner_.pendingItemQueries_.size()); + LOG_WARNING("handleItemQueryResponse: entry=", data.entry, " name='", data.name, + "' displayInfoId=", data.displayInfoId, " valid=", data.valid, + " pending=", owner_.pendingItemQueries_.size()); if (data.valid) { owner_.itemInfoCache_[data.entry] = data; @@ -3105,7 +3106,7 @@ void InventoryHandler::updateOtherPlayerVisibleItems(uint64_t guid, const std::m int nonZero = 0; for (uint32_t e : newEntries) { if (e != 0) nonZero++; } if (nonZero > 0) { - LOG_INFO("updateOtherPlayerVisibleItems: guid=0x", std::hex, guid, std::dec, + LOG_WARNING("updateOtherPlayerVisibleItems: guid=0x", std::hex, guid, std::dec, " nonZero=", nonZero, " base=", base, " stride=", stride, " head=", newEntries[0], " shoulders=", newEntries[2], " chest=", newEntries[4], " legs=", newEntries[6], @@ -3166,7 +3167,7 @@ void InventoryHandler::emitOtherPlayerEquipment(uint64_t guid) { resolved++; } - LOG_INFO("emitOtherPlayerEquipment: guid=0x", std::hex, guid, std::dec, + LOG_WARNING("emitOtherPlayerEquipment: guid=0x", std::hex, guid, std::dec, " entries=", (anyEntry ? "yes" : "none"), " resolved=", resolved, " unresolved=", unresolved, " head=", displayIds[0], " shoulders=", displayIds[2],