Thread Tools Display Modes
03-15-09, 07:36 PM   #1
PProvost
A Deviate Faerie Dragon
AddOn Author - Click to view addons
Join Date: Aug 2006
Posts: 13
Proposal - Embeddable oUF Extension Mods

Lately I've been looking in to embedding oUF into my layout to make a self-contained addon. Haste supports this quite well with his metadata trick at the top of each file in oUF:

oUF.lua:
Code:
local parent = debugstack():match[[\AddOns\(.-)\]]
local global = GetAddOnMetadata(parent, 'X-oUF')
assert(global, 'X-oUF needs to be defined in the parent add-on.')


All the files in oUF\elements:

Code:
local parent = debugstack():match[[\AddOns\(.-)\]]
local global = GetAddOnMetadata(parent, 'X-oUF')
assert(global, 'X-oUF needs to be defined in the parent add-on.')
local oUF = _G[global]
This is a slick trick because it lets me embed haste's oUF code inside my addon, and all I have to do is put this in my addon's TOC (assuming I've put oUF in a subfolder called oUFembed):

MyAddon\MyAddon.toc:
Code:
## X-oUF: oUFembed
oUFembed/oUF.xml
There is no required relationship between the two names in used in the TOC, but I tend to keep it that way. The X-oUF metadata tag instructs the embedded oUF to publish itself into the global namespace using the provided name. That is the important bit. The second line simply brings in the embedded oUF files.

Then, at the top of my layout file, I can reference the embedded oUF like this:

MyAddon\layout.lua:
Code:
local oUF = oUFembed
oUFembed = nil
Now anywhere in my code that I reference the symbol oUF, I will get the embedded one. Perfect! I can test against a specific version of oUF and embed it within my addon.

The problem comes when I want to embed an oUF extension written by someone else. Let's use as an example oUF_Banzai by Rabbit. If I wanted to embed it into my addon, it will fail. Oh, it won't crash, but it also won't work.

Why?

Because it makes an assumption that oUF is installed as an independent addon, and that it is published on the global symbol oUF and not oUFembed as I did above.

The first non-comment line of code enforces it like this:

oUF_Banzai.lua:
Code:
if not oUF then return end
I understand why Rabbit did this, but I think with a simple change, we can make it so oUF_Banzai (or any other oUF Extension) can work standalone or embedded. And this requires no change to oUF and should let the extensions continue to work standalone OR embedded.

If the top lines in the oUF_Banzai were as follows instead of the simple check used currently, the embedded version would work:

Proposed oUF_Banzai.lua:
Code:
local parent = debugstack():match[[\AddOns\(.-)\]]
local global = GetAddOnMetadata(parent, 'X-oUF')
local oUF = _G[global] or oUF
assert(oUF, 'oUF not loaded')
Here I take advantage of the scheme used by Haste already in oUF. The only issue, which haste and I have discussed but for which there is no good workaround, is one of path length. If you embed oUF too deeply in your addon, you can hit some kind of a max-path issue in the WoW runtime, and the string returned by debugstack() will not contain a full path.

So what I'd like to propose / ask is that all oUF extension authors add these four lines of code to the top of their extensions. It makes it easier to embed and causes no harm to your existing code.

Question/comments appreciated.
  Reply With Quote
03-16-09, 11:52 AM   #2
Slakah
A Molten Giant
 
Slakah's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2007
Posts: 863
I already do this in oUF_Fader (at least I think I do).

Although I don't like your generic global name, why not use <MyAddon>oUF instead of oUFembed, as your current name could cause some conflicts at a later date.
  Reply With Quote
03-16-09, 02:20 PM   #3
PProvost
A Deviate Faerie Dragon
AddOn Author - Click to view addons
Join Date: Aug 2006
Posts: 13
Originally Posted by Slakah View Post
I already do this in oUF_Fader (at least I think I do).

Although I don't like your generic global name, why not use <MyAddon>oUF instead of oUFembed, as your current name could cause some conflicts at a later date.
In fact I don't use that global name, I follow the pattern you describe. My point was simply that the name the addon author chooses is HIS NAME and not anyone else's.

Thanks for calling that out.
  Reply With Quote
03-16-09, 02:22 PM   #4
PProvost
A Deviate Faerie Dragon
AddOn Author - Click to view addons
Join Date: Aug 2006
Posts: 13
Originally Posted by Slakah View Post
I already do this in oUF_Fader (at least I think I do).

Although I don't like your generic global name, why not use <MyAddon>oUF instead of oUFembed, as your current name could cause some conflicts at a later date.
Ummm... doesn't look like you do in oUF_Fader by the way:

oUF_Fader.lua Line 1:
Code:
if not oUF then return end
This makes oUF_Fader unembeddable.
  Reply With Quote
03-16-09, 02:55 PM   #5
p3lim
A Pyroguard Emberseer
 
p3lim's Avatar
AddOn Author - Click to view addons
Join Date: Feb 2007
Posts: 1,710
All my plug-ins support embedding.
  Reply With Quote
03-16-09, 03:02 PM   #6
PProvost
A Deviate Faerie Dragon
AddOn Author - Click to view addons
Join Date: Aug 2006
Posts: 13
Originally Posted by p3lim View Post
All my plug-ins support embedding.
Not that I can see.

In both oUF_BarFader and oUF_RuneBar you reference the global symbol oUF (bad) without any assert or check (good). In an embedded scenario the global oUF symbol probably doesn't exist unless the layout author republished it into global scope.

The part you're missing is having this at the top of the lua file:

Code:
local parent = debugstack():match[[\AddOns\(.-)\]]
local global = GetAddOnMetadata(parent, 'X-oUF')
local oUF = _G[global] or oUF
assert(oUF, 'oUF not loaded')
  Reply With Quote
03-16-09, 03:18 PM   #7
Slakah
A Molten Giant
 
Slakah's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2007
Posts: 863
Meh I did it for my local version, I just forgot to update it :P.
  Reply With Quote
12-11-09, 12:02 PM   #8
Freebaser
A Molten Kobold Bandit
 
Freebaser's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2008
Posts: 135
This should be updated to the new system.
  Reply With Quote
12-11-09, 01:10 PM   #9
yj589794
A Rage Talon Dragon Guard
AddOn Author - Click to view addons
Join Date: Mar 2009
Posts: 314
Within oUF_HealComm4 I currently use the following which if safe for servers running patch 3.2.X and patch 3.3:

Code:
local oUF
local parent
if(...) then
	parent = ...
else
	parent = debugstack():match[[\AddOns\(.-)\]]
end

local global = GetAddOnMetadata(parent, 'X-oUF')
assert(global, 'X-oUF needs to be defined in the parent add-on.')
if(...) then
	local _, ns = ...
	oUF = ns.oUF or _G[global]
else
	oUF = _G[global]
end

a version that supports only servers running patch 3.3 would be:
Code:
local parent, ns = ...
local global = GetAddOnMetadata(parent, 'X-oUF')
assert(global, 'X-oUF needs to be defined in the parent add-on.')
local oUF = ns.oUF or _G[global]

I think all current live servers run patch 3.3. It just depends on what patch the China servers will be at if they ever get running again.
  Reply With Quote
12-11-09, 03:19 PM   #10
haste
Featured Artist
 
haste's Avatar
Premium Member
Featured
Join Date: Dec 2005
Posts: 1,027
Last time I talked to someone playing on China they were still on TBC, but that was around the start of November. Most of the people who care aren't playing on the Chinese servers anyway.

Anyway, just do:
Lua Code:
  1. local _, ns = ...
  2. local oUF = ns.oUF or oUF
  3.  
  4. assert(oUF, "<name> was unable to locate oUF install.")
No use support 3.2 anymore.
__________________
「貴方は1人じゃないよ」
  Reply With Quote

WoWInterface » Featured Projects » oUF (Otravi Unit Frames) » Proposal - Embeddable oUF Extension Mods


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