Friday, September 4, 2020

Enforcer 1.0 release

Enforcer 1.0 is going up in vendors as I type this, and will be on MP shortly.  Incidentally, regardless of whether you purchased a copiable CHAOS product on Marketplace or through a vendor, you can always get a redelivery of the latest version of that product through any CasperVend vendor.   If you use one of my vendors (locations given in the stickies to the right), your purchases from me will be collected at the top of the page, so you can easily find the item you're looking for.  I generally release new versions in vendors first, with MP listings lagging, so if you buy something on MP, it's worth getting a redelivery from CasperVend right away to make sure you have the very latest version.

Most of the new features in Enforcer 1.0 have already been discussed here and here, but there is one additional new feature that slipped in before the release cut-off, as well as a a new standard namespace, and a minor change to observable behavior relating to empty strings and undefined variables.  Also, just as I was preparing what I expected to be 1.0, the latest rolling restart seemed to have introduced some significant script performance issues, which were bad enough that I felt I needed to make a few compensating changes to The Enforcer.


Event command

The new feature is the ability to create an event from inside another event.  This is achieved by the new !event command.  The event command takes three parameters: the name of the event, the canonical legacy name of the user the event should run under, and a series of initial variable values, separated by semicolons.  As an example, the following command:

!event MyEvent::Nue Broome::answer=42;question=unknown

will generate an event called "MyEvent" for user "Nue Broome" (which will look in order for notecards called "MyEvent:Nue Broome", "MyEvent:*" or "MyEvent" and run the first one that it finds), and it will populate the new event's namespace with two variables: answer and question, initialized with the values "42" and "unknown" respectively.

The event command is a programmatic version of the Event choice on The Enforcer's menu, the only difference being that variable initializations are separated by semicolons in the event command, whereas they're specified on individual lines when creating an event via the menu.  Also, the individual variable values in the event command can be enclosed in double or single quotes, in case you want to include a semicolon in a value, or use leading or trailing spaces around the value (without quoting the value, such external whitespace would be removed).

So why would you want to create an event from inside another event?  The most important use for this is to cause activity in one user's Mesmerizer when a second user's Mesmerizer (or communicator) signals an event.  For example, let's assume that I have a sub called "Jane Doe", and I want to have Jane automatically teleport home if she's online when I log in.   Assuming that I always wear either a Communicator or a Mesmerizer, then a Logon event will be generated whenever I connect to a Hub, and this will happen when I log in to SL, and so this event would seem like a good place to teleport Jane home.  The problem is that the Logon event is running for me, and so it can't talk to Jane's Mesmerizer.   But if my Logon event were to generate a custom "SummonHome" event for Jane, that event would run on behalf of Jane and could send her Mesmerizer a tpto command to bring her home.  So the notecards involved would be:

----- Logon:Nue Broome -----

!event SummonHome::Jane Doe::


-----  SummonHome:Jane Doe -----

^tpto "My Home Sim (128, 128, 25)"


If Jane were not logged in, then the tpto command would simply be dropped (since her Mesmerizer would not be rezzed and listening for commands).

If you wanted to perform a number of tasks in the event running for Jane, you might want to make sure that she is actually online first, both so that The Enforcer doesn't waste time sending commands when nothing's listening, and also in case Jane does log in while the SummonHome event is still running, which might cause her to be sent only the last few commands in the notecard.  One obvious way to do this would be the use the new !checkonline command - something like:

!checkonline JaneOnline::Jane Doe
!exitif $JaneOnline isfalse
^tpto "My Home Sim (128, 128, 25)"
...


However, a better method might be to have the SummonHome event tell Jane's Mesmerizer to signal that it's ready to accept those commands:

^signal BringMeHome "$$sim"

This will cause Jane's Mesmerizer to initiate an event called BringMeHome, and that event can then issue multiple commands (including the tpto to bring her home).  Note the use of the $$sim in the second parameter to signal.  If you had used $sim, then before sending the command to Jane's Mesmerizer, The Enforcer would attempt to replace the $sim with the value of an Enforcer variable called sim, which probably isn't defined, and so would expand to an empty string.  However, a double dollar sign causes The Enforcer to simply replace the $$ with $ and not attempt to perform local expansion on sim, resulting in the string $sim being passed to Jane's Mesmerizer.  "sim" is a predefined symbol inside the Mesmerizer, so when Jane's Mesmerizer executes the signal command, "$sim" will expand to the name of the sim where Jane currently is, and this value would be sent back to The Enforcer as the data parameter to Jane's BringMeHome event, which might, for example, avoid issuing the tpto if Jane was already in her home sim.

In the near future, I will introduce commands to allow events to be scheduled in advance.

System Namespace

I talked about Persistent Namespaces in a previous post.  There is now a standard Persistent Namespace, called "System".  Whenever the main script in The Enforcer is reset, a variable called StartTime will be set in the System namespace, and will contain the timestamp of the restart.

There is nothing special about the System namespace (other than it automatically being created and populated when The Enforcer is restarted), but you should avoid creating or modifying variables in it, as I may use it for additional internal purposes in future releases.

Expansion of undefined variables

Previously, if you tried to expand a variable that hasn't been defined, the expansion would simply return the name of the variable (followed by a semicolon to separate it from any surrounding text).  So if variable X is not defined, a use of "$X" in an Enforcer commands would be translated to "$X;".  As of V1.0, this is no longer the case - undefined variables will now expand to an empty string.  There is no difference between a variable that's not defined and one that is set to an empty string (in fact, setting a variable to an empty string will delete the variable entirely).

This is a much more logical way of handling unset variables, but it requires that empty strings be properly supported, for example as operands within expressions.  This should now be the case.  For instance, the following tests whether variable X is defined:

!if "$X" "" streq
...
!fi 

Either single or double-quotes can be used to group words into single operands in an expression (but you have to open and close the quoted text with the same character).

When The Enforcer sees a dollar sign in a notecard line, it will assume this is a request to expand a variable (except if there are two consecutive dollar signs, as discussed above).  The variable name is everything after the dollar sign, until (and excluding) a character that isn't allowed in a variable name (basically any character that's not a letter or a number).  This means that if you had the following variable definitions:

!setvar foo::FOO
!setvar bar::BAR
!setvar baz::BAZ

Then the following expansions would be made:

source expansion
$foo $bar $baz FOO BAR BAZ
$foo$bar$baz FOOBARBAZ
$fooBAR$baz BAZ
$foo;BAR;$baz FOOBAR;BAZ
$foo;;BAR;$baz FOO;BAR;BAZ

Note the third row, there is no separating character between "foo" and "BAR", so The Enforcer treats these as a single variable name "fooBAR", which is undefined, and therefore expands to an empty string.  If you need to immediately follow a variable expansion with an alphanumeric character, you can use a semicolon to mark the end of the variable name, as in the fourth line.  This terminating semicolon is removed during variable expansion, as shown (so if you actually want a semicolon to appear immediately following a variable expansion, you need to provide two semicolons, as in the fifth line).

Futures


V1.0 of The Enforcer is a significant advance over the pre-release version, in terms of both capacity and the power of the new language features.  I have ideas for improving both of these areas further, so I anticipate a V1.1 release in the not too distant future.  However, I also realize there's a need for better documentation for both The Enforcer and the Mesmerizer, so I intend to spend some time (after Mesmerizer V1.5 is released) on putting together reference manuals for both, here in the blog, where they can be kept current.  The reference manual for The Enforcer can be found here, and is also available via the stickies on the right of the page.

No comments:

Post a Comment