fix: quest reward items stuck as 'Item #ID' due to stale pending queries

Two fixes for item name resolution:

1. Clear entry from pendingItemQueries_ even when response parsing fails.
   Previously a malformed response left the entry stuck in pending forever,
   blocking all retries so the UI permanently showed "Item 12345".

2. Add 5-second periodic cleanup of pendingItemQueries_ so lost/dropped
   responses don't permanently block item info resolution.
This commit is contained in:
Kelsi 2026-03-29 17:44:46 -07:00
parent 51da88b120
commit 020e016853
3 changed files with 19 additions and 0 deletions

View file

@ -2455,6 +2455,7 @@ private:
std::unordered_map<uint64_t, OnlineItemInfo> onlineItems_; std::unordered_map<uint64_t, OnlineItemInfo> onlineItems_;
std::unordered_map<uint32_t, ItemQueryResponseData> itemInfoCache_; std::unordered_map<uint32_t, ItemQueryResponseData> itemInfoCache_;
std::unordered_set<uint32_t> pendingItemQueries_; std::unordered_set<uint32_t> pendingItemQueries_;
float pendingItemQueryTimer_ = 0.0f;
// Deferred SMSG_ITEM_PUSH_RESULT notifications for items whose info wasn't // Deferred SMSG_ITEM_PUSH_RESULT notifications for items whose info wasn't
// cached at arrival time; emitted once the query response arrives. // cached at arrival time; emitted once the query response arrives.

View file

@ -1116,6 +1116,17 @@ for (auto& [guid, entity] : entityController_->getEntityManager().getEntities())
void GameHandler::updateTimers(float deltaTime) { void GameHandler::updateTimers(float deltaTime) {
if (spellHandler_) spellHandler_->updateTimers(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) { if (auctionSearchDelayTimer_ > 0.0f) {
auctionSearchDelayTimer_ -= deltaTime; auctionSearchDelayTimer_ -= deltaTime;
if (auctionSearchDelayTimer_ < 0.0f) auctionSearchDelayTimer_ = 0.0f; if (auctionSearchDelayTimer_ < 0.0f) auctionSearchDelayTimer_ = 0.0f;

View file

@ -2352,6 +2352,13 @@ void InventoryHandler::handleItemQueryResponse(network::Packet& packet) {
? owner_.packetParsers_->parseItemQueryResponse(packet, data) ? owner_.packetParsers_->parseItemQueryResponse(packet, data)
: ItemQueryResponseParser::parse(packet, data); : ItemQueryResponseParser::parse(packet, data);
if (!parsed) { 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()); LOG_WARNING("handleItemQueryResponse: parse failed, size=", packet.getSize());
return; return;
} }