Good afternoon,
I along with other users have noticed a recent change with BFA where certain quests utilize an attribute change on action buttons to show them. The best example of this is during the quest Righteous Retribution:
https://www.wowhead.com/quest=49741/...ution#comments
After mounting the gryphon Galeheart, you enter an Overridebar state. However, you initially don't have any buttons. The buttons are later added via an attribute change. Addons such as rActionBar, and I'm sure others, do not account for this, and assume the buttons will be there during their '_onstate-page' secure snippets. As such, I first came up with a solution to simply hooksecureframe a function that ran just as this occurred. While this code:
Lua Code:
hooksecurefunc('ActionBarController_UpdateAll', function()
for i = 1, 12 do
local button = _G['ActionButton'..i]
local overrideButton = _G['OverrideActionBarButton'..i]
local _, spellID
if overrideButton then
_, spellID = GetActionInfo(overrideButton.action)
end
if ((HasOverrideActionBar() or HasVehicleActionBar()) and (spellID and spellID > 0)) or (not HasOverrideActionBar() and not HasVehicleActionBar()) then
button:SetAttribute('statehidden', false)
button:Show()
else
button:SetAttribute('statehidden', true)
button:Hide()
end
end
end)
works wonderfully, it causes taint, as I'm changing the attributes of buttons outside of a secureframe.
As such, and not knowing much about SecureHandler*Template coding, I embarked on this endeavor. I came up with the following code:
Lua Code:
local AttributeChangedFrame = CreateFrame('frame', nil, UIParent, 'SecureHandlerAttributeTemplate')
for i = 1, 12 do
local button = _G['ActionButton'..i]
AttributeChangedFrame:SetFrameRef('ActionButton'..i, button)
end
for i = 1, 6 do
local overrideButton = _G['OverrideActionBarButton'..i]
AttributeChangedFrame:SetFrameRef('OverrideActionBarButton'..i, overrideButton)
end
AttributeChangedFrame:Execute([[
buttons = table.new()
for i = 1, 12 do
table.insert(buttons, self:GetFrameRef('ActionButton'..i))
end
overridebuttons = table.new()
for i = 1, 6 do
table.insert(overridebuttons, self:GetFrameRef('OverrideActionBarButton'..i))
end
]])
for i = 1, 6 do
local overrideButton = _G['OverrideActionBarButton'..i]
overrideButton:HookScript('OnAttributeChanged', function()
AttributeChangedFrame:Execute[[
for i = 1, 6 do
if not overridebuttons[i]:GetAttribute('statehidden') then
buttons[i]:SetAttribute('statehidden', false)
buttons[i]:Show()
else
buttons[i]:SetAttribute('statehidden', true)
buttons[i]:Hide()
end
end
]]
end)
local button = _G['ActionButton'..i]
button:HookScript('OnAttributeChanged', function()
AttributeChangedFrame:Execute[[
for i = 1, 6 do
if (not HasOverrideActionBar() and not HasVehicleActionBar() and buttons[i]:GetAttribute('statehidden')) then
buttons[i]:SetAttribute('statehidden', false)
buttons[i]:Show()
end
end
]]
end)
end
The basic idea is to hook into the OnAttributeChanged functions for both the normal actionbar button (ActionButton1-12) and the OverrideActionBarButton1-6. Here, I would execute secure code to change the attributes of the buttons to properly display the actionbutton when you "page" into an actionbar but the buttons come later. Just looking at this code, I feel like it is not great. I'm sure it can be better optimized, but I wanted to reach out to people who perhaps have better experience with SecureHandlers to determine my next steps.
Any feedback is greatly appreciated. Please note, the bottom code functions precisely how I'd like it to. It is taint free, and handles every scenario I can think of without fail. All I'm asking is for optimization so it doesn't run 36 times instead of 6 for example.