Difference between revisions of "User:Rolig Loon/High-Capacity Greeter-Counter"

From Second Life Wiki
Jump to navigation Jump to search
m (<lsl> tag to <source>)
 
(2 intermediate revisions by 2 users not shown)
Line 8: Line 8:
* Optionally, provides the owner with a week-end report of the total number of visitors that week.
* Optionally, provides the owner with a week-end report of the total number of visitors that week.
* Stores the weekly total each week in the object's Description field, which will survive if the script is reset for any reason or if the object is taken to the owner's inventory.
* Stores the weekly total each week in the object's Description field, which will survive if the script is reset for any reason or if the object is taken to the owner's inventory.
Update (4/13/2013): Modified by replacing the sensor sweep that was in the original version with llGetAgentList, which is much more sim-friendly.


=== Script ===  
=== Script ===  
<lsl>//High-Capacity greeter/counter -- Rolig Loon --  March 2010
<source lang="lsl2">//High-Capacity greeter/counter -- Rolig Loon --  March 2010
//Incorporating a memory compression algorithm by Becky Pippen (https://wiki.secondlife.com/wiki/User:Becky_Pippen/Hashing)
//Incorporating a memory compression algorithm by Becky Pippen (https://wiki.secondlife.com/wiki/User:Becky_Pippen/Hashing)
//Please keep all notes intact, including this header.
//Please keep all notes intact, including this header.


//Revision (4/13/2013): Replaced llSensor with llGetAgentList. As written, this sensor now detects all traffic in the parcel.
// Records unique visitors only, not repeaters. Stores the weekly count in the object's Description field and (optionally) sends a report to the owner
// Records unique visitors only, not repeaters. Stores the weekly count in the object's Description field and (optionally) sends a report to the owner
 
// Commands on channel 37:  "list" gives the current traffic count since the previous Saturday midnight
// Commands on channel 37:  "list" gives the current traffic count since the previous Saturday midnight
//                          "reports" toggles the weekly report to the owner on or off
//                          "reports" toggles the weekly report to the owner on or off
 
// If there is a notecard in inventory, the counter will offer it on a visitor's first encounter.
// If there is a notecard in inventory, the counter will offer it on a visitor's first encounter.
 
integer count;
integer count;
integer restart = TRUE;
integer restart = TRUE;
Line 26: Line 30:
string hashedNames;
string hashedNames;
integer hashSize = 3;
integer hashSize = 3;
 
string getDay()
string getDay()
{
{
Line 35: Line 39:
     return llList2String(weekdays, day_of_week);
     return llList2String(weekdays, day_of_week);
}
}
 
string encode15BitsToChar(integer num)
string encode15BitsToChar(integer num)
{
{
Line 44: Line 48:
         escapeHexChar(0x80 + (num & 0x3f)));
         escapeHexChar(0x80 + (num & 0x3f)));
}
}
 
string escapeHexChar(integer n)
string escapeHexChar(integer n)
{
{
Line 52: Line 56:
         llGetSubString(hexChars, n & 0xf, n & 0xf);
         llGetSubString(hexChars, n & 0xf, n & 0xf);
}
}
 
default
default
{
{
     state_entry(){
     state_entry()
        llSensor( "", "", AGENT, 25.0, PI );
    {
         llSetTimerEvent( 30.0 );
         llSetTimerEvent( 30.0 );
         llListen(37,"","","");
         llListen(37,"","","");
     }
     }
 
     listen(integer channel, string name, key id, string msg)
     listen(integer channel, string name, key id, string msg)
     {
     {
Line 72: Line 76:
         }
         }
     }
     }
 
     timer()
     timer()
     {
     {
Line 89: Line 93:
             restart = TRUE;
             restart = TRUE;
         }
         }
         llSensor( "", "", AGENT, 25.0, PI );
         list Who = llGetAgentList(AGENT_LIST_PARCEL,[]); //Modify here to detect AGENT_LIST_REGION if desired
    }
         integer i = llGetListLength(Who);
 
         while(i)
    sensor( integer vIntTtl )
    {
         integer i;
         for (i=0;i< vIntTtl; ++i)
         {
         {
             if ((llStringLength( hashedNames ) * 4.2) > llGetFreeMemory()) // In case memory gets tight
             if ((llStringLength( hashedNames ) * 4.2) > llGetFreeMemory()) // In case memory gets tight
             {
             {
                 hashedNames = llGetSubString(hashedNames,3,-1);
                 hashedNames = llGetSubString(hashedNames,3,-1); //Delete the oldest entry in hashedNames
             }
             }
             string AvKey = llDetectedKey(i);
             string AvKey = llList2Key(Who,i);
             string md5 = llMD5String(AvKey, 0);
             string md5 = llMD5String(AvKey, 0);
             integer n1 = (integer)("0x" + llGetSubString(md5, 0, 7));
             integer n1 = (integer)("0x" + llGetSubString(md5, 0, 7));
Line 110: Line 110:
                 encode15BitsToChar(n2);
                 encode15BitsToChar(n2);
             integer idx = llSubStringIndex(hashedNames, encoded3Chars);
             integer idx = llSubStringIndex(hashedNames, encoded3Chars);
             if (idx == -1)  
             if (idx == ERR_GENERIC)  
             {
             {
             // this is a new one, so save it and send a notecard, if there is one
             // this is a new one, so save it and send a notecard, if there is one
Line 117: Line 117:
                 if(llGetInventoryNumber(INVENTORY_NOTECARD))
                 if(llGetInventoryNumber(INVENTORY_NOTECARD))
                 {
                 {
                     llGiveInventory(llDetectedKey(i),llGetInventoryName(INVENTORY_NOTECARD,0));
                     llGiveInventory(AvKey,llGetInventoryName(INVENTORY_NOTECARD,0));
                 }
                 }
             }
             }
            --i;
         }
         }
     }
     }
}</lsl>
}</source>

Latest revision as of 21:33, 24 January 2015

Features

Uses a memory compression algorithm to store hashed visitor UUID's in a string instead of using a list, thus avoiding the extra memory overhead associated with lists as well as reducing the UUID to a 3-character element in that string. See notes in the script and the reference to Becky Pippen's User page for a description of the technique.

  • Records unique visitors only.
  • Offers a notecard to unique visitors, if a notecard has been placed in inventory.
  • Provides the current weekly count, if requested by chat command on channel 37.
  • Optionally, provides the owner with a week-end report of the total number of visitors that week.
  • Stores the weekly total each week in the object's Description field, which will survive if the script is reset for any reason or if the object is taken to the owner's inventory.

Update (4/13/2013): Modified by replacing the sensor sweep that was in the original version with llGetAgentList, which is much more sim-friendly.

Script

//High-Capacity greeter/counter -- Rolig Loon --  March 2010
//Incorporating a memory compression algorithm by Becky Pippen (https://wiki.secondlife.com/wiki/User:Becky_Pippen/Hashing)
//Please keep all notes intact, including this header.

//Revision (4/13/2013): Replaced llSensor with llGetAgentList. As written, this sensor now detects all traffic in the parcel.
 
// Records unique visitors only, not repeaters. Stores the weekly count in the object's Description field and (optionally) sends a report to the owner
 
// Commands on channel 37:   "list" gives the current traffic count since the previous Saturday midnight
//                           "reports" toggles the weekly report to the owner on or off
 
// If there is a notecard in inventory, the counter will offer it on a visitor's first encounter.
 
integer count;
integer restart = TRUE;
integer TellOwner = TRUE;
string hashedNames;
integer hashSize = 3;
 
string getDay()
{
    list weekdays = ["Thursday", "Friday", "Saturday", "Sunday", "Monday", "Tuesday", "Wednesday"];
    integer hours = llGetUnixTime()/3600;
    integer days = (hours -4)/24;
    integer day_of_week = days%7;
    return llList2String(weekdays, day_of_week);
}
 
string encode15BitsToChar(integer num)
{
    num = 0x1000 + (num & 0x00007fff);
    return llUnescapeURL(
        escapeHexChar(0xe0 + (num >> 12)) +
        escapeHexChar(0x80 + ((num >> 6) & 0x3f)) +
        escapeHexChar(0x80 + (num & 0x3f)));
}
 
string escapeHexChar(integer n)
{
    string hexChars = "0123456789abcdef";
    return "%" +
        llGetSubString(hexChars, n >> 4, n >> 4) +
        llGetSubString(hexChars, n & 0xf, n & 0xf);
}
 
default
{
    state_entry()
    {
        llSetTimerEvent( 30.0 );
        llListen(37,"","","");
    }
 
    listen(integer channel, string name, key id, string msg)
    {
        if (llToLower(msg) == "list")
        {
            llSay(0, "We have had " + (string)count + " unique visitors since midnight last Saturday.");
        }
        else if (llToLower(msg) == "reports") // Toggles weekly report to owner on /off
        {
            TellOwner = !TellOwner;
        }
    }
 
    timer()
    {
        if (getDay() == "Sunday" && restart == TRUE)
        {
            llSetObjectDesc(llGetObjectDesc() + ","+(string)count);
            if(TellOwner)
            {
                llInstantMessage(llGetOwner(),"The count for the week is " + (string)count);
            }
            count = 0;
            restart = FALSE;
        }
        else if (getDay() == "Monday")
        {
            restart = TRUE;
        }
        list Who = llGetAgentList(AGENT_LIST_PARCEL,[]); //Modify here to detect AGENT_LIST_REGION if desired
        integer i = llGetListLength(Who);
        while(i)
        {
            if ((llStringLength( hashedNames ) * 4.2) > llGetFreeMemory()) // In case memory gets tight
            {
                hashedNames = llGetSubString(hashedNames,3,-1); //Delete the oldest entry in hashedNames
            }
            string AvKey = llList2Key(Who,i);
            string md5 = llMD5String(AvKey, 0);
            integer n1 = (integer)("0x" + llGetSubString(md5, 0, 7));
            integer n2 = (integer)("0x" + llGetSubString(md5, 8, 11));
            string encoded3Chars =
                encode15BitsToChar(n1 >> 16) +
                encode15BitsToChar(n1) +
                encode15BitsToChar(n2);
            integer idx = llSubStringIndex(hashedNames, encoded3Chars);
            if (idx == ERR_GENERIC) 
            {
            // this is a new one, so save it and send a notecard, if there is one
                hashedNames += encoded3Chars;
                ++count;
                if(llGetInventoryNumber(INVENTORY_NOTECARD))
                {
                    llGiveInventory(AvKey,llGetInventoryName(INVENTORY_NOTECARD,0));
                }
            }
            --i;
        }
    }
}