Online Detector

From Second Life Wiki
Jump to: navigation, search
KBnote.png Note: Due to licensing issues, all contributions to this wiki have stopped and the articles that we posted are just being maintained. This is one of the projects that has gone further and for updates you are cordially invited to the project page on our wiki.

ChangeLog

  • 4 February 2012

Added the FailedNoob Resident variation which accomplishes the same but takes requests on local chat instead of using a notecard.

Introduction

Similar to instant messenger invisible detectors, this script relies on the fact that your online/offline status does not mean too much and continuously scans for a list of agents provided in a notecard called agents. The system is meant to replace the default viewer online status reporting system by dynamically add and taking people off the lists as they go on- and offline. They do not even have to be in your friends list.

You can find the same functionality by searching "offline detector" on marketplace (which were not made by Kira Komarov), all ranging from L$50 to L$500. [WaS] is thereby offering a free version as an open-source contributor.

Reliability & Caveats

During tests we noticed the following:

  • The indication of the offline status is slow (can last up to ~10 minutes before you are announced).
  • The indication of the online status is much faster (<1 minute).

Because of this, we have shunted the first sweep to just collect data and the script will just notify you of changes. This way you will avoid the first wave of data which can be misleading. This way, whenever the script notifies you, you can be sure they have changed status from either online to offline or vice-verse. In that sense, just the change is meaningful. Do not base your assumptions on old data. That is, when the script tells you they are online, they have just now appeared online. Conversely, when the script tells you they are offline, they have just now gone offline.

However, if after a while you check your logs checking for the last state of an agent, the information is old and do not rely on it.

Setup

  • Create a new notecard and name it agents and list all agents names line-by-line along with their keys, separated by a hash sign:
Kira Komarov#2af23607-a672-476d-a5e3-16327d0102bf
Annika Hansen#99999999-9999-9999-9999-999999999997

  • Make sure the notecard has a blank line at the end and create a primitive and drop the agents notecard in it.
  • Create a new script in the same primitive and copy & paste the code below.
  • Save the script.
  • Place the primitive wherever you like: you can even attach it to yourself.

The script will tell you: Notecard read, waiting for events... when the script has begun the sweep. That is an indication that the script has started to sweep the list of agents you provided. You will see no changes and no other messages until an agent changes status.

Code

<lsl> ////////////////////////////////////////////////////////// // [K] Kira Komarov - 2011, License: GPLv3 // // Please see: http://www.gnu.org/licenses/gpl.html // // for legal details, rights of fair usage and // // the disclaimer and warranty conditions. // //////////////////////////////////////////////////////////

key nQuery = NULL_KEY; integer nLine = 0; list nList = []; list oList = []; integer on = 0; integer shunted = 0;

default {

   state_entry()
   {
       integer itra;
       for(itra=0, nList=[], oList=[], nLine=0; itra<llGetInventoryNumber(INVENTORY_NOTECARD); ++itra) {
           if(llGetInventoryName(INVENTORY_NOTECARD, itra) == "agents")
               jump found_notecard;
       }
       llInstantMessage(llGetOwner(), "Could not read agents notecard.");
       return;

@found_notecard;

       nQuery = llGetNotecardLine("agents", nLine);
   }
   changed(integer change) {
       if(change & CHANGED_INVENTORY) llResetScript();
   }
   dataserver(key id, string data) {
       if(id != nQuery) return;
       if(data == EOF) {
           --nLine; --nLine;
            do {
               oList += 0;
           } while(--nLine>=0);
           llInstantMessage(llGetOwner(), "Notecard read, waiting for events...");
           state scan;
       }
       if(data == "") jump next_line;
       nList += data;

@next_line;

       nQuery = llGetNotecardLine("agents", ++nLine);
   }

}

state scan {

   state_entry() {
       shunted = 0;
       nLine = 0;
       nQuery = llRequestAgentData(llList2Key(llParseString2List(llList2String(nList, nLine), ["#"], []), 1), DATA_ONLINE);
       llSetTimerEvent(10); // alarm 30
   }
   timer() {
       llSetTimerEvent(0); // alarm 0
       if(++nLine == llGetListLength(nList)) nLine = 0;
       nQuery = llRequestAgentData(llList2Key(llParseString2List(llList2String(nList, nLine), ["#"], []), 1), DATA_ONLINE);
       llSetTimerEvent(10);
   }
   changed(integer change) {
       if(change & CHANGED_INVENTORY) llResetScript();
   }
   dataserver(key id, string data)
   {
       if(nQuery != id) return;
       llSetTimerEvent(0); // alarm 0
       string name = llList2String(llParseString2List(llList2String(nList, nLine), ["#"], []), 0);
       on = llList2Integer(oList, nLine);
       if(data == "0" && on == 1) {
           if(shunted) llInstantMessage(llGetOwner(), name + " is offline.");
           oList = (oList = []) + llListReplaceList(oList, (list)0, nLine, nLine);
           jump next;
       }
       if(data == "1" && on == 0) {
           if(shunted) llInstantMessage(llGetOwner(), name + " is online.");
           oList = (oList = []) + llListReplaceList(oList, (list)1, nLine, nLine);
           jump next;
       }

@next;

       if(++nLine == llGetListLength(nList)) {
           shunted = 1;
           nLine = 0;
       }
       llSensorRepeat("", NULL_KEY, on = 1, 0.1, 0, llFrand(2));
   }
   no_sensor() {
       if(on) {
           --on;
           return;
       }
       nQuery = llRequestAgentData(llList2Key(llParseString2List(llList2String(nList, nLine), ["#"], []), 1), DATA_ONLINE);
       llSetTimerEvent(10);
   }

} </lsl>

FailedNoob Variation

This one accepts messages on local chat based on a touch trigger. It also requires the N2K script in the same primitive.

<lsl> ////////////////////////////////////////////////////////// // [K] Kira Komarov - 2011, License: GPLv3 // // Please see: http://www.gnu.org/licenses/gpl.html // // for legal details, rights of fair usage and // // the disclaimer and warranty conditions. // //////////////////////////////////////////////////////////

key _kReq = NULL_KEY; string _kName = ""; key _kKey = NULL_KEY;

default {

   state_entry()
   {
       llSetText(_kName = "Touch me to look for an agent's status.", <1,1,1>, 1.0);
   }
   touch_start(integer num) {
       llListen(0, "", llDetectedKey(0), "");
       llSetText("Type the name of the agent in local chat.", <1,1,1>, 1.0);
   }
   listen(integer channel, string name, key id, string message) {
       llSetText("Checking...", <1,1,1>, 1.0);
       llMessageLinked(LINK_THIS, 0, _kName = message, "");
       llSetTimerEvent(10);
   }
   timer() {
       llSetTimerEvent(0);
       if(_kReq == NULL_KEY) {
           _kReq = "a";
           llSetText("Agent could not be found.", <1,1,1>, 1.0);
           llSetTimerEvent(5);
           return;
       }
       llResetScript();
   }
   link_message(integer sender, integer num, string str, key id) {
       if(sender != 0) return;
       if(str == "KN2K") if(id) {
           _kKey = (key)id;
           state check;
           return;
       }
   }
   changed(integer change) {
       if(change & CHANGED_INVENTORY) llResetScript();
   }

}

state check {

   state_entry() {
       _kReq = llRequestAgentData(_kKey, DATA_ONLINE);
       llSetTimerEvent(10);
   }
   timer() {
       llSetTimerEvent(0);
       llSetText("Agent could not be found.", <1,1,1>, 1.0);
       llResetScript();
   }
   dataserver(key id, string data) {
       if(id != _kReq) return;
       if(data == "1") {
           llSetText(_kName + " is online.", <0,1,0>, 1.0);
           return;
       }
       llSetText(_kName + " is offline.", <1,0,0>, 1.0);
   }
   touch_start(integer num) {
       state default;
   }
   

} </lsl>