fix(items): grace window for nil-after-occupied without retry polling

GetContainerItemInfo returns nil for some occupied slots during server
lag, causing Bagnon to draw the slot empty. Earlier retry-polling
approach caused massive lag because every legitimately emptied slot
also matched the "previously had item, now nil" condition and ran ~30
live reads over 3s per move.

New approach: on a nil-after-occupied read, if we're within
GRACE_WINDOW (0.5s) of the last good draw, keep the prior draw and
queue ONE re-check at the deadline — no polling. A genuinely emptied
slot resolves at the deadline; a recovered slot redraws with correct
data. lastGoodTime is set only on non-nil reads, so persistent lag
eventually accepts the empty.
This commit is contained in:
2026-05-15 16:13:34 +02:00
parent 592808792a
commit c955937b12
+44
View File
@@ -248,6 +248,38 @@ end
--[[ Update Methods ]]
--
-- Lag-race protection for slots that read nil briefly after being occupied.
-- When this happens we keep the prior draw and schedule ONE re-check at the
-- grace deadline; we never poll. After the deadline, whatever the live read
-- says wins, so genuinely emptied slots resolve within GRACE_WINDOW seconds.
local GRACE_WINDOW = 0.5
local pendingVerify = {} -- slot -> deadline (GetTime)
local verifyFrame = CreateFrame('Frame')
verifyFrame:Hide()
verifyFrame:SetScript('OnUpdate', function(self, elapsed)
self.tick = (self.tick or 0) + elapsed
if self.tick < 0.1 then return end
self.tick = 0
local now = GetTime()
for slot, deadline in pairs(pendingVerify) do
if now >= deadline then
pendingVerify[slot] = nil
if slot:IsVisible() then
slot:Update()
end
end
end
if not next(pendingVerify) then
self:Hide()
end
end)
local function scheduleVerify(slot)
if pendingVerify[slot] then return end
pendingVerify[slot] = GetTime() + GRACE_WINDOW
verifyFrame:Show()
end
-- Update the texture, lock status, and other information about an item
function ItemSlot:Update()
@@ -255,6 +287,18 @@ function ItemSlot:Update()
local texture, count, locked, quality, readable, lootable, link = self:GetItemSlotInfo()
-- If the slot was occupied at our last good draw and the live read just
-- returned nil within the grace window, keep the previous draw and queue
-- a single re-check. No retry storm.
if (not link) and self.hasItem and (self.lastGoodTime or 0) + GRACE_WINDOW > GetTime() then
scheduleVerify(self)
return
end
if link then
self.lastGoodTime = GetTime()
end
self:SetItem(link)
self:SetTexture(texture)
self:SetCount(count)