LSL Protocol/RestrainedLifeAPI
Restrained Life viewer v1.10 Specification
Audience
This document is aimed at people who wish to modify or create their own LSL scripts to use the functionalities of the RestrainedLife viewer. It does not, however, explains LSL concepts such as messages and events, nor universal concepts such as UUIDs.
Introduction
The RestrainedLife viewer is meant to execute certain behaviours when receiving special messages from scripts in-world. These messages are mostly calls to the llOwnerSay() LSL function.
Architecture
The RestrainedLife viewer parses every llOwnerSay call and executes every command beginning with '@'. For instance, a call to llOwnerSay ("@detach=n") will tell the viewer that the object sending the message cannot be detached until further notice.
Version 1.10 and above are able to parse multiple commands in one message, in order to avoid spamming the user who is not using this viewer. The format of a message is therefore :
@behaviour1:option1=param1,behaviour2:option2=param2,...,behaviourN:optionN=paramN Note that there is only one '@' sign, placed at the beginning of the message. The viewer understands this as "this whole llOwnerSay() is actually a command to execute", so no need to put a '@' before every command, it wouldn't even work. If at least one command fails (typo), the viewer says "... fails command : ... " and mentions it all. However correct commands are parsed and executed, only incorrect ones are discarded.
Warning : These behaviours are not persistent between sessions, and an object changes UUID everytime it rezzes. This means the object must resend its "status" (undetachable, preventing IMs...) in the on_rez () event as well as when it changes.
List of commands
Note : These commands are not case-sensitive but are spacing-sensitive. In other words, "@detach = n" will not work.
- Automated version checking : "@version=<channel_number>"
Makes the viewer automatically say its version immediately on the chat channel number <channel_number> that the script can listen to. Always use a positive integer. Remember that regular viewers do not answer anything at all so remove the listener after a timeout.
Warning : when logging in, the on_rez event of all the attachments occurs way before the avatar can actually send chat messages (about half the way through the login progress bar). This means the timeout should be long enough, like 30 seconds to one minute in order to receive the automatic reply from the viewer.
- Manual version checking : "@version"
This command must be sent in IM from an avatar to the user (will not work from objects). The viewer automatically answers its version to the sender in IM, but neither the message nor the answer appears in the user's IM window, so it's totally stealthy.
- Render an object detachable/nondetachable : "@detach=<y/n>"
When called with the "n" option, the object sending this message (which must be an attachment) will be made nondetachable. It can be detached again when the "y" option is called.
- Allow/prevent sending chat messages : "@sendchat=<y/n>"
When prevented, everything typed on channel 0 will be discarded. However, emotes and messages beginning with a slash ('/') will go through, truncated to strings of 30 and 15 characters long respectively (likely to change later). Messages with special signs like ()"-*=_^ are prohibited, and will be discarded. When a period ('.') is present, the rest of the message is discarded.
- Remove/add an exception to the emote truncation above : "@emote=<rem/add>"
When adding this exception, the emotes are not truncated anymore (however, special signs will still discard the message).
- Allow/prevent sending instant messages : "@sendim=<y/n>"
When prevented, everything typed in IM will be discarded and a bogus message will be sent to the receiver instead.
- Remove/add exceptions to the instant message sending prevention : "@sendim:<UUID>=<rem/add>"
When adding an exception, the user can send IMs to the receiver whose UUID is specified in the command. This overrides the prevention for this avatar only (there is no limit to the number of exceptions), don't forget to remove it when it becomes obsolete.
- Allow/prevent receiving chat messages : "@recvchat=<y/n>"
When prevented, everything heard in public chat will be discarded.
- Remove/add exceptions to the chat message receiving prevention : "@recvchat:<UUID>=<rem/add>"
When adding an exception, the user can hear chat messages from the sender whose UUID is specified in the command. This overrides the prevention for this avatar only (there is no limit to the number of exceptions), don't forget to remove it when it becomes obsolete.
- Allow/prevent receiving instant messages : "@recvim=<y/n>"
When prevented, every incoming IM will be discarded and the sender will be notified that the user cannot read them.
- Remove/add exceptions to the chat message receiving prevention : "@recvim:<UUID>=<rem/add>"
When adding an exception, the user can read instant messages from the sender whose UUID is specified in the command. This overrides the prevention for this avatar only (there is no limit to the number of exceptions), don't forget to remove it when it becomes obsolete.
- Allow/prevent teleporting to a landmark : "@tplm=<y/n>"
When prevented, the user cannot use a landmark, pick or any other preset location to teleport there.
- Allow/prevent teleporting to a location : "@tploc=<y/n>"
When prevented, the user cannot use teleport to a coordinate by using the map and such.
- Allow/prevent teleporting by a friend : "@tplure=<y/n>"
When prevented, the user automatically discards any teleport offer, and the avatar who initiated the offer is notified.
- Remove/add exceptions to the friend teleport prevention : "@tplure:<UUID>=<rem/add>"
When adding an exception, the user can be teleported by the avatar whose UUID is specified in the command. This overrides the prevention for this avatar only (there is no limit to the number of exceptions), don't forget to remove it when it becomes obsolete.
- Unlimit/limit sit-tp : "@sittp=<y/n>"
When limited, the avatar cannot sit on a prim unless it is closer than 1.5 m. This allows cages to be secure, preventing the avatar from warping its position through the walls (unless the prim is too close).
- Clear all the rules tied to an object : "@clear"
This command clears all the restrictions and exceptions tied to a particular UUID.
- Clear a subset of the rules tied to an object : "@clear=<string>"
This command clears all the restrictions and exceptions tied to a particular UUID which name contains <string>. A good example would be "@clear=tp" which clears all the teleport restrictions and exceptions tied to that object, whereas "@clear=tplure:" would only clear the exceptions to the "teleport-by-friend" restriction
- Allow/prevent editing objects : "@edit=<y/n>"
When prevented from editing and deleting objects, the Build & Edit window will refuse to open.
- Allow/prevent rezzing inventory : "@rez=<y/n>"
When prevented from rezzing stuff, creating objects, drag-dropping from inventory and dropping attachments will fail.
- Allow/prevent wearing clothes : @addoutfit[:<part>]=<y/n>
Where part is :
gloves|jacket|pants|shirt|shoes|skirt|socks|underpants|undershirt|skin
If part is not specified, prevents from wearing anything beyond what the avatar is already wearing.
- Allow/prevent removing clothes : @remoutfit[:<part>]=<y/n> (underpants and underwear are kept for teens)
Where part is :
gloves|jacket|pants|shirt|shoes|skirt|socks|underpants|undershirt|skin
If part is not specified, prevents from anything anything in what the avatar is wearing.
- Force removing clothes : @remoutfit[:<part>]=force (*)
Where part is :
gloves|jacket|pants|shirt|shoes|skirt|socks|underpants|undershirt|skin
If part is not specified, removes everything.
- Force removing attachments : @detach[:attachpt]=force (*) (underpants and underwear are kept for teens)
Where part is :
chest|skull|left shoulder|right shoulder|left hand|right hand|left foot|right foot|spine| pelvis|mouth|chin|left ear|right ear|left eyeball|right eyeball|nose|r upper arm|r forearm| l upper arm|l forearm|right hip|r upper leg|r lower leg|left hip|l upper leg|l lower leg|stomach|left pec| right pec|center 2|top right|top|top left|center|bottom left|bottom|bottom right
If part is not specified, removes everything.
- Get the list of worn clothes : @getoutfit[:part]=<channel_number>
Makes the viewer automatically answer the current occupation of clothes layers as a list of 0s (empty) and 1s (occupied) immediately on the chat channel number <channel_number> that the script can listen to. Always use a positive integer. Remember that regular viewers do not answer anything at all so remove the listener after a timeout. The list of 0s and 1s corresponds to : gloves,jacket,pants,shirt,shoes,skirt,socks,underpants,undershirt,skin in that order. If a part is specified, answers a single 0 (empty) or 1 (occupied) corresponding to the part. Ex 1 : @getoutfit=2222 => "0011000111" => avatar is wearing pants, shirt, underpants and undershirt, and of course a skin. Ex 2 : @getoutfit:socks=2222 => "0" => the avatar is not wearing socks.
- Get the list of worn attachments : @getattach[:attachpt]=<channel_number>
Makes the viewer automatically answer the current occupation of attachment points as a list of 0s (empty) and 1s (occupied) immediately on the chat channel number <channel_number> that the script can listen to. Always use a positive integer. Remember that regular viewers do not answer anything at all so remove the listener after a timeout. The list of 0s and 1s corresponds to : none,chest,skull,left shoulder,right shoulder,left hand,right hand,left foot,right foot,spine,pelvis,mouth,chin,left ear,right ear,left eyeball,right eyeball,nose,r upper arm,r forearm,l upper,arm,l forearm,right hip,r upper leg,r lower leg,left hip,l upper leg,l lower leg,stomach,left pec,right pec,center 2,top right,top,top left,center,bottom left,bottom,bottom right in that order. If an attachment point is specified, answers a single 0 (empty) or 1 (occupied) corresponding to the point. Ex 1 : @getattach=2222 => "011000011010000000000000100100000000101" => avatar is wearing attachments on chest, skull, left and right foot, pelvis, l and r lower leg, HUD bottom left and HUD bottom right. Ex 2 : @getattach:chest=2222 => "1" => avatar is wearing something on the chest. Note : The first character ("none") is always '0', so the index of each attach point in the string is exactly equal to the corresponding ATTACH_* macro in LSL. For instance, the index 9 in the string is ATTACH_BACK (which means "spine"). Remember the indices start at zero.
- Allow/prevent using inventory : @showinv=<y/n>
Forces the inventory windows to close and stay closed.
- Allow/prevent reading notecards : @viewnode=<y/n>
Prevents from opening notecards but does not close the ones already open.
- Allow/prevent standing up : @unsit=<y/n>
Hides the Stand up button.
- Force sit on an object : @sit:<UUID>=force (*)
Does not work if the user is prevented from sit-tping and further than 1.5 meters away, or when prevented from unsitting.
- Force unsit : @unsit=force (*)
Self-explanatory but for some reason it randomly fails, so don't rely on it for now. Further testing is needed.
- Allow/prevent using any chat channel but certain channels : @sendchannel[:<channel>]=<y/n>
Complimentary of @sendchat, this command prevents the user from sending messages on non-public channels. If channel is specified, it becomes an exception to the aforementioned restriction.
(*) Silently discarded if the user is prevented from doing so by the corresponding restriction. This is on purpose.
Ex : Force detach won't work if the object is undetachable. Force undress won't work if the user is prevented from undressing.
Important note about the global behaviours such as sendchat
Such behaviours are global, which means they don't depend on a particular object. However, they are triggered by objects with a set UUID which can change, and several objects can add the same behaviour, which will be stored several times as the UUIDs are different. This has a nice side effect : when wearing 2 locked devices that prevent chat, it is necessary to unlock them both to be able to chat again. But it has a nasty side effect, too : if the item changes UUID (for instance it was derezzed and rezzed again), and it doesn't allow chat beforehand, then the user will have to wait a short moment because the rule stays "orphaned" (its UUID is defunct) until the garbage collector kicks in. Therefore : ALWAYS DEACTIVATE A BEHAVIOUR WHEN THE OBJECT THAT HAS ACTIVATED IT DEREZZES FOR ANY REASON BESIDES LOGGING OUT ! "@CLEAR" IS YOUR FRIEND !
For your information
Here is how it works internally, for a better understanding of the gotchas one may encounter :
- Each command is parsed into a Behaviour (ex: "remoutfit"), an Option (ex: "shirt") and a Param (ex: "force") and comes from an UUID (the unique identifier of the emitting object).
- There are two types of commands : one-shot commands (those which Param is "force" and those which Param is a number such as the channel number of a "version" call) and rules (those which Param is "y", "n", "add" or "rem"). "clear" is special but can be seen as a one-shot command.
- Parameters "n" and "add" are exactly equal and are treated exactly the same way, they are just synonyms. Same goes for "y" and "rem". The only purpose is to distinguish rules ("sendchannel=n") from exceptions ("sendchannel:8=add") in a script for clarity.
- Rules are stored inside a table linking the UUID of the emitter to the rule itself. They are added when receiving a "n"/"add" Param, and removed when receiving a "y"/"rem" Param.
If UUID1 is a collar and UUID2 is a gag :
UUID1 => detach, tploc, tplm, tplure, sittp UUID2 => detach, sendim, sendim:(keyholder)
Those two rules mean that the user cannot send IMs except to their keyholder, and cannot TP at all. Those two items are undetachable. Now if the collar sends "@sendim=n", the table becomes :
UUID1 => detach, tploc, tplm, tplure, sittp, sendim UUID2 => detach, sendim, sendim:(keyholder)
If it sends "@sendim=n" a second time nothing changes, as there is a check for its existence prior to adding it. If the gag is unlocked and detached, either it sends a "@clear" or the garbage collector kicks in so the rules linked to UUID2 disappear. However, the avatar is still unable to send IMs even to their keyholder, as the exception has disappeared as well. This is because rules linked to one object don't conflict with rules linked to another one.
- One-shot commands are executed on-the-fly and are not stored.
- When logging on, the avatar stays non-operational (cannot chat, cannot move) for some time, while the user sees the progress bar. However, worn scripted objects rez in the meantime and start sending rules and commands before the viewer can execute them. Therefore it stores them in a buffer and executes them only when the user is given controls (when the progress bar disappears).
- The viewer periodically (every N seconds) checks all its rules and removes the ones linked to an UUID that does not exist around anymore ("garbage collector"). This means that rules issued by an unworn owned object will be discarded as soon as the avatar teleports elsewhere.