Friday, September 18, 2020

The Enforcer - release post-mortem and upcoming Mesmerizer 1.5 release

Hot on the heels of The Enforcer 1.0, I will soon be releasing Mesmerizer 1.5.  This is only a minor version update, with the significant new features being the randoutfitmenu, menu2maygroup and getgroup commands described earlier.  In addition to these new features, the on-text event now sets a variable called text when it's invoked, and there are a couple of bugfixes to the RLV relay.

I hope that the Mesmerizer 1.5 release goes more smoothly than The Enforcer 1.0.  For the latter release, I found two late-breaking bugs that I'd introduced in my performance enhancements, that meant I had to take down The Enforcer from MP and the vendors while I fixed them.  The good news is that, in this week's rolling restarts, LL seems to have addressed the script performance issues that were introduced a few weeks ago, and which forced me to delay the 1.0 release of The Enforcer while I made compensating performance improvements.  Now that raw script performance seems to be back to more-or-less how it was originally, with those performance enhancements The Enforcer simply flies - in fact it runs so fast that after the restart I had thought at first that it was completely broken, because contexts were completing and disappearing before I noticed them.

If you enable statistics on The Enforcer ("Stats On" in The Enforcer's menu), it will display and continuously update some information in hovertext above The Enforcer.  The first line of this hovertext gives the name of The Enforcer, and you should probably change this from simply "The Enforcer" to something more specific.  That will simplify things in the future if you ever find a reason to rez a second Enforcer (for example, to share traffic).  The second line of the statistics display shows how many Hubs are being monitored, and how many users are currently logged in across all those Hubs.  The third line shows the number of contexts and the number of namespaces being maintained.

I've discussed namespaces in previous posts.  The statistics display shows the total number of namespaces (persistent plus transient).  Contexts are the objects that The Enforcer uses to represent a notecard that's currently being executed.  So when The Enforcer is idle, the number of contexts shown should be 0, and the number of namespaces shown should be just the persistent namespaces that have been created, although there is a small delay between a context terminating and the associated transient namespace being deleted.

I have posted a reference guide to programming The Enforcer in the stickies to the right.  I intend to do something similar for the Mesmerizer, although because the Mesmerizer has a huge number of commands it will take a while to put them into a sensible structure for documentation.  In the mean time, also in the stickies is the "Useful Blog Pages" link, which includes a live query that will return all the blog pages flagged as containing Mesmerizer command documentation.

Once Mesmerizer 1.5 is out, I expect the next version of the Mesmerizer to be mostly a performance update.  I also plan to add at least the randoutfit and maygroup commands to the Owner HUD.  And in the next release of The Enforcer, I intend to add a scheduler, so that you can cause scripts to run at specific times, rather than just in response to external events.  Those are my current plans;  in almost all previous releases, I've ended up inserting additional functionality as a result of continued use of the current versions of the CHAOS products, and in response to user requests.  If you have an idea for a feature, please tell me about it in an IM in-world.

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.