fix: Added isUnusable detection with caching

This commit is contained in:
Salikh Gurgenidze
2026-01-24 12:36:48 +04:00
parent 06db5f15fa
commit 52af32daaa
12 changed files with 198 additions and 258 deletions
+68 -2
View File
@@ -91,18 +91,25 @@ local function ScanTooltipLines(bagID, slotID, itemLink)
local leftText = leftLine and leftLine:GetText() or "" local leftText = leftLine and leftLine:GetText() or ""
local rightText = rightLine and rightLine:GetText() or "" local rightText = rightLine and rightLine:GetText() or ""
-- Get text colors (for detecting yellow/green text) -- Get left text colors (for detecting yellow/green/red text)
local lr, lg, lb, la = 1, 1, 1, 1 local lr, lg, lb, la = 1, 1, 1, 1
if leftLine and leftLine.GetTextColor then if leftLine and leftLine.GetTextColor then
lr, lg, lb, la = leftLine:GetTextColor() lr, lg, lb, la = leftLine:GetTextColor()
end end
-- Get right text colors (for detecting red requirements)
local rr, rg, rb, ra = 1, 1, 1, 1
if rightLine and rightLine.GetTextColor then
rr, rg, rb, ra = rightLine:GetTextColor()
end
table.insert(lines, { table.insert(lines, {
left = leftText, left = leftText,
right = rightText, right = rightText,
leftLower = leftText and string.lower(leftText) or "", leftLower = leftText and string.lower(leftText) or "",
rightLower = rightText and string.lower(rightText) or "", rightLower = rightText and string.lower(rightText) or "",
r = lr, g = lg, b = lb, r = lr, g = lg, b = lb,
rightR = rr, rightG = rg, rightB = rb,
}) })
end end
@@ -255,12 +262,63 @@ local function DetectQuestUsable(lines)
return false return false
end end
-- Durability pattern for filtering out broken item red text
local durabilityPattern = DURABILITY_TEMPLATE and string.gsub(DURABILITY_TEMPLATE, "%%d", "%%d+") or nil
-- Check if text color is red (unusable requirement)
local function IsRedColor(r, g, b)
if not r or not g or not b then return false end
-- RED_FONT_COLOR is typically (1.0, 0.1, 0.1)
local dr = math.abs(r - 1.0)
local dg = math.abs(g - 0.125)
local db = math.abs(b - 0.125)
return (dr < 0.15 and dg < 0.15 and db < 0.15)
end
-- Check if item is unusable (has red text indicating unmet requirements)
-- Excludes durability lines (broken items show red durability)
local function DetectUnusable(lines)
for _, line in ipairs(lines) do
if line.r and line.g and line.b then
-- Check for red text (requirements not met)
local isRed = IsRedColor(line.r, line.g, line.b) or
(line.r > 0.85 and line.g < 0.3 and line.b < 0.3)
if isRed then
local text = line.left or ""
-- Ignore durability lines (broken items)
if durabilityPattern and string.find(text, durabilityPattern) then
-- skip durability
else
return true
end
end
end
-- Also check right column (some requirements appear there)
if line.rightR and line.rightG and line.rightB then
local isRed = IsRedColor(line.rightR, line.rightG, line.rightB) or
(line.rightR > 0.85 and line.rightG < 0.3 and line.rightB < 0.3)
if isRed then
local text = line.right or ""
if durabilityPattern and string.find(text, durabilityPattern) then
-- skip durability
else
return true
end
end
end
end
return false
end
--===================================================== --=====================================================
-- Public API - Cached Detection -- Public API - Cached Detection
--===================================================== --=====================================================
-- Get all item properties at once (cached) -- Get all item properties at once (cached)
-- Returns: { isQuestItem, isQuestStarter, isQuestUsable, isJunk, isPermanentEnchant } -- Returns: { isQuestItem, isQuestStarter, isQuestUsable, isJunk, isPermanentEnchant, isUnusable }
function ItemDetection:GetItemProperties(itemData, bagID, slotID) function ItemDetection:GetItemProperties(itemData, bagID, slotID)
if not itemData then if not itemData then
return { return {
@@ -269,6 +327,7 @@ function ItemDetection:GetItemProperties(itemData, bagID, slotID)
isQuestUsable = false, isQuestUsable = false,
isJunk = false, isJunk = false,
isPermanentEnchant = false, isPermanentEnchant = false,
isUnusable = false,
} }
end end
@@ -296,6 +355,7 @@ function ItemDetection:GetItemProperties(itemData, bagID, slotID)
local isQuestItem, isQuestStarter = DetectQuestItem(lines, itemData) local isQuestItem, isQuestStarter = DetectQuestItem(lines, itemData)
local isQuestUsable = DetectQuestUsable(lines) local isQuestUsable = DetectQuestUsable(lines)
local isJunk = DetectJunk(lines, itemData) local isJunk = DetectJunk(lines, itemData)
local isUnusable = DetectUnusable(lines)
-- Debug: log junk detection for gray items -- Debug: log junk detection for gray items
if addon.DEBUG then if addon.DEBUG then
@@ -320,6 +380,7 @@ function ItemDetection:GetItemProperties(itemData, bagID, slotID)
isQuestUsable = isQuestUsable, isQuestUsable = isQuestUsable,
isJunk = isJunk, isJunk = isJunk,
isPermanentEnchant = isPermanentEnchant, isPermanentEnchant = isPermanentEnchant,
isUnusable = isUnusable,
} }
-- Cache result -- Cache result
@@ -356,6 +417,11 @@ function ItemDetection:IsPermanentEnchant(itemData, bagID, slotID)
return props.isPermanentEnchant return props.isPermanentEnchant
end end
function ItemDetection:IsUnusable(itemData, bagID, slotID)
local props = self:GetItemProperties(itemData, bagID, slotID)
return props.isUnusable
end
--===================================================== --=====================================================
-- Initialization -- Initialization
--===================================================== --=====================================================
+4 -10
View File
@@ -615,16 +615,10 @@ function Tooltip:Initialize()
if event == "BAG_UPDATE" then if event == "BAG_UPDATE" then
if cacheClearPending then return end if cacheClearPending then return end
cacheClearPending = true cacheClearPending = true
-- Debounce: batch rapid BAG_UPDATE events -- Debounce: batch rapid BAG_UPDATE events (uses pooled timer)
local debounceFrame = CreateFrame("Frame") Guda_ScheduleTimer(0.2, function()
debounceFrame.elapsed = 0 cacheClearPending = false
debounceFrame:SetScript("OnUpdate", function() Tooltip:ClearCache()
this.elapsed = this.elapsed + arg1
if this.elapsed >= 0.2 then
this:SetScript("OnUpdate", nil)
cacheClearPending = false
Tooltip:ClearCache()
end
end) end)
end end
end) end)
+33
View File
@@ -5,6 +5,39 @@ local addon = Guda
local Utils = {} local Utils = {}
addon.Modules.Utils = Utils addon.Modules.Utils = Utils
--=============================================================================
-- Timer Frame Pool (prevents memory leaks from temporary timers)
-- Global function so all modules can use it
--=============================================================================
local timerPool = {}
local TIMER_POOL_MAX = 10 -- Limit pool size to prevent unbounded growth
function Guda_ScheduleTimer(delay, callback)
-- Try to get a frame from the pool
local frame = table.remove(timerPool)
if not frame then
frame = CreateFrame("Frame")
end
frame.elapsed = 0
frame.delay = delay
frame.callback = callback
frame:SetScript("OnUpdate", function()
this.elapsed = this.elapsed + arg1
if this.elapsed >= this.delay then
this:SetScript("OnUpdate", nil)
this:Hide()
-- Return frame to pool if not full
if table.getn(timerPool) < TIMER_POOL_MAX then
table.insert(timerPool, this)
end
-- Execute callback
this.callback()
end
end)
frame:Show()
end
--============================================================================= --=============================================================================
-- Tooltip Scan Caching -- Tooltip Scan Caching
-- Caches results of expensive tooltip scanning operations -- Caches results of expensive tooltip scanning operations
+3 -9
View File
@@ -188,15 +188,9 @@ function BankScanner:Initialize()
BankScanner:ClearCache() -- Clear cache on open BankScanner:ClearCache() -- Clear cache on open
addon:Debug("Bank opened") addon:Debug("Bank opened")
-- Delay scan to ensure bank is fully loaded -- Delay scan to ensure bank is fully loaded (uses pooled timer)
local frame = CreateFrame("Frame") Guda_ScheduleTimer(0.5, function()
local elapsed = 0 BankScanner:SaveToDatabase()
frame:SetScript("OnUpdate", function()
elapsed = elapsed + arg1
if elapsed >= 0.5 then
frame:SetScript("OnUpdate", nil)
BankScanner:SaveToDatabase()
end
end) end)
end, "BankScanner") end, "BankScanner")
+4 -10
View File
@@ -91,16 +91,10 @@ function EquipmentScanner:Initialize()
playerLoggedIn = true playerLoggedIn = true
addon:Print("Scanning equipped items...") addon:Print("Scanning equipped items...")
-- Delay scan to ensure character is fully loaded -- Delay scan to ensure character is fully loaded (uses pooled timer)
local frame = CreateFrame("Frame") Guda_ScheduleTimer(2.0, function()
local elapsed = 0 EquipmentScanner:SaveToDatabase()
frame:SetScript("OnUpdate", function() addon:Print("Equipped items scanned and saved!")
elapsed = elapsed + arg1
if elapsed >= 2.0 then
frame:SetScript("OnUpdate", nil)
EquipmentScanner:SaveToDatabase()
addon:Print("Equipped items scanned and saved!")
end
end) end)
end, "EquipmentScanner") end, "EquipmentScanner")
+4 -10
View File
@@ -36,17 +36,11 @@ function MoneyTracker:Initialize()
MoneyTracker:Update() MoneyTracker:Update()
end, "MoneyTracker") end, "MoneyTracker")
-- Initial update and save on login -- Initial update and save on login (uses pooled timer)
addon.Modules.Events:OnPlayerLogin(function() addon.Modules.Events:OnPlayerLogin(function()
local frame = CreateFrame("Frame") Guda_ScheduleTimer(1, function()
local elapsed = 0 MoneyTracker:Update()
frame:SetScript("OnUpdate", function() addon:Debug("Initial money saved")
elapsed = elapsed + arg1
if elapsed >= 1 then
frame:SetScript("OnUpdate", nil)
MoneyTracker:Update()
addon:Debug("Initial money saved")
end
end) end)
end, "MoneyTracker") end, "MoneyTracker")
end end
+44 -66
View File
@@ -1722,52 +1722,42 @@ function SortEngine:ExecuteSort(sortFunction, analyzeFunction, updateFrame, sort
-- Sorting is complete! -- Sorting is complete!
addon:DebugSort("%s sort complete! (%d passes, %d total moves)", sortType, passCount, totalMoves) addon:DebugSort("%s sort complete! (%d passes, %d total moves)", sortType, passCount, totalMoves)
-- Final update (cache clearing happens after delay) -- Final update (cache clearing happens after delay, uses pooled timer)
local frame = CreateFrame("Frame") Guda_ScheduleTimer(0.3, function()
local startTime = GetTime() SortEngine.sortingInProgress = false
frame:SetScript("OnUpdate", function() SortEngine:UpdateSortButtonState(false)
if GetTime() - startTime >= 0.3 then currentSortType = "bags" -- Reset sort context
frame:SetScript("OnUpdate", nil) -- Clear caches after sorting to ensure fresh detection
SortEngine.sortingInProgress = false if sortType == "bank" then
SortEngine:UpdateSortButtonState(false) addon.Modules.BankScanner:ClearCache()
currentSortType = "bags" -- Reset sort context else
-- Clear caches after sorting to ensure fresh detection addon.Modules.BagScanner:ClearCache()
if sortType == "bank" then
addon.Modules.BankScanner:ClearCache()
else
addon.Modules.BagScanner:ClearCache()
end
if addon.Modules.ItemDetection then
addon.Modules.ItemDetection:ClearCache()
end
updateFrame()
end end
if addon.Modules.ItemDetection then
addon.Modules.ItemDetection:ClearCache()
end
updateFrame()
end) end)
elseif passCount >= safetyLimit then elseif passCount >= safetyLimit then
-- Hit safety limit but not fully sorted -- Hit safety limit but not fully sorted
addon:DebugSort("%s sort stopped at safety limit! (%d/%d items still need sorting after %d passes)", addon:DebugSort("%s sort stopped at safety limit! (%d/%d items still need sorting after %d passes)",
sortType, currentAnalysis.itemsOutOfPlace, currentAnalysis.totalItems, passCount) sortType, currentAnalysis.itemsOutOfPlace, currentAnalysis.totalItems, passCount)
-- Final update (cache clearing happens after delay) -- Final update (cache clearing happens after delay, uses pooled timer)
local frame = CreateFrame("Frame") Guda_ScheduleTimer(0.3, function()
local startTime = GetTime() SortEngine.sortingInProgress = false
frame:SetScript("OnUpdate", function() SortEngine:UpdateSortButtonState(false)
if GetTime() - startTime >= 0.3 then currentSortType = "bags" -- Reset sort context
frame:SetScript("OnUpdate", nil) -- Clear caches after sorting to ensure fresh detection
SortEngine.sortingInProgress = false if sortType == "bank" then
SortEngine:UpdateSortButtonState(false) addon.Modules.BankScanner:ClearCache()
currentSortType = "bags" -- Reset sort context else
-- Clear caches after sorting to ensure fresh detection addon.Modules.BagScanner:ClearCache()
if sortType == "bank" then
addon.Modules.BankScanner:ClearCache()
else
addon.Modules.BagScanner:ClearCache()
end
if addon.Modules.ItemDetection then
addon.Modules.ItemDetection:ClearCache()
end
updateFrame()
end end
if addon.Modules.ItemDetection then
addon.Modules.ItemDetection:ClearCache()
end
updateFrame()
end) end)
else else
-- No progress guard: stop if we make no moves repeatedly -- No progress guard: stop if we make no moves repeatedly
@@ -1781,26 +1771,21 @@ function SortEngine:ExecuteSort(sortFunction, analyzeFunction, updateFrame, sort
addon:DebugSort("%s sort stopped due to no progress after %d passes (items remaining: %d/%d)", addon:DebugSort("%s sort stopped due to no progress after %d passes (items remaining: %d/%d)",
sortType, passCount, currentAnalysis.itemsOutOfPlace, currentAnalysis.totalItems) sortType, passCount, currentAnalysis.itemsOutOfPlace, currentAnalysis.totalItems)
-- Final update (cache clearing happens after delay) -- Final update (cache clearing happens after delay, uses pooled timer)
local frame = CreateFrame("Frame") Guda_ScheduleTimer(0.3, function()
local startTime = GetTime() SortEngine.sortingInProgress = false
frame:SetScript("OnUpdate", function() SortEngine:UpdateSortButtonState(false)
if GetTime() - startTime >= 0.3 then currentSortType = "bags" -- Reset sort context
frame:SetScript("OnUpdate", nil) -- Clear caches after sorting to ensure fresh detection
SortEngine.sortingInProgress = false if sortType == "bank" then
SortEngine:UpdateSortButtonState(false) addon.Modules.BankScanner:ClearCache()
currentSortType = "bags" -- Reset sort context else
-- Clear caches after sorting to ensure fresh detection addon.Modules.BagScanner:ClearCache()
if sortType == "bank" then
addon.Modules.BankScanner:ClearCache()
else
addon.Modules.BagScanner:ClearCache()
end
if addon.Modules.ItemDetection then
addon.Modules.ItemDetection:ClearCache()
end
updateFrame()
end end
if addon.Modules.ItemDetection then
addon.Modules.ItemDetection:ClearCache()
end
updateFrame()
end) end)
return return
end end
@@ -1819,15 +1804,8 @@ function SortEngine:ExecuteSort(sortFunction, analyzeFunction, updateFrame, sort
addon:DebugSort("Waiting %.1f seconds before next pass...", totalDelay) addon:DebugSort("Waiting %.1f seconds before next pass...", totalDelay)
-- Wait with progressive delay, then sort again -- Wait with progressive delay, then sort again (uses pooled timer)
local frame = CreateFrame("Frame") Guda_ScheduleTimer(totalDelay, DoSortPass)
local startTime = GetTime()
frame:SetScript("OnUpdate", function()
if GetTime() - startTime >= totalDelay then
frame:SetScript("OnUpdate", nil)
DoSortPass() -- Recursive call for next pass
end
end)
end end
end end
+2 -14
View File
@@ -1849,20 +1849,8 @@ function Guda_BagFrame_MergeStacks()
ProcessNextMove() ProcessNextMove()
end end
-- Simple timer helper -- NOTE: Guda_ScheduleTimer is defined in Core/Utils.lua (loaded earlier)
function Guda_ScheduleTimer(delay, callback) -- to ensure it's available for all modules that need timers
local frame = CreateFrame("Frame")
frame.elapsed = 0
frame.delay = delay
frame.callback = callback
frame:SetScript("OnUpdate", function()
this.elapsed = this.elapsed + arg1
if this.elapsed >= this.delay then
this:SetScript("OnUpdate", nil)
this.callback()
end
end)
end
-- Hook bag container buttons to open Guda Bag View -- Hook bag container buttons to open Guda Bag View
local function HookBagContainers() local function HookBagContainers()
+19 -31
View File
@@ -1611,40 +1611,28 @@ function BankFrame:Initialize()
-- Update when bank is opened -- Update when bank is opened
addon.Modules.Events:OnBankOpen(function() addon.Modules.Events:OnBankOpen(function()
-- Delay showing custom bank to let TransmogUI finish processing -- Delay showing custom bank to let TransmogUI finish processing (uses pooled timer)
local frame = CreateFrame("Frame") Guda_ScheduleTimer(0.2, function()
local elapsed = 0 -- Show current character's bank in interactive mode
frame:SetScript("OnUpdate", function() currentViewChar = nil
elapsed = elapsed + arg1
if elapsed >= 0.2 then
frame:SetScript("OnUpdate", nil)
-- Show current character's bank in interactive mode -- Do not auto-hide BagFrame when opening BankFrame
currentViewChar = nil -- Users may want both frames visible simultaneously; layout issues, if any,
-- should be addressed via positioning rather than auto-hiding.
-- Do not auto-hide BagFrame when opening BankFrame -- Show and update custom bank frame
-- Previously, we hid BagFrame to prevent button overlap: local customBankFrame = getglobal("Guda_BankFrame")
-- local bagFrame = getglobal("Guda_BagFrame") if customBankFrame then
-- if bagFrame and bagFrame:IsShown() then customBankFrame:Show()
-- bagFrame:Hide()
-- end
-- Users may want both frames visible simultaneously; layout issues, if any,
-- should be addressed via positioning rather than auto-hiding.
-- Show and update custom bank frame
local customBankFrame = getglobal("Guda_BankFrame")
if customBankFrame then
customBankFrame:Show()
end
-- Force disable pfUI banks if enabled (pfUI uses pfBank for its bank frame)
if pfUI and pfUI.bag and pfUI.bag.left and pfUI.bag.left.Hide then
pfUI.bag.left:Hide()
end
addon.Modules.BankFrame:EnsureBagButtonsInitialized()
addon.Modules.BankFrame:Update()
end end
-- Force disable pfUI banks if enabled (pfUI uses pfBank for its bank frame)
if pfUI and pfUI.bag and pfUI.bag.left and pfUI.bag.left.Hide then
pfUI.bag.left:Hide()
end
addon.Modules.BankFrame:EnsureBagButtonsInitialized()
addon.Modules.BankFrame:Update()
end) end)
end, "BankFrameUI") end, "BankFrameUI")
+9 -86
View File
@@ -110,91 +110,10 @@ local function Guda_GetUnusableColor()
return 0.9, 0.2, 0.2, 1.0 return 0.9, 0.2, 0.2, 1.0
end end
-- Build durability match pattern based on the client template -- NOTE: IsItemUnusable detection is now handled by ItemDetection:IsUnusable()
local durabilityPattern -- which uses cached tooltip scanning to avoid duplicate scans per item.
if DURABILITY_TEMPLATE then -- The old IsItemUnusable, IsRedColor, and durabilityPattern have been removed
-- e.g. "Durability %d / %d" -> "Durability (.+)" -- to prevent redundant tooltip scanning - all detection is now centralized.
durabilityPattern = string.gsub(DURABILITY_TEMPLATE, "%%[^%s]+", "(.+)")
end
-- Tiny helper to compare font color to Blizzard's RED_FONT_COLOR
local function IsRedColor(r, g, b)
if not r or not g or not b or not RED_FONT_COLOR then return false end
local dr = math.abs(r - RED_FONT_COLOR.r)
local dg = math.abs(g - RED_FONT_COLOR.g)
local db = math.abs(b - RED_FONT_COLOR.b)
return (dr < 0.08 and dg < 0.08 and db < 0.08)
end
-- Scan tooltip for red text that is NOT a durability line
-- Uses shared tooltip from Utils module
local function IsItemUnusable(bagID, slotID, isBank)
bagID = tonumber(bagID)
slotID = tonumber(slotID)
if not bagID or not slotID then return false end
-- Get shared tooltip from Utils
local scanTooltip, tooltipName = addon.Modules.Utils:GetScanTooltip()
-- Some clients require SetOwner before every SetBagItem/SetInventoryItem to populate lines
if scanTooltip.SetOwner then
scanTooltip:SetOwner(UIParent or WorldFrame, "ANCHOR_NONE")
end
scanTooltip:ClearLines()
if isBank and bagID == -1 then
-- Bank frame item buttons map slots 1.. to inventory slots 40.. (39 + slot)
if scanTooltip.SetInventoryItem then
scanTooltip:SetInventoryItem("player", 39 + slotID)
else
-- Fallback to bag scan if API missing
scanTooltip:SetBagItem(bagID, slotID)
end
else
scanTooltip:SetBagItem(bagID, slotID)
end
if scanTooltip.Show then scanTooltip:Show() end
local num = scanTooltip:NumLines() or 0
for i = 1, num do
-- Scan LEFT column
local left = getglobal(tooltipName .. "TextLeft" .. i)
if left and left:IsShown() then
local text = left:GetText()
local r, g, b = left:GetTextColor()
-- Be tolerant with red detection in case client colors differ slightly
local isRed = IsRedColor(r, g, b) or (r and g and b and r > 0.85 and g < 0.3 and b < 0.3)
if text and isRed then
-- Ignore red durability (broken) lines
if durabilityPattern and string.find(text, durabilityPattern, 1) then
-- skip durability
else
if scanTooltip.Hide then scanTooltip:Hide() end
return true
end
end
end
-- Scan RIGHT column as well (required level etc can appear here on some clients)
local right = getglobal(tooltipName .. "TextRight" .. i)
if right and right:IsShown() then
local text = right:GetText()
local r, g, b = right:GetTextColor()
local isRed = IsRedColor(r, g, b) or (r and g and b and r > 0.85 and g < 0.3 and b < 0.3)
if text and isRed then
if durabilityPattern and string.find(text, durabilityPattern, 1) then
-- skip durability
else
if scanTooltip.Hide then scanTooltip:Hide() end
return true
end
end
end
end
return false
end
-- Apply/remove red tint on item texture for unusable items -- Apply/remove red tint on item texture for unusable items
local function Guda_ItemButton_UpdateUsableTint(self) local function Guda_ItemButton_UpdateUsableTint(self)
@@ -225,7 +144,11 @@ local function Guda_ItemButton_UpdateUsableTint(self)
return return
end end
local unusable = IsItemUnusable(self.bagID, self.slotID, self.isBank) -- Use cached detection from ItemDetection module (avoids duplicate tooltip scans)
local unusable = false
if self.itemData and addon.Modules.ItemDetection then
unusable = addon.Modules.ItemDetection:IsUnusable(self.itemData, self.bagID, self.slotID)
end
-- Ensure overlay exists (created in OnLoad, but be defensive) -- Ensure overlay exists (created in OnLoad, but be defensive)
if not self.unusableOverlay then if not self.unusableOverlay then
+4 -10
View File
@@ -649,16 +649,10 @@ function QuestItemBar:Initialize()
addon.Modules.Events:Register("BAG_UPDATE", function() addon.Modules.Events:Register("BAG_UPDATE", function()
if bagUpdatePending then return end if bagUpdatePending then return end
bagUpdatePending = true bagUpdatePending = true
-- Debounce: wait 0.15 seconds before updating to batch rapid events -- Debounce: wait 0.15 seconds before updating (uses pooled timer)
local debounceFrame = CreateFrame("Frame") Guda_ScheduleTimer(0.15, function()
debounceFrame.elapsed = 0 bagUpdatePending = false
debounceFrame:SetScript("OnUpdate", function() QuestItemBar:Update()
this.elapsed = this.elapsed + arg1
if this.elapsed >= 0.15 then
this:SetScript("OnUpdate", nil)
bagUpdatePending = false
QuestItemBar:Update()
end
end) end)
end, "QuestItemBar") end, "QuestItemBar")
+4 -10
View File
@@ -312,16 +312,10 @@ function TrackedItemBar:Initialize()
addon.Modules.Events:Register("BAG_UPDATE", function() addon.Modules.Events:Register("BAG_UPDATE", function()
if bagUpdatePending then return end if bagUpdatePending then return end
bagUpdatePending = true bagUpdatePending = true
-- Debounce: wait 0.15 seconds before updating to batch rapid events -- Debounce: wait 0.15 seconds before updating (uses pooled timer)
local debounceFrame = CreateFrame("Frame") Guda_ScheduleTimer(0.15, function()
debounceFrame.elapsed = 0 bagUpdatePending = false
debounceFrame:SetScript("OnUpdate", function() TrackedItemBar:Update()
this.elapsed = this.elapsed + arg1
if this.elapsed >= 0.15 then
this:SetScript("OnUpdate", nil)
bagUpdatePending = false
TrackedItemBar:Update()
end
end) end)
end, "TrackedItemBar") end, "TrackedItemBar")