Thread Tools Display Modes
07-11-16, 10:37 AM   #1
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Run secure code

Is it possible to securely run a code snippet based on events like "GROUP_ROSTER_UPDATE" in combat and modify a position of another secure frame? I've tried everything but no luck so far.
  Reply With Quote
07-11-16, 11:24 AM   #2
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,879
I would imagine that is exactly the kind of thing they don't want you to do so you can't move buttons and the like under your cursor etc.
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.
  Reply With Quote
07-11-16, 11:50 AM   #3
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
Originally Posted by Resike View Post
Is it possible to securely run a code snippet based on events like "GROUP_ROSTER_UPDATE" in combat and modify a position of another secure frame? I've tried everything but no luck so far.
You can run code in response to someone joining or leaving the group because you can set a unit watch or state driver for any valid unit ID, eg. [raid1,exists].

If this is for unit frames you can just use a group header to control the layout.
  Reply With Quote
07-11-16, 12:28 PM   #4
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by semlar View Post
You can run code in response to someone joining or leaving the group because you can set a unit watch or state driver for any valid unit ID, eg. [raid1,exists].

If this is for unit frames you can just use a group header to control the layout.
Hmm gonna try this. I guess you just have to set up the snippet descending like raid40 to raid1.
  Reply With Quote
07-11-16, 12:33 PM   #5
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,879
Would this be able to actually move a secure frame in combat?
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.
  Reply With Quote
07-11-16, 01:07 PM   #6
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by Fizzlemizz View Post
Would this be able to actually move a secure frame in combat?
Yes, but only when a player joins/leaves the group.

I basically want to use this to setpoint the pet header frames based on the size/width of the current raid frame.
  Reply With Quote
07-11-16, 01:18 PM   #7
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,879
Well there you go, I must stop doing that assuming thingy.
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.
  Reply With Quote
07-11-16, 02:03 PM   #8
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by Fizzlemizz View Post
Well there you go, I must stop doing that assuming thingy.
It's still not perfect because the state driver won't get triggered when someone rearrange the groups, like when you have 3 full groups and someone gets pulled to the group 4.
  Reply With Quote
07-11-16, 02:15 PM   #9
Fizzlemizz
I did that?
 
Fizzlemizz's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Dec 2011
Posts: 1,879
Originally Posted by Resike View Post
It's still not perfect because the state driver won't get triggered when someone rearrange the groups, like when you have 3 full groups and someone gets pulled to the group 4.
Good to know, something to play with.
__________________
Fizzlemizz
Maintainer of Discord Unit Frames and Discord Art.
Author of FauxMazzle, FauxMazzleHUD and Move Pad Plus.
  Reply With Quote
07-11-16, 09:19 PM   #10
kurapica.igas
A Chromatic Dragonspawn
Join Date: Aug 2011
Posts: 152
The SecureGroupHeader is using "GROUP_ROSTER_UPDATE" to update itself, you may give it's unit buttons a "refreshUnitChange" snippet where you can move other secure frames.

You can create a SecureGroupHeader and throw it out of the screen, it's what I do for my raid panels, I don't want to use it, but based on it, I can refresh the raid panels without taint.
  Reply With Quote
07-12-16, 12:59 AM   #11
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by kurapica.igas View Post
The SecureGroupHeader is using "GROUP_ROSTER_UPDATE" to update itself, you may give it's unit buttons a "refreshUnitChange" snippet where you can move other secure frames.

You can create a SecureGroupHeader and throw it out of the screen, it's what I do for my raid panels, I don't want to use it, but based on it, I can refresh the raid panels without taint.
Could you give an example for this? To be honest this was the first way i tried to do it, however the group headers won't accept a :SetFrameRef, and :Execute snippets by default, so that was my main issue.
  Reply With Quote
07-12-16, 02:31 AM   #12
kurapica.igas
A Chromatic Dragonspawn
Join Date: Aug 2011
Posts: 152
Since the group header is a strict secure frame, don't know why you can't use SecureHandlerExecute.

My code is at IGAS-IFGroup, but it may be hard for reading.

I'll try to explain the details :

Don't use the group header's auto generated unit buttons, control them is too difficult. I only use them to notify me their units is changed or more unit buttons is created.

Here is the code for the group header(I try to convert my code to common one and only those code related to the group header, so it is not run-able) :

Lua Code:
  1. local grpHeader = CreateFrame("Frame", "MyGrpHeader", UIParent, "SecureGroupHeaderTemplate")
  2.  
  3. -- Some helper methods
  4. function grpHeader:Execute(body) return SecureHandlerExecute(self, body) end
  5. function grpHeader:WrapScript(frame, script, preBody, postBody) return SecureHandlerWrapScript(frame, script, self, preBody, postBody) end
  6. function grpHeader:SetFrameRef(label, refFrame) return SecureHandlerSetFrameRef(self, label, refFrame) end
  7.  
  8. -- Init the header
  9. grpHeader:Execute[=[
  10.     Manager = self -- Register self to avoid some bugs
  11.  
  12.     UnitFrames = newtable()  -- Our own unit buttons, may be your secure frames
  13.     ShadowFrames = newtable()-- The auto-generated unit buttons
  14.  
  15.     -- The snippet for auto-generated unit buttons's unit changed event
  16.     -- This is only used when you entering the game world during a combat
  17.     refreshUnitChange = [[
  18.         local unit = self:GetAttribute("unit")
  19.         local frame = self:GetAttribute("UnitFrame")
  20.  
  21.         -- Here you can handle the thing like moving, refreshing and etc
  22.         -- I just refresh the real unit button's unit
  23.         if frame then
  24.             frame:SetAttribute("unit", unit) -- Refresh the real unit button's unit
  25.         end
  26.     ]]
  27. ]=]
  28.  
  29. -- Use SecureHandlerAttributeTemplate for unit buttons
  30. grpHeader:SetAttribute("template", "SecureHandlerAttributeTemplate")
  31.  
  32. -- The init code for each auto-generated unit buttons
  33. grpHeader:SetAttribute("initialConfigFunction", [[
  34.     tinsert(ShadowFrames, self)
  35.  
  36.     -- I don't really need to show those auto-generated buttons
  37.     self:SetWidth(0)
  38.     self:SetHeight(0)
  39.     self:SetID(#ShadowFrames)
  40.  
  41.     -- Binding
  42.     local frame = UnitFrames[#ShadowFrames]
  43.  
  44.     self:SetAttribute("Manager", Manager)
  45.  
  46.     if frame then
  47.         self:SetAttribute("UnitFrame", frame)
  48.     end
  49.  
  50.     -- Only for entering game during combat
  51.     -- refreshUnitChange won't fire when the unit is set to nil, so it's not a good choice
  52.     self:SetAttribute("refreshUnitChange", refreshUnitChange)
  53.  
  54.     -- Call an un-secure method to notify new unit button is generated
  55.     Manager:CallMethod("UpdateUnitCount", #ShadowFrames)
  56. ]])
  57.  
  58. -- Throw out of the screen, but keep it shown
  59. grpHeader:SetPoint("TOPRIGHT", WorldFrame, "TOPLEFT")
  60.  
  61. -- The real snippet for unit changing
  62. -- We don't use refreshUnitChange because it won't fire when the unit is changed to nil
  63. local _Onattributechanged = [[
  64.     if name == "unit" then
  65.         if type(value) == "string" then
  66.             value = strlower(value)
  67.         else
  68.             value = nil
  69.         end
  70.  
  71.         local frame = self:GetAttribute("UnitFrame")
  72.  
  73.         -- Here you can handle the thing like moving, refreshing and etc
  74.         if frame then
  75.             frame:SetAttribute("unit", value)
  76.         end
  77.     end
  78. ]]
  79.  
  80. local function GenerateUnitFrames(self, count)
  81.     -- re-init the auto-generated unit button
  82.     local child = self:GetAttribute("child"..count)
  83.  
  84.     child:SetAttribute("refreshUnitChange", nil)    -- only used for the entering game combat
  85.     child:SetAttribute("_onattributechanged", _Onattributechanged)
  86.  
  87.     -- Other code to generate the unit frames, just ignored here
  88. end
  89.  
  90. function grpHeader:UpdateUnitCount(count)
  91.     if InCombatLockdown() then
  92.         -- Task.NoCombatCall is used to call the function wit args until the player is out of combat
  93.         return Task.NoCombatCall(GenerateUnitFrames, self, count)
  94.     else
  95.         -- Wait the SecureGroupHeader finished the init
  96.         -- Task.DelayCall is used to call the function with args after several time
  97.         return Task.DelayCall(0.1, Task.NoCombatCall, GenerateUnitFrames, self, count)
  98.     end
  99. end

Here is code for register other secure frames :
Lua Code:
  1. function grpHeader:RegisterUnitFrame(frame)
  2.     self:SetFrameRef("UnitFrame", frame)
  3.     self:Execute[=[
  4.         local frame = Manager:GetFrameRef("UnitFrame")
  5.  
  6.         if frame then
  7.             tinsert(UnitFrames, frame)
  8.  
  9.             -- Binding
  10.             local shadow = ShadowFrames[#UnitFrames]
  11.  
  12.             if shadow then
  13.                 shadow:SetAttribute("UnitFrame", frame)
  14.                 frame:SetAttribute("unit", shadow:GetAttribute("unit"))
  15.             end
  16.         end
  17.     ]=]
  18. end

Here I only use them to refresh their units, I use other features(like wrap the OnShow and OnHide) to control their positions.
  Reply With Quote
07-12-16, 04:01 AM   #13
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Okay everything seems to be working, up to where you get the child value with self:GetAttribute("child"..count), but the child there is nil for some reason.
  Reply With Quote
07-12-16, 04:12 AM   #14
kurapica.igas
A Chromatic Dragonspawn
Join Date: Aug 2011
Posts: 152
When the UpdateUnitCount is called, the "child"..count attribute is not set, so you only get nil value

You could see I have a delay to call the GenerateUnitFrames.
Lua Code:
  1. if InCombatLockdown() then
  2.         -- Task.NoCombatCall is used to call the function wit args until the player is out of combat
  3.         return Task.NoCombatCall(GenerateUnitFrames, self, count)
  4.     else
  5.         -- Wait the SecureGroupHeader finished the init
  6.         -- Task.DelayCall is used to call the function with args after several time
  7.         return Task.DelayCall(0.1, Task.NoCombatCall, GenerateUnitFrames, self, count)
  8.     end

If the player is in combat, I can just wait the combat is ended and do the call. If the player is not in combat, I wait 0.1 sec then call the function.
  Reply With Quote
07-12-16, 04:23 AM   #15
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
Originally Posted by kurapica.igas View Post
When the UpdateUnitCount is called, the "child"..count attribute is not set, so you only get nil value

You could see I have a delay to call the GenerateUnitFrames.
Lua Code:
  1. if InCombatLockdown() then
  2.         -- Task.NoCombatCall is used to call the function wit args until the player is out of combat
  3.         return Task.NoCombatCall(GenerateUnitFrames, self, count)
  4.     else
  5.         -- Wait the SecureGroupHeader finished the init
  6.         -- Task.DelayCall is used to call the function with args after several time
  7.         return Task.DelayCall(0.1, Task.NoCombatCall, GenerateUnitFrames, self, count)
  8.     end

If the player is in combat, I can just wait the combat is ended and do the call. If the player is not in combat, I wait 0.1 sec then call the function.
I see, the problem was with my throttle updater. But as i see at the end of the day, the _Onattributechanged can't get triggered in combat without taint. And that would be the whole point.
  Reply With Quote
07-12-16, 04:46 AM   #16
kurapica.igas
A Chromatic Dragonspawn
Join Date: Aug 2011
Posts: 152
No, it's set to "_onattributechanged", so it's secure snippet called by the auto-generated unit buttons, and it'll be triggered during combat(since you can't re-define it during combat).

It's environment is the button's, so you can't access the table like UnitFrames. You should get the Manager and use the Manager to run snippets in the manager's environment like :

Lua Code:
  1. grpHeader:SetAttribute("refreshUnitFrames", [[
  2.     for _, frm in ipairs(UnitFrames) do
  3.         -- ...
  4.     end
  5. ]])
  6.  
  7. local _Onattributechanged = [[
  8.     if name == "unit" then
  9.         if type(value) == "string" then
  10.             value = strlower(value)
  11.         else
  12.             value = nil
  13.         end
  14.  
  15.         -- Use Manager to call the snippet that in the manager's secure environment
  16.         self:GetAttribute("Manager"):RunAttribute("refreshUnitFrames")
  17.     end
  18. ]]
  Reply With Quote
07-12-16, 04:54 AM   #17
kurapica.igas
A Chromatic Dragonspawn
Join Date: Aug 2011
Posts: 152
If you _Onattributechanged is not running, you may check the line

Lua Code:
  1. grpHeader:SetAttribute("template", "SecureHandlerAttributeTemplate")

It's used to make sure the unit buttons will fire the _Onattributechanged
  Reply With Quote
07-12-16, 06:01 AM   #18
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
I still get taint in combat:

Lua Code:
  1. local grpHeader = CreateFrame("Frame", "MyGrpHeader", UIParent, "SecureGroupHeaderTemplate")
  2.  
  3. grpHeader:SetAttribute("showRaid", true)
  4.  
  5. --grpHeader:SetAttribute("useparent-unit", true)
  6. grpHeader:SetAttribute("strictFiltering", nil)
  7. grpHeader:SetAttribute("startingIndex", 1)
  8. grpHeader:SetAttribute("maxColumns", 8)
  9. grpHeader:SetAttribute("unitsPerColumn", 5)
  10.  
  11. grpHeader:SetAttribute("sortMethod", nil)
  12. --grpHeader:SetAttribute("sortMethod", "NAME")
  13.  
  14. --grpHeader:SetAttribute("minWidth", 50)
  15. --grpHeader:SetAttribute("minHeight", 25)
  16. grpHeader:SetAttribute("minWidth", 0)
  17. grpHeader:SetAttribute("minHeight", 0)
  18.  
  19. grpHeader:SetAttribute("xOffset", 0)
  20. grpHeader:SetAttribute("yOffset", 0)
  21. grpHeader:SetAttribute("point", "TOP")
  22.  
  23. grpHeader:SetAttribute("columnSpacing", 1)
  24. grpHeader:SetAttribute("columnAnchorPoint", "LEFT")
  25.  
  26. --grpHeader:SetAttribute("groupBy", "ASSIGNEDROLE")
  27. --grpHeader:SetAttribute("groupingOrder", "TANK,HEALER,DAMAGER,NONE")
  28. grpHeader:SetAttribute("groupBy", "GROUP")
  29. grpHeader:SetAttribute("groupingOrder", "1,2,3,4,5,6,7,8")
  30. --grpHeader:SetAttribute("groupBy", nil)
  31. --grpHeader:SetAttribute("groupingOrder", nil)
  32.  
  33. grpHeader:SetAttribute("groupFilter", nil)
  34.  
  35. grpHeader:SetAttribute("template", "SecureHandlerAttributeTemplate")
  36.  
  37. grpHeader:SetAttribute("initial-unitWatch", true)
  38.  
  39. grpHeader:SetAttribute("style-width", 68)
  40. grpHeader:SetAttribute("style-height", 41)
  41. grpHeader:SetAttribute("style-scale", 1)
  42.  
  43. -- Some helper methods
  44. function grpHeader:Execute(body) return SecureHandlerExecute(self, body) end
  45. function grpHeader:WrapScript(frame, script, preBody, postBody) return SecureHandlerWrapScript(frame, script, self, preBody, postBody) end
  46. function grpHeader:SetFrameRef(label, refFrame) return SecureHandlerSetFrameRef(self, label, refFrame) end
  47.  
  48. -- Init the header
  49. grpHeader:Execute[=[
  50.     Manager = self -- Register self to avoid some bugs
  51.  
  52.     UnitFrames = newtable()  -- Our own unit buttons, may be your secure frames
  53.     ShadowFrames = newtable()-- The auto-generated unit buttons
  54.  
  55.     -- The snippet for auto-generated unit buttons's unit changed event
  56.     -- This is only used when you entering the game world during a combat
  57.     refreshUnitChange = [[
  58.         local unit = self:GetAttribute("unit")
  59.         local frame = self:GetAttribute("UnitFrame")
  60.  
  61.         -- Here you can handle the thing like moving, refreshing and etc
  62.         -- I just refresh the real unit button's unit
  63.         if frame then
  64.             frame:SetAttribute("unit", unit) -- Refresh the real unit button's unit
  65.         end
  66.     ]]
  67. ]=]
  68.  
  69. -- Use SecureHandlerAttributeTemplate for unit buttons
  70. grpHeader:SetAttribute("template", "SecureHandlerAttributeTemplate")
  71.  
  72. -- The init code for each auto-generated unit buttons
  73. grpHeader:SetAttribute("initialConfigFunction", [[
  74.     tinsert(ShadowFrames, self)
  75.  
  76.     -- I don't really need to show those auto-generated buttons
  77.     self:SetWidth(0)
  78.     self:SetHeight(0)
  79.     self:SetID(#ShadowFrames)
  80.  
  81.     -- Binding
  82.     local frame = UnitFrames[#ShadowFrames]
  83.  
  84.     self:SetAttribute("Manager", Manager)
  85.  
  86.     if frame then
  87.         self:SetAttribute("UnitFrame", frame)
  88.     end
  89.  
  90.     -- Only for entering game during combat
  91.     -- refreshUnitChange won't fire when the unit is set to nil, so it's not a good choice
  92.     self:SetAttribute("refreshUnitChange", refreshUnitChange)
  93.  
  94.     -- Call an un-secure method to notify new unit button is generated
  95.     Manager:CallMethod("UpdateUnitCount", #ShadowFrames)
  96. ]])
  97.  
  98. -- Throw out of the screen, but keep it shown
  99. grpHeader:SetPoint("TOPRIGHT", WorldFrame, "TOPLEFT")
  100.  
  101. grpHeader:SetAttribute("refreshUnitFrames", [[
  102.     print("HELLO")
  103. ]])
  104.  
  105. -- The real snippet for unit changing
  106. -- We don't use refreshUnitChange because it won't fire when the unit is changed to nil
  107. local _Onattributechanged = [[
  108.     if name == "unit" then
  109.         if type(value) == "string" then
  110.             value = strlower(value)
  111.         else
  112.             value = nil
  113.         end
  114.         print(value)
  115.         self:GetAttribute("Manager"):RunAttribute("refreshUnitFrames")
  116.     end
  117. ]]
  118.  
  119. local function GenerateUnitFrames(self, count)
  120.     -- re-init the auto-generated unit button
  121.     local child = self:GetAttribute("child"..count)
  122.  
  123.     child:SetAttribute("refreshUnitChange", nil)    -- only used for the entering game combat
  124.     child:SetAttribute("_onattributechanged", _Onattributechanged)
  125.  
  126.     -- Other code to generate the unit frames, just ignored here
  127. end
  128.  
  129. function grpHeader:UpdateUnitCount(count)
  130.     local timer = 0
  131.     grpHeader:SetScript("OnUpdate", function(self, elapsed)
  132.         timer = timer + elapsed
  133.         if timer < 1 then
  134.             return
  135.         end
  136.         timer = 0
  137.        
  138.         GenerateUnitFrames(self, count)
  139.     end)
  140. end
  141.  
  142. grpHeader:Show()

What i ment when someone joins my group while i'm in combat, then you can't set it's child:SetAttribute("_onattributechanged", _Onattributechanged).

Last edited by Resike : 07-12-16 at 06:16 AM.
  Reply With Quote
07-12-16, 06:27 AM   #19
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
I found a way to do this:

You set your frame references to the header [SecureRaidGroupHeaderTemplate] frame itself, then and you wrap a script to every UnitFrame [SecureUnitButtonTemplate] created by initialConfigFunction, then you can reach you reference frames with the :GetParent() call like this:

Lua Code:
  1. SecureHandlerWrapScript(frame, "OnAttributeChanged", header, [[
  2.     local petheader1 = self:GetParent():GetFrameRef("ZPerlRaidPetsGroup1")
  3.     if not petheader1 then
  4.         return
  5.     end
  6.     --print(self:GetName(), petheader1)
  7.  
  8.     local groups = 0
  9.  
  10.     for i = 1, 8 do
  11.         if self:GetParent():GetFrameRef("ZPerlRaidHeader"..i.."UnitButton1"):IsShown() then
  12.             groups = groups + 1
  13.         end
  14.     end
  15.  
  16.     local x = (8 - groups) / 10
  17.     print(groups, x)
  18.  
  19.     local point, relativeTo, relativePoint, xOfs, yOfs = petheader1:GetPoint(1)
  20.  
  21.     if xOfs ~= x then
  22.         petheader1:SetPoint("TOPLEFT", self:GetParent():GetFrameRef("ZPerlRaidHeader8"), "TOPRIGHT", -x, 0)
  23.     end
  24. ]])

You just need to make sure to pre-create every UnitFrame OnLoad with this trick:

Lua Code:
  1. local maxColumns = self.header:GetAttribute("maxColumns") or 1
  2. local unitsPerColumn = self.header:GetAttribute("unitsPerColumn") or 5
  3. local startingIndex = self.header:GetAttribute("startingIndex")
  4. local maxUnits = maxColumns * unitsPerColumn
  5.  
  6. self.self.header:Show()
  7. self.self.header:SetAttribute("startingIndex", - maxUnits + 1)
  8. self.self.header:SetAttribute("startingIndex", startingIndex)

This method triggers the changes with every joined/left and moved units. However it gets triggered fuckzillion times and me no likey that.

Then boom you can do any secure changes you want on "GROUP_ROSTER_UPDATE". Just need to look into that how to filter that swarming OnAttributeChanged a bit more.

I'm also not sure yet if this shit worth the hassle performace wise.

Last edited by Resike : 07-12-16 at 06:31 AM.
  Reply With Quote
07-12-16, 06:32 AM   #20
kurapica.igas
A Chromatic Dragonspawn
Join Date: Aug 2011
Posts: 152
Well, you can't call the GenerateUnitFrames during combat, the GenerateUnitFrames is used to replace the "refreshUnitChange" to "_onattributechanged", here is a simple version

Lua Code:
  1. local _Task = {}
  2.  
  3. grpHeader:SetScript("OnUpdate", function(self, elapsed)
  4.     if not InCombatLockdown() and #_Task > 0 then
  5.         for _, cnt in ipairs(_Task) do
  6.             GenerateUnitFrames(self, count)
  7.         end
  8.         wipe(_Task)
  9.     end
  10. end)
  11.  
  12. function grpHeader:UpdateUnitCount(count)
  13.     tinsert(_Task, count)
  14. end

If you don't create buttons based on the auto-generated unit buttons, the refreshUnitChange and _onattributechanged will do the same work, only the refreshUnitChange won't be fired when a unit is set to nil, so I replace it with a better one when out of combat.

Last edited by kurapica.igas : 07-12-16 at 06:35 AM.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Run secure code


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off