From 63b484b1ea107930e953cdb9539802a02acd4274 Mon Sep 17 00:00:00 2001 From: Brues <5278969+brues-code@users.noreply.github.com> Date: Fri, 21 Aug 2026 21:02:34 -0500 Subject: [PATCH] Replace WDB tooltip warmup with GET_ITEM_INFO_RECEIVED handler ClassicAPI hooks the global GetItemInfo to auto-warm the item cache on a miss and fires GET_ITEM_INFO_RECEIVED when the async fill lands, so the tooltip-scan warmup is obsolete: IndexItems's own GetItemInfo calls already trigger the same warmup, and owned items (bags + equipped) are priority-prefetched by the engine. The old warmup also assumed the fill was synchronous, which no longer holds. Drop DoWDBWarmup and its login scheduling; instead listen for GET_ITEM_INFO_RECEIVED and run a debounced re-index. IndexItems records owned itemIDs it could not resolve into pendingItemInfo, and the handler ignores any fill not in that set (quest DB scans, AH sweeps, chat-link hovers, inspects) in O(1) so unrelated bursts do not cause reindex churn. --- Core.lua | 88 +++++++++++++--------------------- Extensions/Tooltip/Generic.lua | 14 ++++++ 2 files changed, 47 insertions(+), 55 deletions(-) diff --git a/Core.lua b/Core.lua index 1f4ee30..e174fdc 100644 --- a/Core.lua +++ b/Core.lua @@ -3942,10 +3942,21 @@ function CleveRoids.OnUpdate(self) return end - -- PERFORMANCE: Delayed WDB warmup after login (ensures GetItemInfo works after WDB clear) - if CR.wdbWarmupTime and time >= CR.wdbWarmupTime then - CR.wdbWarmupTime = nil - CR.DoWDBWarmup() + -- Coalesced re-index after async item data arrives (GET_ITEM_INFO_RECEIVED). + -- ClassicAPI warms the item cache asynchronously, so items that were still + -- uncached during an earlier index pass land here once their + -- SMSG_ITEM_QUERY_SINGLE response resolves. Bursts are debounced into one + -- re-index via CR.itemInfoReindexTime (armed by the event handler). + if CR.itemInfoReindexTime and time >= CR.itemInfoReindexTime then + CR.itemInfoReindexTime = nil + -- In combat: drop it; PLAYER_LEAVE_COMBAT does a full re-index once safe. + if not UnitAffectingCombat("player") then + CR.lastItemIndexTime = GetTime() + CR.IndexItems() + CR.Actions = {} + CR.Macros = {} + CR.IndexActionBars() + end end -- PERFORMANCE: Cache refresh rate calculation (avoid per-frame division) @@ -4824,6 +4835,7 @@ CleveRoids.Frame:RegisterEvent("UPDATE_MACROS") CleveRoids.Frame:RegisterEvent("SPELLS_CHANGED") CleveRoids.Frame:RegisterEvent("ACTIONBAR_SLOT_CHANGED") CleveRoids.Frame:RegisterEvent("BAG_UPDATE_DELAYED") +CleveRoids.Frame:RegisterEvent("GET_ITEM_INFO_RECEIVED") CleveRoids.Frame:RegisterEvent("PLAYER_EQUIPMENT_CHANGED") CleveRoids.Frame:RegisterEvent("UNIT_PET") @@ -4964,57 +4976,6 @@ function CleveRoids.Frame:PLAYER_LOGIN() -- PERFORMANCE: Initialize event-driven cache states CleveRoids._cachedPlayerInCombat = UnitAffectingCombat("player") and true or false - - -- Schedule delayed WDB warmup (loads items into client cache via tooltip scan) - -- This ensures GetItemInfo() works for all inventory items after a WDB clear - CleveRoids.wdbWarmupTime = GetTime() + 3.0 -- 3 second delay after login -end - --- PERFORMANCE: WDB warmup - tooltip scan all bag items to ensure they're cached --- This prevents GetItemInfo() returning nil for items after a WDB clear -function CleveRoids.DoWDBWarmup() - if CleveRoids.wdbWarmupDone then return end - CleveRoids.wdbWarmupDone = true - - -- Create a hidden tooltip for scanning if it doesn't exist - local tip = CleveRoidsWDBTip - if not tip then - tip = CreateFrame("GameTooltip", "CleveRoidsWDBTip", UIParent, "GameTooltipTemplate") - tip:SetOwner(WorldFrame, "ANCHOR_NONE") - end - - local scanned = 0 - - -- Scan all bag slots - for bag = 0, 4 do - local slots = GetContainerNumSlots(bag) or 0 - for slot = 1, slots do - if C_Container.GetContainerItemID(bag, slot) then - -- Tooltip scan loads the item into WDB - tip:ClearLines() - tip:SetBagItem(bag, slot) - scanned = scanned + 1 - end - end - end - - -- Scan equipped items - for slot = 1, 19 do - if GetInventoryItemID("player", slot) then - tip:ClearLines() - tip:SetInventoryItem("player", slot) - scanned = scanned + 1 - end - end - - -- Now trigger a full item index to populate the cache with valid data - if CleveRoids.IndexItems then - CleveRoids.IndexItems() - end - - if CleveRoids.debug then - CleveRoids.Print("|cff88ff88[WDB Warmup]|r Scanned " .. scanned .. " items into cache") - end end function CleveRoids.Frame:ADDON_LOADED(addon) @@ -5690,6 +5651,23 @@ function CleveRoids.Frame:ACTIONBAR_SLOT_CHANGED() end end +-- ClassicAPI fires GET_ITEM_INFO_RECEIVED when an async item-cache fill lands +-- (the hooked GetItemInfo auto-warms on a miss). It fires for EVERY fill in the +-- game though - quest DB scans, AH sweeps, chat-link hovers, inspects - so we +-- ignore anything not in pendingItemInfo (items we own that missed the last +-- index pass). That check is O(1) and keeps unrelated bursts free. +function CleveRoids.Frame:GET_ITEM_INFO_RECEIVED() + local pending = CleveRoids.pendingItemInfo + if not (pending and pending[arg1]) then return end + -- Skip during combat; PLAYER_LEAVE_COMBAT re-indexes once it's safe. + if UnitAffectingCombat("player") then return end + -- Arm once per burst; the update loop clears it after re-indexing. Later + -- arrivals re-arm it, guaranteeing the final resolved state is captured. + if not CleveRoids.itemInfoReindexTime then + CleveRoids.itemInfoReindexTime = GetTime() + 0.5 + end +end + function CleveRoids.Frame:BAG_UPDATE_DELAYED() -- In combat: Skip expensive indexing but still queue icon update -- so conditionals like [inbag] re-evaluate (they use live bag APIs) diff --git a/Extensions/Tooltip/Generic.lua b/Extensions/Tooltip/Generic.lua index c48166e..fbffc4e 100644 --- a/Extensions/Tooltip/Generic.lua +++ b/Extensions/Tooltip/Generic.lua @@ -238,6 +238,14 @@ function CleveRoids.IndexItems() local items = {} local NUM_BAG_SLOTS = NUM_BAG_SLOTS -- Upvalue for bag constant + -- Rebuilt each pass: itemIDs the player owns that GetItemInfo couldn't + -- resolve yet (cold cache under ClassicAPI's async warmup). The + -- GET_ITEM_INFO_RECEIVED handler consults this so it only re-indexes for + -- our own uncached items and ignores the flood of unrelated fills (quest + -- DB scans, AH, chat-link hovers, inspects) in O(1). + local pendingItemInfo = {} + CleveRoids.pendingItemInfo = pendingItemInfo + -- PERFORMANCE: Local function references local GetContainerNumSlots = GetContainerNumSlots local GetContainerItemInfo = GetContainerItemInfo @@ -281,6 +289,9 @@ function CleveRoids.IndexItems() if lowerName ~= name then items[lowerName] = name end + else + -- Owned but not cached yet; wait for GET_ITEM_INFO_RECEIVED. + pendingItemInfo[itemID] = true end end end @@ -318,6 +329,9 @@ function CleveRoids.IndexItems() if lowerName ~= name then items[lowerName] = name end + else + -- Owned but not cached yet; wait for GET_ITEM_INFO_RECEIVED. + pendingItemInfo[itemID] = true end end end