lotrointerface.com
Search Downloads


Go Back   LoTROInterface > LotRO > Developer Discussions > Lua Programming Help (L)

Reply
Thread Tools Display Modes
  #1  
Unread 04-21-2013, 01:30 PM
Stever1388 Stever1388 is offline
The Undying
Interface Author - Click to view interfaces
 
Join Date: Nov 2010
Posts: 33
Using Add/Remove callback functions with the localplayer EffectList

I'm working/updating my simple Party Debuff Tracker plugin, and I'm trying to get it to remove the local players "EffectAdded" event from the EffectList. For whatever reason, it does not work, yet will work for all other members of a players fellowship. Here is some relevant code:

Code:
-- player is the current member of the fellowship we are creating events for (loop is in another function)
function EffectTracker:HandleEffects(player)
	self.effectList[player:GetName()] = player:GetEffects(); -- kept for removecallback function
	self.effectAddedHandler = function(sender, args)
		-- outputs data to chat window (code not important to discussion)
	end
	AddCallback(player:GetEffects(), "EffectAdded", self.effectAddedHandler);
end

-- used to make sure party is current
function EffectTracker:UpdateParty()
	self.partyChangedHandler = function(sender, args)
		if localPlayer:GetParty() == nil then
			RemoveCallback(party, "MemberAdded", self.partyChangedHandler);
			RemoveCallback(party, "MemberRemoved", self.partyChangedHandler);
			self:RemoveEffectCallbacks();
		end
		party = localPlayer:GetParty();
		self:TrackEffects();
	end
	AddCallback(localPlayer, "PartyChanged", self.partyChangedHandler);
	AddCallback(localPlayer, "RaidChanged", self.partyChangedHandler);
	if party ~= nil then
		self:TrackEffects();
	end
end

-- this is where the problem is
function EffectTracker:RemoveEffectCallbacks()
	if self.effectList ~= nil then
		for k, v in pairs(self.effectList) do
                 -- should remove event functions for the EffectAdded events for all members of the fellowship. It works for every member of the fellowship, but fails to remove the localplayers event.
			RemoveCallback(v, "EffectAdded", self.effectAddedHandler);
		end
                -- added this to remove that callback that is not removed using RemoveCallback() function
		if localPlayer:GetEffects()["EffectAdded"] ~= nil then
			localPlayer:GetEffects()["EffectAdded"] = nil;
		end
	end
end
When I added some chat output lines to the RemoveCallback() function, it seems that "if object[event] == callback then" isn't "working" correctly for the EffectList of the local player. I cannot tell why, as the EffectList for other party members works correctly. It seems the table that holds the EffectList changes somewhat from setting the event function to removing it so the "object[event]" points somewhere else, however, the object[event] isn't nil, but I'm not quite sure how to check what exactly it is holding (apparently not the self.effectAddedHandler function). Considering that my workaround won't play safe with other plugins or other EffectAdded events to the local player, this is a somewhat annoying problem. Perhaps I am just missing something but I can't see it right now. If you need clarification please let me know. Thanks for your help!
Reply With Quote
  #2  
Unread 04-21-2013, 04:24 PM
Garan's Avatar
Garan Garan is offline
The Undying
Interface Author - Click to view interfaces
 
Join Date: Oct 2010
Posts: 340
Just a quick glance shows that you are redefining the self.effectAddedHandler function on every call to EffectTracker:HandleEffects so the table representing the function is not the same after each call. The function should either be defined once and used for everyone or there should be a table of functions with one instance for each player depending on what exactly you are doing with the function. But in any case you definately should not be redefining the function and then expecting it to match when you remove it - in other words, only functions that match an entry in the event table will get removed and since you redefined it, it doesn't match and isn't removed. As implemented, this actually should fail for all but one party member, that being the last one passed to EffectTracker:HandleEffects so I'm not sure how you were testing but if you only tested with a party of two then it would appeared to be working for all but the local player (when in fact it was just working for the last one added).

Basically, to fix this, move the definition of the callback funtions outside of the routine that adds them (you would use the "sender" argument to determine which player triggered the event) or create a table of functions, one for each player, i.e. self.effectAddedHandler[player:GetName()]=function...
Of couse, if you go the route of using a table, then you have to pass the correct instance to the removecallback -
RemoveCallback(v, "EffectAdded", self.effectAddedHandler[k]);

So, option 1 is to move the definition outside :HandleEffects and use the Sender to determine the player that fired the event
Code:
self.effectAddedHandler = function(sender, args)
 -- outputs data to chat window (code not important to discussion)
end
function EffectTracker:HandleEffects(player)
 self.effectList[player:GetName()] = player:GetEffects(); -- kept for removecallback function
 AddCallback(player:GetEffects(), "EffectAdded", self.effectAddedHandler);
end
-- used to make sure party is current
self.partyChangedHandler = function(sender, args)
 if localPlayer:GetParty() == nil then
  RemoveCallback(party, "MemberAdded", self.partyChangedHandler);
  RemoveCallback(party, "MemberRemoved", self.partyChangedHandler);
  self:RemoveEffectCallbacks();
 end
 party = localPlayer:GetParty();
 self:TrackEffects();
end
function EffectTracker:UpdateParty()
 AddCallback(localPlayer, "PartyChanged", self.partyChangedHandler);
 AddCallback(localPlayer, "RaidChanged", self.partyChangedHandler);
 if party ~= nil then
  self:TrackEffects();
 end
end
-- this is where the problem is
function EffectTracker:RemoveEffectCallbacks()
 if self.effectList ~= nil then
  for k, v in pairs(self.effectList) do
                 -- should remove event functions for the EffectAdded events for all members of the fellowship. It works for every member of the fellowship, but fails to remove the localplayers event.
   RemoveCallback(v, "EffectAdded", self.effectAddedHandler);
  end
                -- added this to remove that callback that is not removed using RemoveCallback() function
  if localPlayer:GetEffects()["EffectAdded"] ~= nil then
   localPlayer:GetEffects()["EffectAdded"] = nil;
  end
 end
end
and option 2 is to use a table of handlers
Code:
self.effectAddedHandler={}
function EffectTracker:HandleEffects(player)
 local playerName=player:GetName()
 self.effectList[playerName] = player:GetEffects(); -- kept for removecallback function
 self.effectAddedHandler[playerName] = function(sender, args)
  -- outputs data to chat window (code not important to discussion)
 end
 AddCallback(player:GetEffects(), "EffectAdded", self.effectAddedHandler[playerName]);
end
-- used to make sure party is current
self.partyChangedHandler = function(sender, args)
 if localPlayer:GetParty() == nil then
  RemoveCallback(party, "MemberAdded", self.partyChangedHandler);
  RemoveCallback(party, "MemberRemoved", self.partyChangedHandler);
  self:RemoveEffectCallbacks();
 end
 party = localPlayer:GetParty();
 self:TrackEffects();
end
function EffectTracker:UpdateParty()
 AddCallback(localPlayer, "PartyChanged", self.partyChangedHandler);
 AddCallback(localPlayer, "RaidChanged", self.partyChangedHandler);
 if party ~= nil then
  self:TrackEffects();
 end
end
-- this is where the problem is
function EffectTracker:RemoveEffectCallbacks()
 if self.effectList ~= nil then
  for k, v in pairs(self.effectList) do
                 -- should remove event functions for the EffectAdded events for all members of the fellowship. It works for every member of the fellowship, but fails to remove the localplayers event.
   RemoveCallback(v, "EffectAdded", self.effectAddedHandler[k]);
  end
                -- added this to remove that callback that is not removed using RemoveCallback() function
  if localPlayer:GetEffects()["EffectAdded"] ~= nil then
   localPlayer:GetEffects()["EffectAdded"] = nil;
  end
 end
end
As I first mentioned, this was just a quick glance so there may be other issues but this was the first that I noticed and seemed to cause the symptom you were experiencing. I also didn't test the solution code so there may be typos but the intent should be clear.

Last edited by Garan : 04-21-2013 at 04:40 PM.
Reply With Quote
  #3  
Unread 04-21-2013, 10:20 PM
Stever1388 Stever1388 is offline
The Undying
Interface Author - Click to view interfaces
 
Join Date: Nov 2010
Posts: 33
Yeah I was only testing with 2 players since it's the easiest way to do it.

And option one is what I was going for. I knew I was overlooking something like that, which is why I posted the question. I miss having a roommate that knows coding because this stuff is solved a lot faster!

Thanks Garan!

Edit: The sender in that event call is the EffectList that calls the event, not the player. How would I go about getting the player that the EffectList is for? Can I add a third parameter to the self.effectAddedHandler to be the player that has the EffectList, or would I have to go with option 2 and use the table?

Last edited by Stever1388 : 04-21-2013 at 10:24 PM. Reason: Additional question.
Reply With Quote
  #4  
Unread 04-21-2013, 11:08 PM
Garan's Avatar
Garan Garan is offline
The Undying
Interface Author - Click to view interfaces
 
Join Date: Oct 2010
Posts: 340
Quote:
Originally Posted by Stever1388
Yeah I was only testing with 2 players since it's the easiest way to do it.

And option one is what I was going for. I knew I was overlooking something like that, which is why I posted the question. I miss having a roommate that knows coding because this stuff is solved a lot faster!

Thanks Garan!

Edit: The sender in that event call is the EffectList that calls the event, not the player. How would I go about getting the player that the EffectList is for? Can I add a third parameter to the self.effectAddedHandler to be the player that has the EffectList, or would I have to go with option 2 and use the table?
You could add a .Player value to the self.effectList[] table entries to create a link back to the player:
change EffectTracker:HandleEffects to
Code:
function EffectTracker:HandleEffects(player)
 self.effectList[player:GetName()] = player:GetEffects(); -- kept for removecallback function
 self.effectList[player:GetName()].Player=player; -- creates a link back to the player
 AddCallback(player:GetEffects(), "EffectAdded", self.effectAddedHandler);
end
and then in effectAddedHandler you could use sender.Player
Code:
self.effectAddedHandler = function(sender, args)
 -- outputs data to chat window (code not important to discussion)
  --sender.Player references the player for this effect list
end

Last edited by Garan : 04-21-2013 at 11:18 PM.
Reply With Quote
  #5  
Unread 04-21-2013, 11:14 PM
Stever1388 Stever1388 is offline
The Undying
Interface Author - Click to view interfaces
 
Join Date: Nov 2010
Posts: 33
Thanks for your help. The second option isn't really that tough to implement anyway, so I went ahead with that.
Reply With Quote
  #6  
Unread 04-21-2013, 11:29 PM
Stever1388 Stever1388 is offline
The Undying
Interface Author - Click to view interfaces
 
Join Date: Nov 2010
Posts: 33
Quote:
Originally Posted by Garan
You could add a .Player value to the self.effectList[] table entries to create a link back to the player:
change EffectTracker:HandleEffects to
Code:
function EffectTracker:HandleEffects(player)
 self.effectList[player:GetName()] = player:GetEffects(); -- kept for removecallback function
 self.effectList[player:GetName()].Player=player; -- creates a link back to the player
 AddCallback(player:GetEffects(), "EffectAdded", self.effectAddedHandler);
end
and then in effectAddedHandler you could use sender.Player
Code:
self.effectAddedHandler = function(sender, args)
 -- outputs data to chat window (code not important to discussion)
  --sender.Player references the player for this effect list
end
This is an interesting way to do it too. Any real advantage to doing it either way?
Reply With Quote
  #7  
Unread 04-21-2013, 11:38 PM
Garan's Avatar
Garan Garan is offline
The Undying
Interface Author - Click to view interfaces
 
Join Date: Oct 2010
Posts: 340
Quote:
Originally Posted by Stever1388
This is an interesting way to do it too. Any real advantage to doing it either way?
Well, fewer function definitions means a slightly smaller memory footprint but in this case that seems pretty minor. Of course, adding a property to a Turbine generated table runs a minor risk of conflicting with a future Turbine property but that risk is nearly infinitesimal in this case. So, no, there isn't a clear advantage to either solution. I personally would probably use option 1 but that's more a matter of personal preference than actual advantage.
Reply With Quote
Reply


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
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Read out the EffectList Kunter Lua Programming Help (L) 14 08-01-2012 06:49 PM
New Warden functions MrJackdaw Lua Programming Help (L) 1 10-04-2011 04:53 PM
Should I wait to add a new UI Silverfoot Interface Help (L) 3 10-02-2011 08:01 AM
LocalPlayer (a table value)? WTH goldbishop Lua Programming Help (L) 4 11-30-2010 05:13 PM
issue with functions inside of a class SanDBoX Lua Programming Help (L) 18 10-08-2010 07:44 PM


All times are GMT -5. The time now is 05:00 AM.


Our Network
EQInterface | EQ2Interface | Minion | WoWInterface | ESOUI | LoTROInterface | MMOUI | Swtorui