Programming the Enforcer is fairly simple. First you decide which event you want to respond to, and then you create a notecard that specifies the action(s) to perform when that event fires. Let's assume you have a Hub called "Hub_A", and you want to have the Enforcer send an email to you when Hub_A changes its address. First you create a notecard containing the action(s) you want to perform, in this case sending an email. Here's what the contents of that notecard might look like:
Hub_A address is $hubAddress
!mailto you@yourEmail.com::New web address for Hub_A::Use this URL to connect to the hub:\n $hubAddress
There are two lines in the notecard, although they may wrap in your browser. Each line is an action, and they are executed in order. Actions come in several flavors: announcements, comments, calls, local commands and Mesmerizer commands. The first character of the line is used to determine which flavor the action is. Local commands begin with an exclamation point (!), comments begin with a hash or pound sign (#), Mesmerizer commands begin with an up-arrow (^), a call begins with an at-sign (@) and anything else is an announcement. So in this example, the first action is an announcement, and the second is a local command. Let's take them in order.
First we have the announcement: Hub_A address is $hubAddress.
Announcements are simply sent verbatim as instant messages to the Enforcer's owner. The intent is that, for debugging, you can write your action notecards with every action as an announcement, and then when the event occurs, you'll see the commands that would be executed, without them actually doing anything. Once you're happy that they appear correct, you can add the appropriate "action character" at the start of each line to make them function. So the first line will send the Enforcer's owner an instant message saying something like:
Hub_A address is https://sim123.agni.lindenlab.com:12043/cap/12345678-1234-5678-9abcdef01234
Note that $hubAddress has been replaced by the address of the Hub. This is an example of variable substitution, and is similar to how the Mesmerizer expands variables. Each event is executed with a number of predefined variables, and additional variables can be set via a local command. The "Address" event, which is what the notecard we are creating will respond to, sets the hubAddress variable prior to invoking the notecard. Variables are expanded before the action is processed further.
The second line begins with an exclamation point, and it is therefore a local command. The command is mailto, and it takes three parameters, which are separated from one another by double-colons (::). The first parameter specifies the destination email address, in this case "you@yourEmail.com", the second is the subject-line of the email "New web address for Hub_A", and the third parameter is the body of the email "Use this URL to connect to the hub:\n $hubAddress". As in the previous line, "$hubAddress" will be expanded to the actual URL of the Hub. Note that the mail body parameter includes a "\n" sequence, which means "newline".
Now that we have the notecard, we need to make it be triggered by an Address event from Hub_A. We do than simply by putting the notecard into the inventory of the Enforcer, and naming it "Address:Hub_A". Whenever the Enforcer receives an "Address" event from Hub_A, it will execute the "Address:Hub_A" notecard.
That's fine, but what if you have lots of Hubs - you don't want to have to create a notecard for each of them. And you don't - instead what you can do is modify the notecard slightly so that it's more generic:
Hub: $hubName address is $hubAddress
!mailto you@yourEmail.com::New web address for hub $hubName::Use the following URL to connect to the hub:\n $hubAddress
Instead of explicitly saying "Hub_A" in the actions, we've used another variable expansion, $hubName, to provide the Hub's name. Any event signaled from a Hub will define the hubName variable.
Then, instead of naming the notecard "Address:Hub_A", we name it "Address:*". In this context, "*" is a wild-card that will match any hub-name. So when processing the Address event for Hub_A, the Enforcer will first look for a notecard called "Address:Hub_A" and if it doesn't find that, it will look for one called "Address:*". This process always tries the most-specific match first, and once a notecard is found, it is executed and no further searching is done.
Logon and Logoff events (which are Hub-generated) are similar, except that the second "field" in the action notecard name is the legacy username of the user who logged on or off. For example, if Mesmerizer user "John Smith" logs in wearing a Mesmerizer connected to Hub_A, their Hub will signal a Logon event and the Enforcer will look for a notecard named "Logon:John Smith", and then if that isn't found it will look for one called "Logon:*".
Mesmerizer-generated events are handled in a similar way, with the most significant difference being that the name of a notecard to respond to a Mesmerizer event has three "fields": the event-name, the avatar legacy name, and the sim they're in. For example, if John Smith teleports to the Lochme sim, their Mesmerizer will signal an event to their Hub, which will send a "Location" event to the Enforcer, which will then look for a notecard named "Location:John Smith:Lochme". If that isn't found, it will then look for a notecard named "Location:John Smith:*", and if that isn't found, it will look for "Location:*:Lochme". Finally if none of those notecards are found, it will look for "Location:*:*". This process allows you to create generic responses for Location events, and over-ride them for particular users and/or particular sims.
Here is the complete list of pre-defined events:
| Event Name | Parameter(s) | Description |
|---|---|---|
| Logon | Username | User logs on to a Hub |
| Logoff | Username | User logs off a Hub |
| Address | Hub-name | Hub changes its address |
| Location | Username, Sim-name | User moves to a new sim or changes position within a sim |
| Update | Username, Sim-name | Periodic "keepalive" event |
Additional user-defined events may be signaled from a Mesmerizer with the new signal command. This Mesmerizer command takes two parameters: the name of the event, and a "parameter" string that is used by the Enforcer to set a variable prior to dispatching the event. In the Enforcer, the event will be dispatched with the two standard parameters: Username and Sim-name.
Now that we have a feel for how a response notecard is picked for a given event, let's look in more detail at what such a notecard can contain. We've already covered announcements. Comments - lines starting with a # - are simply ignored. Mesmerizer commands - introduced by an up-arrow (^) - can be any channel 99 command, and are sent to the Mesmerizer that caused the event to be generated, as if they came from the user who owns the Enforcer and Hub. So they can only be used in events that originate at a Mesmerizer - they won't work, for example, in an Address event. Calls - lines starting with an @ - cause a new notecard to be invoked. When that notecard finishes executing, either by running out of actions or by executing an action that performs a "return", any subsequent actions in the original notecard will be executed. Local commands - introduced by a ! - are the most complex (other than Mesmerizer commands, which, being standard channel 99 commands, are already documented elsewhere in this blog).
The table below gives the available local commands:
| Command | Parameter(s) | Description |
|---|---|---|
| !mailto | Address :: Subject :: Body | Send an email to the specified address. |
| !sendim | RecipientKey :: Message | Send an IM to the specified avatar. |
| !setvar | Variable :: String | Set the variable to the String |
| !setvarex | Variable :: Expression | Evaluate an expression and set a variable to the result |
| !exit | Return from a called notecard | |
| !exitif | Expression | Return from a called notecard if the expression evaluates to True |
| !if | Expression | Start a condition. See text for description |
| !delay | Float | Delay for the specified number of seconds |
Conditionals
The Enforcer supports two types of conditional. The simplest is a conditional return: exitif. This is used within a called notecard (called via @), and will cause execution to return to the calling notecard if the expression evaluates to true.
The more general conditional form is the if ... then ... else ... fi. The following is the general form of the conditional:
!if expression
do_something
do_another_something
...
!else
do_something_else
...
!fi
Note that each keyword (if, else, fi) is an individual command, and must therefore appear on a notecard line by itself. An if must always have a terminating fi, but the else and the lines between it and fi are optional.
A note on variable substitution
Variable substitution is distinct from expression evaluation. As with the Mesmerizer, expressions are only permitted in a few places: In the second parameter of a setvarex command and the condition of an if or exitif. Variable substitution is performed on all actions. If you want to use an expression in some other context, you should use setvarex to evaluate the expression and assign the result to a variable, and then use variable substitution to insert the value of the evaluated expression where you want it.Variable substitution is requested by preceding a variable name with a $-symbol. The name can be ended with any non-alphanumeric character, but using a semicolon is most flexible since a terminating semicolon will be removed as part of the substitution, allowing you to butt the variable expansion up against following text if you wish.
No comments:
Post a Comment