Skip to content
This repository has been archived by the owner on Feb 28, 2024. It is now read-only.

[BUG-233039] Add a function: llListenPrefix() #10199

Open
sl-service-account opened this issue Dec 7, 2022 · 5 comments
Open

[BUG-233039] Add a function: llListenPrefix() #10199

sl-service-account opened this issue Dec 7, 2022 · 5 comments

Comments

@sl-service-account
Copy link

How would you like the feature to work?

Currently we already have llListen(). The problem is llListen() can only filter exact-match messages, meaning that its usage is limited.

I propose llListenPrefix() with the following signature:

integer llListenPrefix( integer channel, string name, key id, string prefix, integer flags );

This matches any message destined to channel/name/id that begins_with the prefix.

For the flags, we can have a bitmask like so:

PREFIX_CASE_SENSITIVE = 0x1;
  // if not specified, the match is case-sensitive
PREFIX_NO_AUTOTRIM = 0x2;
  // if not specified, then space between channel "/1" and prefix will be trimmed before matching. So "/1 prefix" and "/1prefix" will match
PREFIX_NO_AUTOCHOMP = 0x4;
  // if not specified, then the prefix will be removed from the message passed to the listen() event

Possible Variants

llListenPrefixes(...)

Same as {}llListenPrefix{}, but rather than a string prefix argument, it accepts a list prefixes argument instead, the list containing possible prefixes to match. This allows an item to respond, for instance, not just to a user-specific prefix (e.g., "cm") but also a 'wildcard' prefix (e.g., "*").

llListenRegex(...)

Similar to {}llListenPrefix{}, except the argument is a {}string regex{}, and the flags CASE_SENSITIVE and NO_AUTOCHOMP should be ignored, as all regex matches will always be case sensitive and not autochomped.

Why is this feature important to you? How would it benefit the community?

In SL, there are several items that all listen to the same channel. To differ between them, these items need messages to them be prefixed with the first letters of the firstname.lastname SL username.

A widespread example is OpenCollar. All OpenCollar collars listen on channel 1. To differ between a collar worn by "Claire Magic" or "Willow Foxpaws", for example, the collar worn by Claire will be invoked using "/1cmmenu", while the collar worn by Willow will be invoked using "/1wfmenu".

(Collars can't filter the messages based on avatar name or avatar UUID because the command they receive can come from anyone/anything)

This requires filtering in the script side, though. So let's say there are 8 collar-wearers within talking distance. If someone typed "/1cmmenu", ALL EIGHT collars will have to wake up and check for the prefix, and only 1 will continue while the others go back to sleep.

With llListenPrefix, the filtering happens by the server. Resulting in only 1 script being awakened, while the other scripts stay asleep.

In addition, some items monitor channel 0 (Local Chat) and also only actually trigger if residents add a prefix. For example, a script might respond only if a resident prefix their sentence using "computer" ... say, like, "computer, open hailing frequency". With the current llListen(), the script is forced to respond to every single line being uttered in Local Chat, prefixed or not

With llListenPrefix, the script can 'rest' in the background until the filter matches with the desired prefix.

Combined, the benefits of (1) keeping all scripts asleep and activating only one, and (2) keeping one script sleeping and waking only when necessary, should greatly reduce server load and thus reducing lag and thus making SL a more enjoyable place to be in.

Original Jira Fields
Field Value
Issue BUG-233039
Summary Add a function: llListenPrefix()
Type New Feature Request
Priority Unset
Status Accepted
Resolution Accepted
Labels scripting
Created at 2022-12-07T18:05:02Z
Updated at 2022-12-14T04:42:00Z
{
  'Build Id': 'unset',
  'Business Unit': ['Platform'],
  'Date of First Response': '2022-12-07T14:20:34.075-0600',
  'How would you like the feature to work?': 'Currently we already have llListen(). The problem is llListen() can only filter exact-match messages, meaning that its usage is limited.\r\n\r\nI propose llListenPrefix() with the following signature:\r\n\r\ninteger llListenPrefix( integer channel, string name, key id, string prefix, integer flags );\r\n\r\nThis matches any message destined to channel/name/id that _begins_with_ the prefix.\r\n\r\nFor the flags, we can have a bitmask like so:\r\n\r\nPREFIX_CASE_SENSITIVE = 0x1;\r\n  // if not specified, the match is case-sensitive\r\nPREFIX_NO_AUTOTRIM = 0x2;\r\n  // if not specified, then space between channel "/1" and prefix will be considered\r\nPREFIX_NO_AUTOCHOMP = 0x4;\r\n  // if not specified, then the prefix will be removed from the message passed to the listen() event\r\n',
  'ReOpened Count': 0.0,
  'Severity': 'Unset',
  'Target Viewer Version': 'viewer-development',
  'Why is this feature important to you? How would it benefit the community?': 'In SL, there are several items that all listen to the same channel. To differ between them, these items need messages to them be prefixed with the first letters of the firstname.lastname SL username.\r\n\r\nA widespread example is OpenCollar. All OpenCollar collars listen on channel 1. To differ between a collar worn by "Claire Magic" or "Willow Foxpaws", for example, the collar worn by Claire will be invoked using "/1cmmenu", while the collar worn by Willow will be invoked using "/1wfmenu".\r\n\r\n(Collars can\'t filter the messages based on avatar name or avatar UUID because the command they receive can come from anyone/anything)\r\n\r\nThis requires filtering in the script side, though. So let\'s say there are 8 collar-wearers within talking distance. If someone typed "/1cmmenu", ALL EIGHT collars will have to wake up and check for the prefix, and only 1 will continue while the others go back to sleep.\r\n\r\nWith llListenPrefix, the filtering happens by the server. Resulting in only 1 script being awakened, while the other scripts stay asleep.\r\n\r\nIn addition, some items monitor channel 0 (Local Chat) and also only actually trigger if residents add a prefix. For example, a script might respond only if a resident prefix their sentence using "computer" ... say, like, "computer, open hailing frequency". With the current llListen(), the script is forced to respond to every single line being uttered in Local Chat, prefixed or not\r\n\r\nWith llListenPrefix, the script can \'rest\' in the background until the filter matches with the desired prefix.\r\n\r\nCombined, the benefits of (1) keeping all scripts asleep and activating only one, and (2) keeping one script sleeping and waking only when necessary, should greatly reduce server load and thus reducing lag and thus making SL a more enjoyable place to be in.',
}
@sl-service-account
Copy link
Author

KT Kingsley commented at 2022-12-07T20:20:34Z, updated at 2022-12-07T20:20:57Z

As mentioned in the forum thread (llListenPrefix), I'd vote for a version that uses a regular expression (regex), or some slimmed down version thereof, rather than simply a prefix.

@sl-service-account
Copy link
Author

JIRAUSER342641 commented at 2022-12-07T20:27:38Z, updated at 2022-12-07T20:29:21Z

Much agree with @kt Kingsley there!

However if that's too complex to implement, I'd settle for the simpler prefix version ;)

. . . how about both?

llListenPrefix() and llListenRegex() ... the latter comes of course with the obligatory link to the xkcd comic ...

@sl-service-account
Copy link
Author

Dan Linden commented at 2022-12-07T20:54:54Z

Issue accepted. We have no estimate when it may be implemented. Please see future release notes for this fix.

@sl-service-account
Copy link
Author

JIRAUSER342641 commented at 2022-12-09T04:38:45Z

Lovely! Thanks @dan Linden!

@sl-service-account
Copy link
Author

JIRAUSER342641 commented at 2022-12-09T05:52:28Z, updated at 2022-12-09T05:56:30Z

Not having anything better to do I decided to write a Python-like pseudocode:

 

def handle_message(message: str, prefix: str):
    if AUTOTRIM:
        message = message.trim_left()
    if CASE_INSENSITIVE:
        to_check = message[0:len(prefix)].casefold()
        prefix = prefix.casefold()
    else:
        to_check = message[0:len(prefix)]
    if to_check != prefix:
        return
    if AUTOCHOMP:
        message = message[len(prefix):]
        if AUTOTRIM:
            message = message.trim_left()
    dispatch_listen_event(message)

A regex variant can be implemented by changing the "if CASE_INSENSITIVE" block and the "to_check != prefix" block. If a regex variant is implemented, though, the AUTOCHOMP block should be taken out as there's no way to easily determine how much to chomp if we do a regex match.

Edit: The reason I'm not using ".startswith()" in the pseudo-code above is that I don't know how the back-end is implemented. It might be inefficient to run something akin to ".startswith()", and might also be inefficient to do a ".casefold()" on the whole message string.

 

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant