Difference between revisions of "LlListen"

From Second Life Wiki
Jump to navigation Jump to search
m
m (Revise caveat regarding DEBUG_CHANNEL and move to notes since it isn't a caveat)
 
(65 intermediate revisions by 22 users not shown)
Line 1: Line 1:
{{LSL_Function
{{LSL_Function
|inject-2={{LSL_Function/uuid|id|pd=filter for specific|group=}}{{LSL Function/chat|channel|msg|input=*|pd=filter for specific}}{{Issues/SVC-3170}}{{Issues/SVC-92}}{{Issues/BUG-3291}}
|func=llListen
|func=llListen
|sort=Listen
|sort=Listen
|func_id=25|func_sleep=0.0|func_energy=10.0
|func_id=25|func_sleep=0.0|func_energy=10.0
|return_type=integer
|return_type=integer
|return_text=that can be used to deactivate or remove the listen.
|return_subtype=handle
|p1_type=integer|p1_name=channel|p1_desc=any valid integer (-2147483648 through 2147483647).
|return_text=that can be used to [[llListenControl|deactivate]] or [[llListenRemove|remove]] the listen.
|p2_type=string|p2_name=name|p2_desc=filter for specific prim or avatar name
|p1_type=integer|p1_name=channel|p1_desc= (-2147483648 through 2147483647)|p1_hover= (-2147483648 through 2147483647)  
|p3_type=key|p3_name=id|p3_desc=filter for specific prim/avatar [[UUID]].
|p2_type=string|p2_name=name|p2_desc=filter for specific prim name or avatar {{LSLGC|Avatar/Name|legacy name}}
|p4_type=string|p4_name=msg|p4_desc=filter for specific chat message
|p2_hover=filter for specific prim name or avatar legacy name
|func_desc=Sets a callback for '''msg''' on '''channel''' from '''name''' and '''id'''.
|p3_type=key|p3_name=id
|func_footnote=If '''msg''', '''name''' or '''id''' are blank they are not used to filter incoming messages.
|p4_type=string|p4_name=msg
If '''id''' is an invalid key or a [[NULL_KEY|null key]], it is considered blank.<br/>
|func_desc=Sets a [http://foldoc.org/index.cgi?query=handle handle] for {{LSLP|msg}} on {{LSLP|channel}} from {{LSLP|name}} and {{LSLP|id}}.
|spec=For the [[listen]] [[event]] to be triggered it must first match the criteria set forth by the filters; only when all the criteria have been met is a listen event generated. First the message must have been transmitted on channel '''channel'''. If '''name''' is set then the speaker's name must match '''name''' exactly. If '''id''' is a valid, non-[[NULL_KEY|null]] key then the speaker's key must be equivalent. If '''msg''' is set then the spoken message must match '''msg''' exactly.
|func_footnote=If {{LSLP|msg}}, {{LSLP|name}} or {{LSLP|id}} are blank (i.e. <code>""</code>) they are not used to filter incoming messages.
If {{LSLP|id}} is an invalid key or assigned the value [[NULL_KEY]], it is considered blank as well.<br/>
|spec=For the [[listen]] [[event]] to be triggered it must first match the criteria set forth by the filters; only when all the criteria have been met is a listen event generated. First the message must have been transmitted on {{LSLP|channel}}. If {{LSLP|id}} is both a [[key#valid|valid]] key and not a [[key#null key|null]] key, then the speaker's key must be equivalent{{Footnote|In general terms this means the matching for {{LSLP|id}} is not case sensitive. See [[key#equivalency]] for details on key equivalency.|In general terms this means the matching for id is not case sensitive.}} to {{LSLP|id}}. If {{LSLP|name}} is set, then the speaker's {{LSLGC|Avatar/Name|legacy name}} must match {{LSLP|name}} exactly (case sensitive). If {{LSLP|msg}} is set, then the spoken message must match {{LSLP|msg}} exactly (case sensitive).
|also_functions={{LSL DefineRow||[[llListenRemove]]|Removes a listen}}
|also_functions={{LSL DefineRow||[[llListenRemove]]|Removes a listen}}
{{LSL DefineRow||[[llListenControl]]|Enables/Disables a listen}}
{{LSL DefineRow||[[llListenControl]]|Enables/Disables a listen}}
Line 19: Line 22:
{{LSL DefineRow||[[llShout]]|Sends chat limited to 100 meters}}
{{LSL DefineRow||[[llShout]]|Sends chat limited to 100 meters}}
{{LSL DefineRow||[[llRegionSay]]|Sends chat limited current sim}}
{{LSL DefineRow||[[llRegionSay]]|Sends chat limited current sim}}
{{LSL DefineRow||[[llRegionSayTo]]|Sends chat region wide to a specific avatar, or their attachments, or to a rezzed object of known UUID}}
|also_events={{LSL DefineRow||[[listen]]|}}
|also_events={{LSL DefineRow||[[listen]]|}}
|also_tests
|also_tests
|also_articles
|also_articles
|notes=Avoid channel 0 and set name or id where possible to avoid ([http://rpgstats.com/wiki/index.php?title=Lag Lag]). llListen(0,"","","") can be extremely laggy as it listens to all chat from everyone in chat range and so it should be avoided at all cost.
|haiku=
|constants={{LSL Constants/Chat}}
{{Haiku|Choose not much to say|Someone might overhear it|Blab no big secrets}}
|notes=*Avoid channel zero ([[PUBLIC_CHANNEL]]) and set {{LSLP|name}} or {{LSLP|id}} where possible to avoid lag. <code>llListen(0, "", NULL_KEY,"")</code> can be laggy as it listens to all chat from everyone in chat range and so should be avoided.
 
*In November 2007, [[User:Kelly_Linden|Kelly Linden]] offered [https://lists.secondlife.com/pipermail/secondlifescripters/2007-November/001993.html this explanation] to help scripters plan listeners more efficiently:
:#Chat that is said gets added to a history.
:#A script that is running and has a [[listen]] [[event]] will ask the history for a chat message during its slice of run time.
:# When the script asks the history for a chat message the checks are done in this order:
:#* {{LSLP|channel}}
:#* self chat (prims can't hear themselves)
:#* distance/[[llRegionSay|RegionSay]]
:#* {{LSLP|id}}
:#* {{LSLP|name}}
:#* {{LSLP|msg}}
:# If a {{LSLP|msg}} is found then a [[listen]] [[event]] is added to the [[event]] queue.
:
:The {{LSLP|id}}/{{LSLP|name}}/{{LSLP|msg}} checks only happen at all if those are specified of course.
:
:So, the most efficient communication method is [[llRegionSay]] on a rarely used {{LSLP|channel}}.
:Nowadays, [[llRegionSayTo]] is to be preferred, where appropriate.
*The integer returned can be assigned to a variable (then called a handle) and used to control the listen via [[llListenRemove]] or [[llListenControl]]. These handles are assigned sequentially starting at <tt>+1</tt> through to <tt>+2,147,483,647</tt>, going beyond which, according to [[User:Simon Linden|Simon Linden]], will roll the returned integer over to <tt>−2,147,483,648</tt>, when positive incrementation resumes. If an [[llListen]] is repeated with the exact same filters as a currently active listener, then the same handle number is returned. If an [[llListen|llListen's]] filters do not match any currently active listener, then the next handle in sequence is allocated (it will not re-allocate a recently removed handle).
*If you are using multiple listens in one script, each listen can be assigned its own handle with which to control it.
* Scripts can listen to and speak on [[DEBUG_CHANNEL]]. Script errors generated by the server are broadcast the same distance as [[llSay]], but any chat command can be used to speak on [[DEBUG_CHANNEL]].
** Messages received on [[DEBUG_CHANNEL]] in the viewer are hidden unless the message is sent by an object owned by the current user.
** Users may just see script errors as the hovering 'script error' icon depending on their viewer settings, and in any case will be able to read errors regardless of whether they are errors thrown by the scripting engine or your own debugging messages.
|caveats=*On [[state]] change or [[llResetScript|script reset]] all listens are removed automatically.
|caveats=*On [[state]] change or [[llResetScript|script reset]] all listens are removed automatically.
**A state change can be used as a shortcut to releasing listens.
**A [[state]] change can be used as a shortcut to releasing listens.
*Only 65 listens can simultaneously be open in any single script.
*Only 65 listens can simultaneously be open in any single script.
**If this number is exceeded ''Script run-time error'' and ''Too Many Listens'' errors occur.
**If this number is exceeded ''Script run-time error'' and ''Too Many Listens'' errors occur.
*Chat on negative channel numbers cannot be generated by the client except with dialog boxes.
*For some time, the official SL viewer and several third-party viewers can use negative channels from the chat bar directly just as any other non-zero channel. Formerly, the standard SL viewer could only send chat on negative channels through [[llDialog]] or [[llTextBox]] responses, meaning negative channels were best suited for applications that did not require direct avatar chat.
**This makes it ideal for object2object communications.
*Be aware that if you mistakenly use an integer literal bigger than the maximum or smaller than the minimum, LSL will treat it as -1, ''without'' giving any compilation error. This means that all scripts listening to an out-of-range integer will be listening to channel -1 instead, or if the number has a minus sign in front, to channel 1. A safe rule is to never use more than 9 digits. If the channel number comes from a conversion from float (for example from [[llFrand]]), if the float is out of range for an integer, it will be converted to the number -2147483648 regardless of its sign or value.
**This may just be an artificial limitation placed on the client and not the underlying protocol.
*Messages sent by script on positive and negative channels are truncated to 1024 bytes. Messages sent by chat on positive channels are truncated to 1023 bytes. Messages sent by chat from negative channels are truncated to 254 bytes.
*Once a listen is registered it's filters cannot be updated, if the listen is register to [[llGetOwner]], the listen will remain registered to the old owner upon owner change.
*Once a [[listen]] is registered its filters cannot be updated, if the listen is registered to [[llGetOwner]], the listen will remain registered to the previous owner upon owner change.
**[[CHANGED_OWNER|Owner change]] can be detected with the [[changed]] event.
**[[CHANGED_OWNER|Owner change]] can be detected with the [[changed]] event.
**To work around this the old listen will need to be closed and a new one opened for the new owner.
**To work around this the old listen will need to be closed and a new one opened for the new owner.
*A prim cannot hear itself talking.
*A prim cannot hear/listen to chat it generates. It can, however, hear a linked prim.
**Chat indirectly generated (as a result of [[llDialog]], [[llTextBox]] or from a [[Link|linked prim]]) can be heard if in range.
|examples=
|examples=
Trivial example to listen to any chat from the object owner and respond once. To reduce lag and avoid spamming surrounding users, it is vastly preferable to listen on channels other than 0 and to trigger the listen event by chatting on an alternative channel such as '/5 hello'.
Trivial example to listen to any chat from the object owner and respond once.
<lsl>// says beep to owner the first time owner says something in main chat;
{{{!}} class="sortable" width="100%" {{Prettytable}}
integer listen_handle;
{{!}}- {{Hl2}}
! '''Single listen handle'''
{{!}}-
{{!!}}<syntaxhighlight lang="lsl2">
// Says beep to owner the first-time owner says something in main chat
//  and then stops listening
 
integer listenHandle;
 
remove_listen_handle()
{
    llListenRemove(listenHandle);
}


default
default
{
{
     state_entry()
     state_entry()
     {   // Registers the listen to the owner of the object at the moment of the call.
     {
        // This does not automatically update when the owner changes.
//     Change the channel number to a positive integer
        // Change 0 to another positive number to listen for '/5 hello' style of chat.
//     to listen for '/5 hello' style of chat.
         listen_handle = llListen(0, "", llGetOwner(), "");
 
//      target only the owner's chat on channel 0 (PUBLIC_CHANNEL)
         listenHandle = llListen(0, "", llGetOwner(), "");
     }
     }
     listen( integer channel, string name, key id, string message )
 
     listen(integer channel, string name, key id, string message)
     {
     {
//      we filtered to only listen on channel 0
//      to the owner's chat in the llListen call above
         llOwnerSay("beep");
         llOwnerSay("beep");
        // Stop listening until script is reset
 
         llListenRemove(listen_handle);
//     stop listening until script is reset
         remove_listen_handle();
     }
     }
     on_rez(integer param)
 
     {   // Triggered when the object is rezed, like after the object had been sold from a vendor
     on_rez(integer start_param)
         llResetScript();//By resetting the script on rez it forces the listen to re-register.
     {
         llResetScript();
     }
     }
     changed(integer mask)
 
     {   // Triggered when the object containing this script changes owner.
     changed(integer change)
         if(mask & CHANGED_OWNER)
     {
         if (change & CHANGED_OWNER)
         {
         {
             llResetScript();
             llResetScript();
         }
         }
     }
     }
}</lsl>
}
</syntaxhighlight>
{{!}}}
 
{{{!}} class="sortable" width="100%" {{Prettytable}}
{{!}}- {{Hl2}}
! '''Two listen handles'''
{{!}}-
{{!!}}<syntaxhighlight lang="lsl2">
//  Opens two listen handles upon touch_start and
//  stops listening whenever something heard passes either filter
 
integer listenHandle_a;
integer listenHandle_b;
 
remove_listen_handles()
{
    llListenRemove(listenHandle_a);
    llListenRemove(listenHandle_b);
}
 
default
{
    touch_start(integer num_detected)
    {
        key    id  = llDetectedKey(0);
        string name = llDetectedName(0);
 
        listenHandle_a = llListen(5, "", id, "");
        listenHandle_b = llListen(6, "", NULL_KEY, "");
 
        llSay(0, "Listening now to '" + name + "' on channel 5.");
        llSay(0, "Listening now to anybody/anything on channel 6.");
    }
 
    listen(integer channel, string name, key id, string message)
    {
        if (channel == 5)
            llSay(0, name + " said: '/5 " + message + "'");
 
        if (channel == 6)
            llSay(0, name + " said: '/6 " + message + "'");
 
        remove_listen_handles();
    }
}
</syntaxhighlight>
{{!}}}
|cat1=Communications
|cat1=Communications
|cat2=Chat
|cat2=Chat
|cat3
|cat3=Legacy Name/As A Parameter
|cat4
|cat4=Error
}}
}}

Latest revision as of 21:11, 5 January 2023

Summary

Function: integer llListen( integer channel, string name, key id, string msg );

Sets a handle for msg on channel from name and id.
Returns a handle (an integer) that can be used to deactivate or remove the listen.

• integer channel input chat channel, any integer value (-2147483648 through 2147483647)
• string name filter for specific prim name or avatar legacy name
• key id filter for specific avatar or prim UUID
• string msg filter for specific message

If msg, name or id are blank (i.e. "") they are not used to filter incoming messages. If id is an invalid key or assigned the value NULL_KEY, it is considered blank as well.

Specification

For the listen event to be triggered it must first match the criteria set forth by the filters; only when all the criteria have been met is a listen event generated. First the message must have been transmitted on channel. If id is both a valid key and not a null key, then the speaker's key must be equivalent[2] to id. If name is set, then the speaker's legacy name must match name exactly (case sensitive). If msg is set, then the spoken message must match msg exactly (case sensitive).

Channel Constant Description
DEBUG_CHANNEL 0x7FFFFFFF Chat channel reserved for script debugging and error messages, broadcasts to all nearby users.
PUBLIC_CHANNEL 0x0 Chat channel that broadcasts to all nearby users. This channel is sometimes referred to as: open chat, local chat and public chat.

Caveats

  • Messages sent on channel zero[1] and DEBUG_CHANNEL are throttled to a rate of <200/10sec, per region, per owner/user.
    • Once the rate is exceeded, all following messages on channel zero or DEBUG_CHANNEL will be dropped until the send rate is again below 200/10sec for the previous 10 sec. Dropped messages, despite being dropped still count against the limit.
  • On state change or script reset all listens are removed automatically.
    • A state change can be used as a shortcut to releasing listens.
  • Only 65 listens can simultaneously be open in any single script.
    • If this number is exceeded Script run-time error and Too Many Listens errors occur.
  • For some time, the official SL viewer and several third-party viewers can use negative channels from the chat bar directly just as any other non-zero channel. Formerly, the standard SL viewer could only send chat on negative channels through llDialog or llTextBox responses, meaning negative channels were best suited for applications that did not require direct avatar chat.
  • Be aware that if you mistakenly use an integer literal bigger than the maximum or smaller than the minimum, LSL will treat it as -1, without giving any compilation error. This means that all scripts listening to an out-of-range integer will be listening to channel -1 instead, or if the number has a minus sign in front, to channel 1. A safe rule is to never use more than 9 digits. If the channel number comes from a conversion from float (for example from llFrand), if the float is out of range for an integer, it will be converted to the number -2147483648 regardless of its sign or value.
  • Messages sent by script on positive and negative channels are truncated to 1024 bytes. Messages sent by chat on positive channels are truncated to 1023 bytes. Messages sent by chat from negative channels are truncated to 254 bytes.
  • Once a listen is registered its filters cannot be updated, if the listen is registered to llGetOwner, the listen will remain registered to the previous owner upon owner change.
    • Owner change can be detected with the changed event.
    • To work around this the old listen will need to be closed and a new one opened for the new owner.
  • A prim cannot hear/listen to chat it generates. It can, however, hear a linked prim.
All Issues ~ Search JIRA for related Bugs

Examples

Trivial example to listen to any chat from the object owner and respond once.

Single listen handle
//  Says beep to owner the first-time owner says something in main chat
//  and then stops listening

integer listenHandle;

remove_listen_handle()
{
    llListenRemove(listenHandle);
}

default
{
    state_entry()
    {
//      Change the channel number to a positive integer 
//      to listen for '/5 hello' style of chat.

//      target only the owner's chat on channel 0 (PUBLIC_CHANNEL)
        listenHandle = llListen(0, "", llGetOwner(), "");
    }

    listen(integer channel, string name, key id, string message)
    {
//      we filtered to only listen on channel 0
//      to the owner's chat in the llListen call above

        llOwnerSay("beep");

//      stop listening until script is reset
        remove_listen_handle();
    }

    on_rez(integer start_param)
    {
        llResetScript();
    }

    changed(integer change)
    {
        if (change & CHANGED_OWNER)
        {
            llResetScript();
        }
    }
}
Two listen handles
//  Opens two listen handles upon touch_start and
//  stops listening whenever something heard passes either filter

integer listenHandle_a;
integer listenHandle_b;

remove_listen_handles()
{
    llListenRemove(listenHandle_a);
    llListenRemove(listenHandle_b);
}

default
{
    touch_start(integer num_detected)
    {
        key    id   = llDetectedKey(0);
        string name = llDetectedName(0);

        listenHandle_a = llListen(5, "", id, "");
        listenHandle_b = llListen(6, "", NULL_KEY, "");

        llSay(0, "Listening now to '" + name + "' on channel 5.");
        llSay(0, "Listening now to anybody/anything on channel 6.");
    }

    listen(integer channel, string name, key id, string message)
    {
        if (channel == 5)
            llSay(0, name + " said: '/5 " + message + "'");

        if (channel == 6)
            llSay(0, name + " said: '/6 " + message + "'");

        remove_listen_handles();
    }
}

Notes

  • Avoid channel zero (PUBLIC_CHANNEL) and set name or id where possible to avoid lag. llListen(0, "", NULL_KEY,"") can be laggy as it listens to all chat from everyone in chat range and so should be avoided.
  1. Chat that is said gets added to a history.
  2. A script that is running and has a listen event will ask the history for a chat message during its slice of run time.
  3. When the script asks the history for a chat message the checks are done in this order:
    • channel
    • self chat (prims can't hear themselves)
    • distance/RegionSay
    • id
    • name
    • msg
  4. If a msg is found then a listen event is added to the event queue.
The id/name/msg checks only happen at all if those are specified of course.
So, the most efficient communication method is llRegionSay on a rarely used channel.
Nowadays, llRegionSayTo is to be preferred, where appropriate.
  • The integer returned can be assigned to a variable (then called a handle) and used to control the listen via llListenRemove or llListenControl. These handles are assigned sequentially starting at +1 through to +2,147,483,647, going beyond which, according to Simon Linden, will roll the returned integer over to −2,147,483,648, when positive incrementation resumes. If an llListen is repeated with the exact same filters as a currently active listener, then the same handle number is returned. If an llListen's filters do not match any currently active listener, then the next handle in sequence is allocated (it will not re-allocate a recently removed handle).
  • If you are using multiple listens in one script, each listen can be assigned its own handle with which to control it.
  • Scripts can listen to and speak on DEBUG_CHANNEL. Script errors generated by the server are broadcast the same distance as llSay, but any chat command can be used to speak on DEBUG_CHANNEL.
    • Messages received on DEBUG_CHANNEL in the viewer are hidden unless the message is sent by an object owned by the current user.
    • Users may just see script errors as the hovering 'script error' icon depending on their viewer settings, and in any case will be able to read errors regardless of whether they are errors thrown by the scripting engine or your own debugging messages.

See Also

Events

•  listen

Functions

•  llListenRemove Removes a listen
•  llListenControl Enables/Disables a listen
•  llWhisper Sends chat limited to 10 meters
•  llSay Sends chat limited to 20 meters
•  llShout Sends chat limited to 100 meters
•  llRegionSay Sends chat limited current sim
•  llRegionSayTo Sends chat region wide to a specific avatar, or their attachments, or to a rezzed object of known UUID

Deep Notes

All Issues

~ Search JIRA for related Issues
   Listeners in child prims get positioned at root prim position first, then switch to child prim position after re-rez (resulting in wrong listener / whisper radius)
   llTargetSay() - region-wide direct communication
   llListen in linked objects is listening at root instead of linked object local position *after re-rezzing the linkset*

Footnotes

  1. ^ Channel zero is also known as: PUBLIC_CHANNEL, open chat, local chat and public chat
  2. ^ In general terms this means the matching for id is not case sensitive. See key#equivalency for details on key equivalency.

Signature

function integer llListen( integer channel, string name, key id, string msg );

Haiku

Choose not much to say
Someone might overhear it
Blab no big secrets