Skip to content

Commit

Permalink
Bag Refresh and Rendering (#181)
Browse files Browse the repository at this point in the history
* Picking up items while in combat will now delay drawing picked up items in your bag until combat is over. This fixes the weird graphical issues that happen sometimes when looting items while in combat (icons appearing large, etc). This is a temporary workaround to the fact that rendering bags takes a long time. More work and research will be conducted on how to make this better in time.

* Added a hackfix for Masque addons that are out of date and don't apply icon border blend like they are supposed to.

* Reworked some internals and fixed some obscure bugs that would cause some slowdowns in some cases.
  • Loading branch information
Cidan authored Feb 20, 2024
1 parent e05495d commit 2438ec8
Show file tree
Hide file tree
Showing 12 changed files with 116 additions and 24 deletions.
27 changes: 25 additions & 2 deletions core/events.lua
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,11 @@ end
-- called when any of the events in the group are fired. The callback will be
-- called at most once every 0.5 seconds.
---@param groupEvents string[]
---@param groupMessages string[]
---@param callback fun(eventData: eventData)
function events:GroupBucketEvent(groupEvents, callback)
function events:GroupBucketEvent(groupEvents, groupMessages, callback)
local joinedEvents = table.concat(groupEvents, '')
joinedEvents = joinedEvents .. table.concat(groupMessages, '')
if not self._bucketTimers[joinedEvents] then
self._bucketCallbacks[joinedEvents] = {}
self._eventArguments[joinedEvents] = {}
Expand All @@ -110,7 +112,7 @@ function events:GroupBucketEvent(groupEvents, callback)
return
end
for _, cb in pairs(self._bucketCallbacks[joinedEvents]) do
cb(self._eventArguments[joinedEvents])
xpcall(cb, geterrorhandler(), self._eventArguments[joinedEvents])
end
self._eventQueue[joinedEvents] = false
self._eventArguments[joinedEvents] = {}
Expand All @@ -121,6 +123,13 @@ function events:GroupBucketEvent(groupEvents, callback)
self._eventQueue[joinedEvents] = true
end)
end

for _, event in pairs(groupMessages) do
self:RegisterMessage(event, function(eventName, ...)
tinsert(self._eventArguments[joinedEvents], {eventName, ...})
self._eventQueue[joinedEvents] = true
end)
end
end
table.insert(self._bucketCallbacks[joinedEvents], callback)
end
Expand All @@ -129,4 +138,18 @@ function events:SendMessage(event, ...)
self._eventHandler:SendMessage(event, ...)
end

---@param event string
---@param callback? function
---@param ... any
function events:SendMessageLater(event, callback, ...)
---@type any[]
local vararg = {...}
C_Timer.After(0, function()
self._eventHandler:SendMessage(event, vararg)
if callback then
callback()
end
end)
end

events:Enable()
9 changes: 9 additions & 0 deletions core/hooks.lua
Original file line number Diff line number Diff line change
Expand Up @@ -43,25 +43,29 @@ function addon:OpenAllBags(interactingFrame)
if interactingFrame ~= nil then return end
debug:Log('Hooks', 'OpenAllBags')
addon.backpackShouldOpen = true
events:SendMessageLater('bags/OpenClose')
end

---@param interactingFrame Frame
function addon:CloseAllBags(interactingFrame)
if interactingFrame ~= nil then return end
debug:Log('Hooks', 'CloseAllBags')
addon.backpackShouldClose = true
events:SendMessageLater('bags/OpenClose')
end

function addon:CloseBackpack(interactingFrame)
if interactingFrame ~= nil then return end
debug:Log('Hooks', 'CloseBackpack')
addon.backpackShouldClose = true
events:SendMessageLater('bags/OpenClose')
end

function addon:OpenBackpack(interactingFrame)
if interactingFrame ~= nil then return end
debug:Log('Hooks', 'OpenBackpack')
addon.backpackShouldOpen = true
events:SendMessageLater('bags/OpenClose')
end

function addon:ToggleBag(interactingFrame)
Expand All @@ -72,12 +76,14 @@ function addon:ToggleBag(interactingFrame)
else
addon.backpackShouldOpen = true
end
events:SendMessageLater('bags/OpenClose')
end

function addon:CloseBag(interactingFrame)
if interactingFrame ~= nil then return end
debug:Log('Hooks', 'CloseBag')
addon.backpackShouldClose = true
events:SendMessageLater('bags/OpenClose')
end

function addon:ToggleAllBags(interactingFrame)
Expand All @@ -88,6 +94,7 @@ function addon:ToggleAllBags(interactingFrame)
else
addon.backpackShouldOpen = true
end
events:SendMessageLater('bags/OpenClose')
end

function addon:ToggleBackpack(interactingFrame)
Expand All @@ -98,6 +105,7 @@ function addon:ToggleBackpack(interactingFrame)
else
addon.backpackShouldOpen = true
end
events:SendMessageLater('bags/OpenClose')
end

function addon:CloseSpecialWindows(interactingFrame)
Expand All @@ -108,6 +116,7 @@ function addon:CloseSpecialWindows(interactingFrame)
addon.Bags.Bank:SwitchToBank()
events:SendMessage('addon/CloseSpecialWindows')
CloseBankFrame()
events:SendMessageLater('bags/OpenClose')
end

function addon:OpenBank(interactingFrame)
Expand Down
20 changes: 14 additions & 6 deletions core/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,6 @@ end

-- OnEnable is called when the addon is enabled.
function addon:OnEnable()
local updateFrame = CreateFrame("Frame")
updateFrame:SetScript("OnUpdate", self.OnUpdate)
itemFrame:Enable()
sectionFrame:Enable()
masque:Enable()
Expand All @@ -134,9 +132,9 @@ function addon:OnEnable()

events:RegisterEvent('BANKFRAME_CLOSED', self.CloseBank)

events:RegisterMessage('items/RefreshBackpack/Done', function(_, itemData)
events:RegisterMessage('items/RefreshBackpack/Done', function(_, args)
debug:Log("init/OnInitialize/items", "Drawing bag")
addon.Bags.Backpack:Draw(itemData)
addon.Bags.Backpack:Draw(args[1])
end)

events:RegisterMessage('items/RefreshBank/Done', function(_, itemData)
Expand All @@ -150,6 +148,16 @@ function addon:OnEnable()
addon.Bags.Bank:UpdateContextMenu()
end)

debug:Log("init", "about refresh all items")
items:RefreshBackpack()
events:RegisterEvent('PLAYER_REGEN_ENABLED', function()
if addon.Bags.Backpack.drawAfterCombat then
addon.Bags.Backpack.drawAfterCombat = false
addon.Bags.Backpack:Refresh()
end
if addon.Bags.Bank.drawAfterCombat then
addon.Bags.Bank.drawAfterCombat = false
addon.Bags.Bank:Refresh()
end
end)

events:RegisterMessage('bags/OpenClose', addon.OnUpdate)
end
18 changes: 12 additions & 6 deletions data/items.lua
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ end

function items:OnEnable()

events:RegisterEvent('EQUIPMENT_SETS_CHANGED', function() self:RefreshAll() end)
events:RegisterEvent('EQUIPMENT_SETS_CHANGED', function()
self:RefreshAll()
end)
local eventList = {
'BAG_UPDATE_DELAYED',
'PLAYERBANKSLOTS_CHANGED',
Expand All @@ -61,7 +63,9 @@ function items:OnEnable()
table.insert(eventList, 'PLAYERREAGENTBANKSLOTS_CHANGED')
end

events:GroupBucketEvent(eventList, function() self:RefreshAll() end)
events:GroupBucketEvent(eventList, {'bags/RefreshAll', 'bags/RefreshBackpack', 'bags/RefreshBank'}, function()
self:RefreshAll()
end)

events:RegisterEvent('BANKFRAME_OPENED', function()
addon.atBank = true
Expand Down Expand Up @@ -169,10 +173,12 @@ function items:ProcessContainer()
end

-- All items in all bags have finished loading, fire the all done event.
events:SendMessage('items/RefreshBackpack/Done', items.dirtyItems)
wipe(items.dirtyItems)
items._container = nil
items._doingRefreshAll = false
events:SendMessageLater('items/RefreshBackpack/Done', function()
wipe(items.dirtyItems)
items._container = nil
items._doingRefreshAll = false
end,
items.dirtyItems)
end)
end

Expand Down
13 changes: 12 additions & 1 deletion frames/bag.lua
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ local search = addon:GetModule('Search')
---@field moneyFrame Money
---@field resizeHandle Button
---@field drawOnClose boolean
---@field drawAfterCombat boolean
---@field menuList MenuList[]
---@field toRelease Item[]
---@field toReleaseSections Section[]
Expand Down Expand Up @@ -162,6 +163,14 @@ end
-- Refresh will refresh this bag's item database, and then redraw the bag.
-- This is what would be considered a "full refresh".
function bagFrame.bagProto:Refresh()
if self.kind == const.BAG_KIND.BACKPACK then
events:SendMessage('bags/RefreshBackpack')
else
events:SendMessage('bags/RefreshBank')
end
end

function bagFrame.bagProto:DoRefresh()
if self.kind == const.BAG_KIND.BACKPACK then
items:RefreshBackpack()
elseif self.kind == const.BAG_KIND.BANK and not self.isReagentBank then
Expand All @@ -185,17 +194,18 @@ end
-- Draw will draw the correct bag view based on the bag view configuration.
---@param dirtyItems ItemData[]
function bagFrame.bagProto:Draw(dirtyItems)
local view = self.views[database:GetBagView(self.kind)]
-- TODO(lobato): Implement slots view, maybe.
if self.slots:IsShown() then
self:Wipe()
end

local view = self.views[database:GetBagView(self.kind)]
if view == nil then
assert(view, "No view found for bag view: "..database:GetBagView(self.kind))
return
end


if self.currentView and self.currentView:GetKind() ~= view:GetKind() then
self.currentView:Wipe()
self.currentView:GetContent():Hide()
Expand Down Expand Up @@ -279,6 +289,7 @@ function bagFrame:Create(kind)
setmetatable(b, { __index = bagFrame.bagProto })
b.currentItemCount = 0
b.drawOnClose = false
b.drawAfterCombat = false
b.isReagentBank = false
b.sections = {}
b.toRelease = {}
Expand Down
2 changes: 1 addition & 1 deletion frames/bagslots.lua
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,6 @@ function BagSlots:CreatePanel(kind)
end)
events:RegisterEvent("BAG_CONTAINER_UPDATE", function() b:Draw() end)
b.kind = kind
b:Hide()
b.frame:Hide()
return b
end
3 changes: 2 additions & 1 deletion frames/classic/item.lua
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ function itemFrame.itemProto:SetItem(data)
SetItemButtonTexture(self.button, data.itemInfo.itemIcon)
self.button.IconBorder:SetTexture([[Interface\Common\WhiteIconFrame]])
self.button.IconBorder:SetVertexColor(unpack(const.ITEM_QUALITY_COLOR[data.itemInfo.itemQuality]))
self.button.IconBorder:SetBlendMode("BLEND")
self.button.IconBorder:Show()
SetItemButtonCount(self.button, data.itemInfo.currentItemCount)
SetItemButtonDesaturated(self.button, data.itemInfo.isLocked)
Expand Down Expand Up @@ -176,7 +177,7 @@ function itemFrame.itemProto:SetFreeSlots(bagid, slotid, count, reagent)
else
self:AddToMasqueGroup(const.BAG_KIND.BACKPACK)
end

self.button.IconBorder:SetBlendMode("BLEND")
self.frame:SetAlpha(1)
self.frame:Show()
self.button:Show()
Expand Down
28 changes: 24 additions & 4 deletions frames/grid.lua
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,8 @@ function gridProto:Sort(fn)
table.sort(self.cells, fn)
end

-- Draw will draw the grid.
---@return number width
---@return number height
function gridProto:Draw()
---@return number, number
function gridProto:stage()
for _, column in pairs(self.columns) do
column:RemoveAll()
column:Release()
Expand Down Expand Up @@ -186,7 +184,13 @@ function gridProto:Draw()
end
elseif self.compactStyle == const.GRID_COMPACT_STYLE.COMPACT then
end
return width, height
end

---@param width number
---@param height number
---@return number, number
function gridProto:render(width, height)
-- Draw all the columns and their cells.
for _, column in pairs(self.columns) do
local w, h = column:Draw(self.compactStyle)
Expand All @@ -202,6 +206,22 @@ function gridProto:Draw()
return width, height
end

-- Draw will draw the grid.
---@param callback? fun(width: number, height: number)
---@return number width
---@return number height
function gridProto:Draw(callback)
if not callback then
return self:render(self:stage())
end
local width, height = self:stage()
C_Timer.After(0, function()
width, height = self:render(width, height)
callback(width, height)
end)
return 0,0
end

-- Clear will remove and release all columns from the grid,
-- but will not release cells.
function gridProto:Clear()
Expand Down
9 changes: 9 additions & 0 deletions frames/item.lua
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ end
function itemFrame.itemProto:Lock()
if self.data.isItemEmpty or self.data.basic then return end
local itemLocation = ItemLocation:CreateFromBagAndSlot(self.data.bagid, self.data.slotid)
if itemLocation == nil or (itemLocation.IsValid and not itemLocation:IsValid()) then return end
C_Item.LockItem(itemLocation)
self.data.itemInfo.isLocked = true
SetItemButtonDesaturated(self.button, self.data.itemInfo.isLocked)
Expand All @@ -185,6 +186,7 @@ end
function itemFrame.itemProto:Unlock()
if self.data.isItemEmpty or self.data.basic then return end
local itemLocation = ItemLocation:CreateFromBagAndSlot(self.data.bagid, self.data.slotid)
if itemLocation == nil or (itemLocation.IsValid and not itemLocation:IsValid()) then return end
C_Item.UnlockItem(itemLocation)
self.data.itemInfo.isLocked = false
SetItemButtonDesaturated(self.button, self.data.itemInfo.isLocked)
Expand Down Expand Up @@ -263,6 +265,12 @@ function itemFrame.itemProto:SetItem(data)
self.button:SetMatchesSearch(not isFiltered)
self.button.minDisplayCount = 1

if self.kind == const.BAG_KIND.BANK then
self:AddToMasqueGroup(const.BAG_KIND.BANK)
else
self:AddToMasqueGroup(const.BAG_KIND.BACKPACK)
end
self.button.IconBorder:SetBlendMode("BLEND")
self:SetAlpha(1)
self.frame:Show()
self.button:Show()
Expand Down Expand Up @@ -318,6 +326,7 @@ function itemFrame.itemProto:SetFreeSlots(bagid, slotid, count, reagent)
else
self:AddToMasqueGroup(const.BAG_KIND.BACKPACK)
end
self.button.IconBorder:SetBlendMode("BLEND")

self.isFreeSlot = true
self.button.ItemSlotBackground:Show()
Expand Down
Loading

0 comments on commit 2438ec8

Please sign in to comment.