From b394d394814713c77a3d730be76f408caf1515b1 Mon Sep 17 00:00:00 2001 From: grom Date: Sun, 8 Nov 2026 12:58:21 -0700 Subject: [PATCH] A quest item he was carrying had no name, because one query went unanswered and nothing asked again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit grom, on the Deeprun Rat Roundup quest: "I'm not recieving the flute item needed for the quest". He had it the whole time. Entry 17117, Rat Catcher's Flute, bag 0 slot 2 — the only trace of it in a three-hour log is `GetNumJunkItems` reporting one carried slot "with no item template yet", twice. The ask-once rule is the reference's `DBCache` and it is right for everything it covers: one `CMSG_ITEM_QUERY_SINGLE` per entry per connection, a negative cached as a negative. What it has no arm for is a query that goes out and is never answered, and the whole cost of that falls on the player — `GetItemInfo` keeps returning nil, so the item draws with no name, no icon and no tooltip, in the bag, in the quest frame's required-items box and in every addon that reads it, for the rest of the session. `QueryCache` now ages its in-flight asks and `items.rs` re-sends one that has waited five seconds, three sends in all, then says so once. Bounded on purpose: an entry the server genuinely does not know is answered with the high-bit miss and never reaches the sweep, so a key that survives three sends is one nothing is going to answer. Ordered after the world-entry release, which forgets every in-flight ask — a sweep that ran first would re-send queries the next statement drops. The same gap exists for creature names and gameobject templates. Left alone until one of them is seen to drop an answer: a nameless mob is at least self-correcting on the next `SMSG_UPDATE_OBJECT`. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn --- crates/benilla-app/src/items.rs | 52 +++++++++++ crates/benilla-app/src/net.rs | 11 +++ crates/benilla-app/src/query_cache.rs | 121 ++++++++++++++++++++++++-- 3 files changed, 178 insertions(+), 6 deletions(-) diff --git a/crates/benilla-app/src/items.rs b/crates/benilla-app/src/items.rs index e4c51bfa..8a1e6a2b 100644 --- a/crates/benilla-app/src/items.rs +++ b/crates/benilla-app/src/items.rs @@ -480,6 +480,58 @@ impl crate::query_cache::AskOnce for Items { } } +/// How long an unanswered `CMSG_ITEM_QUERY_SINGLE` waits before it is sent again. +/// +/// Long enough that a slow answer is never raced (the realm's own answers land in tens of +/// milliseconds), short enough that a lost one is invisible: an item that appears in a bag with +/// no name and gets one a few seconds later reads as the cache filling, which is what the player +/// already sees on a cold login. +const TEMPLATE_RETRY_AFTER: f64 = 5.0; + +/// Sends in all, so two re-asks past the original. Bounded on purpose: an entry the server +/// genuinely does not know is answered with the high-bit miss and never reaches the sweep, so a +/// key that survives three sends is one nothing is going to answer, and asking forever would +/// turn a lost packet into a standing stream. +const TEMPLATE_MAX_TRIES: u8 = 3; + +/// Re-ask item templates whose answer never arrived, and say so once when giving up. +/// +/// The ask-once rule is the reference's ([`crate::query_cache`]), and it is right for everything +/// it covers: one query per entry per connection, a negative cached as a negative. What it has no +/// arm for is an ask that is simply never answered, and the cost of that falls entirely on the +/// player — `GetItemInfo` keeps answering nil, so the item draws with no name, no icon and no +/// tooltip, in the bag, in the quest frame's required-items box and in every addon that reads it, +/// for the rest of the session. That is grom's *"I'm not recieving the flute item needed for the +/// quest"*: entry 17117 sat in bag 0 slot 2 the whole time, and the only trace of it was +/// `GetNumJunkItems` reporting a carried slot *"with no item template yet"*. +/// +/// The same gap exists for creature names and gameobject templates ([`crate::names`], +/// [`crate::go_templates`]); they are left alone until one of them is actually seen to drop an +/// answer, since a nameless mob is at least self-correcting on the next `SMSG_UPDATE_OBJECT`. +pub(crate) fn retry_unanswered_templates( + items: Res, + commands: Res, + time: Res