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