perf: add caching and transfer limiting for bag/bank operations
This commit is contained in:
+112
-20
@@ -1,12 +1,100 @@
|
||||
-- Guda Bag Scanner
|
||||
-- Scans and stores bag contents
|
||||
-- Scans and stores bag contents with caching and event pending tracking
|
||||
|
||||
local addon = Guda
|
||||
|
||||
local BagScanner = {}
|
||||
addon.Modules.BagScanner = BagScanner
|
||||
|
||||
-- Scan all bags and return data
|
||||
-- Cache for bag data to avoid re-scanning all slots on every update
|
||||
local bagCache = nil
|
||||
local cacheValid = false
|
||||
|
||||
-- Event pending tracking (like Baganator's IsBagEventPending)
|
||||
local eventPending = false
|
||||
local dirtySlots = {} -- Track specific slots that changed: dirtySlots[bagID][slotID] = true
|
||||
|
||||
-- Clear the bag cache
|
||||
function BagScanner:ClearCache()
|
||||
bagCache = nil
|
||||
cacheValid = false
|
||||
dirtySlots = {}
|
||||
end
|
||||
|
||||
-- Check if a bag event is pending (use before transfers)
|
||||
function BagScanner:IsEventPending()
|
||||
return eventPending
|
||||
end
|
||||
|
||||
-- Clear the pending flag (call after processing)
|
||||
function BagScanner:ClearEventPending()
|
||||
eventPending = false
|
||||
end
|
||||
|
||||
-- Mark a specific slot as dirty (incremental tracking)
|
||||
function BagScanner:MarkSlotDirty(bagID, slotID)
|
||||
if not dirtySlots[bagID] then
|
||||
dirtySlots[bagID] = {}
|
||||
end
|
||||
dirtySlots[bagID][slotID] = true
|
||||
eventPending = true
|
||||
end
|
||||
|
||||
-- Get dirty slots and clear them
|
||||
function BagScanner:GetAndClearDirtySlots()
|
||||
local dirty = dirtySlots
|
||||
dirtySlots = {}
|
||||
return dirty
|
||||
end
|
||||
|
||||
-- Get cached bag data, or scan if cache is invalid
|
||||
function BagScanner:GetBagData()
|
||||
if cacheValid and bagCache then
|
||||
-- Process any dirty slots incrementally
|
||||
for bagID, slots in pairs(dirtySlots) do
|
||||
if bagCache[bagID] then
|
||||
for slotID in pairs(slots) do
|
||||
local oldData = bagCache[bagID].slots[slotID]
|
||||
local newData = self:ScanSlot(bagID, slotID)
|
||||
bagCache[bagID].slots[slotID] = newData
|
||||
|
||||
-- Update free slot count
|
||||
local wasEmpty = (oldData == nil)
|
||||
local isEmpty = (newData == nil)
|
||||
if wasEmpty and not isEmpty then
|
||||
bagCache[bagID].freeSlots = bagCache[bagID].freeSlots - 1
|
||||
elseif not wasEmpty and isEmpty then
|
||||
bagCache[bagID].freeSlots = bagCache[bagID].freeSlots + 1
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Bag not in cache, scan it
|
||||
bagCache[bagID] = self:ScanBag(bagID)
|
||||
end
|
||||
end
|
||||
dirtySlots = {}
|
||||
return bagCache
|
||||
end
|
||||
|
||||
-- Cache miss - do full scan
|
||||
bagCache = self:ScanBags()
|
||||
cacheValid = true
|
||||
dirtySlots = {}
|
||||
return bagCache
|
||||
end
|
||||
|
||||
-- Invalidate cache (force full re-scan on next update)
|
||||
function BagScanner:InvalidateCache()
|
||||
cacheValid = false
|
||||
end
|
||||
|
||||
-- Invalidate a specific bag in the cache
|
||||
function BagScanner:InvalidateBag(bagID)
|
||||
if not bagCache then return end
|
||||
bagCache[bagID] = nil
|
||||
end
|
||||
|
||||
-- Scan all bags and return data (full scan)
|
||||
function BagScanner:ScanBags()
|
||||
local bagData = {}
|
||||
|
||||
@@ -61,8 +149,6 @@ function BagScanner:ScanSlot(bagID, slot)
|
||||
local itemLink = GetContainerItemLink(bagID, slot)
|
||||
|
||||
-- Get item info
|
||||
-- Correct order: itemName, itemLink, itemRarity, itemLevel, itemCategory, itemType,
|
||||
-- itemStackCount, itemSubType, itemTexture, itemEquipLoc, itemSellPrice
|
||||
local name, link, itemQuality, iLevel, itemCategory, itemType, itemStackCount, itemSubType, itemTexture, itemEquipLoc, itemSellPrice
|
||||
if itemLink then
|
||||
name, link, itemQuality, iLevel, itemCategory, itemType, itemStackCount, itemSubType, itemTexture, itemEquipLoc, itemSellPrice = addon.Modules.Utils:GetItemInfo(itemLink)
|
||||
@@ -76,9 +162,9 @@ function BagScanner:ScanSlot(bagID, slot)
|
||||
name = name,
|
||||
iLevel = iLevel,
|
||||
type = itemType,
|
||||
class = itemCategory, -- Category (e.g., "Consumable", "Armor")
|
||||
subclass = itemSubType, -- SubType (e.g., "Potion", "Cloth")
|
||||
equipSlot = itemEquipLoc, -- Equipment slot (e.g., "INVTYPE_HEAD") - correct now!
|
||||
class = itemCategory,
|
||||
subclass = itemSubType,
|
||||
equipSlot = itemEquipLoc,
|
||||
locked = locked,
|
||||
}
|
||||
end
|
||||
@@ -88,29 +174,35 @@ function BagScanner:SaveToDatabase()
|
||||
local bagData = self:ScanBags()
|
||||
addon.Modules.DB:SaveBags(bagData)
|
||||
addon:Debug("Bag data saved to database")
|
||||
|
||||
|
||||
-- Clear tooltip cache so counts update immediately
|
||||
if addon.Modules.Tooltip and addon.Modules.Tooltip.ClearCache then
|
||||
addon.Modules.Tooltip:ClearCache()
|
||||
end
|
||||
end
|
||||
|
||||
-- Initialize with auto-save on bag changes
|
||||
-- Initialize with event pending tracking
|
||||
function BagScanner:Initialize()
|
||||
-- Create event frame for bag updates
|
||||
local eventFrame = CreateFrame("Frame")
|
||||
self.eventFrame = eventFrame
|
||||
|
||||
-- Register bag update events
|
||||
-- Register bag update events for pending tracking
|
||||
eventFrame:RegisterEvent("BAG_UPDATE")
|
||||
eventFrame:RegisterEvent("BAG_UPDATE_DELAYED")
|
||||
--
|
||||
--eventFrame:SetScript("OnEvent", function()
|
||||
-- if event == "BAG_UPDATE" or event == "BAG_UPDATE_DELAYED" then
|
||||
-- addon:Debug("Bag update detected, saving data...")
|
||||
-- self:SaveToDatabase()
|
||||
-- end
|
||||
--end)
|
||||
eventFrame:SetScript("OnEvent", function()
|
||||
eventPending = true
|
||||
-- Mark the specific bag as having changes
|
||||
if arg1 then
|
||||
if not dirtySlots[arg1] then
|
||||
dirtySlots[arg1] = {}
|
||||
end
|
||||
-- We don't know which slot, so mark entire bag for rescan
|
||||
-- by invalidating it
|
||||
if bagCache and bagCache[arg1] then
|
||||
bagCache[arg1] = nil
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
addon:Debug("Bag scanner initialized with auto-save")
|
||||
end
|
||||
addon:Debug("Bag scanner initialized with event pending tracking")
|
||||
end
|
||||
|
||||
+101
-5
@@ -1,5 +1,5 @@
|
||||
-- Guda Bank Scanner
|
||||
-- Scans and stores bank contents
|
||||
-- Scans and stores bank contents with caching and event pending tracking
|
||||
|
||||
local addon = Guda
|
||||
|
||||
@@ -8,7 +8,102 @@ addon.Modules.BankScanner = BankScanner
|
||||
|
||||
local bankOpen = false
|
||||
|
||||
-- Scan all bank bags and return data
|
||||
-- Cache for bank data to avoid re-scanning all slots on every update
|
||||
local bankCache = nil
|
||||
local cacheValid = false
|
||||
|
||||
-- Event pending tracking (like Baganator's IsBagEventPending)
|
||||
local eventPending = false
|
||||
local dirtySlots = {} -- Track specific slots that changed
|
||||
|
||||
-- Clear the bank cache (called when bank opens or significant changes occur)
|
||||
function BankScanner:ClearCache()
|
||||
bankCache = nil
|
||||
cacheValid = false
|
||||
dirtySlots = {}
|
||||
eventPending = false
|
||||
end
|
||||
|
||||
-- Check if a bank event is pending (use before transfers)
|
||||
function BankScanner:IsEventPending()
|
||||
return eventPending
|
||||
end
|
||||
|
||||
-- Clear the pending flag (call after processing)
|
||||
function BankScanner:ClearEventPending()
|
||||
eventPending = false
|
||||
end
|
||||
|
||||
-- Mark a specific slot as dirty (incremental tracking)
|
||||
function BankScanner:MarkSlotDirty(bagID, slotID)
|
||||
if not dirtySlots[bagID] then
|
||||
dirtySlots[bagID] = {}
|
||||
end
|
||||
dirtySlots[bagID][slotID] = true
|
||||
eventPending = true
|
||||
end
|
||||
|
||||
-- Get cached bank data, or scan if cache is invalid
|
||||
function BankScanner:GetBankData()
|
||||
if not bankOpen then
|
||||
return {}
|
||||
end
|
||||
|
||||
if cacheValid and bankCache then
|
||||
-- Process any dirty slots incrementally
|
||||
for bagID, slots in pairs(dirtySlots) do
|
||||
if bankCache[bagID] then
|
||||
for slotID in pairs(slots) do
|
||||
local oldData = bankCache[bagID].slots[slotID]
|
||||
local newData = addon.Modules.BagScanner:ScanSlot(bagID, slotID)
|
||||
bankCache[bagID].slots[slotID] = newData
|
||||
|
||||
-- Update free slot count
|
||||
local wasEmpty = (oldData == nil)
|
||||
local isEmpty = (newData == nil)
|
||||
if wasEmpty and not isEmpty then
|
||||
bankCache[bagID].freeSlots = bankCache[bagID].freeSlots - 1
|
||||
elseif not wasEmpty and isEmpty then
|
||||
bankCache[bagID].freeSlots = bankCache[bagID].freeSlots + 1
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Bag not in cache, scan it
|
||||
bankCache[bagID] = self:ScanBankBag(bagID)
|
||||
end
|
||||
end
|
||||
dirtySlots = {}
|
||||
return bankCache
|
||||
end
|
||||
|
||||
-- Cache miss - do full scan
|
||||
bankCache = self:ScanBank()
|
||||
cacheValid = true
|
||||
dirtySlots = {}
|
||||
return bankCache
|
||||
end
|
||||
|
||||
-- Update a single slot in the cache (incremental update)
|
||||
function BankScanner:UpdateSlot(bagID, slotID)
|
||||
if not bankOpen then return end
|
||||
|
||||
-- Mark as dirty for next GetBankData call
|
||||
self:MarkSlotDirty(bagID, slotID)
|
||||
end
|
||||
|
||||
-- Invalidate cache (force full re-scan on next update)
|
||||
function BankScanner:InvalidateCache()
|
||||
cacheValid = false
|
||||
end
|
||||
|
||||
-- Invalidate a specific bag in the cache (force re-scan of just that bag)
|
||||
function BankScanner:InvalidateBag(bagID)
|
||||
if not bankOpen then return end
|
||||
if not bankCache then return end
|
||||
bankCache[bagID] = nil
|
||||
end
|
||||
|
||||
-- Scan all bank bags and return data (full scan)
|
||||
function BankScanner:ScanBank()
|
||||
if not bankOpen then
|
||||
addon:Debug("Cannot scan bank - not open")
|
||||
@@ -67,16 +162,17 @@ function BankScanner:SaveToDatabase()
|
||||
return
|
||||
end
|
||||
|
||||
local bankData = self:ScanBank()
|
||||
local bankData = self:GetBankData() -- Use cached data
|
||||
addon.Modules.DB:SaveBank(bankData)
|
||||
addon:Debug("Bank data saved")
|
||||
end
|
||||
|
||||
-- Initialize bank scanner
|
||||
function BankScanner:Initialize()
|
||||
-- Bank opened - save bank data
|
||||
-- Bank opened - do initial scan
|
||||
addon.Modules.Events:OnBankOpen(function()
|
||||
bankOpen = true
|
||||
BankScanner:ClearCache() -- Clear cache on open
|
||||
addon:Debug("Bank opened")
|
||||
|
||||
-- Delay scan to ensure bank is fully loaded
|
||||
@@ -94,11 +190,11 @@ function BankScanner:Initialize()
|
||||
-- Bank closed
|
||||
addon.Modules.Events:OnBankClose(function()
|
||||
-- Do a final save on close before marking bank as closed
|
||||
-- so that any last changes are captured.
|
||||
addon:Debug("Bank closing - performing final save")
|
||||
BankScanner:SaveToDatabase()
|
||||
|
||||
bankOpen = false
|
||||
BankScanner:ClearCache() -- Clear cache on close
|
||||
addon:Debug("Bank closed")
|
||||
end, "BankScanner")
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user