Thread Tools Display Modes
09-22-09, 02:53 AM   #1
Dawn
A Molten Giant
 
Dawn's Avatar
AddOn Author - Click to view addons
Join Date: May 2006
Posts: 918
oUF_AuraSort

What happened to it? I can't find it anymore and the latest version (seems to be from november 2008) I found on my HDD spits out a lua error @
Code:
    oUF:SetAuraPosition(icons, visible)
Is there a new or better way to sort auras?
  Reply With Quote
09-22-09, 05:12 AM   #2
wurmfood
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Apr 2009
Posts: 122
How are you wanting to sort them? Assuming it's by time left, I use the following in preAuraSetPosition:

Code:
for i=1, #buffs do
	if( buffs[i].timeLeft == nil ) then
		buffs[i].timeLeft = 0
	end
end
table.sort(buffs, function(a,b) return a.timeLeft > b.timeLeft end)
The checking for nil avoids problems with buffs that don't have a time (auras).
  Reply With Quote
09-22-09, 10:01 AM   #3
Dawn
A Molten Giant
 
Dawn's Avatar
AddOn Author - Click to view addons
Join Date: May 2006
Posts: 918
"AuraSort" sorted buffs by "your own first" and/or time left, afaik. Which is what I was aiming for, too. Time left will do it, though. I'll try that.

E: Not quite sure where to put this, though.
  Reply With Quote
09-22-09, 11:06 AM   #4
p3lim
A Pyroguard Emberseer
 
p3lim's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2007
Posts: 1,710
That is a very bad implementation wurmfood, the icons can jump and hide alot.
  Reply With Quote
09-22-09, 12:09 PM   #5
Dawn
A Molten Giant
 
Dawn's Avatar
AddOn Author - Click to view addons
Join Date: May 2006
Posts: 918
That's how AuraSort did it. However it seems broken since 3.1 or 3.0, not quite sure.

Code:
-- Compares two icons for sorting
local function sortIcons(a, b)
    local auras = a:GetParent()
    local frame = auras:GetParent()
    local settings = frame.sortAuras
    local unit, filter = frame.unit, auras.filter
        
    local nameA, _, _, countA, debuffTypeA, _, expiresA, isMineA, isStealableA = UnitAura(unit, a.oUF_AuraSort_index, filter)
    local nameB, _, _, countB, debuffTypeB, _, expiresB, isMineB, isStealableB = UnitAura(unit, b.oUF_AuraSort_index, filter)
        
    if(not expiresA) then expiresA = -1 end
    if(not expiresB) then expiresB = -1 end

    local result

    if(settings.selfFirst) then
        if(isMineA == isMineB) then
            result = expiresA > expiresB
        else
            result = isMineA and true or false
        end
    else
        result = expiresA > expiresB
    end
    
    if(settings.reverse) then result = not result end
    return result
end

-- Overrides the layouts SetAuraPosition function with a new one that will sort the auras
local function OverrideSetAuraPosition(self, icons, visible)
    if(self.oUF_AuraSort_SetAuraPosition) then self.oUF_AuraSort_SetAuraPosition(self, icons, visible) end -- If layout has its own SetAuraPosition function already then call it
    if(visible <= 0) then return end
    
    -- Make a copy of the icon list and then sort it
    local sorted = {}
    
    for i = 1, visible do
        icons[i].oUF_AuraSort_index = i
        sorted[i] = icons[i]
    end
    sort(sorted, sortIcons)
    
    -- Iterate through each icon then find the match for its ID in the new sorted list. Once found reset the order of the icons with the final icon order
    local final = {}
    for i = 1, visible do final[i] = sorted[icons[i]:GetID()] end
    for i = 1, visible do icons[i] = final[i] end
    
    oUF:SetAuraPosition(icons, visible)
end

-- Applies aura sorting to a oUF layout frame
local function applyAuraSorting(object)
    if(not object.sortAuras) then return end
    
    -- Store any predefined functions layout has, if any
    if(object.SetAuraPosition) then object.oUF_AuraSort_SetAuraPosition = object.SetAuraPosition end
    
    -- Override old functions with new ones
    object.SetAuraPosition = OverrideSetAuraPosition
end

local f = CreateFrame("Frame", nil)
f:SetScript("OnEvent", function(s, e)
    for _, object in pairs(oUF.objects) do applyAuraSorting(object) end
end)
f:RegisterEvent("PLAYER_LOGIN")
  Reply With Quote
09-22-09, 02:47 PM   #6
wurmfood
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Apr 2009
Posts: 122
p3lim, I honestly don't know of a better way to do it. At some point the table has to be sorted and I didn't really see a better place or way to do it. I'd love to see another suggestion.

Dawn, it shouldn't be too hard to take what's there and make it work. The most important part seems to be the sort function and the way it chooses to sort them.

There's two parts that I used to make this work. The first was to copy over the customFilter from aura.lua to my layout. I just added "icon.timeLeft = timeLeft" just before the "return true". (The time left on the auras doesn't seem to be preserved anywhere else, though I may have missed it.)

Then I created a preAuraSetPosition function. Here's the relevant part:
Code:
local preAuraSetPosition = function(self, buffs, max)
	local visBuffs = 0
	for i=1, #buffs do
		if( buffs[i].timeLeft == nil ) then
			buffs[i].timeLeft = 0
		end
	end
	
	table.sort(buffs, function(a,b) return a.timeLeft > b.timeLeft end)
end
Then, near the end of the style, I added this:
Code:
self.CustomAuraFilter = customFilter
self.PreAuraSetPosition = preAuraSetPosition
I think what you want can be done with the same thing, but a small change. The function is expecting isMine, which was taken out a while ago from the UnitAuras function, replaced with the name of the caster. Some tweaks need to be done to the sort to make it work, but then you can just pass the function as the second argument of table.sort and it should work.
  Reply With Quote
09-22-09, 03:50 PM   #7
p3lim
A Pyroguard Emberseer
 
p3lim's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2007
Posts: 1,710
Originally Posted by wurmfood View Post
p3lim, I honestly don't know of a better way to do it. At some point the table has to be sorted and I didn't really see a better place or way to do it. I'd love to see another suggestion.

Dawn, it shouldn't be too hard to take what's there and make it work. The most important part seems to be the sort function and the way it chooses to sort them.

There's two parts that I used to make this work. The first was to copy over the customFilter from aura.lua to my layout. I just added "icon.timeLeft = timeLeft" just before the "return true". (The time left on the auras doesn't seem to be preserved anywhere else, though I may have missed it.)

Then I created a preAuraSetPosition function. Here's the relevant part:
Code:
local preAuraSetPosition = function(self, buffs, max)
	local visBuffs = 0
	for i=1, #buffs do
		if( buffs[i].timeLeft == nil ) then
			buffs[i].timeLeft = 0
		end
	end
	
	table.sort(buffs, function(a,b) return a.timeLeft > b.timeLeft end)
end
Then, near the end of the style, I added this:
Code:
self.CustomAuraFilter = customFilter
self.PreAuraSetPosition = preAuraSetPosition
I think what you want can be done with the same thing, but a small change. The function is expecting isMine, which was taken out a while ago from the UnitAuras function, replaced with the name of the caster. Some tweaks need to be done to the sort to make it work, but then you can just pass the function as the second argument of table.sort and it should work.
Replacing the whole SetAuraPositions would be way better.
Anyways, you forgot you need to set the .timeLeft somewhere.
Also, Im guessing you followed my code to make the timers in the first place, you don't really need to check for nil time if you do things properly with the initial creation of time text.
  Reply With Quote
09-22-09, 04:07 PM   #8
wurmfood
A Flamescale Wyrmkin
AddOn Author - Click to view addons
Join Date: Apr 2009
Posts: 122
Hadn't looked at your layout yet, but will do so. I'm always open to better ways of doing thing.

I'm setting timeLeft in the customFilter function as it's the only good place I know of to set it. The only reason I'm checking it for nil is for the sorting. I'm letting OmniCC take care of the text part, so I don't worry about it.
  Reply With Quote
09-22-09, 04:07 PM   #9
Dawn
A Molten Giant
 
Dawn's Avatar
AddOn Author - Click to view addons
Join Date: May 2006
Posts: 918
Err, ... you lost me. Sorting by time left would be really enough for me. I don't really need to sort my own auras first. That is just a bonus I could live without.

From what I understand, I should copy the whole SetAuraPosition code from aura.lua ...

Code:
local SetAuraPosition = function(self, icons, x)
	if(icons and x > 0) then
		local col = 0
		local row = 0
		local spacing = icons.spacing or 0
		local gap = icons.gap
		local size = (icons.size or 16) + spacing
		local anchor = icons.initialAnchor or "BOTTOMLEFT"
		local growthx = (icons["growth-x"] == "LEFT" and -1) or 1
		local growthy = (icons["growth-y"] == "DOWN" and -1) or 1
		local cols = math.floor(icons:GetWidth() / size + .5)
		local rows = math.floor(icons:GetHeight() / size + .5)

		for i = 1, x do
			local button = icons[i]
			if(button and button:IsShown()) then
				if(gap and button.debuff) then
					if(col > 0) then
						col = col + 1
					end

					gap = false
				end

				if(col >= cols) then
					col = 0
					row = row + 1
				end
				button:ClearAllPoints()
				button:SetPoint(anchor, icons, anchor, col * size * growthx, row * size * growthy)

				col = col + 1
			end
		end
	end
end
and somehow implement
Code:
	local visBuffs = 0
	for i=1, #buffs do
		if( buffs[i].timeLeft == nil ) then
			buffs[i].timeLeft = 0
		end
	end
	
	table.sort(buffs, function(a,b) return a.timeLeft > b.timeLeft end)
?

Edit: I have timeleft set here, maybe I can use this to also sort the buffs?

Code:
local function auraUpdateTime(self, elapsed)
	self.timeLeft = math.max(self.timeLeft - elapsed, 0)
	
	local timeFormat, value = SecondsToTimeAbbrev(math.floor(self.timeLeft))
	
	if type(value) == 'number' then
		self.time:SetFormattedText(timeFormat, value)
	else
		self.timeLeft = nil
		self.time:SetText()
		
		self:SetScript('OnUpdate', nil)
	end
end

local function auraUpdateTimeShort(self, elapsed)
	self.timeLeft = math.max(self.timeLeft - elapsed, 0)
	self.time:SetText(self.timeLeft < 120 and math.floor(self.timeLeft) or '')
end

local function auraUpdateIcon(self, icons, unit, icon, index, offset, filter, isDebuff)
	if(unit) or (self:GetParent():GetName():match"oUF_Party") then 
		local _, _, _, _, _, duration, timeLeft = UnitAura(unit, index, filter)
		
		if duration > 0 and timeLeft then
			icon.timeLeft = timeLeft - GetTime()
			
			if unit == 'player' then
				--icon:SetScript('OnUpdate', auraUpdateTime)
				icon:SetScript('OnUpdate', auraUpdateTimeShort)
			else
				icon:SetScript('OnUpdate', auraUpdateTimeShort)
			end
		else
			icon.timeLeft = nil
			icon.time:SetText()
			
			icon:SetScript('OnUpdate', nil)
		end
	end
end

Last edited by Dawn : 09-22-09 at 04:10 PM.
  Reply With Quote
09-22-09, 07:15 PM   #10
haste
Featured Artist
 
haste's Avatar
Premium Member
Featured
Join Date: Dec 2005
Posts: 1,027
Originally Posted by p3lim View Post
That is a very bad implementation wurmfood, the icons can jump and hide alot.
Originally Posted by p3lim View Post
Replacing the whole SetAuraPositions would be way better.
:PreAuraSetPosition() exists for one thing and one thing only -- to allow manipulation of the indexes before the positioning is done, without having to replace the entire :SetAuraPosition() function.

Calling his sort method a bad implementation is also plain wrong. Are you really expecting someone to implement id consistent time sort?

But now that you've said what you have. Then please explain to the crowd here exactly why re-implementing the entire :SetAuraPosition() is a better solution that just sorting the table before it's positioned.

It would also be beneficial that you post your far superior sort algorithm that respects icon position and sort order.

Enough bashing of you for now at least:
The way oUF updates auras is quite straight forward, but it has a lot of different ways to manipulate it. A really short example of why it's beneficial to use :PreAuraSetPosition() would be:

lua Code:
  1. local PreAuraSetPosition = function(self, a, n)
  2.    for i = 1, n/2 do
  3.       local j = n-i+1
  4.       a[i], a[j] = a[j], a[i]
  5.    end
  6. end

What the function above those is basically invert the aura sort direction. Now compare it with what you would have to do with :SetAuraPosition():
lua Code:
  1. local SetAuraPosition = function(self, icons, x)
  2.     if(icons and x > 0) then
  3.         local col = 0
  4.         local row = 0
  5.         local spacing = icons.spacing or 0
  6.         local gap = icons.gap
  7.         local size = (icons.size or 16) + spacing
  8.         local anchor = icons.initialAnchor or "BOTTOMLEFT"
  9.         local growthx = (icons["growth-x"] == "LEFT" and -1) or 1
  10.         local growthy = (icons["growth-y"] == "DOWN" and -1) or 1
  11.         local cols = math.floor(icons:GetWidth() / size + .5)
  12.         local rows = math.floor(icons:GetHeight() / size + .5)
  13.  
  14.         for i = x, 1 do
  15.             local button = icons[i]
  16.             if(button and button:IsShown()) then
  17.                 if(gap and button.debuff) then
  18.                     if(col > 0) then
  19.                         col = col + 1
  20.                     end
  21.  
  22.                     gap = false
  23.                 end
  24.  
  25.                 if(col >= cols) then
  26.                     col = 0
  27.                     row = row + 1
  28.                 end
  29.                 button:ClearAllPoints()
  30.                 button:SetPoint(anchor, icons, anchor, col * size * growthx, row * size * growthy)
  31.  
  32.                 col = col + 1
  33.             end
  34.         end
  35.     end
  36. end
This is ofc the default :SetAuraPosition() function copy/pasted and one line changed. What we could do now is have a long argument about how the :PreAuraSetPosition() is an extra for loop + function call, but that isn't really a problem at all. And if you think it is, then it's time to write your own unit frame add-on from scratch, because you won't like how auras in oUF are coded in general.

Enough about that: To get your timer based sort you'll have to:
1. Add a start or end time variable to the icon, so that you can compare it. There's several ways to do this: CreateAuraIcon, PostCreateAuraIcon, CustomAuraFilter, PostUpdateAuraIcon, PreAuraSetPosition. CustomAuraFilter is most likely the best way to do this, as you have direct access to the variables you need.
2. Use :PreAuraSetPosition() to re-arrange the icon list. It's table.sort() compatible for a reason.
3. ???
4. Profit!

What you don't need for just aura sorting like this however is: an OnUpdate, duration, endTime and startTime is way more that you need for this. If you want to update some text, then you obviously will need this ofc tho'...
__________________
「貴方は1人じゃないよ」
  Reply With Quote
09-23-09, 08:04 AM   #11
p3lim
A Pyroguard Emberseer
 
p3lim's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2007
Posts: 1,710
I just said what my experience with his code was, the buffs jumped alot and were placed way off the frame by index.

Saying that replacing SetAuraPosition could be better is just a guess, as I have not looked at this that much.
  Reply With Quote
09-23-09, 10:36 AM   #12
Dawn
A Molten Giant
 
Dawn's Avatar
AddOn Author - Click to view addons
Join Date: May 2006
Posts: 918
Ok, it's working.... most of the time.

I added
Code:
local preAuraSetPosition = function(self, buffs, max)
	local visBuffs = 0
	for i=1, #buffs do
		if( buffs[i].timeLeft == nil ) then
			buffs[i].timeLeft = 0
		end
	end
	
	table.sort(buffs, function(a,b) return a.timeLeft > b.timeLeft end)
end
and at the end of the style
Code:
	self.PreAuraSetPosition = preAuraSetPosition
Most of the time it works, but for some reason it can bug out. Which results in buff icons overlapping/hiding/disappearing (for buffs that are still active).

I didn't copy the customaurafilter to add "icon.timeLeft = timeLeft", because like I said above, I'm having some timeleft code already as part of my aura duration update code. However it's a little different. Instead of
Code:
icon.timeLeft = timeLeft
it is
Code:
 	self.timeLeft = math.max(self.timeLeft - elapsed, 0)
Could this be the reason?

Btw, reload UI fixes the bug, until it bugs out again (can't determine for what reason it bugs out, yet).
  Reply With Quote
09-23-09, 01:14 PM   #13
haste
Featured Artist
 
haste's Avatar
Premium Member
Featured
Join Date: Dec 2005
Posts: 1,027
I would recommend using starttime or endtime instead of timeleft. The main reason for this is the fact that it's updated by your OnUpdate all the time, and it usually contains more decimals than any sane person would use . It's really why I recommended customaurafilter in the first place.
__________________
「貴方は1人じゃないよ」
  Reply With Quote
09-24-09, 09:25 PM   #14
Dawn
A Molten Giant
 
Dawn's Avatar
AddOn Author - Click to view addons
Join Date: May 2006
Posts: 918
Mhm, seems like I can only get this to work with timeleft and preAuraSetPosition, which is buggy as hell.

I tried to fix AuraSort, but can't figure out why it
Code:
... attempt to call method 'SetAuraPosition' (a nil value)
for line
Code:
 oUF:SetAuraPosition(icons, visible)
neither.
  Reply With Quote
09-25-09, 07:10 AM   #15
haste
Featured Artist
 
haste's Avatar
Premium Member
Featured
Join Date: Dec 2005
Posts: 1,027
:SetAuraPosition() only exists on the frames as of 1.3.0. It was the breaking change in that release I believe. It would really be better to update AuraSort to use the new API instead of just replacing the old one tho'.
__________________
「貴方は1人じゃないよ」
  Reply With Quote
09-25-09, 11:41 AM   #16
Dawn
A Molten Giant
 
Dawn's Avatar
AddOn Author - Click to view addons
Join Date: May 2006
Posts: 918
Yeah, I've pm'ed Atrophia (author of AuraSort), but I don't know if he's still around and/or willing to maintain it, since he even removed it from WoWi after he started to work on his own unitframes.
  Reply With Quote

WoWInterface » Featured Projects » oUF (Otravi Unit Frames) » oUF_AuraSort


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