Reply
 
Thread Tools Display Modes
Old 04-16-13, 03:01 PM   #1
Rainrider
A Rage Talon Dragon Guard
Join Date: Nov 2008
Posts: 314
Sorting auras with gap by time left

I have buffs and debuffs displayed together and separated by a gap for the pet frame. I create custom timers for auras (see CreateAuraTimer) by setting an OnUpdate script to the aura button in PostUpdateIcon. I then sort the auras at PreSetPosition (see SortAuras). In order to not sort the gap aura so buffs and debuff remain separated I nil timeLeft in PostUpdateGapIcon. Well, I do something wrong, as buffs and debuffs get mixed up when sorted. Would by thankful for pointers on that.

Last edited by Rainrider : 04-20-13 at 11:38 AM. Reason: Updated links to point to my topic branch
Rainrider is offline   Reply With Quote
Old 04-17-13, 07:22 AM   #2
haste
Featured Artist
 
haste's Avatar
Premium Member
Featured
Join Date: Dec 2005
Posts: 979
It's your sort function. Sorting .Auras is a real PITA.

You basically need to implement a sort function that sorts buffs and debuffs for themselves, while maintaining the gap between and handles auras without a timer correctly.

You can simplify it quite a bit by mandating the auras to always have a timer. Something like this might work:
Lua Code:
  1. function(a, b)
  2.    if(not a:IsShown()) then
  3.       return b.isDebuff
  4.    elseif(not b:IsShown()) then
  5.      return not a.isDebuff
  6.    elseif(a.isDebuff == b.isDebuff) then
  7.       return a.timeLeft < b.timeLeft
  8.    else
  9.       return a:GetID() < b:GetID()
  10.    end
  11. end
__________________
「貴方は1人じゃないよ」
haste is offline   Reply With Quote
Old 04-17-13, 07:30 PM   #3
Rainrider
A Rage Talon Dragon Guard
Join Date: Nov 2008
Posts: 314
It doesn't work. Used the code you provided as follows:
Code:
local SortAuras = function(a, b)
	if (not a or not b) then return end

	if(not a:IsShown()) then
		return b.isDebuff
	elseif(not b:IsShown()) then
		return not a.isDebuff
	elseif(a.isDebuff == b.isDebuff) then
		return a.timeLeft > b.timeLeft
	else
		return a:GetID() > b:GetID()
	end
end
and set timeLeft for the gap aura to -5 in PostUpdateGapAura (I noticed timeLeft could be negative (-0.062 the smallest I got and it happened very seldom, probably some OnUpdate lag)). Some screenshots of the results are attached. Auras without borders are buffs.

Click image for larger version

Name:	buffs and dubuffs swapped.jpg
Views:	35
Size:	6.6 KB
ID:	7681

Click image for larger version

Name:	mixed with spaces.jpg
Views:	23
Size:	6.3 KB
ID:	7682

Click image for larger version

Name:	not mixed with spaces.jpg
Views:	24
Size:	6.3 KB
ID:	7683

Edit:
Also got the following after some time.
55x oUF-1.6.4\elements\aura.lua:307: attempt to index field "?" (a nil value)
oUF-1.6.4\elements\aura.lua:307: in function <oUF\elements\aura.lua:287>
oUF-1.6.4\elements\aura.lua:361: in function "?"
oUF-1.6.4\events.lua:69: in function <oUF\events.lua:62>

Locals:
...
and
invalid order function for sorting
which is triggered by lua's ltablib.c

Sorry for editing this that often

Last edited by Rainrider : 04-17-13 at 08:10 PM.
Rainrider is offline   Reply With Quote
Old 04-17-13, 10:41 PM   #4
Rainrider
A Rage Talon Dragon Guard
Join Date: Nov 2008
Posts: 314
Hm, I assumed that the gap aura is always a buff which it isn't. So me setting timeLeft to a negative value caused the gap to be sorted wrongly if debuff. Changed that to
Code:
aura.timeLeft = aura.isDebuff and math.huge or -5
and now this
Code:
local SortAuras = function(a, b)
	if (a and b) then
		if (a:IsShown() and b:IsShown()) then
			if (a.isDebuff == b.isDebuff) then
				return a.timeLeft > b.timeLeft
			end
		elseif (a:IsShown()) then
			return true
		end
	end
end
kind of works. There is an issue sometimes when a buff gets applied when there are debuffs present and it looks like this: DE DE BU GAP BU BU

I'll take another look at it later today or tomorrow. Your solution still produces mixed up auras as in the screenshot, it's just the errors that are now gone.
Rainrider is offline   Reply With Quote
Old 04-20-13, 12:09 AM   #5
Rainrider
A Rage Talon Dragon Guard
Join Date: Nov 2008
Posts: 314
I simply cannot understand why my sorting function would not work. It mixes buffs and debuffs together. I'll just post my assumptions. Please tell me where I'm wrong:

The sorting function.

The aura button properties (duration and expTime are the 6th and 7th return of UnitAura):
IsShown() return value:
- true for buffs, debuffs and the gap aura
- nil for other created but unused aura buttons

isDebuff value:
- nil for buffs
- true for debuffs
- true or nil for the gap aura and other created but unused aura buttons

timeLeft value (set by my layout):
- expTime - GetTime() for buffs and debuffs if duration and duration > 0
- math.huge for buffs and debuffs if not duration or duration <= 0
- -5 for gap aura if not isDebuff (so it's the buff with the lowest timeLeft)
- math.huge for gap aura if isDebuff == true (so it's the debuff with the highest timeLeft)
- whatever from the above from when the button was last used for unused created aura buttons

The aura array before PreSetPosition (PreSetPosition is where we are supposed to sort):
[buffs (index sorted)][gap aura][debuffs (index sorted)][unused created icons]

The aura array is without holes.

The sorting function gets two parameters a and b, where a always has a higher array index than b. The sorting function returning true means a should come before b.

PreSetPosition should return a range (2 array indices) in which SetPosition operates to (re)anchor the corresponding auras. I return 1 and auras.createdIcons so it reanchors all of them (wouldn't it be even better to use auras.visibleAuras?).

Also why do I need elseif (a:IsShown()) then in my sorting function? It should not be possible to have a hidden aura button in between. I added that as per haste's advice here.

A short video of the results so far:

A topic branch of my layout could be reviewed on github.
Rainrider is offline   Reply With Quote
Old 04-24-13, 03:12 PM   #6
Rainrider
A Rage Talon Dragon Guard
Join Date: Nov 2008
Posts: 314
I would really love to get some feedback on that.
Rainrider is offline   Reply With Quote
Old 04-27-13, 05:07 AM   #7
haste
Featured Artist
 
haste's Avatar
Premium Member
Featured
Join Date: Dec 2005
Posts: 979
A lot on my plate currently, but I'll try to come with some feedback during this weekend.
__________________
「貴方は1人じゃないよ」
haste is offline   Reply With Quote
Old 04-28-13, 08:31 AM   #8
Rainrider
A Rage Talon Dragon Guard
Join Date: Nov 2008
Posts: 314
I appreciate that, haste, take your time with it. I'd rather enjoy my free weekend if I were you
Rainrider is offline   Reply With Quote
Old 04-28-13, 12:53 PM   #9
Rainrider
A Rage Talon Dragon Guard
Join Date: Nov 2008
Posts: 314
Hm, it seems my sorting function somehow mixes buffs and debuffs when it compares with the gap aura.

I used the following to debug:
lua Code:
  1. local PrintAuras = function(Auras)
  2.     local button
  3.     local text = {}
  4.     for i = 1, #Auras do
  5.         button = Auras[i]
  6.         if (not button) then
  7.             tinsert(text, i, "NC") -- not created
  8.         elseif (button:IsShown()) then
  9.             if (not button.isDebuff) then -- buff
  10.                 if (button.timeLeft == -5) then
  11.                     tinsert(text, i, "|cff00ff00GAP|r")
  12.                 else
  13.                     tinsert(text, i, "|cff00ff00B|r")
  14.                 end
  15.             else -- debuff
  16.                 if (button.timeLeft == math.huge) then
  17.                     tinsert(text, i, "|cffff0000GAP|r")
  18.                 else
  19.                     tinsert(text, i, "|cffff0000D|r")
  20.                 end
  21.             end
  22.         else
  23.             tinsert(text, i, "U") -- unused, hidden
  24.         end
  25.     end
  26.     return table.concat(text, "-")
  27. end
  28.  
  29. local PreSetPosition = function(Auras)
  30.     local pre = PrintAuras(Auras)
  31.     table.sort(Auras, SortAuras)
  32.     local post = PrintAuras(Auras)
  33.     if (pre ~= post) then print(pre, "\n", post) end
  34.     return 1, Auras.createdIcons
  35. end

and got the following output:
B-GAP-D-D (pre sort)
B-D-GAP-D (post sort)

B-B-B-GAP-D-D (pre sort)
B-B-GAP-B-D-D (post sort)

B-B-B-GAP-D-D (pre sort)
B-B-D-B-GAP-D (post sort)

B-B-B-GAP-D-D (pre sort)
B-B-D-B-GAP-D (post sort)

B-B-B-GAP-D-D-D (pre sort)
B-B-B-D-GAP-D-D (post sort)

B-B-B-GAP-D-D-U (pre sort)
B-B-GAP-D-B-D-U (post sort)

B-B-B-GAP-D-U-U (pre sort)
B-B-GAP-D-B-U-U (post sort)

B-B-GAP-D-U-U-U (pre sort)
B-GAP-D-B-U-U-U (post sort)

B-B-GAP-D-D-U-U (pre sort)
B-GAP-D-D-B-U-U (post sort)

B-B-GAP-D-D-U-U (pre sort)
B-GAP-D-D-B-U-U (post sort)

B-B-GAP-D-D-D-U (pre sort)
B-GAP-D-D-B-D-U (post sort)

B-B-GAP-D-D-U-U (pre sort)
B-GAP-D-D-B-U-U (post sort)

B-B-GAP-D-U-U-U (pre sort)
B-GAP-D-B-U-U-U (post sort)

B-B-GAP-D-D-U-U (pre sort)
B-GAP-D-D-B-U-U (post sort)

B-B-GAP-D-U-U-U (pre sort)
B-GAP-D-B-U-U-U (post sort)

B-B-GAP-D-D-U-U (pre sort)
B-GAP-D-D-B-U-U (post sort)

B-B-GAP-D-D-D-U (pre sort)
B-GAP-D-D-B-D-U (post sort)

B-B-GAP-D-D-U-U (pre sort)
B-GAP-D-D-B-U-U (post sort)

B-B-GAP-D-U-U-U (pre sort)
B-GAP-D-B-U-U-U (post sort)

B-B-GAP-D-D-U-U (pre sort)
B-GAP-D-D-B-U-U (post sort)

B-B-GAP-D-U-U-U (pre sort)
B-GAP-D-B-U-U-U (post sort)
With either only buffs or only debuffs or just 1 buff and 1 debuff present it works well. With multiple buffs and debuffs it gets mixed up but not always. It's hard to tell how to exactly reproduce.

Buffs used: Threatening Presence, Unending Breath, Health Funnel, First Aid
Debuffs used: Recently Bandaged, Dazed, Shrill Cry

To apply the above I go to Silken Fields in Valley of the Four Winds and let my Voidwalker taunt Tawnyhide Doe.

Any ideas?
Rainrider is offline   Reply With Quote
Old 04-30-13, 11:52 AM   #10
Rainrider
A Rage Talon Dragon Guard
Join Date: Nov 2008
Posts: 314
Head -> table (not in the lua sense)

Lua Code:
  1. local SortAuras = function(a, b)
  2.     if (a:IsShown() and b:IsShown()) then
  3.         if (a.isDebuff == b.isDebuff) then
  4.             return a.timeLeft > b.timeLeft
  5.         elseif (not a.isDebuff) then
  6.             return b.isDebuff
  7.         end
  8.     elseif (a:IsShown()) then
  9.         return true
  10.     end
  11. end

I'm not quite sure why debuffs come before buffs when I get an ordered auras table from oUF, but I blame table.sort for it and me not being able to understand how it exactly works. But fair enough, tell her to put buffs before debuffs and get done with it.
Rainrider is offline   Reply With Quote
Reply

Go BackWoWInterface » Featured Projects » oUF (Otravi Unit Frames) » Sorting auras with gap by time left

Thread Tools
Display Modes

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