Difference between revisions of "LSL Protocol/RestrainedLifeAPI"

From Second Life Wiki
Jump to navigation Jump to search
(Making this a redirect)
 
(88 intermediate revisions by 11 users not shown)
Line 1: Line 1:
=Restrained Life viewer v1.12 Specification=
#redirect [[LSL_Protocol/RestrainedLoveAPI]]
 
By [[User:Marine Kelley|Marine Kelley]]
 
 
==Audience==
 
This document is aimed at people who wish to modify or create their own [[LSL]] scripts to use the functionalities of the [http://realrestraint.blogspot.com RestrainedLife viewer]. It does not, however, explains [[LSL]] concepts such as messages and events, nor universal concepts such as [[UUID]]s.
 
==Introduction==
 
The [http://realrestraint.blogspot.com 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 [http://realrestraint.blogspot.com 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 [[rez]]zes. 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>"
''Implemented in v1.0b''
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"
''Implemented in v1.0a''
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>"
''Implemented in v1.0a''
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>"
''Implemented in v1.0b''
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>"
''Implemented in v1.01''
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>"
''Implemented in v1.0b''
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>"
''Implemented in v1.01''
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>"
''Implemented in v1.0b''
When prevented, everything heard in public chat will be discarded.
 
* '''''Remove/add exceptions to the chat message receiving prevention''''' : "@recvchat:<UUID>=<rem/add>"
''Implemented in v1.01''
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>"
''Implemented in v1.0b''
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>"
''Implemented in v1.01''
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>"
''Implemented in v1.0''
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>"
''Implemented in v1.0''
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>"
''Implemented in v1.0''
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>"
''Implemented in v1.0''
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>"
''Implemented in v1.0''
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"
''Implemented in v1.0a, but working only since v1.04a''
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>"
''Implemented in v1.0a, but working only since v1.04a''
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>"
''Implemented in v1.03''
When prevented from editing and opening objects, the Build & Edit window will refuse to open.
 
* '''''Allow/prevent rezzing inventory''''' : "@rez=<y/n>"
''Implemented in v1.03''
When prevented from [[rez]]zing stuff, creating and deleting objects, drag-dropping from inventory and dropping attachments will fail.
 
* '''''Allow/prevent wearing clothes''''' : @addoutfit[:<part>]=<y/n>
''Implemented in v1.10, added skin hair and eyes in v1.10.1''
Where part is :
gloves|jacket|pants|shirt|shoes|skirt|socks|underpants|undershirt|skin|eyes|hair|shape
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)
''Implemented in v1.10, added skin hair and eyes in v1.10.1''
Where part is :
gloves|jacket|pants|shirt|shoes|skirt|socks|underpants|undershirt|skin|eyes|hair|shape
If part is not specified, prevents from removing anything in what the avatar is wearing.
 
* '''''Force removing clothes''''' : @remoutfit[:<part>]=force (*) (teens can't be forced to remove underpants and underwear)
''Implemented in v1.10''
Where part is :
gloves|jacket|pants|shirt|shoes|skirt|socks|underpants|undershirt|skin|eyes|hair|shape
If part is not specified, removes everything.
 
* '''''Force removing attachments''''' : @detach[:attachpt]=force (*)
''Implemented in v1.10''
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>
''Implemented in v1.10, added skin hair and eyes in v1.10.1''
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,eyes,hair,shape
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>
''Implemented in v1.10''
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>
''Implemented in v1.10''
Forces the [[inventory]] windows to close and stay closed.
 
* '''''Allow/prevent reading notecards''''' : @viewnote=<y/n>
''Implemented in v1.10''
Prevents from opening [[notecards]] but does not close the ones already open.
 
* '''''Allow/prevent standing up''''' : @unsit=<y/n>
''Implemented in v1.10''
Hides the Stand up button.
 
* '''''Force sit on an object''''' : @sit:<UUID>=force (*)
''Implemented in v1.10''
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 (*)
''Implemented in v1.10''
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>
''Implemented in v1.10''
Complimentary of @sendchat, this command prevents the user from sending messages on non-public [[channel]]s. If channel is specified, it becomes an exception to the aforementioned restriction. It does not prevent the viewer automatic replies like @version=nnnn, @getstatus=nnnn etc.
 
* '''''Get the list of restrictions the avatar is currently submitted to''''' : @getstatus[:<part_of_rule>]=<channel>
''Implemented in v1.10''
Makes the viewer automatically answer the list of rules the avatar is currently under, only for the object containing the script issuing that command, 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 answer is a list of rules, separated by slashes ('/').
 
This command is useful for people who write scripts that may conflict with other scripts in the same object (for instance : third-party plugins). Conflict do not occur in different objects, that's why this command only applies to the object calling it.
 
<part_of_rule> is the name of a rule, or a part of it, useful if the script only needs to know about a certain restriction.
 
Example : If the avatar is under tploc, tplure, tplm and sittp, here is what the script would get :
@getstatus=2222  =>  tploc/tplure/tplm/sittp
@getstatus:sittp=2222  =>  sittp
@getstatus:tpl=2222  =>  tploc/tplure/tplm  (because "tpl" is part of "tploc", "tplure" and "tplm" but not "sittp")
 
* '''''Get the list of shared folders in the avatar's inventory''''' : @getinv=<channel_number>
''Implemented in v1.11''
Makes the viewer automatically answer the list of folders contained into the folder named "#RLV" (if it exists), 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 answer is a list of names, separated by commas (',').
 
* '''''Force attach items contained inside a shared folder''''' : @attach:<folder_name>=force (*)
''Implemented in v1.11''
Forces the viewer to attach every object and wear every piece of clothing contained inside <folder_name> (which must be directly under "#RLV"). Objects names '''must''' contain the name of their target attachment point or they won't be attached.
 
Attachment point names are the same as the ones contained into the Attach To submenu : "skull", "chest", "l forearm"...
 
* '''''Force detach items contained inside a shared folder''''' : @detach:<folder_name>=force (*)
''Implemented in v1.11''
Forces the viewer to detach every object and unwear every piece of clothing contained inside <folder_name>(which must be directly under "#RLV"). If "@detach" is used with an attachment point name (skull, pelvis... see above), it takes priority over this way of detaching since it is the same command.
 
* '''''Allow/prevent touching objects located further than 1.5 meters away from the avatar''''' : @fartouch=<y/n>
''Implemented in v1.11''
When prevented, the avatar is unable to touch/grab objects from more than 1.5 m away, this command makes restraints more realistic since the avatar litterally has to press against the object in order to click on it.
 
* '''''Allow/prevent viewing the world map''''' : @showworldmap=<y/n>
''Implemented in v1.11''
When prevented, the avatar is unable to view the world map, and it closes if it is open when the restriction becomes active.
 
* '''''Allow/prevent viewing the mini map''''' : @showminimap=<y/n>
''Implemented in v1.11''
When prevented, the avatar is unable to view the mini map, and it closes if it is open when the restriction becomes active.
 
* '''''Allow/prevent knowing the current location''''' : @showloc=<y/n>
''Implemented in v1.12''
When prevented, the user is unable to know where they are : the world map is hidden, the parcel and region name on the top menubar are hidden, they can't create landmarks, nor buy the land, nor see what land they have just left after a teleport, nor see the location in the About box, and even system and object messages are obfuscated if they contain the name of the region and/or the name of the parcel. However, [[llOwnerSay]] calls are ''not'' obfuscated so radars ''will'' still work (and RL commands as well).
 
* '''''Force-Teleport the user''''' : @tpto:X/Y/Z=force (*)
''Implemented in v1.12''
This command forces the avatar to teleport to the indicated coordinates. Note that these coordinates are always '''global''', hence the script that calls this command will not be trivial. Moreso, if the destination contains a telehub or a landing point, the user will land there instead of the desired point. This is a SL limitation. Also keep in mind that @tpto is inhibited by @tploc=n.
 
Here is a sample code to call that command properly :
 
<lsl>
 
// FORCE TELEPORT EXAMPLE
// Listens on channel 4 for local coordinates and a sim name
// and tells your viewer to teleport you there.
//
// By Marine Kelley 2008-08-26
// RLV version required : 1.12 and above
//
// HOW TO USE :
//  * Create a script inside a box
//  * Overwrite the contents of the script with this one
//  * Wear the box
//  * Say the destination coords Region/X/Y/Z on channel 4 :
//    Example : /4 Help Island Public/128/128/50
 
key kRequestHandle; // UUID of the dataserver request
vector vLocalPos;  // local position extracted from the
 
Init () {
  kRequestHandle = NULL_KEY;
  llListen (4, "", llGetOwner (), "");
}
 
 
default
{
  state_entry () {
    Init ();
  }
 
  on_rez(integer start_param) {
    Init ();
  }
 
  listen(integer channel, string name, key id, string message) {
    list tokens = llParseString2List (message, ["/"], []);
    integer L = llGetListLength (tokens);
 
    if (L==4) {
      // Extract local X, Y and Z
      vLocalPos.x = llList2Float (tokens, 1);
      vLocalPos.y = llList2Float (tokens, 2);
      vLocalPos.z = llList2Float (tokens, 3);
 
      // Request info about the sim
      kRequestHandle=llRequestSimulatorData (llList2String (tokens, 0), DATA_SIM_POS);
    }
  }
 
  dataserver(key queryid, string data) {
    if (queryid == kRequestHandle) {
      // Parse the dataserver response (it is a vector cast to a string)
      list tokens = llParseString2List (data, ["<", ",", ">"], []);
      string pos_str = "";
      vector global_pos;
 
      // The coordinates given by the dataserver are the ones of the
      // South-West corner of this sim
      // => offset with the specified local coordinates
      global_pos.x = llList2Float (tokens, 0);
      global_pos.y = llList2Float (tokens, 1);
      global_pos.z = llList2Float (tokens, 2);
      global_pos += vLocalPos;
 
      // Build the command
      pos_str =      (string)((integer)global_pos.x)
                +"/"+(string)((integer)global_pos.y)
                +"/"+(string)((integer)global_pos.z);
      llOwnerSay ("Global position : "+(string)pos_str); // Debug purposes
 
      // Fire !
      llOwnerSay ("@tpto:"+pos_str+"=force");
    }
  }
 
}
 
</lsl>
 
 
(*) 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 [[UUID]]s 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 !'''
 
==Shared Folders==
 
Since v1.11, the viewer can "share" some of your items with scripts in world in order to let them force you to attach, detach and list what you have shared.
 
To do this :
* Create a folder named "#RLV" (without the quotes) directly under "My Inventory" (right-click on "My Inventory", select "New Folder"). We'll call this folder the "shared root".
* Move a folder containing restraints or other attachments directly into this new folder, that's it !
 
So it would look like this :
 
My Inventory
|- #RLV
|  |- cuffs
|  |  |- left cuff (l forearm)
|  |  \- right cuff (r forearm)
|  \- gag
|    \- gag (mouth)
|- Animations
|- Body Parts
.
.
.
 
For example : If you're owning a set of RR Straps and want to share them, just move the folder Straps BOXED under the shared root.
 
- Either wear all the items of the folders you have just moved (one folder at a time !) or rename your items yourself, so that each item name contains the name of the target attachment point. For example : "left cuff (l forearm)", "right ankle cuff (r lower leg)".
 
The attachment point name is the same as the one you find in the "Attach To" menu of your inventory, and is case insensitive (for example : "chest", "skull", "stomach", "left ear", "r upper arm"...). If you wear the item without renaming it first it will be renamed automatically, but only if it is in a shared folder and does not contain any attachment point name already. If you want to wear it on another attachment point, you'll need to rename it by hand.
 
Pieces of clothing are treated exactly the same way (in fact they can even be put in the folder of a set of restraints and be worn with the same command). Shoes, for instance, are a good example of mixed outfits : some attachments and the Shoes layer. Clothes are NOT renamed automatically when worn.
 
GOTCHAS :
* Do NOT put several levels of folders inside the shared root, it wouldn't work. For instance, do not create a folder named "Restraints" and put the "Straps BOXED" folder inside it.
* Do NOT put a comma (',') in the name of the folders under the shared root or it would screw the list up.
* Don't forget to rename the items in the shared folders (or to wear these items at least once to have them be renamed automatically) or the force attach command will appear to do nothing at all.
* Avoid cluttering the shared root with many folders, since some scripts may rely on the list they got with the @getinv command and chat messages are limited to 1023 characters. Choose wisely, and use short names.
 
 
 
==For your information==
Here is how it works internally, for a better understanding of the gotchas you 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 not detachable. 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, on the other hand, 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.
 
[[Category:Third Party Client]]

Latest revision as of 11:14, 5 April 2010