Thread Tools Display Modes
01-27-10, 08:12 PM   #21
Slakah
A Molten Giant
 
Slakah's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2007
Posts: 863
Originally Posted by Cralor View Post
I don't know much about metatables, but trusting your knowledge with them, the above does print "Frames share same metatable".
nah I was being special :P. This would work.

Code:
if getmetatable(CreateFrame("Frame")).__index == getmetatable(CreateFrame("Frame")).__index then
	print("Frames share same metatable")
else
	print("Slakah fails and is special")
end
  Reply With Quote
01-27-10, 11:52 PM   #22
nightcracker
A Molten Giant
 
nightcracker's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 716
Originally Posted by Slakah View Post
nah I was being special :P. This would work.

Code:
if getmetatable(CreateFrame("Frame")).__index == getmetatable(CreateFrame("Frame")).__index then
	print("Frames share same metatable")
else
	print("Slakah fails and is special")
end
THAT works, FRAMES have shared metatables, but you seam to forget:
Code:
Animation
AnimationGroup
Button
CheckButton
ColorSelect
ControlPoint
Cooldown
DressUpModel
EditBox
Font
FontInstance
FontString
GameTooltip
LayeredRegion
MessageFrame
Minimap
Model
MovieFrame
ParentedObject
PlayerModel
QuestPOIFrame
ScriptObject
ScrollFrame
ScrollingMessageFrame
SimpleHTML
Slider
StatusBar
TabardModel
Texture
So:
Code:
local f = CreateFrame("Frame")
local tex = f:CreateTexture()
print(getmetatable(f).__index==getmetatable(tex).__index)

RESULT: False.
There is an other difference between this and OmniCC, OmniCC securehooks the "SetCooldown" function. Once they got their hands on the setcooldown function it works for ALL metatables, because metatables do have shared functions. But if you add a function to "Frame" it's not automaticly added to "texture".
__________________
Three things are certain,
Death, taxes and site not found,
You, victim of one.

Last edited by nightcracker : 01-28-10 at 12:00 AM.
  Reply With Quote
01-28-10, 05:53 AM   #23
Slakah
A Molten Giant
 
Slakah's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2007
Posts: 863
Originally Posted by nightcracker View Post
There is an other difference between this and OmniCC, OmniCC securehooks the "SetCooldown" function. Once they got their hands on the setcooldown function it works for ALL metatables, because metatables do have shared functions. But if you add a function to "Frame" it's not automaticly added to "texture".
I never suggested that frames of different types have the same metatable:
You don't need to at all, all frames of the same type share the same metatable
Anyway looping through a few frame types would be a lot easier than going through _G.
  Reply With Quote
01-28-10, 06:54 AM   #24
nightcracker
A Molten Giant
 
nightcracker's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 716
Originally Posted by Slakah View Post
I never suggested that frames of different types have the same metatable:


Anyway looping through a few frame types would be a lot easier than going through _G.
Finally the answer :P

Originally Posted by nightcracker View Post
Should I loop _G like this for gathering all metatables, or should I run this once, write the names down, and always use these(subject to changes/deletion of frames by blizzard)?

lua Code:
  1. local metatables = {}
  2. for key, val in pairs(_G) do
  3.     if type(val)=="table" and val.GetObjectType then
  4.         obj = val:GetObjectType()
  5.         if not metatables[obj] then
  6.             metatables[obj] = getmetatable(val).__index
  7.         end
  8.     end
  9. end
__________________
Three things are certain,
Death, taxes and site not found,
You, victim of one.
  Reply With Quote
01-28-10, 07:06 AM   #25
haste
Featured Artist
 
haste's Avatar
Premium Member
Featured
Join Date: Dec 2005
Posts: 1,027
Oh joy. Yet another library putting semi-arbitrary functions into on bloated scope while modifying the global environment for everyone. I'm guessing AlarLib was starting to feel lonely...

That out of the way; What your doing is really just a bad idea. Your plan to modify the metatable for _all_ objects is just asking for collisions to happen. The chance of it happening increases with every reference you add to the tables.

If you want something like this it's a lot better to just apply the functions to your frames and leave the rest of us alone. Your going to step on a lot of toes if you go with your current way of doing it.
__________________
「貴方は1人じゃないよ」
  Reply With Quote
01-28-10, 08:17 AM   #26
nightcracker
A Molten Giant
 
nightcracker's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 716
Originally Posted by haste View Post
Oh joy. Yet another library putting semi-arbitrary functions into on bloated scope while modifying the global environment for everyone. I'm guessing AlarLib was starting to feel lonely...

That out of the way; What your doing is really just a bad idea. Your plan to modify the metatable for _all_ objects is just asking for collisions to happen. The chance of it happening increases with every reference you add to the tables.

If you want something like this it's a lot better to just apply the functions to your frames and leave the rest of us alone. Your going to step on a lot of toes if you go with your current way of doing it.
Please, just give me ONE example.
__________________
Three things are certain,
Death, taxes and site not found,
You, victim of one.
  Reply With Quote
01-28-10, 08:35 AM   #27
haste
Featured Artist
 
haste's Avatar
Premium Member
Featured
Join Date: Dec 2005
Posts: 1,027
Originally Posted by nightcracker View Post
Please, just give me ONE example.
A collision will happen when someone sets option functions on their frame, which happen to have the same name as yours. If these are used for any type of validation you'll be wrecking havoc on the code following.

Changing the core metatables to include "features" for _everyone_ regardless if they want to have them or not is a horrible design choice. Especially for a "library".
__________________
「貴方は1人じゃないよ」
  Reply With Quote
01-28-10, 09:07 AM   #28
nightcracker
A Molten Giant
 
nightcracker's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 716
Originally Posted by haste View Post
A collision will happen when someone sets option functions on their frame, which happen to have the same name as yours. If these are used for any type of validation you'll be wrecking havoc on the code following.

Changing the core metatables to include "features" for _everyone_ regardless if they want to have them or not is a horrible design choice. Especially for a "library".
Hmm, collisions won't happen, because that's how metatable.__index works, but I respect your opinion, so my question is, how SHOULD I implement it? Like this?

Code:
local lib = LibStub:GetLibrary("LibCoreAPI")
local f = lib:CreateFrame("Frame")
But I hate that I can't use methods like estroy on the Micromenu, for example without having to set them. That's my laziness :P
__________________
Three things are certain,
Death, taxes and site not found,
You, victim of one.
  Reply With Quote
01-28-10, 09:20 AM   #29
haste
Featured Artist
 
haste's Avatar
Premium Member
Featured
Join Date: Dec 2005
Posts: 1,027
[quote=nightcracker;176460]Hmm, collisions won't happen, because that's how metatable.__index works, but I respect your opinion, so my question is, how SHOULD I implement it? Like this?/QUOTE]
Collisions _will_ happen because of how metatables works.
If I use :Fire() on my frames to execute a temporary queue, and use the function to indicate that there's a need for that queue to be run:
if(object.Fire) then -- will evaluate to true.
if(rawget(object, 'Fire')) -- won't evaluate to true.

And no-one in their sane mind would use rawget to check for that without _knowing_ that the metatable under it could possibly have that variable name.

Originally Posted by nightcracker View Post
Code:
local lib = LibStub:GetLibrary("LibCoreAPI")
local f = lib:CreateFrame("Frame")
But I hate that I can't use methods like estroy on the Micromenu, for example without having to set them. That's my laziness :P
Take a look at your code.
local functionName = function(self, ...)
end

when you insert you variables into the frame table (not the metatable) and do: frame:functionName() this translates to frame.functionName(frame), which is equal to lib.functionName(frame) (if the functions are exposed).

This means that it would be possible to use it like a ordinary utility set by doing:
lib.functionName(MicroMenuFrame) (or whatever it's named).

This is of course expecting those functions to be exposed in the lib.
__________________
「貴方は1人じゃないよ」
  Reply With Quote
01-28-10, 09:26 AM   #30
Rilgamon
Premium Member
 
Rilgamon's Avatar
Premium Member
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 822
A perfect world is where what you expect is always true.
When writing an addon I have to know what certain values are
at any given time ... even when its unset.

With your aproach all is fine when I use your lib and everyone else, too.
Everyone expects the same.

But we're far from a perfect world. Addons are written, uploaded and
then author stops because he leaves wow.

Do you want to rewrite every addon that is no longer working because
you changed the "default" environment ?

This is not a "**** happens" , addons stop working lots of times.
You're building a lib that will start with "Use it, and its certain **** will happen".
__________________
The cataclysm broke the world ... and the pandas could not fix it!
  Reply With Quote
01-28-10, 09:37 AM   #31
nightcracker
A Molten Giant
 
nightcracker's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 716
I see, I will stop using the metatables. Is it possible though that you(for example) call a function from an other file:
Code:
ChangeDefaults()
Like that, and then it has created a LOCAL variable in your current Lua script.
So this would work:
Code:
print(something) -- OUTPUT: nil
ChangeDefaults()
print(something) -- OUTPUT: "Yay!"
__________________
Three things are certain,
Death, taxes and site not found,
You, victim of one.
  Reply With Quote
01-28-10, 09:40 AM   #32
haste
Featured Artist
 
haste's Avatar
Premium Member
Featured
Join Date: Dec 2005
Posts: 1,027
No, functions can't change locals outside their own scope. You can do some nifty tricks with the debug library in Lua which allows this, but we don't have that in WoW.
__________________
「貴方は1人じゃないよ」
  Reply With Quote
01-28-10, 09:47 AM   #33
nightcracker
A Molten Giant
 
nightcracker's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 716
Originally Posted by haste View Post
No, functions can't change locals outside their own scope. You can do some nifty tricks with the debug library in Lua which allows this, but we don't have that in WoW.
Hmm, then I'll LibStub it... Is it also bad to MODIFY certain functions(like setsize) so that they can take other parameters(look at my setsize function, it's exactly the same as the original, but will be content with 1 parameter too)? Or like :Hide("forever").
__________________
Three things are certain,
Death, taxes and site not found,
You, victim of one.
  Reply With Quote
01-28-10, 10:50 AM   #34
nightcracker
A Molten Giant
 
nightcracker's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 716
Ok, update, I think I will start using metatables again! I check wether the call for the function is by a whilelisted addon, and if not I return nil, giving expected behaviour.

How do I check which addon called the function?
Code:
gsub(debugstack(2), ".*\\(.+)\\.+", "%1")
Sometime I think I'm smart, this is one of them(most likely this will get proven otherwise within the hour, but w/e).
__________________
Three things are certain,
Death, taxes and site not found,
You, victim of one.
  Reply With Quote
01-28-10, 12:36 PM   #35
Shadowed
...
Premium Member
Featured
Join Date: Feb 2006
Posts: 387
You're worried about the unmeasurable performance loss of setting a = b. Then you want to do a debugstack and a gsub to search for whitelisted addons, on a function call... ?
  Reply With Quote
01-28-10, 02:58 PM   #36
Mikord
A Theradrim Guardian
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 61
I really wish addon authors would stop mucking about with the global environment. It's never a good idea. I've had to fix several "bugs" that are due to this type of stuff and frankly, it is frustrating.

You asked for an example earlier. Here is some example code that I've seen in a legitimate addon before that your changes would break:

Lua Code:
  1. local frame=CreateFrame("Frame")
  2.  
  3. '...
  4.  
  5. if someEventHasHappened then frame.Fire = true end
  6.  
  7. ' ...Later in the code
  8.  
  9. ' Check if some event should be fired
  10. if frame.Fire then DoSomethingUseful() end

Because you've added a Fire entry that would be detected via the metatable, the check would always pass regardless and you've just hosed this code. It would have to be changed to use rawget. Making others code around you is not very responsible.

Also, what if I were to come behind you, decide to be clever too and create a metatable of my own with some functions *I* think are useful? In the process I blow away your metatables to use my own. Now every addon that makes use of your extensions will break.

I hope you can see why modifying the global environment is just a bad idea. Please don't do it.


Edit:

I see haste beat me to it above. Using LibStub with a specialized CreateFrame call is a much better approach.

Everybody using the global CreateFrame is unaffected as it should be and those who want to use your extensions have an easy way to do so.

Last edited by Mikord : 01-28-10 at 03:54 PM.
  Reply With Quote
01-28-10, 06:58 PM   #37
Saiket
A Chromatic Dragonspawn
 
Saiket's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2008
Posts: 154
Feels like I'm forum muted.
  Reply With Quote
01-29-10, 12:39 AM   #38
nightcracker
A Molten Giant
 
nightcracker's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 716
My new system(which is immume to frame.Fire):
lua Code:
  1. local version = 1.0
  2.  
  3. local metatables, registered = {}, {}
  4. local noop = function() end
  5.  
  6. if LibCoreAPI then if LibCoreAPI.version<version then registered=LibCoreAPI.RegisteredAddons else return end end
  7.  
  8. for key, val in pairs(_G) do
  9.     if type(val)=="table" and val.GetObjectType then
  10.         obj = val:GetObjectType()
  11.         if not metatables[obj] then
  12.             metatables[obj] = getmetatable(val).__index
  13.         end
  14.     end
  15. end
  16.  
  17. local function registeraddon()
  18.     registered[gsub(debugstack(2), ".*\\(.+)\\.+", "%1")] = true
  19. end
  20.  
  21. local function destroy(self)
  22.     self.Show = noop
  23.     self:Hide()
  24.     if self.UnregisterAllEvents then
  25.         self:UnregisterAllEvents()
  26.     end
  27. end
  28.  
  29. local function fireevent(self, event, ...)
  30.     local handler = self:GetScript("OnEvent")
  31.     if handler then
  32.         handler(self, event, ...)
  33.         return true
  34.     end
  35.     return false
  36. end
  37.  
  38. local function fire(self, script, ...)
  39.     local handler = self:GetScript(script)
  40.     if handler then
  41.         handler(self, ...)
  42.         return true
  43.     end
  44.     return false
  45. end
  46.  
  47. local function lock(self)
  48.     self.ClearAllPoints = noop
  49.     self.SetPoint = noop
  50.     self.SetAllPoints = noop
  51. end
  52.  
  53. local function unlock(self)
  54.     self.ClearAllPoints = nil
  55.     self.SetPoint = nil
  56.     self.SetAllPoints = nil
  57. end
  58.  
  59. local function setsize(self, w, h)
  60.     self:SetWidth(w)
  61.     self:SetHeight(h or w)
  62. end
  63.  
  64. local function getclassbycolor(r, g, b)
  65.     r, g, b = floor(r*100+.5)/100, floor(g*100+.5)/100, floor(b*100+.5)/100
  66.     for class, color in pairs(RAID_CLASS_COLORS) do
  67.         if color.r==r and color.g==g and color.b==b then
  68.             return class
  69.         end
  70.     end
  71.     return false
  72. end
  73.  
  74. local function getsize(self)
  75.     return self:GetWidth(), self:GetHeight()
  76. end
  77.  
  78. local function setclassicon(self, class)
  79.     self:SetTexture("Interface\\WorldStateFrame\\Icons-Classes")
  80.     if class then
  81.         local classcoords = CLASS_BUTTONS[class]
  82.         if classcoords then
  83.             self:SetTexCoord(unpack(classcoords))
  84.             return true
  85.         else
  86.             self:SetTexCoord(.5, .75, .5, .75)
  87.             return false
  88.         end
  89.     end
  90.     return false
  91. end
  92.  
  93. local function islocked(self)
  94.     if self.ClearAllPoints==noop and self.SetPoint==noop and self.SetAllPoints==noop then
  95.         return true
  96.     end
  97.     return false
  98. end
  99.  
  100. local function isdestroyed(self)
  101.     if self.Show==noop and not self:IsShown() then
  102.         return true
  103.     end
  104.     return false
  105. end
  106.  
  107. local function toggle(self)
  108.     if self:IsShown() then
  109.         self:Hide()
  110.         return false
  111.     end
  112.     self:Show()
  113.     return true
  114. end
  115.  
  116. local function setshown(self, show)
  117.     if show then
  118.         self:Show()
  119.     else
  120.         self:Hide()
  121.     end
  122. end
  123.  
  124. local methods = {
  125.     Destroy = destroy,
  126.     IsDestroyed = isdestroyed,
  127.     SetSize = setsize,
  128.     GetSize = getsize,
  129.     Lock = lock,
  130.     Unlock = unlock,
  131.     IsLocked = islocked,
  132.     Toggle = toggle,
  133.     SetShown = setshown,
  134.     FireEvent = fireevent,
  135.     Fire = fire,
  136.     SetClassIcon = setclassicon,
  137. }
  138.  
  139. local dependencies = {
  140.     Destroy = "Hide",
  141.     IsDestroyed = "Hide",
  142.     SetSize = "Hide",
  143.     GetSize = "Hide",
  144.     Lock = "Hide",
  145.     Unlock = "Hide",
  146.     IsLocked = "Hide",
  147.     Toggle = "Hide",
  148.     SetShown = "Hide",
  149.     FireEvent = "RegisterEvent",
  150.     Fire = "GetScript",
  151.     SetClassIcon = "SetTexture",
  152. }
  153.  
  154. local mt = {
  155.     __index = function(tab, func)
  156.         return registered[gsub(debugstack(2), ".*\\(.+)\\.+", "%1")] and methods[func] or nil
  157.     end
  158. }
  159.  
  160. for key, val in pairs(metatables) do
  161.     setmetatable(val, mt)
  162. end
  163.  
  164. LibCoreAPI = {
  165.     GetClassByColor = getclassbycolor,
  166.     Metatables = metatables,
  167.     RegisteredAddons = registered,
  168.     version = version,
  169. }
  170.  
  171. setmetatable(LibCoreAPI, {
  172.     __call = registeraddon,
  173. })

If an addon calls LibCoreAPI() then it get's whitelisted and frameestroy() will return the correct function. If it's not whitelisted then frame.Fire will return an not found error.
__________________
Three things are certain,
Death, taxes and site not found,
You, victim of one.
  Reply With Quote
01-29-10, 12:40 AM   #39
nightcracker
A Molten Giant
 
nightcracker's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 716
Originally Posted by Shadowed View Post
You're worried about the unmeasurable performance loss of setting a = b. Then you want to do a debugstack and a gsub to search for whitelisted addons, on a function call... ?
Nah, I'm not worried, I just was interested in the best practice. Is that really that bad?
__________________
Three things are certain,
Death, taxes and site not found,
You, victim of one.
  Reply With Quote
01-29-10, 12:56 PM   #40
nightcracker
A Molten Giant
 
nightcracker's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2009
Posts: 716
OK, I screwed the metatables, if I use the above method then it taints the secure functions. LibStub it is!

The first uploaded BETA: http://www.wowinterface.com/download...reAPIBETA.html
__________________
Three things are certain,
Death, taxes and site not found,
You, victim of one.
  Reply With Quote

WoWInterface » AddOns, Compilations, Macros » Alpha/Beta AddOns and Compilations » LibCoreAPI


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