From 345b41b810b2268e17d640f260680e0c91fa37db Mon Sep 17 00:00:00 2001 From: Kelsi Date: Fri, 3 Apr 2026 18:46:49 -0700 Subject: [PATCH] fix(auction): resolve item GUID with fallback and gate packet format auctionSellItem now resolves the item GUID internally via backpackSlotGuids_ with resolveOnlineItemGuid fallback, matching the pattern used by vendor sell and item use. Previously the UI passed the GUID directly from getBackpackItemGuid() with no fallback, so items with unset slot GUIDs silently failed to list. Also gates CMSG_AUCTION_SELL_ITEM format by expansion: Classic/TBC omits the itemCount and stackCount fields that WotLK requires. --- include/game/game_handler.hpp | 2 +- include/game/inventory_handler.hpp | 2 +- include/game/world_packets.hpp | 3 ++- src/game/game_handler.cpp | 6 +++--- src/game/inventory_handler.cpp | 19 +++++++++++++++++-- src/game/world_packets.cpp | 15 +++++++++++---- src/ui/window_manager.cpp | 15 +++++---------- 7 files changed, 40 insertions(+), 22 deletions(-) diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index b6c86794..a121d440 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -1990,7 +1990,7 @@ public: void auctionSearch(const std::string& name, uint8_t levelMin, uint8_t levelMax, uint32_t quality, uint32_t itemClass, uint32_t itemSubClass, uint32_t invTypeMask, uint8_t usableOnly, uint32_t offset = 0); - void auctionSellItem(uint64_t itemGuid, uint32_t stackCount, uint32_t bid, + void auctionSellItem(int backpackIndex, uint32_t bid, uint32_t buyout, uint32_t duration); void auctionPlaceBid(uint32_t auctionId, uint32_t amount); void auctionBuyout(uint32_t auctionId, uint32_t buyoutPrice); diff --git a/include/game/inventory_handler.hpp b/include/game/inventory_handler.hpp index 3c4574c9..15c5b5b7 100644 --- a/include/game/inventory_handler.hpp +++ b/include/game/inventory_handler.hpp @@ -194,7 +194,7 @@ public: void auctionSearch(const std::string& name, uint8_t levelMin, uint8_t levelMax, uint32_t quality, uint32_t itemClass, uint32_t itemSubClass, uint32_t invTypeMask, uint8_t usableOnly, uint32_t offset = 0); - void auctionSellItem(uint64_t itemGuid, uint32_t stackCount, uint32_t bid, + void auctionSellItem(int backpackIndex, uint32_t bid, uint32_t buyout, uint32_t duration); void auctionPlaceBid(uint32_t auctionId, uint32_t amount); void auctionBuyout(uint32_t auctionId, uint32_t buyoutPrice); diff --git a/include/game/world_packets.hpp b/include/game/world_packets.hpp index d0f98577..19cbf3ba 100644 --- a/include/game/world_packets.hpp +++ b/include/game/world_packets.hpp @@ -2736,7 +2736,8 @@ class AuctionSellItemPacket { public: static network::Packet build(uint64_t auctioneerGuid, uint64_t itemGuid, uint32_t stackCount, uint32_t bid, - uint32_t buyout, uint32_t duration); + uint32_t buyout, uint32_t duration, + bool preWotlk = false); }; /** CMSG_AUCTION_PLACE_BID packet builder */ diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index c4bd725a..f955cca9 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -6640,9 +6640,9 @@ void GameHandler::auctionSearch(const std::string& name, uint8_t levelMin, uint8 if (inventoryHandler_) inventoryHandler_->auctionSearch(name, levelMin, levelMax, quality, itemClass, itemSubClass, invTypeMask, usableOnly, offset); } -void GameHandler::auctionSellItem(uint64_t itemGuid, uint32_t stackCount, - uint32_t bid, uint32_t buyout, uint32_t duration) { - if (inventoryHandler_) inventoryHandler_->auctionSellItem(itemGuid, stackCount, bid, buyout, duration); +void GameHandler::auctionSellItem(int backpackIndex, uint32_t bid, + uint32_t buyout, uint32_t duration) { + if (inventoryHandler_) inventoryHandler_->auctionSellItem(backpackIndex, bid, buyout, duration); } void GameHandler::auctionPlaceBid(uint32_t auctionId, uint32_t amount) { diff --git a/src/game/inventory_handler.cpp b/src/game/inventory_handler.cpp index 74903f86..d81f444d 100644 --- a/src/game/inventory_handler.cpp +++ b/src/game/inventory_handler.cpp @@ -1860,10 +1860,25 @@ void InventoryHandler::auctionSearch(const std::string& name, uint8_t levelMin, auctionSearchDelayTimer_ = 5.0f; } -void InventoryHandler::auctionSellItem(uint64_t itemGuid, uint32_t stackCount, uint32_t bid, +void InventoryHandler::auctionSellItem(int backpackIndex, uint32_t bid, uint32_t buyout, uint32_t duration) { if (owner_.state != WorldState::IN_WORLD || !owner_.socket || auctioneerGuid_ == 0) return; - auto packet = AuctionSellItemPacket::build(auctioneerGuid_, itemGuid, stackCount, bid, buyout, duration); + if (backpackIndex < 0 || backpackIndex >= owner_.inventory.getBackpackSize()) return; + const auto& slot = owner_.inventory.getBackpackSlot(backpackIndex); + if (slot.empty()) return; + + uint64_t itemGuid = owner_.backpackSlotGuids_[backpackIndex]; + if (itemGuid == 0) { + itemGuid = owner_.resolveOnlineItemGuid(slot.item.itemId); + } + if (itemGuid == 0) { + LOG_ERROR("auctionSellItem: could not resolve GUID for backpack slot ", backpackIndex); + return; + } + + uint32_t stackCount = slot.item.stackCount; + auto packet = AuctionSellItemPacket::build(auctioneerGuid_, itemGuid, stackCount, bid, buyout, duration, + isPreWotlk()); owner_.socket->send(packet); } diff --git a/src/game/world_packets.cpp b/src/game/world_packets.cpp index e5753b70..4867b295 100644 --- a/src/game/world_packets.cpp +++ b/src/game/world_packets.cpp @@ -5726,13 +5726,20 @@ network::Packet AuctionListItemsPacket::build( network::Packet AuctionSellItemPacket::build( uint64_t auctioneerGuid, uint64_t itemGuid, uint32_t stackCount, uint32_t bid, - uint32_t buyout, uint32_t duration) + uint32_t buyout, uint32_t duration, + bool preWotlk) { network::Packet p(wireOpcode(Opcode::CMSG_AUCTION_SELL_ITEM)); p.writeUInt64(auctioneerGuid); - p.writeUInt32(1); // item count (WotLK supports multiple, we send 1) - p.writeUInt64(itemGuid); - p.writeUInt32(stackCount); + if (!preWotlk) { + // WotLK: itemCount(4) + per-item [guid(8) + stackCount(4)] + p.writeUInt32(1); + p.writeUInt64(itemGuid); + p.writeUInt32(stackCount); + } else { + // Classic/TBC: just itemGuid, no count fields + p.writeUInt64(itemGuid); + } p.writeUInt32(bid); p.writeUInt32(buyout); p.writeUInt32(duration); diff --git a/src/ui/window_manager.cpp b/src/ui/window_manager.cpp index b7a516dc..19e1c81f 100644 --- a/src/ui/window_manager.cpp +++ b/src/ui/window_manager.cpp @@ -3375,16 +3375,11 @@ void WindowManager::renderAuctionHouseWindow(game::GameHandler& gameHandler, + static_cast(auctionSellBuyout_[2]); const uint32_t durationMins[] = {720, 1440, 2880}; uint32_t dur = durationMins[auctionSellDuration_]; - uint64_t itemGuid = gameHandler.getBackpackItemGuid(auctionSellSlotIndex_); - const auto& slot = gameHandler.getInventory().getBackpackSlot(auctionSellSlotIndex_); - uint32_t stackCount = slot.item.stackCount; - if (itemGuid != 0) { - gameHandler.auctionSellItem(itemGuid, stackCount, bidCopper, buyoutCopper, dur); - // Clear sell inputs - auctionSellSlotIndex_ = -1; - auctionSellBid_[0] = auctionSellBid_[1] = auctionSellBid_[2] = 0; - auctionSellBuyout_[0] = auctionSellBuyout_[1] = auctionSellBuyout_[2] = 0; - } + gameHandler.auctionSellItem(auctionSellSlotIndex_, bidCopper, buyoutCopper, dur); + // Clear sell inputs + auctionSellSlotIndex_ = -1; + auctionSellBid_[0] = auctionSellBid_[1] = auctionSellBid_[2] = 0; + auctionSellBuyout_[0] = auctionSellBuyout_[1] = auctionSellBuyout_[2] = 0; } if (!canCreate) ImGui::EndDisabled();