Difference between revisions of "LSL Protocol/Restrained Living Relay/Other Implementations/Dominatech RLV Relay"
(New page: <lsl> // Dominatech RLV Relay Script 2.0 // Copyright (C) 2009 Julia Banshee // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Gen...) |
m |
||
Line 1: | Line 1: | ||
{{Restrained Life Relay Specs TOC}} | |||
<lsl> | <lsl> | ||
// Dominatech RLV Relay Script 2.0 | // Dominatech RLV Relay Script 2.0 |
Revision as of 00:13, 14 February 2009
<lsl> // Dominatech RLV Relay Script 2.0 // Copyright (C) 2009 Julia Banshee // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // See http://www.gnu.org/licenses/gpl.html for terms of this license.
integer relayChannel = -1812221819; string version = "1030"; string implversion = "Dominatech Relay 2.0";
integer backChannel; // for @getsitid key sitting;
list objects; list restrictions;
list pingObjects; list pingRestrictions; key pingSitting; integer pingSitRetry;
integer lit;
integer askMode; list allowedObjects; list rejectedObjects; list pendingObjects; list pendingCommands;
integer permChannel; integer permListener; integer permClose;
updateStatus(integer r) {
if ( r ) { if ( ! lit ) { llMessageLinked(LINK_SET, TRUE, "relay-lock", NULL_KEY); llSetColor(<1.0, 0.0, 0.0>, ALL_SIDES); lit = TRUE; } } else { if ( lit ) { llMessageLinked(LINK_SET, FALSE, "relay-lock", NULL_KEY); llSetColor(<0.0, 1.0, 0.0>, ALL_SIDES); lit = FALSE; } }
}
clear(key obj) {
integer o = llListFindList(objects, [obj]); if ( o >= 0 ) { integer i; while ( (i = llListFindList(restrictions, [o])) >= 0 ) { string restr = llList2String(restrictions, i + 1); restrictions = llDeleteSubList(restrictions, i, i + 1); if ( llListFindList(restrictions, [restr]) < 0 ) llOwnerSay("@" + restr + "=y"); } } if ( llGetListLength(restrictions) == 0 ) { objects = []; updateStatus(FALSE); }
}
clearSome(key obj, string param) {
integer o = llListFindList(objects, [obj]); if ( o >= 0 ) { integer len = llGetListLength(restrictions); integer i; for ( i = 0 ; i < len ; i += 2 ) { if ( llList2Integer(restrictions, i) == o ) { string restr = llList2String(restrictions, i + 1); if ( llSubStringIndex(restr, param) >= 0 ) { restrictions = llDeleteSubList(restrictions, i, i + 1); if ( llListFindList(restrictions, [restr]) < 0 ) llOwnerSay("@" + restr + "=y"); i -= 2; len -= 2; } } } } if ( llGetListLength(restrictions) == 0 ) { objects = []; updateStatus(FALSE); }
}
rlvCommand(key id, string cmd) {
integer e = llSubStringIndex(cmd, "="); if ( e >= 0 ) { string restr = llGetSubString(cmd, 1, e - 1); string param = llGetSubString(cmd, e + 1, -1); if ( param == "n" || param == "add" ) { llOwnerSay(cmd); integer i; integer o = llListFindList(objects, [id]); if ( o < 0 ) { o = llGetListLength(objects); objects += id; i = -1; } else i = llListFindList(restrictions, [o, restr]); if ( i < 0 ) { restrictions += [o, restr]; updateStatus(TRUE); } if ( restr == "unsit" ) llOwnerSay("@getsitid=" + (string)backChannel); } else if ( param == "y" || param == "rem" ) { integer o = llListFindList(objects, [id]); if ( o >= 0 ) { integer i = llListFindList(restrictions, [o, restr]); if ( i >= 0 ) { restrictions = llDeleteSubList(restrictions, i, i + 1); if ( llGetListLength(restrictions) == 0 ) { objects = []; updateStatus(FALSE); } } } if ( llListFindList(restrictions, [restr]) < 0 ) llOwnerSay(cmd); } else { if ( restr == "clear" ) clearSome(id, param); else llOwnerSay(cmd); } } else { if ( cmd == "@clear" ) clear(id); else llOwnerSay(cmd); }
}
string getStatus(integer o) // it's okay if o is not an existing object, or -1, we just result an empty string {
string result = ""; integer len = llGetListLength(restrictions); integer i; for ( i = 0 ; i < len ; i += 2 ) if ( llList2Integer(restrictions, i) == o ) result += "/" + llList2String(restrictions, i + 1); return result;
}
integer allowCommand(key id, string cmd) {
if ( ! askMode ) return TRUE; // not in ask mode, automatically allow if ( llListFindList(allowedObjects, [id]) >= 0 ) return TRUE; // this object has permission if ( llGetOwnerKey(id) == llGetOwner() ) return TRUE; // owner's own objects always have permission if ( llGetSubString(cmd, -2, -1) == "=n" ) return FALSE; // adding restrictions not allowed without permission if ( llGetSubString(cmd, -4, -1) == "=add" ) return FALSE; // adding restrictions not allowed without permission if ( llGetSubString(cmd, -6, -1) == "=force" ) return FALSE; // forcing actions not allowed without permission return TRUE; // anything else is okay (e.g. @version)
}
default {
state_entry() { llSetObjectName(implversion); lit = TRUE; updateStatus(FALSE); llListen(relayChannel, "", NULL_KEY, ""); llListen(backChannel = 16777216 + (integer)llFrand(16777216.0), "", llGetOwner(), ""); llSetTimerEvent(5.0); llMessageLinked(LINK_SET, -123, llGetScriptName() + " free: " + (string)llGetFreeMemory(), NULL_KEY); } listen(integer ch, string name, key id, string msg) { if ( ch == relayChannel ) { list pack = llCSV2List(msg); key target = llList2String(pack, 1); if ( target == llGetOwner() ) { string cmdid = llList2String(pack, 0); list cmds = llParseString2List(llList2String(pack, 2), ["|"], []); integer len = llGetListLength(cmds); integer i; for ( i = 0 ; i < len ; ++i ) { string cmd = llList2String(cmds, i); if ( llGetSubString(cmd, 0, 0) == "@" ) { if ( allowCommand(id, cmd) ) { rlvCommand(id, cmd); llShout(relayChannel, cmdid + "," + (string)id + "," + cmd + ",ok"); } else if ( llListFindList(rejectedObjects, [id]) >= 0 ) { llShout(relayChannel, cmdid + "," + (string)id + "," + cmd + ",ko"); } else { integer p = llListFindList(pendingObjects, [id]); if ( p < 0 ) { p = llGetListLength(pendingObjects); pendingObjects += id; list buttons; if ( p ) buttons = ["Yes " + (string)p, "No " + (string)p]; else buttons = ["Yes", "No"]; string object = llKey2Name(id); string ownedby = llKey2Name(llGetOwnerKey(id)); if ( ownedby ) object += " (owned by " + ownedby + ")"; if ( ! permListener ) permListener = llListen(permChannel = -16777216 - (integer)llFrand(16777216.0), "", llGetOwner(), ""); llDialog(llGetOwner(), "The object " + object + " is attempting to use your Restrained Life Viewer relay. Do you wish to allow it?", buttons, permChannel); permClose = llGetUnixTime() + 120; } if ( llListFindList(pendingCommands, [p, cmdid, cmd]) < 0 ) // some devices spam the same command over and over, don't keep growing list pendingCommands += [p, cmdid, cmd]; } } else if ( cmd == "!release" ) { clear(id); llShout(relayChannel, cmdid + "," + (string)id + "," + cmd + ",ok"); } else if ( cmd == "!getstatus" ) { integer o = llListFindList(objects, [id]); llShout(relayChannel, cmdid + "," + (string)id + "," + cmd + "," + getStatus(o)); } else if ( cmd == "!version" ) { llShout(relayChannel, cmdid + "," + (string)id + "," + cmd + "," + version); } else if ( cmd == "!implversion" ) { llShout(relayChannel, cmdid + "," + (string)id + "," + cmd + "," + implversion); } else if ( cmd == "!pong" ) { integer p = llListFindList(pingObjects, [id]); if ( p >= 0 ) { llOwnerSay("Got pong, you're out of luck. Reapplying restrictions from " + name + "..."); integer o = llListFindList(objects, [id]); if ( o < 0 ) { o = llGetListLength(objects); objects += id; } string cmd = ""; string pre = "@"; integer i; while ( (i = llListFindList(pingRestrictions, [p])) >= 0 ) { string restr = llList2String(pingRestrictions, i + 1); if ( restr == "unsit" ) { if ( pingSitting ) { llOwnerSay("@sit:" + (string)pingSitting + "=force"); pingSitRetry = 12; // keep trying for a minute -- it can take that long for things to rez } } cmd += pre + restr + "=n"; pre = ","; restrictions += [o, restr]; pingRestrictions = llDeleteSubList(pingRestrictions, i, i + 1); } if ( cmd ) llOwnerSay(cmd); updateStatus(TRUE); if ( llGetListLength(pingRestrictions) == 0 ) pingObjects = []; } } } } else if ( target == llGetKey() ) { string cmdid = llList2String(pack, 0); if ( cmdid == "uniquecheck" ) llOwnerSay("You are wearing another RLV relay (" + name + "). Remove it. You should never wear more than one RLV relay at a time."); } return; } if ( ch == permChannel ) { integer o = (integer) llGetSubString(msg, -2, -1); key obj = llList2Key(pendingObjects, o); if ( llGetSubString(msg, 0, 2) == "Yes" ) { allowedObjects = obj + llList2List(allowedObjects, 0, 8); integer i; while ( (i = llListFindList(pendingCommands, [o])) >= 0 ) { string cmd = llList2String(pendingCommands, i + 2); rlvCommand(obj, cmd); llShout(relayChannel, llList2String(pendingCommands, i + 1) + "," + (string)obj + "," + cmd + ",ok"); pendingCommands = llDeleteSubList(pendingCommands, i, i + 2); } if ( llGetListLength(pendingCommands) == 0 ) pendingObjects = []; } else { rejectedObjects = obj + llList2List(rejectedObjects, 0, 8); integer i; while ( (i = llListFindList(pendingCommands, [o])) >= 0 ) { string cmd = llList2String(pendingCommands, i + 2); llShout(relayChannel, llList2String(pendingCommands, i + 1) + "," + (string)obj + "," + cmd + ",ko"); pendingCommands = llDeleteSubList(pendingCommands, i, i + 2); } if ( llGetListLength(pendingCommands) == 0 ) pendingObjects = []; } return; } if ( ch == backChannel ) { sitting = msg; return; } } on_rez(integer param) { if ( objects ) { integer len = llGetListLength(objects); integer i; for ( i = 0 ; i < len ; ++i ) if ( llListFindList(restrictions, [i]) >= 0 ) llShout(relayChannel, "ping," + (string)llList2Key(objects, i) + ",ping,ping"); } pingObjects = objects; pingRestrictions = restrictions; pingSitting = sitting; pingSitRetry = 0; objects = []; restrictions = []; sitting = NULL_KEY; updateStatus(FALSE); allowedObjects = []; rejectedObjects = []; pendingObjects = []; pendingCommands = []; } timer() { if ( llGetAgentInfo(llGetOwner()) & AGENT_ON_OBJECT ) { llOwnerSay("@getsitid=" + (string)backChannel); pingSitRetry = 0; } else { sitting = NULL_KEY; if ( pingSitRetry ) { llOwnerSay("@sit:" + (string)pingSitting + "=force"); --pingSitRetry; } } if ( permListener ) { if ( llGetUnixTime() >= permClose ) { pendingObjects = []; pendingCommands = []; llListenRemove(permListener); permListener = 0; } } } link_message(integer src, integer num, string msg, key id) { if ( msg == "relay-ask" ) { askMode = num; if ( askMode ) { allowedObjects = objects; rejectedObjects = []; pendingObjects = []; pendingCommands = []; } else if ( permListener ) { allowedObjects = []; rejectedObjects = []; pendingObjects = []; pendingCommands = []; llListenRemove(permListener); permListener = 0; } return; } if ( msg == "relay-status" ) { integer len = llGetListLength(objects); if ( len ) { integer i; for ( i = 0 ; i < len ; ++i ) llMessageLinked(LINK_SET, num, getStatus(i), llList2Key(objects, i)); } else llMessageLinked(LINK_SET, num, "", NULL_KEY); return; } if ( msg == "relay-reset" ) { integer len = llGetListLength(objects); integer i; for ( i = 0 ; i < len ; ++i ) llShout(relayChannel, "safeword," + (string)llList2Key(objects, i) + ",!release,ok"); llResetScript(); return; } } attach(key id) { if ( id ) llWhisper(relayChannel, "uniquecheck," + (string)id + ",!version"); } changed(integer change) { if ( change & CHANGED_OWNER ) llResetScript(); }
} </lsl>