diff --git a/Bagnon/utility/itemEvents.lua b/Bagnon/utility/itemEvents.lua index acc1843..fbd0dcc 100644 --- a/Bagnon/utility/itemEvents.lua +++ b/Bagnon/utility/itemEvents.lua @@ -46,6 +46,14 @@ Bagnon.BagEvents = BagEvents local slots = {} local bagTypes = {} local pendingBags = {} +local retryCounts = {} + +-- Retry knobs. Server lag spikes on Ascension can easily exceed a second; +-- keep retrying so we don't broadcast an empty slot while item data is still +-- in flight. Accept whatever we read after RETRY_MAX attempts so a genuinely +-- emptied slot eventually resolves. +local RETRY_INTERVAL = 0.25 +local RETRY_MAX = 12 -- ~3s worst case local function ToIndex(bag, slot) return (bag < 0 and bag*100 - slot) or bag*100 + slot @@ -55,20 +63,20 @@ local function GetBagSize(bag) return (bag == KEYRING_CONTAINER and GetKeyRingSize()) or GetContainerNumSlots(bag) end --- Defers a re-check of a bag by ~0.25s; used when a previously occupied slot --- reads back nil (lag race between BAG_UPDATE and item data arriving). local retryFrame = CreateFrame('Frame') retryFrame.elapsed = 0 retryFrame:Hide() retryFrame:SetScript('OnUpdate', function(self, elapsed) self.elapsed = self.elapsed + elapsed - if self.elapsed < 0.25 then return end + if self.elapsed < RETRY_INTERVAL then return end self.elapsed = 0 - self:Hide() local bags = pendingBags pendingBags = {} for bag in pairs(bags) do - Bagnon.BagEvents:UpdateItems(bag, true) + Bagnon.BagEvents:UpdateItems(bag) + end + if not next(pendingBags) then + self:Hide() end end) @@ -134,8 +142,9 @@ function BagEvents:RemoveItem(bag, slot) end end -function BagEvents:UpdateItem(bag, slot, isRetry) - local data = slots[ToIndex(bag, slot)] +function BagEvents:UpdateItem(bag, slot) + local index = ToIndex(bag, slot) + local data = slots[index] if data then local prevLink = data[1] @@ -146,12 +155,17 @@ function BagEvents:UpdateItem(bag, slot, isRetry) local onCooldown = (start > 0 and duration > 0 and enable > 0) -- A previously occupied slot reading back nil is usually a lag race between - -- BAG_UPDATE and item data arriving from the server. Defer once before drawing - -- the slot as empty; on the second pass we trust whatever we read. - if prevLink and (not link) and (not isRetry) then - scheduleRetry(bag) - return + -- BAG_UPDATE and item data arriving from the server. Keep deferring up to + -- RETRY_MAX times so a multi-second lag spike doesn't flash items empty. + if prevLink and (not link) then + local n = (retryCounts[index] or 0) + 1 + if n < RETRY_MAX then + retryCounts[index] = n + scheduleRetry(bag) + return + end end + retryCounts[index] = nil if not(prevLink == link and prevCount == count) then data[1] = link @@ -164,9 +178,9 @@ function BagEvents:UpdateItem(bag, slot, isRetry) end end -function BagEvents:UpdateItems(bag, isRetry) +function BagEvents:UpdateItems(bag) for slot = 1, GetBagSize(bag) do - self:UpdateItem(bag, slot, isRetry) + self:UpdateItem(bag, slot) end end