Combined LockMeister Handle Post and Collar

From Second Life Wiki
Revision as of 12:34, 31 January 2010 by Tianna Violet (talk | contribs)
Jump to navigation Jump to search

LockMeister+ Handles, Posts and Collar

Overview

The LockMeister system protocol for cuffs, collars and leash handles has been around from many years and in that time a number of extensions to the protocol have been added and have been documented.

LockMeister+ is an effort to bring together those extensions and define a set of expected behaviours to allow greater interoperability and functionality between devices that use the extended protocol. The aims of LockMeister+ are:

  • To gather up the existing extensions into a new extended protocol.
  • To add functionality that can be gained from combining those extensions.
  • To define the expected behaviour for a number if classes of devices.
  • To be 100% backwards compatible with what has gone before.

The LockMeister+ Handle reference script

The LockMeister+ Handle:

  • MUST respond to basic "handle" messages with an "ok".
  • MUST implement the "here" and "gone" messages.

<lsl>/////////////////////////////////////////////////////////////////////// // // Lockmeister+ Handle Reference Script // // Tianna Violet // 20 Jan 2010 // // http://wiki.secondlife.com/wiki/LSL_Protocol/LockMeister_System // // Note that this script will only work in the ROOT PRIM ONLY as it // uses an "attach" event which aren't handled properly in child prims. /////////////////////////////////////////////////////////////////////// // The lockmeister name of the handle. string LOCKMEISTER_NAME = "handle"; /////////////////////////////////////////////////////////////////////// string gCuffMessage;

default {

   state_entry()
   {
       gCuffMessage = (string) llGetOwner() + LOCKMEISTER_NAME;
       llListen(-8888, "", NULL_KEY, "");
   }
   attach(key id)
   {
       string message;
       message = " gone";
       if (id)
       {
           gCuffMessage = (string) llGetOwner() + LOCKMEISTER_NAME;
           message = " here";
       }
       llSay(-8888, gCuffMessage + message);	// send the "here" and "gone" message
   }
   listen(integer channel, string name, key id, string message)
   {
       if (message == gCuffMessage)
       {
           llSay(-8888, gCuffMessage + " ok");	// the basic response
           return;
       }
   }

} </lsl>

The LockMeister+ Post reference script

The LockMeister+ Post:

  • MUST send a "posk ok" message when the post is touched the key being the toucher's UUID
  • MUST respond to basic "handle" messages where the message key is its own UUID with an "ok".
  • SHOULD contain 'post' in its name and script SHOULD be in the root prim so that a post that is found through a scan of nearby objects can be confirmed as a LockMeister+ post.

<lsl>/////////////////////////////////////////////////////////////////////// // // Lockmeister+ Post Reference Script // // Tianna Violet // 21 Jan 2010 // // http://wiki.secondlife.com/wiki/LSL_Protocol/LockMeister_System /////////////////////////////////////////////////////////////////////// // The lockmeister name of the leash. string LOCKMEISTER_NAME = "handle"; ///////////////////////////////////////////////////////////////////////

default {

   state_entry()
   {
       llListen(-8888, "", NULL_KEY, "");
   }
   touch_start(integer total_number)
   {
       llSay(-8888, (string) llDetectedKey(0) + "post ok");
   }
   listen(integer channel, string name, key id, string message)
   {
       string postMessage;
       postMessage = (string) llGetKey() + LOCKMEISTER_NAME;
       if (message == postMessage)
       {
           llSay(-8888, postMessage + " ok");
           return;
       }
   }

} </lsl>

The LockMeister+ Collar reference script

The LockMeister+ Collar:

  • MUST look for a handle using the basic LockMeister query/response.
  • MUST monitor "here" messages in order to connect to a handle should it appear.
  • MUST monitor the "gone" event to remove the leash should the handle disappear.
  • MUST send out new target requests should the current handle disappear.
  • MUST support the "post ok" message and basic query/response to the post.
  • SHOULD support basic LockMeister query/responses for the "collar" attach point.
  • SHOULD reconnect the leash when the AV logs on if the attach point is still available.
  • SHOULD support one touch transfer of the leash from the leash holder to a post.

<lsl>/////////////////////////////////////////////////////////////////////// // // Lockmeister+ Collar Reference Script // // Tianna Violet // 31 Jan 2010 // // http://wiki.secondlife.com/wiki/LSL_Protocol/LockMeister_System // // the collar reponds on channel 53 // // /53xxleash - grab the leash // /53xxunleash - unleash // /53xxleashpost - leash to a previously touch post // // xx = the initials of the wearer or * to effect all collars // // Note that this script will only work in the ROOT PRIM ONLY as it // uses an "attach" event which aren't handled properly in child prims. /////////////////////////////////////////////////////////////////////// // The lockmeister name of the collar. string LOCKMEISTER_NAME = "collar"; string gCuffMessage; key gLeashHolder; key gCurrentTarget; key gPostToucher; key gPost; key gPending; integer isLeashed; string gPrefix;


// Who has access to the collar // This is where the owner list etc is checked integer hasAccess(key id) {

   return TRUE;	// everyone has access

}

// Start or update the particle stream updateParticles() {

   llParticleSystem( [PSYS_PART_START_SCALE, <0.1, 0.1, 0>, PSYS_PART_END_SCALE, <1, 1, 0>,
       PSYS_PART_START_COLOR, <1, 1, 1>, PSYS_PART_END_COLOR, <1, 1, 1>,
       PSYS_PART_START_ALPHA, 1.0, PSYS_PART_END_ALPHA, 1.0,
       PSYS_SRC_TEXTURE, "1ffb37fa-2fc1-dbec-d8ea-0607583a03c6",
       PSYS_SRC_BURST_PART_COUNT, 1, PSYS_SRC_BURST_RATE, 0.0, PSYS_PART_MAX_AGE, 2,
       PSYS_SRC_MAX_AGE, 0.0, PSYS_SRC_PATTERN, PSYS_SRC_PATTERN_DROP, PSYS_SRC_BURST_RADIUS, 0.5,
       PSYS_SRC_INNERANGLE, 0.0, PSYS_SRC_OUTERANGLE, 0.0, PSYS_SRC_OMEGA, <0, 0, 0>,
       PSYS_SRC_ACCEL, <0, 0, -0.7>, PSYS_SRC_BURST_SPEED_MIN, 1000.0,
       PSYS_SRC_BURST_SPEED_MAX, 1000.0, PSYS_SRC_TARGET_KEY, gCurrentTarget,
       PSYS_PART_FLAGS, PSYS_PART_FOLLOW_VELOCITY_MASK | PSYS_PART_FOLLOW_SRC_MASK | PSYS_PART_TARGET_POS_MASK]);

}

setPrefix() {

   list l;
   l = llParseString2List(llToLower(llKey2Name(llGetOwner())), [" "], []);
   gPrefix = llGetSubString(llList2String(l, 0), 0, 0) + llGetSubString(llList2String(l, 1), 0, 0);

}

releash() {

   if (isLeashed)
   {
       if (gLeashHolder)
       {
           llSensor("", gLeashHolder, AGENT, 30.0, PI);
       } else {
           gPending = gCurrentTarget;
           llSay(-8888, ((string) gPending + "handle"));
       }
       llParticleSystem([]);
       isLeashed = 0;
       gLeashHolder = NULL_KEY;
       gCurrentTarget = NULL_KEY;
   }

}

default {

   state_entry()
   {
       gLeashHolder = NULL_KEY;
       gCurrentTarget = NULL_KEY;
       gPostToucher = NULL_KEY;
       gPost = NULL_KEY;
       gPending = NULL_KEY;
       isLeashed = 0;
       setPrefix();
       gCuffMessage = (string) llGetOwner() + LOCKMEISTER_NAME;
       llListen(-8888, "", NULL_KEY, "");
       llListen(53, "", NULL_KEY, "");
   }
   listen(integer channel, string name, key id, string message)
   {
       list commands = ["leash", "unleash", "leashpost"];
       list responses = ["handle ok", "handle here", "handle gone", "post ok"];
       key target;
       integer index;
       integer len;
       if (channel == 53 && hasAccess(id))
       {
           message = llStringTrim(llToLower(message), STRING_TRIM);
           index = -1;
           if (llGetSubString(message, 0, 0) == "*")
           {
               index = 1;
           } else {
               len = llStringLength(gPrefix);
               if (llGetSubString(message, 0, len - 1) == gPrefix)
               {
                   index = len;
               }
           }
           if (~index)
           {
               index = llListFindList(commands, [llGetSubString(message, index, -1)]);
           }
           if (~index)
           {
               gPending = NULL_KEY;
               if (!index)
               {
                   if (gLeashHolder == NULL_KEY)
                   {
                       gLeashHolder = id;
                       gCurrentTarget = id;
                       isLeashed = 1;
                       updateParticles();
                       llSay(-8888, ((string) id) + "handle");
                       gPending = id;
                   }
               }
               if (gLeashHolder == NULL_KEY || gLeashHolder == id)
               {
                   if (index == 1)
                   {
                       gLeashHolder = NULL_KEY;
                       isLeashed = 0;
                       llParticleSystem([]);
                   }
                   if (index == 2)
                   {
                       if (gPost != NULL_KEY && gPost != gCurrentTarget && gPostToucher == id)
                       {
                           llSay(-8888, ((string) gPost) + "handle");
                           gPending = gPost;
                       }
                   }
               }
           }
       }
       if (channel == -8888)
       {
           if (message == gCuffMessage)
           {
               llSay(-8888, gCuffMessage + " ok");	// the basic response
               return;
           }
           target = (key) llGetSubString(message, 0, 35);
           if (target)
           {
               index = llListFindList(responses, [llGetSubString(message, 36, -1)]);
               if (~index)
               {
                   if (!index && target == gPending)
                   {
                       gCurrentTarget = id;
                       isLeashed = 1;
                       if (id == target)
                       {
                           gLeashHolder = NULL_KEY;
                       }
                       gPending = NULL_KEY;
                       updateParticles();
                   }
                   if (target == gLeashHolder)
                   {
                       if (index == 1 && gCurrentTarget != id)
                       {
                           gCurrentTarget = id;
                           isLeashed = 1;
                           gPending = NULL_KEY;
                           updateParticles();
                       }
                       if (index == 2 && gCurrentTarget == id)
                       {
                           releash();
                       }
                   }
                   if (index == 3)
                   {
                       if (target == gLeashHolder || (gLeashHolder == NULL_KEY && hasAccess(target)))
                       {
                           gPostToucher = target;
                           gPost = id;
                           if (gLeashHolder != NULL_KEY && gPost != gCurrentTarget)
                           {
                               gLeashHolder = NULL_KEY;
                               gCurrentTarget = gPost;
                               isLeashed = 1;
                               gPending = NULL_KEY;
                               updateParticles();
                           }
                       }
                   }
               }
           }
       }
   }
   attach(key id)
   {
       string message;
       message = " gone";
       if (id)
       {
           gCuffMessage = (string) llGetOwner() + LOCKMEISTER_NAME;
           message = " here";
           if (isLeashed)
           {
               releash();
           }
       }
       llSay(-8888, gCuffMessage + message);	// send the "here" and "gone" message
   }
   sensor(integer total_number)
   {
       gLeashHolder = llDetectedKey(0);
       gCurrentTarget = gLeashHolder;
       isLeashed = 1;
       updateParticles();
       llSay(-8888, ((string) gLeashHolder) + "handle");
       gPending = gLeashHolder;
   }
   on_rez(integer start_param)
   {
       setPrefix();
   }

} </lsl>