I had been thinking on how to make use of the AceEvent for ParserLib
ParserLib needs to :
1. Maintains a list of client addons, and the event they registered.
2. Only registers those events which there are at least one client addon interested.
3. Parse arg1 for information, save it in a backup info table.
4. Notifies the client with the event and info table when the event occured.
5. Each time ParserLib will restore the info data from the backup table before sending to a client, because client may modify contents of the info table.
AceEvent can save ParserLib from doing (1), (4), but how can I do (2) (5) ?
(2) requires that ParserLib know when some addon registers to an event, if an addon registers to AceEvent and not ParserLib, I cannot know it.
On method to do this is to have AceEvent fires a ADDON_REGISTER_EVENT event when Ace2 addon reigsters to an event (especially custom events).
Another method is to let addon do a TriggerEvent insteand of RegisterEvent:
function ParserLib:OnClientRegisteringEvent(event, client, handler)
1. client:RegisterEvent("PARSER_COMBAT_SELF_HITS", "OnCombatEvent")
2. parser:RegisterEvent("CHAT_MSG_COMBAT_SELF_HITS");
end
But I think this doesn't look very intutive?
---
(5) also requires ParserLib to be involved in the notification of clients.
One method is to have AceEvent do this automatically when they see an arg of type table, since it makes sense that every client addon should receive exactly the same arg.
For both (2) and (5), I think another possible solution is to make ParserLib as an inherited class of AceEvent, and overwrite related those related functions.
Since AceEvent now fires a custom event when someone registers an event, I am able to start writing Parser-2.0. The initial code for Parser-2.0 is done (haven't upload to svn yet ), I'll need some more testing first though.
AceEvent will an optional dependency, if it exists, ParserLib simply fires a custom event PARSER_XXX with AceEvent.
self:RegisterEvent("PARSER_COMBAT_SELF_HITS"); -- Replace "CHAT_MSG" with "PARSER"
I hope this is the best method to implement, this way authors can optionally choose to use the new AceEvent methods, or goes back the old embedded library approach if the addon doesn't need the functionalities of AceEvent at all.
Just thinking here, but instead of returning an event for that specific chat event, why not return a parserlib event that is of the info.type. For example "PARSER_ENVIRONMENT", "PARSER_HIT", "PARSER_HEAL", etc...
Seems like that would work out better than having to figure out what an event is after getting the custom event. But I could just be misunderstanding your idea =)
It would also be nice if ParserLib could support then new BulkEvents feature of AceEvent. I imagine a lot of mods will begin to take advantage of it. Not sure how diffcult that would be to add, but just something to consider.
If there is any naming convention suggested in AceEvent I'll be sure to use it, doesn't really matter. (That isn't being mentioned in the AceEvent wiki though, I think you should add it? Or is it already there and I missed it ?)
When I started developing ParserLib 1 I have thought about the idea of client registering to types insteand of the events. But in the case that the author is only interested in some events, for example "only damages done by me", then the author only has to register to CHAT_MSG_COMBAT_SELF_HITS, CHAT_MSG_SPELL_SELF_DAMAGE and the possible events for DOTs. In the registering-to-types approach ParserLib have to register to all combat-related events even if this is the case. I was mainly concerned about the efficency when not every addon wants to listen to all the events, so to simplify the problem I just let authors take care of what events they want.
But I can see how that will be convenient to authors, it'll remove the need of info.type checking, and authors no longer have to care about "what patterns are fired from what event". I'll have to think about it.
If I am to make both approaches available, that is, firing a Parser_CHAT_MSG_COMBAT_SELF_HITS, when CHAT_MSG_COMBAT_SELF_HITS occurs, and also firing a Parser_Hit if the message is a "hit" message, how does that sounds to you? In this case, you'll get duplicate events if you registered to both the Parser_CHAT_MSG event and the Parser_Type event.
for the BulkEvents do you mean RegisterBucketEvent()? I think you can use that as long as I am firing the events with AceEvent?
My thinking was you would register the chat events with the specific chat events that you know you want, but you wouldn't be "listening" for those events, you would only listen for the Parser_Hit, etc...This way in your example they would only register for events that contain self damage, then listen for the Parser_Hit, Parser_Miss, etc...
But I think like you said, if there is a way to do both or just select what type you want upon registering would work. But I'm not sure how much overhead there would be having to throw two seperate events. If its affected performance at all, would probably be best just to pick one.
I'm not sure about the performance of TriggerEvent(), but I can do a AceEvent:IsEventRegistered() check before firing Parser_CHAT_MSG_COMBAT_SELF_HITS and Parser_Message_Hit, the overhead should be minimal when addons only registered to one of the above. I guess I'll just make all the options available to users.
So, ParserLib defaults to "auto mode" that if anyone registered a "Parser_Message_Hit", ParserLib registers all events containing "hit" message.
Addons can choose to do the "manual mode" if they want, may be with a call to something like parser:SetAutoRegister("addonID", false). In this case, they'll have to specific what events they want by parser:RegisterEvent("addonID", "event") (leave handler nil).
In this case, I'll need some way to know who you are, to check that you are in manual mode or not when AceEvent_EventRegistered is fired, so "addonID" should be the reference to self. ( Because when AceEvent_EventRegistered fired, I got your class object reference. )
So the usage is something like this:
parser:SetAutoRegister(self, false)
parser:RegisterEvent(self, "CHAT_MSG_COMBAT_SELF_HITS"); -- don't pass a handler
self:RegisterEvent("Parser_Message_Hit"); -- ParserLib will not register to any Blizzard event by this call.
or like this:
self:RegisterEvent("Parser_Message_Hit"); -- ParserLib will registers to all Blizzard events containing "hit" patterns.
when CHAT_MSG_COMBAT_SELF_HITS occurs, ParserLib will fire Parser_CHAT_MSG_COMBAT_SELF_HITS AND Parser_Message_Hit if there are addon registered to them.
hmm......... need wait till I'm not so busy IRL before I can really think about these carefully :X
for 'type' events, may be I should just make the fields in info table as args, so instead of
function Addon:Parser_Message_Hit(event, info);
function Addon:Parser_Message_Death(event, info);
you'll have
function Addon:Parser_Message_Hit(sorce, victim, skill, amount, element, isCrit, isDOT, isSplit);
function Addon:Parser_Message_Death(victim, source, isItem);
this way also prevents the fields in info table from being modified by some addons' event handler.
I didn't do this in old ParserLib becase you don't know what the fields are until you check the 'type' field, so passing a table seems more convenient to authors.
Either way works for me, but if passing the info as args reduces table churning, then makes sense. I think you could do it with the old way too, but would require specfic args to always be in a certain order, so the table appraoch made that much easier. However, as long as the type was always the 2nd arg, it would work.
Question, will the blizzard event and args still be available with the new Parser fired events? If not you may want to include them in the list of args. SCT for example uses them to do custom event parsing, because if a custom event is found it ultimately ignores the parsed data supplied from ParserLib. I wanted to find a way to do the custom event parsing and if one was found, not even call ParserLib for that event to remove that processing, but didn't see any easy way to do that.
Blizzard's events use global variables "event", "arg1", "arg2" etc and no one should be modifying them except Blzzard. So I think you should be able to check them even in the callback from ParserLib.
And for the sct custom events I'm not so sure what do you mean, why do you have to call ParserLib?
I don't call it =) Basically with SCT custom events, if a custom event is found everything about what to display comes from the custom event settings. So in those cases I don't care what Parserlib parsed out. I was just saying that in an ideal situation I could do the custom event check/parse before ParserLib ever got the event and never send it to ParserLib if a custom event was found. However this is a very specific case probably unique to SCT, so I wouldn't expect ParserLib to worry about it. Might be some way to do it with hooks, but haven't really cared enough to mess with it yet =).
Edit:
Of course, ParserLib can be used my multiple clients, so doing that wouldn't work at all. So just ignore me =)
edit: ok i think i know what the problem is now, you don't know what the custom patterns are until you actually parse it in your OnEvent handler. So you want to be able to have your OnEvent handler get called before ParserLib's one. hmmm i'm not sure how to do that too :p
Not that I am an expert or anything, but I was looking into making a combat log parser to do a few things like color coding and maybe a damgemeters type thing.
Just looking at the AceEvent API and the ParserLib code for a while now.
It seems that the AceEvent is really a replacement of ParserLib. Well maybe not a full one, but it seems as though you want to create custom events for parsing combat messages only. Why not just do that?
Just have the ParserLib create custom events for CHAT_MSG_SPELL_XXX and CHAT_MSG_COMBAT_XXX events and trigger the specific events based on the type of message it is.
So for instance
...
Ace_Parser = AceLibrary("AceAddon 2.0"):new("AceEvent-2.0")
....
function Ace_Parser:OnEnable()
begin
self:RegiisterEvent("CHAT_MSG_COMBAT_SELF_HITS")
self:RegisterEvents("Parser__Self_Crit_Hit")
...
end;
function Ace_Parser:CHAT_MSG_COMBAT_SELF_HITS(pattern)
begin
x = self:GetPattern(1,pattern); --1 is the representation for the message, could be a const like PARSERCHATMSGCOMBATSELFHITS = 1 just for clarity
if (x <> nil)
then
self:TriggerEvent(eventpatterns[x]);
end;
--or i wonder
--self:TriggerEvent(eventpatterns[self:GetPattern(PARSERCHATMSGCOMBATSELFHITS,pattern)]);
--you would have to have all the patterns in there to do this though.
end;
end;
I think this just buys you what the pattern it is but then you could change the event fire to be Parser__Self_Hit_Crit to parse the actual arguments internally and the event Parser_Self_Hit_Crit for the client addons.
Lastly, can't you gleen the combat log preferences to see what events the client should or should not parse?
Sorry but I don't get what you mean, are you suggesting a way to improve the ParserLib core, or suggesting a better "API" (AceEvent custom events) ?
Either way I don't understand what is the purpose of Parser__Self_Crit_Hit?
The main advantages for adding AceEvent to ParserLib is that it can replace the client-addon handling part and does it better, but the parser core gets no benefit from AceEvent.
And for the "combat log preferences" do you mean the settings in Blizzard chat frames? That has nothing to do with what events a ParserLib user wants to listen.
No, I am not saying Ace events can replace ParserLib. I am saying that it can take alot of the work out of it. It is still really a useful lib because it does one thing extremely well and other Ace addons would benefit from it.
The chat flags, the user may want to grab the existing ones or set a new group of events. All I was suggesting there was that if someone wanted to easily grab those settings and register those events/patterns for listening it would be a nice function.
As far as streamlining the pattern matching, I am not as familiar with Lua yet to grasp the FindString construct you created. Using the events would eliminate the if then else construct and only be watching for the specific ones you need.
Parser__Self_Crit_Hit would be an internal event, not registered to other addons, that is used for the internal communication to the same addon.
Its like saying within a win32 application that a click event happened but you dont want to send a message to another application.
Hence, you dont have to create your tree because you already know the pattern and just have to parse the data from the arguments passed in.
So if I have a function called Parse__Self_Crit_Hit(msg) I already know the pattern for it and can disassemble it. Then trigger the real event Parse_Self_Crit_Hit with the arguments "CRIT", Victim, Damage, Absorbed. Absorbed is there for the cases where there is a damage redux like "You Crit Onyxia for 132(50)." It would be null if nothing was absorbed.
You only register the events needed by clients and register the internal ones to parse the patterns. So if a client wanted to know about CHAT_MSG_COMBAT_SELF_HITS specifically Critical Hits, you register CHAT_MSG_COMBAT_SELF_HITS and ONLY the internal evens that you will generate from the original event, say Parser__Hit_Crit_Self_Other. The others might be Parser__Hit_Self_Other, Parser_Damage_Falling_Self, Parser__Damage_Fire_Self and Parser__Damage_Lava_Self. You would then trigger the real Parser events from the internal one and the clients would have to themselves listen for the real ones and only pass them in for registration like
Some type of tracking system like you have for clients is not needed because the addon itself is listening for the event and should handle it. All they need to do is call the inherited func from your Ace_Parser.
Of course this is all based on if the lib can listen for events generated by itself :P
venjens - I think you should again look at the ParserLib and try to understand what it does before posting enhancement suggestions nobody understands...
I think you underestimate ParserLib and the parse engine behind it and what it does. The engine is a very abstract and generic.
It does not listen to specific events and parse each event for it own. It has an engine with which is it easy to include more events in a very nice an quick way.
You also should concern, that incomming events are mapped on several outgoing events and that it's not a one to one relation.
The suggestions from you would only decrease the object oriented and generic approach - and with it the maintanability.
Look at SW_Stats - it was at the time a unique way to parse the combat messages without localization based string searches. So the parsing would do it in every language. It helped me a lot to understand ParserLib.
I imagine PaserLib is going to need some decent size changes for WoW 2.0. Anyone have access to beta that can start posting and/or helping with what needs fixed?
I would if I had the time for it. While ParserLib / MCombatParser does a decent job, I think it's way better to build search tables dynamically, which saves us from updating the lists (80%+ of the code) everytime something changes. But as GlobalStrings is quite large, we'll need a pretty efficient algorithm to searth through it, O(n) or better preferred.
Rollback Post to RevisionRollBack
To post a comment, please login or register a new account.
ParserLib needs to :
AceEvent can save ParserLib from doing (1), (4), but how can I do (2) (5) ?
(2) requires that ParserLib know when some addon registers to an event, if an addon registers to AceEvent and not ParserLib, I cannot know it.
On method to do this is to have AceEvent fires a ADDON_REGISTER_EVENT event when Ace2 addon reigsters to an event (especially custom events).
Another method is to let addon do a TriggerEvent insteand of RegisterEvent:
and in ParserLib:
But I think this doesn't look very intutive?
---
(5) also requires ParserLib to be involved in the notification of clients.
One method is to have AceEvent do this automatically when they see an arg of type table, since it makes sense that every client addon should receive exactly the same arg.
For both (2) and (5), I think another possible solution is to make ParserLib as an inherited class of AceEvent, and overwrite related those related functions.
AceEvent will an optional dependency, if it exists, ParserLib simply fires a custom event PARSER_XXX with AceEvent.
So you can do either the old:
or with AceEvent:
I hope this is the best method to implement, this way authors can optionally choose to use the new AceEvent methods, or goes back the old embedded library approach if the addon doesn't need the functionalities of AceEvent at all.
Seems like that would work out better than having to figure out what an event is after getting the custom event. But I could just be misunderstanding your idea =)
It would also be nice if ParserLib could support then new BulkEvents feature of AceEvent. I imagine a lot of mods will begin to take advantage of it. Not sure how diffcult that would be to add, but just something to consider.
_only_ Blizzard events should be in CONSTANT_CASE.
Don't make me put checks in to stop you from doing this.
When I started developing ParserLib 1 I have thought about the idea of client registering to types insteand of the events. But in the case that the author is only interested in some events, for example "only damages done by me", then the author only has to register to CHAT_MSG_COMBAT_SELF_HITS, CHAT_MSG_SPELL_SELF_DAMAGE and the possible events for DOTs. In the registering-to-types approach ParserLib have to register to all combat-related events even if this is the case. I was mainly concerned about the efficency when not every addon wants to listen to all the events, so to simplify the problem I just let authors take care of what events they want.
But I can see how that will be convenient to authors, it'll remove the need of info.type checking, and authors no longer have to care about "what patterns are fired from what event". I'll have to think about it.
If I am to make both approaches available, that is, firing a Parser_CHAT_MSG_COMBAT_SELF_HITS, when CHAT_MSG_COMBAT_SELF_HITS occurs, and also firing a Parser_Hit if the message is a "hit" message, how does that sounds to you? In this case, you'll get duplicate events if you registered to both the Parser_CHAT_MSG event and the Parser_Type event.
for the BulkEvents do you mean RegisterBucketEvent()? I think you can use that as long as I am firing the events with AceEvent?
But I think like you said, if there is a way to do both or just select what type you want upon registering would work. But I'm not sure how much overhead there would be having to throw two seperate events. If its affected performance at all, would probably be best just to pick one.
^--- definitely has the naming convention there.
So, ParserLib defaults to "auto mode" that if anyone registered a "Parser_Message_Hit", ParserLib registers all events containing "hit" message.
Addons can choose to do the "manual mode" if they want, may be with a call to something like parser:SetAutoRegister("addonID", false). In this case, they'll have to specific what events they want by parser:RegisterEvent("addonID", "event") (leave handler nil).
In this case, I'll need some way to know who you are, to check that you are in manual mode or not when AceEvent_EventRegistered is fired, so "addonID" should be the reference to self. ( Because when AceEvent_EventRegistered fired, I got your class object reference. )
So the usage is something like this:
or like this:
when CHAT_MSG_COMBAT_SELF_HITS occurs, ParserLib will fire Parser_CHAT_MSG_COMBAT_SELF_HITS AND Parser_Message_Hit if there are addon registered to them.
hmm......... need wait till I'm not so busy IRL before I can really think about these carefully :X
you'll have
this way also prevents the fields in info table from being modified by some addons' event handler.
I didn't do this in old ParserLib becase you don't know what the fields are until you check the 'type' field, so passing a table seems more convenient to authors.
Question, will the blizzard event and args still be available with the new Parser fired events? If not you may want to include them in the list of args. SCT for example uses them to do custom event parsing, because if a custom event is found it ultimately ignores the parsed data supplied from ParserLib. I wanted to find a way to do the custom event parsing and if one was found, not even call ParserLib for that event to remove that processing, but didn't see any easy way to do that.
And for the sct custom events I'm not so sure what do you mean, why do you have to call ParserLib?
Edit:
Of course, ParserLib can be used my multiple clients, so doing that wouldn't work at all. So just ignore me =)
Just looking at the AceEvent API and the ParserLib code for a while now.
It seems that the AceEvent is really a replacement of ParserLib. Well maybe not a full one, but it seems as though you want to create custom events for parsing combat messages only. Why not just do that?
Just have the ParserLib create custom events for CHAT_MSG_SPELL_XXX and CHAT_MSG_COMBAT_XXX events and trigger the specific events based on the type of message it is.
So for instance
I think this just buys you what the pattern it is but then you could change the event fire to be Parser__Self_Hit_Crit to parse the actual arguments internally and the event Parser_Self_Hit_Crit for the client addons.
Lastly, can't you gleen the combat log preferences to see what events the client should or should not parse?
Am I way off on this?
Either way I don't understand what is the purpose of Parser__Self_Crit_Hit?
The main advantages for adding AceEvent to ParserLib is that it can replace the client-addon handling part and does it better, but the parser core gets no benefit from AceEvent.
And for the "combat log preferences" do you mean the settings in Blizzard chat frames? That has nothing to do with what events a ParserLib user wants to listen.
The chat flags, the user may want to grab the existing ones or set a new group of events. All I was suggesting there was that if someone wanted to easily grab those settings and register those events/patterns for listening it would be a nice function.
As far as streamlining the pattern matching, I am not as familiar with Lua yet to grasp the FindString construct you created. Using the events would eliminate the if then else construct and only be watching for the specific ones you need.
Parser__Self_Crit_Hit would be an internal event, not registered to other addons, that is used for the internal communication to the same addon.
Its like saying within a win32 application that a click event happened but you dont want to send a message to another application.
Hence, you dont have to create your tree because you already know the pattern and just have to parse the data from the arguments passed in.
So if I have a function called Parse__Self_Crit_Hit(msg) I already know the pattern for it and can disassemble it. Then trigger the real event Parse_Self_Crit_Hit with the arguments "CRIT", Victim, Damage, Absorbed. Absorbed is there for the cases where there is a damage redux like "You Crit Onyxia for 132(50)." It would be null if nothing was absorbed.
You only register the events needed by clients and register the internal ones to parse the patterns. So if a client wanted to know about CHAT_MSG_COMBAT_SELF_HITS specifically Critical Hits, you register CHAT_MSG_COMBAT_SELF_HITS and ONLY the internal evens that you will generate from the original event, say Parser__Hit_Crit_Self_Other. The others might be Parser__Hit_Self_Other, Parser_Damage_Falling_Self, Parser__Damage_Fire_Self and Parser__Damage_Lava_Self. You would then trigger the real Parser events from the internal one and the clients would have to themselves listen for the real ones and only pass them in for registration like
MYADDON:ParserRegisterNewEvent("Parser_Hit_Crit_Self_Other");
Some type of tracking system like you have for clients is not needed because the addon itself is listening for the event and should handle it. All they need to do is call the inherited func from your Ace_Parser.
Of course this is all based on if the lib can listen for events generated by itself :P
I think you underestimate ParserLib and the parse engine behind it and what it does. The engine is a very abstract and generic.
It does not listen to specific events and parse each event for it own. It has an engine with which is it easy to include more events in a very nice an quick way.
You also should concern, that incomming events are mapped on several outgoing events and that it's not a one to one relation.
The suggestions from you would only decrease the object oriented and generic approach - and with it the maintanability.
Look at SW_Stats - it was at the time a unique way to parse the combat messages without localization based string searches. So the parsing would do it in every language. It helped me a lot to understand ParserLib.
Btw: Someone want to Ace SW_Stats? :P
Sorry, couldn't hold off the comment ;)