This plugin was inspired by Shadowfyr's reply in:
http://www.gammon.com.au/forum/bbshowpost.php?bbsubject_id=3925&page=999999
I've always wanted to make some system of propagating custom events throughout the entire script network of my world: from one plugin to several others and/or main script file, main script to several plugins. World.CallPlugin only works one way, therefore it's not very useful for that purpose, besides it requires always keeping in mind what plugins need to be notified, and constantly putting in more CallPlugin calls in a multitude of places in a multitude of scripts. Ack! World.Execute, on the other hand, is suited perfectly for this. All that was missing was a simple realization that you don't need a separate alias for each call, they can all go through basically the same alias, duplicated in each "event-aware" plugin and the world file. Here's what I am talking about:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE muclient >
<muclient>
<plugin name="EventManager" author="Keldar" language="vbscript" purpose="Managing custom script events"
save_state="y" date_written="2004-03-11" requires="3.32" version="1.0" id="fc8161da9a2a5d7f56a03600">
</plugin>
<aliases>
<alias
name="register_listener"
match="fc8161da9a2a5d7f56a03600 reg_listener */*"
enabled="y"
sequence="100"
send_to="12"
><send>call RegisterListener("%1", "%2")</send></alias>
<alias
name="register_event"
match="fc8161da9a2a5d7f56a03600 reg_event *"
enabled="y"
sequence="100"
send_to="12"
><send>call RegisterEvent("%1")</send></alias>
<alias
name="dispatch_event"
match="fc8161da9a2a5d7f56a03600 dispatch_event */*"
enabled="y"
sequence="100"
send_to="12"
><send>call DispatchEvent("%1", "%2")</send></alias>
</aliases>
<script>
<![CDATA[
option explicit
dim evt_list()
ReDim evt_list(0, 0)
'Register a new event
RegisterEvent "OnTest"
'Register a plugin to listen for the event, supplying the plugin's ID and the event's name.
'The listening plugin must have a sub with the same name as an event it is listening to and
'this sub must accept exactly 1 argument, otherwise the event will cause an error
RegisterListener "8019349d696b61bfba64b08a", "OnTest"
sub RegisterListener (id, evt)
dim i, j, listenerExists
listenerExists = 0
for i = 0 to ubound(evt_list, 1)
if evt_list(i, 0) = evt then
for j = 0 to ubound(evt_list, 2)
if evt_list(i, j) = id then
listenerExists = 1
exit for
end if
next
if listenerExists then
exit for
end if
Redim Preserve evt_list(ubound(evt_list, 1), ubound(evt_list, 2) + 1)
evt_list(i, ubound(evt_list, 2)) = id
exit for
end if
next
end sub
sub RegisterEvent(evt_name)
dim i, eventExists, j
dim tempEvents_list(), tempListeners_list()
eventExists = 0
Redim tempEvents_list(ubound(evt_list, 1))
Redim tempListeners_list(ubound(evt_list, 2))
for i = 0 to ubound(evt_list, 1)
if evt_list(i, 0) = evt_name then
eventExists = 1
exit for
end if
tempEvents_list(i) = evt_list(i, 0)
for j = 0 to ubound(evt_list, 2)
tempListeners_list(j) = evt_list(i, j)
next
next
if eventExists then
exit sub
end if
Redim evt_list((ubound(evt_list, 1) + 1), 0)
for i = 0 to ubound(tempEvents_list)
evt_list(i, 0) = tempEvents_list(i)
for j = 0 to ubound(tempListeners_list)
evt_list(i, j) = tempListeners_list(j)
next
next
evt_list(ubound(evt_list, 1), 0) = evt_name
end sub
sub DispatchEvent(evt, args)
dim i, j
for i = 0 to ubound(evt_list, 1)
if evt_list(i, 0) = evt then
if ubound(evt_list, 2) = 0 then
exit for
end if
for j = 1 to ubound(evt_list, 2)
world.Execute evt_list(i, j) & ":" & evt_list(i, 0) & " " & args
next
exit for
end if
next
end sub
]]>
</script>
</muclient>
From here all that is needed to dispatch a registered event from any outside script is to do:
world.Execute "fc8161da9a2a5d7f56a03600 dispatch_event OnTest//none"
All that is needed to accept this event is an alias like this:
<alias
name="Sur_Send"
match="8019349d696b61bfba64b08a\:(\w+) (.*)"
enabled="y"
regexp="y"
keep_evaluating="y"
send_to="12"
>
<send>call %1 (%2)</send>
<//alias>
where 8019349d696b61bfba64b08a is the listener's id: either a plugin id (if it's a plugin) or the world's id (if it's the main script). Another requirement from a listener is a sub with the same name as the event it is listening to, which sub must accept exactly 1 argument.
Note, that although EventManager provides aliases for registering events and listeners, it is better to register both (event first, listeners after that) directly in EventManager's script section in global scope, the way it is done with the "OnTest" event. This is because there's no easy way to define an exact sequence in which the plugins are loaded, therefore if a dispatching plugin is loaded before EventManager, and tries to register new events upon startup, its' World.Execute calls will go straight to the world as text commands, which is no big deal but results in missing events and errors when these events are being dispatched later.
The following post has 2 test plugins that I used for testing this system - Test1 dispatched the "OnTest" event and Test2 catches it.
|