fix(items): retry render when slot reads nil for a previously occupied slot

The event-level retry only protected the ITEM_SLOT_UPDATE broadcast, but
ItemSlot:Update() reads GetContainerItemInfo live on every call and is
invoked from many paths (OnShow → ReloadAllItemSlots, AddItemSlot,
BAG_UPDATE_TYPE, search updates). On a laggy server those live reads
flash slots empty. Add a shared retry queue at the slot-render level so
a slot with self.hasItem set will defer rather than draw nil; cap at
RENDER_RETRY_MAX so a genuinely emptied slot still resolves within ~3s.
This commit is contained in:
2026-05-14 04:27:35 +02:00
parent 60e3cea9fd
commit 770695dc77
+42
View File
@@ -248,6 +248,37 @@ end
--[[ Update Methods ]]
--
-- Shared retry queue for slots whose live read returned nil for a previously
-- occupied slot — almost always a server lag race where item data hasn't
-- arrived yet. Retrying renders the correct texture instead of flashing empty.
local RENDER_RETRY_INTERVAL = 0.1
local RENDER_RETRY_MAX = 30 -- ~3s cap so a genuine empty still resolves
local pendingSlots = {}
local slotRetryFrame = CreateFrame('Frame')
slotRetryFrame.elapsed = 0
slotRetryFrame:Hide()
slotRetryFrame:SetScript('OnUpdate', function(self, elapsed)
self.elapsed = self.elapsed + elapsed
if self.elapsed < RENDER_RETRY_INTERVAL then return end
self.elapsed = 0
local q = pendingSlots
pendingSlots = {}
for slot in pairs(q) do
if slot:IsVisible() then
slot:Update()
end
end
if not next(pendingSlots) then
self:Hide()
end
end)
local function scheduleSlotRetry(slot)
pendingSlots[slot] = true
slotRetryFrame.elapsed = 0
slotRetryFrame:Show()
end
-- Update the texture, lock status, and other information about an item
function ItemSlot:Update()
@@ -255,6 +286,17 @@ function ItemSlot:Update()
local texture, count, locked, quality, readable, lootable, link = self:GetItemSlotInfo()
-- Lag race: the slot was occupied a moment ago but the server hasn't
-- delivered item data yet. Defer rendering so the slot doesn't flash empty.
if self.hasItem and (not link) then
self.renderRetries = (self.renderRetries or 0) + 1
if self.renderRetries < RENDER_RETRY_MAX then
scheduleSlotRetry(self)
return
end
end
self.renderRetries = nil
self:SetItem(link)
self:SetTexture(texture)
self:SetCount(count)