Log-In Detection (LID™) provides a way to determine that the user has logged-in from a script contained in an attachment.
LID™ exploits event-handlers by noticing the following distinction:
id
parameter of the attach
event handler becomes the agent key of the avatar that the object attaches to.id
parameters of the attach
event handler becomes the NULL_KEY
.
When the object is detached, LID™ sets a flag (logon
:= -1
) on a linked primitive using the key value data API marking whether the primitive has been attached or detached. A linked primitive is chosen because the root primitive is unable to retain its description once the object is detached. The key value data API is used for consistency but any custom implementation that is able to write to a linked-primitive's description will suffice.
When the object is attached or the avatar logs on, LID™ increments the flag (logon
:= logon + 1
) and resets the script using llResetScript
, thus:
logon
was -1
(meaning, previously detached), then the new value of logon
becomes 0
and LID™ does not trigger.logon
was 0
(meaning the script was previously running), then the new value of logon
becomes 1
and LID™ runs.
Lastly, when the avatar logs out, the attach
event does not run.
It should be noted that event handlers do not run atomically and may be interrupted on the avatar's whims. This means that LID™ is susceptible to race conditions (generally, the attach
event handler is susceptible to race conditions (so is on_rez
)). This can be verified by quickly attaching and detaching the object containing a LID™ script which may trigger LID™ when it is not supposed to. The implication for LID™ is that, on interruption of the attach
event handler, the variable login
may be set to:
login
beyond 1
. This makes LID™ run again in state_entry
.attach
handler to run at all which will trigger LID™ on the next attaching of the object.default
state to check whether RLV is enabled in the viewer and the RLV documentation states that scripts should pause for a certain amount of time (empirically, seconds) before querying the viewer (via llOwnerSay("@version=" + (string)_comChannel);
) when the user logged-in in order to determine whether RLV is enabled. The judgment is made based on the fact that RLV may not yet be initialized when the avatar logs in. Although, one could choose to wait for 30
seconds every time the script is restarted, LID™ is used instead in order to pause for 30
seconds only when the user logs-in.
Note that resetting the script in the on_rez
event handler is not necessary because the attach
event handler resets the script instead - this applies only to worn objects.
/////////////////////////////////////////////////////////////////////////// // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// default { state_entry() { // LID™ reasoning - http://grimore.org/fuss:lsl#log-in_detection_with_attachments // if LID™, then login = 1 // else login = 0 - script running | parameter undefined if((integer)wasKeyValueGet("login", llGetObjectDesc()) > 0) { llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("login", "0", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); llOwnerSay("[LID™]: The user has logged-in wearing this object."); return; } llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("login", "0", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); llOwnerSay("[LID™]: The script was restarted."); } // LID™ reasoning - http://grimore.org/fuss:lsl#log-in_detection_with_attachments // order: on_rez -> attach // // if object attached, then login := login+1 // else login := -1 attach(key id) { // attached if(id != NULL_KEY && llGetAttached() != 0) { llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("login", (string)((integer)wasKeyValueGet("login", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))+1), llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); // Reset script for llGetOwner() bugture. llResetScript(); } // detached llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("login", "-1", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]); } // login = 1 after object attached // = -1 after object detached }