integer llListen(integer channel, string name, key id, string msg)
Sets a filter for listening to the specified chat channel
while the current state persists. If a message is heard that meets the specified criteria, the object's listen() event
handler is invoked.
Messages are heard from the root prim of a link-set, not the scripted prim, making this command awkward for use in large builds. To avoid this causing a problem, keep root prims towards the center, or most used part, of your builds.
, and msg arguments
specify the filtering criteria. You can pass the empty string
) for these to set a completely open filter; this causes the listen()
event handler to be invoked for all chat on the channel. To listen only for chat spoken by a specific object
, specify the name
arguments. To listen only for a specific command, specify the (case-sensitive) msg
argument. You can also use all the arguments to establish the most restrictive filtering criteria.
Caution: The id
is the key
of the originator of the chat. In the case of an agentandavatar
it will coorespond with llGetOwner
. In the case of an object
of the root prim (which changes on rez) is returned not the key
of the owner of the prim. To verify that a chat message emitted by an object is owned by a particular agentandavatar
(as is often the case with HUDs) use llGetOwnerKey
and compare that with the value returned by llGetOwner
inside the listen
This function returns
a handle that can be used to deactivate or remove the specific channel filter using llListenControl
. An object should remove any filters it has established when it no longer needs them. Listen filters DO NOT
persist and are automatically removed on state
changes. The returned handles start at 1, so you can set your handle variable to 0 (zero) when you deactivate a channel and test for that elsewhere when you need to know if it's active or not.
Using many instances of llListen
can have a visible effect on sim
performance and cause lag
. If there is a viable alternative communication
method such as llMessageLinked
, consider using that instead. Especially avoid listening on channel 0 whenever possible. If you must listen to regular chat conversation, use a filter if possible.
If a script with an llListen
"hears" a string longer than the script's amount of available free memory, it will halt with a "stack/heap collision" error before your code in the listen()
event handler has a chance to begin executing. As of SL v1.13, a single chat string on any channel can be up to 1023 bytes
Establishes a completely open filter for avatar chat:
Sets a filter that listens only for chat spoken by the object's owner
Sets a filter that listens on channel 96 for objects named "button":
This could be used, for example, in an elevator that responds to button objects on different floors of a building. Each button object would have the same name, but could identify its floor through the specific message it sends.
To set up to 65 filters on different channels, call llListen
repeatedly with different criteria. All messages found by any filter are passed to the same listen event handler. If llListen
is called again with the identical criteria, the same listener handle is returned, and the listen()
event will only be called once.
If a script
goes over its limit of 65, it crashes with a run-time "Too Many Listens" error
As of SL 1.5.4
, the following does
To listen on a single channel, for both chat from the owner and from an object with a certain name, (or any other combination of logic) the best option is to use a single llListen
function and an if-else
in the listen
Selling scripts which contain listeners can be problematic if the id parameter
is set to llGetOwner
. Be sure to update listen filters or use llResetScript
when it changes owners if a script's listeners are set to only listen to their owner.
// listen on channel zero for any chat spoken by the object owner.
listen(integer channel, string name, key id, string message)
// check if the message corresponds to a predefined string.
// llToLower converts the message to lowercase.
// This way, "HELLO", "Hello" or "HeLLo" will all work the same way.
if (llToLower(message) == "hello")
// if the message from the owner is "hello", respond with "Hello.".
One common problem that is easy to forget about when creating a fancy new scripted widget is crosstalk. This occurs when objects get confused about whose messages are whose. This can be two identical objects which mistake each other's messages or other people's objects which happen to use the same channel and may send problematic (partially compatible and invalid) messages.
There are a number of ways to deal with this problem. A few are listed here:
- Make filters as tight as possible. For example, use llGetOwner for the id filter.
- For scripts that only need to talk to themselves (dialogs for example) use a random channel. An example can be found on the llFrand page. This strategy can also be utilized when establishing communication with a rezzed object (pass the random integer via llRezObject's integer parameter).
- For private channels across multiple objects use a deterministic equation that results in a unique value yet is repeatable. For example, base the channel on the integers contained in the owner's key. This way two users can both use their copies of the same object in close proximity without difficulty.
- Pass additional data (like a unique command word or the key of the sender or intended recipient) in the message that clues the listener in on the intended recipient or lets the listener know the message isn't from an object they're interested in.
- Avoid channels below 100. If you don't need humans to type the channel and listen on anything below 10 your object will be spammed. Negative channels cannot be used by avatars without an object intermediary, so these are the most ideal for object-object chat.
- Do a llGetOwnerKey(id) == llGetOwner() check in your listen event to filter out chat emitted by objects not owned by the same owner.
This is a common issue and the solution can vary widely based on the requirements of a particular problem.
I know that it is listed that 64 listens per script is the limit but i was able to put in 65. Now 64 may be a suggested limit for memory useage reasons or something but I fit 65 listen functions into 1 script all in 1 state and 1 event and the script had no errors and works fine.
It is not a memory constraint it is a specific run-time error, the wiki is simply wrong the number is 65 not 64, add one more listen to your script and it will fail with two errors
Q: I can see how the millions of scripts out there listening to channel 0 would collectively create lots of lag. But, with the callback mechanism and a listener on a private channel, it seems like the only time resources would be used is when an actual message is present. Is this the case?
A: Well, the real server-side problem is the filter. When a script listens on channel 0, it calls the filtering methods every time it hears something. This doesn't create a lot of lag, but tons of these without good use of callback can create some effect on server resources.
Q: Can a wildcard be used for the msg argument? I only want to monitor text that begins with "ls" but can be anything after it ("on", "off", "silence", etc).
A: Wildcards are not supported. You'll want to use llGetSubString or llSubStringIndex in your listen() event.
Q: How close to my listener do I have to be for it to hear me?
A: When saying chat, under 20m. When shouting, 100m. See chat for specifics with dealing with the other chat functions.
A2: Also, more recently, llRegionSay has been implemented, which allows communication throughout an entire sim. Though it cannot chat on channel 0.
This article wasn't helpful for you? Maybe the related article at the LSL Portal
is able to bring enlightenment.