diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index ff5adc36..6504402b 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -2455,6 +2455,7 @@ private: std::unordered_map onlineItems_; std::unordered_map itemInfoCache_; std::unordered_set pendingItemQueries_; + float pendingItemQueryTimer_ = 0.0f; // Deferred SMSG_ITEM_PUSH_RESULT notifications for items whose info wasn't // cached at arrival time; emitted once the query response arrives. diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 766dec0a..f9906c8d 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -1116,6 +1116,17 @@ for (auto& [guid, entity] : entityController_->getEntityManager().getEntities()) void GameHandler::updateTimers(float deltaTime) { if (spellHandler_) spellHandler_->updateTimers(deltaTime); + // Periodically clear stale pending item queries so they can be retried. + // Without this, a lost/malformed response leaves the entry stuck forever. + pendingItemQueryTimer_ += deltaTime; + if (pendingItemQueryTimer_ >= 5.0f) { + pendingItemQueryTimer_ = 0.0f; + if (!pendingItemQueries_.empty()) { + LOG_DEBUG("Clearing ", pendingItemQueries_.size(), " stale pending item queries"); + pendingItemQueries_.clear(); + } + } + if (auctionSearchDelayTimer_ > 0.0f) { auctionSearchDelayTimer_ -= deltaTime; if (auctionSearchDelayTimer_ < 0.0f) auctionSearchDelayTimer_ = 0.0f; diff --git a/src/game/inventory_handler.cpp b/src/game/inventory_handler.cpp index 09e4e622..b0ff75ca 100644 --- a/src/game/inventory_handler.cpp +++ b/src/game/inventory_handler.cpp @@ -2352,6 +2352,13 @@ void InventoryHandler::handleItemQueryResponse(network::Packet& packet) { ? owner_.packetParsers_->parseItemQueryResponse(packet, data) : ItemQueryResponseParser::parse(packet, data); if (!parsed) { + // Extract entry from raw packet so we can clear the pending query even on parse failure. + // Without this, the entry stays in pendingItemQueries_ forever, blocking retries. + if (packet.getSize() >= 4) { + packet.setReadPos(0); + uint32_t rawEntry = packet.readUInt32() & ~0x80000000u; + owner_.pendingItemQueries_.erase(rawEntry); + } LOG_WARNING("handleItemQueryResponse: parse failed, size=", packet.getSize()); return; }