chain_sync.lsl
///////////////////////////////////////////////////////////////////////////
//  Copyright (C) Wizardry and Steamworks 2013 - License: GNU GPLv3      //
//  Please see: http://www.gnu.org/licenses/gpl.html for legal details,  //
//  rights of fair usage, the disclaimer and warranty conditions.        //
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueGet(string var, string kvp) {
    list dVars = llParseString2List(kvp, ["&"], []);
    do {
        list data = llParseString2List(llList2String(dVars, 0), ["="], []);
        string k = llList2String(data, 0);
        if(k != var) jump continue;
        return llList2String(data, 1);
@continue;
        dVars = llDeleteSubList(dVars, 0, 0);
    } while(llGetListLength(dVars));
    return "";
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueSet(string var, string val, string kvp) {
    list dVars = llParseString2List(kvp, ["&"], []);
    if(llGetListLength(dVars) == 0) return var + "=" + val;
    list result = [];
    do {
        list data = llParseString2List(llList2String(dVars, 0), ["="], []);
        string k = llList2String(data, 0);
        if(k == "") jump continue;
        if(k == var && val == "") jump continue;
        if(k == var) {
            result += k + "=" + val;
            val = "";
            jump continue;
        }
        string v = llList2String(data, 1);
        if(v == "") jump continue;
        result += k + "=" + v;
@continue;
        dVars = llDeleteSubList(dVars, 0, 0);
    } while(llGetListLength(dVars));
    if(val != "") result += var + "=" + val;
    return llDumpList2String(result, "&");
}
 
///////////////////////////////////////////////////////////////////////////
//    Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3    //
///////////////////////////////////////////////////////////////////////////
LID(key id) {
    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))]);
        llResetScript();
    }
    llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("login", "-1", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]);
}
 
///////////////////////////////////////////////////////////////////////////
//    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))]);
            state tellkey;
            return;
        }
        llSetLinkPrimitiveParamsFast(2, [PRIM_DESC, wasKeyValueSet("login", "0", llList2String(llGetLinkPrimitiveParams(2, [PRIM_DESC]), 0))]);
        state tellkey;
    }
 
    // 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
}
 
state tellkey {
 
    state_entry() {
        integer comChannel = (integer)("0x8" + llGetSubString(llGetOwner(), 0, 6));
        llListen(comChannel+1, "", "", "");
    }
 
    listen(integer channel, string name, key id, string messsage) {
        if(messsage == "sync") llWhisper(channel, "sync="+(string)llGetKey());
        if(messsage == "stop") state stop;
    }
 
    changed(integer change) {
        if(change & CHANGED_INVENTORY || change & CHANGED_OWNER) {
            llResetScript();
        }
    }
 
    // LID™ - http://grimore.org/fuss:lsl#log-in_detection_with_attachments
    attach(key id) {
        LID(id);
    }
}
 
state stop {
    changed(integer change) {
        if(change & CHANGED_INVENTORY || change & CHANGED_OWNER) {
            llResetScript();
        }
    }
 
    // LID™ - http://grimore.org/fuss:lsl#log-in_detection_with_attachments
    attach(key id) {
        LID(id);
    }
}