View Single Post
07-24-13, 01:37 AM   #20
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Originally Posted by Niketa View Post
I don't understand the code here that you've used to call the function. I'm assuming "self[event]" would refer to events and whatever the event is and "(self, event, ...)" is just what it is?
Okay, let's break that down:

Code:
events:SetScript("OnEvent", function(self, event, ...)
end)
The above assigns a function to be run when an event your frame ("events") was registered for happens. Functions assigned as OnEvent scripts receive at least two arguments -- the first being a reference to the frame itself, the second being a string value containing the name of the event being handled -- plus any and all arguments specific to the event being handled.

Typically, the first two arguments are named "self" and "event" but variable names do not actually affect the variables, so you can could name them "panda" and "polkadot" if you really wanted, though I'd recommend you stick with the established conventions to keep your code readable, both for yourself and for anyone else who looks at it.

Code:
events:SetScript("OnEvent", function(self, event, ...)
    local method = self[event]
end)
Now we perform a table lookup on the frame ("self") to find the value assigned to the key with the same name as the event. So, if your frame is currently handling the "PLAYER_LOGIN" event, the "method" variable above would contain whatever value is found at self["PLAYER_LOGIN"]. Since self["PLAYER_LOGIN"] is just another way of writing self.PLAYER_LOGIN, if you correctly defined your function:

Code:
function events:PLAYER_LOGIN(event)
   print("I am now logged in!")
end
... then "method" refers to that function.

Code:
events:SetScript("OnEvent", function(self, event, ...)
    local method = self[event]
    if method then
        method(self, event, ...)
    end
end)
Now we check that "method" actually contains a value -- if we don't do this check, and it doesn't contain a value, then we'll get an error when we try to call it as a function. If you wanted to be really safe, you could check if type(method) == "function" then instead of just if method then, but realistically you will never be assigning any value to events.PLAYER_LOGIN other than the function you want to run for the PLAYER_LOGIN event, so we skip the extra function call and just assume it's a function.

Finally, if the function exists, we call it, passing along all the arguments received by the OnEvent script.

Code:
events:SetScript("OnEvent", function(self, event, ...)
    return self[event] and self[event](self, event, ...)
end)
This is just a shorter (and slightly more efficient) way to write the previous example, using ternary syntax ("x = a and b or c" vs "if a then x = b else x = c end") and taking advantage of tail calls. If you find the shorter syntax too confusing for now, just use the longer version from above.

Originally Posted by Niketa View Post
Also, I'm having issues getting that to work for me. Is that the code as it should be or are there things I need to change? Sorry, that might be a stupid question but I don't really understand what's going on well enough.
You need to remove your old SetScript("OnEvent", function ... end) line, but first, you need to copy your actual code into the event handlers. So, for example, for your first block (also, I took the liberty of reformatting your code to clean up some redundancy and avoid some unnecessary function calls):

Code:
function events:PLAYER_ENTERING_WORLD(event)
	local isInInstance, instanceType = IsisInInstance("player")
	if not isInInstance or instanceType ~= "raid" then
		-- Quit:
		return
	end

	if not UnitIsGroupLeader("player") then
		-- Stop listening to events:
		self:UnregisterEvent("PLAYER_REGEN_DISABLED")
		self:UnregisterEvent("PLAYER_REGEN_ENABLED")
		self:UnregisterEvent("PARTY_LOOT_METHOD_CHANGED")

		-- Tell the player:
		print("|cff00ff00Niketa's Mount Looter disabled: You need to be raid leader to use this addon.")

		-- Quit:
		return
	end

	-- If you've gotten to this point, you are in a raid instance,
	-- and you are the group leader.

	-- Start listening to events:
	self:RegisterEvent("PLAYER_REGEN_DISABLED")
	self:RegisterEvent("PLAYER_REGEN_ENABLED")
	self:RegisterEvent("PARTY_LOOT_METHOD_CHANGED")

	-- Tell the player:
	print("|cff00ff00Niketa's Mount Looter enabled!")
end

events.PARTY_LEADER_CHANGED = events.PLAYER_ENTERING_WORLD
Do the same for the code you want to run for other events, putting each block of code into an appropriately named function.

Originally Posted by Niketa View Post
I'm not sure where the "t" comes from in the code. Is it just an alias for the table where "function(t, guid)" is essentially "function(self,parameter)" or something along those lines?
Yes. As explained above, you can name variables whatever you want. Since most parts of your code will be using "self" to refer to your addon object (in your case, your frame, so "self" and "events" will usually mean the same thing) I used a different name here ("t" for "table", but you can't use "table" because that's already a Lua global) to avoid confusion.

The only time you are required to use a specific variable name is when you are using method notation, in which case the variable "self" is automatically created and assigned.

This is method notation:

Code:
function MyAddon:DoSomething()
    print(type(self))
end
If you call this function -- eg. by typing "/run MyAddon:DoSomething()" -- you will see "table" printed, even though you did not actually define the variable "self" anywhere. Using a colon is a shortcut for this:

Code:
function MyAddon.DoSomething(self)
    print(type(self))
end
No matter which way you define your function (method notation with a colon, or regular notation with a period) you can call it via either notation, even if it's not the same notation used when you defined your function.

Code:
MyAddon:DoSomething()
and

Code:
MyAddon.DoSomething(MyAddon)
are functionally identical. Personally, I always use method notation (colon) since it's less code to type, but whichever you choose to use, use it consistently to keep your code readable.

This is also why inside your OnEvent function, you can just refer to "self" instead of "events", though both variables mean the same thing in that particular scope.
__________________
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 : 07-24-13 at 01:44 AM.
  Reply With Quote