Thread Tools Display Modes
09-14-12, 04:48 PM   #1
sirann
A Flamescale Wyrmkin
Join Date: Mar 2007
Posts: 142
oUF_AuraBars

So I tried modifying/adding some code to this plug in. Essentially I'd like 4 aura blocks, player buffs, player debuffs, target buffs, target debuffs.

It seemed to me there was no easy way to separate buff from debuff other than to write a separate function that only chose buffs, and alter the current function to only choose debuffs.

The following is the code that I came up with:

http://pastebin.com/V0uFmRGD

Code:
Message: Interface\AddOns\oUF_AuraBars\oUF_AuraBars.lua:271: Usage: UnitDebuff("unit", [index] or ["name", "rank"][, "filter"])
Time: 09/14/12 18:46:54
Count: 1
Stack: [C]: ?
[C]: ?
Interface\FrameXML\RestrictedFrames.lua:604: in function <Interface\FrameXML\RestrictedFrames.lua:603>
Interface\FrameXML\RestrictedFrames.lua:742: in function `CallMethod'
[string "		local header = self:GetParent()..."]:44: in function <[string "		local header = self:GetParent()..."]:1>
(tail call): ?
[C]: ?
Interface\FrameXML\RestrictedExecution.lua:441: in function <Interface\FrameXML\RestrictedExecution.lua:412>
Interface\FrameXML\SecureGroupHeaders.lua:108: in function <Interface\FrameXML\SecureGroupHeaders.lua:102>
Interface\FrameXML\SecureGroupHeaders.lua:158: in function <Interface\FrameXML\SecureGroupHeaders.lua:115>
Interface\FrameXML\SecureGroupHeaders.lua:393: in function <Interface\FrameXML\SecureGroupHeaders.lua:382>
[C]: in function `Show'
Interface\FrameXML\SecureStateDriver.lua:100: in function <Interface\FrameXML\SecureStateDriver.lua:95>
Interface\FrameXML\SecureStateDriver.lua:164: in function <Interface\FrameXML\SecureStateDriver.lua:146>
[C]: in function `SetAttribute'
Interface\FrameXML\SecureStateDriver.lua:11: in function `RegisterAttributeDriver'
Interface\AddOns\oUF\ouf.lua:411: in function `SpawnHeader'
Interface\AddOns\oUF_Skaarj\layout.lua:442: in function `func'
Interface\AddOns\oUF\factory.lua:13: in function <Interface\AddOns\oUF\factory.lua:10>
(tail call): ?

Locals: <none>
Is the error I get upon login. Any help or ideas would be greatly appreciated
  Reply With Quote
09-14-12, 06:05 PM   #2
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
This is the problem:
Code:
oUF:AddElement('AuraBars', UpdateBuff, UpdateDebuff, EnableBuff, EnableDebuff, DisableBuff, DisableDeuff)
AddElement only accepts four arguments: (1) the element name, (2) the update function, (3) the enable function, and (4) the disable function. You can't register multiple elements in one AddElement call, or change the order of the arguments.

(Also, "DisableDeuff" is misspelled.)

If you want separate elements for buffs and debuffs, you need to add them separately:
Code:
oUF:AddElement('AuraBarsBuff', UpdateBuff, EnableBuff, DisableBuff)
oUF:AddElement('AuraBarsDebuff', UpdateDebuff, EnableDebuff, DisableDebuff)
Also, I'd suggest using the names "BuffBars" and "DebuffBars" instead of "AuraBarsBuff" and "AuraBarsDebuff"; they're shorter, and more descriptive.

Also, a lot of that code is really inefficient; I'm not sure whether that was in the original module, or part of your changes. Creating 2-82 tables every time the unit's auras change (1-41 in each UpdateBuff and UpdateDebuff) is basically a memory leak, and your module will consume memory like a horde of kids in a candy store. Reuse tables as much as possible, instead of simply discarding them and creating new ones.

Consistent indentation, and separating blocks with empty lines, will also help the code be more readable.

Compare your UpdateDebuff function with:
Code:
local debuffs = {} -- Only create one table, and reuse it.

local function UpdateDebuff(self, event, unit)
	if self.unit ~= unit then return end

	local auraBarsDebuff = self.AuraBarsDebuff

	local numDebuffs = 0
	for index = 1, 40 do
		local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellID = UnitDebuff(unit, index)
		if not name then break end
		if auraBarsDebuff.filter(self, unit, name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellID) then
			local t = debuffs[i] or {} -- Reuse tables where possible.
			t.name = name
			t.rank = rank
			t.icon = icon
			t.count = count
			t.debuffType = debuffType
			t.duration = duration
			t.expirationTime = expirationTime
			t.unitCaster = unitCaster
			t.isStealable = isStealable
			t.noTime = duration == 0 and expirationTime == 0
			t.filter = auraBarsDebuff.enemyAuraType
			t.shouldConsolidate = shouldConsolidate
			t.spellID = spellID
			debuffs[i] = t
			numDebuffs = i
		end
	end

	-- Clear unused debuff slots.
	for i = numDebuffs + 1, #debuffs do
		debuffs[i] = nil
		-- wipe(debuffs[i]) would be better, but then you would need to either:
		-- (a) accomodate empty tables in your sort function, putting them at the end,
		-- or (b) introduce a table pool and recycling scheme.
	end

	if auraBarsDebuff.sort then
		table.sort(debuffs, type(auraBarsDebuff.sort) == 'function' and auraBarsDebuff.sort or nil) -- no need to pass the global "sort"
	end

	local bars = auraBarsDebuff.bars
	for index = 1, #debuffs do
		if auraBarsDebuff:GetWidth() == 0 then
			break
		end

		local frame = bars[index]
		if not frame then
			frame = CreateAuraBar(self, index == 1 and auraBarsDebuff or bars[index - 1])
			bars[index] = frame
		end

		local bar = frame.statusBar
		frame.index = index

		local aura = debuffs[index]
		bar.aura = aura

		if aura.noTime then -- you already have a local aura, no need to spend an extra table lookup getting it out of bar.aura
			bar:SetMinMaxValues(0, 1)
			bar:SetValue(1)
		else
			if auraBarsDebuff.scaleTime then
				local maxvalue = math.min(auraBarsDebuff.scaleTime, bar.aura.duration)
				bar:SetMinMaxValues(0, maxvalue)
				bar:SetWidth((maxvalue/auraBarsDebuff.scaleTime)*((auraBarsDebuff.auraBarWidth or auraBarsDebuff:GetWidth())-(bar:GetHeight()+(auraBarsDebuff.gap or 0))))-- icon size + gap
			else
				bar:SetMinMaxValues(0, aura.duration)
			end
			bar:SetValue(aura.expirationTime - GetTime())
		end

		bar.icon:SetTexture(aura.icon)

		bar.spellname:SetText(aura.count > 1 and string.format("%s [%d]", bar.aura.name, aura.count) or aura.name)
		bar.spelltime:SetText(not bar.noTime and FormatTime(aura.expirationTime-GetTime()))

		local debuffType = aura.debuffType or 'none'
		r, g, b = DebuffTypeColor[debuffType].r, DebuffTypeColor[debuffType].g, DebuffTypeColor[debuffType].b
		if auraBarsDebuff.debuffColor then
			r, g, b = unpack(auraBarsDebuff.debuffColor)
		end
		bar:SetStatusBarColor(r, g, b)

		frame:Show()
	end

	for index = #auras + 1, #bars do
		bars[index]:Hide()
	end

	if auraBarsDebuff.PostUpdate then
		auraBarsDebuff:PostUpdate(event, unit)
	end
end
(Might be some drycoded errors in there; I didn't load it in-game.)
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.

Last edited by Phanx : 09-14-12 at 06:29 PM.
  Reply With Quote
09-15-12, 10:33 AM   #3
sirann
A Flamescale Wyrmkin
Join Date: Mar 2007
Posts: 142
First off, thank you for taking the time to fix and optimize my code that you'll never use. That's pretty awesome.

Secondly, I put your suggested code in, but I'm getting this pretty frustrating error. I can't seem to put my finger on what causes it. Sometimes I don't get it for a few minutes, sometimes it's as I start attacking something.

Code:
Message: Interface\AddOns\oUF_AuraBars\oUF_AuraBars.lua:331: attempt to index local 'aura' (a nil value)
Time: 09/15/12 19:54:32
Count: 31
Stack: Interface\AddOns\oUF_AuraBars\oUF_AuraBars.lua:331: in function `func'
Interface\AddOns\oUF\events.lua:14: in function <Interface\AddOns\oUF\events.lua:12>
(tail call): ?
and sometimes this:
Code:
Message: Interface\AddOns\oUF_AuraBars\oUF_AuraBars.lua:331: attempt to index local 'aura' (a nil value)
Time: 09/15/12 19:54:29
Count: 2
Stack: Interface\AddOns\oUF_AuraBars\oUF_AuraBars.lua:331: in function `func'
Interface\AddOns\oUF\ouf.lua:117: in function <Interface\AddOns\oUF\ouf.lua:110>
(tail call): ?
[C]: in function `Show'
Interface\FrameXML\SecureStateDriver.lua:83: in function <Interface\FrameXML\SecureStateDriver.lua:73>
Interface\FrameXML\SecureStateDriver.lua:137: in function <Interface\FrameXML\SecureStateDriver.lua:119>
Code:
Message: Interface\AddOns\oUF_AuraBars\oUF_AuraBars.lua:331: attempt to index local 'aura' (a nil value)
Time: 09/15/12 19:55:42
Count: 1
Stack: Interface\AddOns\oUF_AuraBars\oUF_AuraBars.lua:331: in function `func'
Interface\AddOns\oUF\ouf.lua:117: in function <Interface\AddOns\oUF\ouf.lua:110>
(tail call): ?
[C]: in function `CameraOrSelectOrMoveStop'
[string "CAMERAORSELECTORMOVE"]:4: in function <[string "CAMERAORSELECTORMOVE"]:1>
Code:
Message: Interface\AddOns\oUF_AuraBars\oUF_AuraBars.lua:163: attempt to index field 'aura' (a nil value)
Time: 09/15/12 19:55:48
Count: 306
Stack: Interface\AddOns\oUF_AuraBars\oUF_AuraBars.lua:163: in function <Interface\AddOns\oUF_AuraBars\oUF_AuraBars.lua:150>
Attached is the updated code. Please note, the bars work flawlessly (except getting them to grow up and down independently) unless this error happens.

http://pastebin.com/SK47CrRG

Last edited by sirann : 09-15-12 at 05:58 PM.
  Reply With Quote
09-16-12, 01:27 AM   #4
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Oh, I think I see what the problem is. Try this:
Code:
local debuffs = {}

local function UpdateDebuff(self, event, unit)
	if self.unit ~= unit then return end
	local DebuffBars = self.DebuffBars

	local numDebuffs = 0

	for i = 1, 40 do
		local name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellID = UnitDebuff(unit, i)
		if not name then break end

		if DebuffBars.filter(self, unit, name, rank, icon, count, debuffType, duration, expirationTime, unitCaster, isStealable, shouldConsolidate, spellID) then
			numDebuffs = numDebuffs + 1

			local t = debuffs[numDebuffs]
			if not t then
				t = table_create()
				debuffs[numDebuffs] = t
			end

			t.name = name
			t.rank = rank
			t.icon = icon
			t.count = count
			t.debuffType = debuffType
			t.duration = duration
			t.expirationTime = expirationTime
			t.unitCaster = unitCaster
			t.isStealable = isStealable
			t.noTime = duration == 0 and expirationTime == 0
			t.filter = DebuffBars.enemyAuraType
			t.shouldConsolidate = shouldConsolidate
			t.spellID = spellID
		end
	end

	for i = #debuffs, numDebuffs + 1, -1 do
		debuffs[i] = table_delete(debuffs[i])
	end

	table.sort(debuffs, DebuffBars.sort or default_sort)

	local bars = DebuffBars.bars
	for i = 1, numDebuffs do
		if DebuffBars:GetWidth() == 0 then
			break
		end

		local bar = bars[i]
		if not bar then
			bar = CreateAuraBar(self, i == 1 and DebuffBars or bars[i - 1])
			bars[i] = bar
		end
		bar:Show()

		local statusbar = bar.statusBar

		local debuff = debuffs[i]
		bar.aura = debuff

		if debuff.noTime then -- something weird here
			statusbar:SetMinMaxValues(0, 1)
			statusbar:SetValue(1)
		else
			if DebuffBars.scaleTime then
				local maxvalue = math.min(DebuffBars.scaleTime, debuff.duration)
				statusbar:SetMinMaxValues(0, maxvalue)
				statusbar:SetWidth((maxvalue/DebuffBars.scaleTime)*((DebuffBars.auraBarWidth or DebuffBars:GetWidth())-(statusbar:GetHeight()+(DebuffBars.gap or 0))))-- icon size + gap
			else
				statusbar:SetMinMaxValues(0, debuff.duration)
			end
			statusbar:SetValue(debuff.expirationTime - GetTime())
		end

		statusbar.icon:SetTexture(debuff.icon)
		statusbar.spellname:SetText(debuff.count > 1 and format("%s [%d]", debuff.name, debuff.count) or debuff.name)
		statusbar.spelltime:SetText(not debuff.noTime and FormatTime(debuff.expirationTime - GetTime()))

		local r, g, b
		local color = DebuffBars.debuffColor
		if color then
			r, g, b = color[1], color[2], color[3] -- don't use unpack; 3 table lookups is faster than 1 function call
		else
			color = DebuffTypeColor[debuff.debuffType or "none"]
			r, g, b = color.r, color.g, color.b
		end
		statusbar:SetStatusBarColor(r, g, b)
	end

	for i = numDebuffs + 1, #bars do
		local bar = bars[i]
		bar.aura = table_delete(bar.aura)
		bar:Hide()
	end
end
Also, add this anywhere before the UpdateBuff and UpdateDebuff functions:
Code:
local table_create, table_delete
do
	local pool = { }

	local function table_create()
		local t = next(pool)
		if t then
			pool[t] = nil
		end
		return t or {}
	end

	local function table_delete(t)
		if type(t) == "table" then
			for k, v in pairs(t) do
				t[k] = nil
			end
			t[true] = true
			t[true] = nil
			pool[t] = true
		end
		return nil
	end
end

local default_sort = function(a, b)
	if a.noTime then
		if b.noTime then
			-- both timeless, sort by name REVERSE
			return a.name < b.name
		else
			-- a timeless, b not
			return true
		end
	else
		if b.noTime then
			-- b timeless, a not
			return false
		else
			-- neither timeless, sort by expiry time
			return a.expires > b.expires
		end
	end
end
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.

Last edited by Phanx : 09-16-12 at 10:33 PM.
  Reply With Quote
09-16-12, 11:34 AM   #5
sirann
A Flamescale Wyrmkin
Join Date: Mar 2007
Posts: 142
Relevant section(s) can be found here:

http://pastebin.com/53q2b56C

targeting friendly or non-friendly throws this error: Message: Interface\AddOns\oUF_AuraBars\oUF_AuraBars.lua:257: attempt to call upvalue 'table_create' (a nil value)
  Reply With Quote
09-16-12, 10:33 PM   #6
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Code:
	local pool = { }

	local function table_new()
Change that to table_create... I need more caffeine or sleep or something. >_<
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
07-29-18, 06:08 PM   #7
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Nope, sorry.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote

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

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