Changes

Jump to navigation Jump to search
11,401 bytes added ,  09:04, 31 January 2021
→‎Script - HelperMessages: - updated the script to detect the region name automatically
== Introduction ==
The Covey Advanced Visitor is as complete a visitor tracking system as is reasonably possible to make using just inworld tools. It records the difference between the total number of visits each day and the number of unique visits. Additionally each day a list of the unique visitors is saved. To stop the memory requirements quickly spiralling out of control this information is saved to a notecard at the end of each day. Then at the end of each month, the daily notecards are combined into one for the previous month. Finally, at the end of the year, each of the monthly notecards is combined into one for the entire year. If in use it will also send instant messages to helpers alerting them when an avi arrives in that region for the first time that day. Similarly each time someone arrives in the region for the first time that day their name will be displayed on a visitors board.
== How it works ==
This script will turn the prim it is in into a volumetric prim. Volumetric prims act like phantom prims while still allowing the recording of collision events. Each time an avi passes through the prim it checks to see if that avi has already visited the sim today. If they have it will increase the total visits count but not the unique count, nor will it save the avatars details again. If however the avatar has not visited yet today the counter stores the avatars details and increases both the unique and total visitors counter. In addition to the collision based detection, the region is periodically scanned. This scan is done to catch avatars who login into their last location or who bypass the sim landing point. If you want to have a displayed visitors list then add another prim with the display board script in it. If you wish to have helpers notified of first-time visits each day, include the HelpersMessages script and the helpers notecard.
== Instructions ==
# Make a notecard called 'Admin' and use the template below to add in the keys (UUID's) of the avatars you wish to be able to see the contents of the counter.
# Make a notecard called 'Ignore' and use the template below to add in the keys (UUID's) of the avatars you wish the counter to ignore.
# Make a notecard called 'Helpers' and use the template below to add in the keys (UUID's) of the avatars you wish to be helpers.
# Add the two notecards you just created to the prim
# Create a new script inside the prim you created
# Copy-paste the script below into the one you just created and save.
# Make a new prim for the display board
# Make a new script and copy the contents from the display board script into the script in the new board
== Admin List ==
== Ignore List ==
Any avi on the ignore list will not be counted at all, and will not be recorded. It will be as though they never visited.
 
== Helpers List ==
Any avi on the helper's list will be sent an IM notification the first time someone visits the region each day.
==== Licence ====
</syntaxhighlight>
==== Script - Visitor Counter ====* [https://github.com/manwapastorelliFire-And-Ice-Grid/OpenSimLSLLSL-And-OSSL-Script-Library/blobtree/mastermain/VisitorCounter(advanced).lsl VisitorCounterAdvanced Advanced Visitor Counter GitHub]
<syntaxhighlight lang="lsl" line>
list todaysVisitors; //list contains names and grid uri as CSV (uniquire visits in the day)
key lastCollider;//uuid of the last avi to collide with this object
integer lastDay; //day of the month at the last point we checked
integer lastMonth; //month at the year at the last point we checked
integer lastYear; //year at the last point we checked
list daysOfMonthNotecards;//used while processing change of month
list monthsOfYearNotecards; //used while processing change of year
integer totalVisitorsCalculation; //used while processing change of month
list lastPeriodsVisitors; //used while processing change of month
list admins;//list of people allowed to access the counters menu
list ignore;//list of people who will not be counted by the visitor counter.
integer menuListen; //used to aid in tracking the listener...shouldn't be needed working aorund OS bugs
list notecardsToProcess; //used when processing a new month or year, temp storage of notecard names
integer debug = TRUEFALSE;integer displayComsChannel = -6827416;
integer GetDate (string dayMonthYear)
else if (dayMonthYear == "Year") toReturn = llList2Integer(dateComponents, 0); //year
return toReturn;
} //close GetDate
CheckDate()
todaysVisitorsUUIDs = []; //clear the list of visitors uuid's
if (lastMonth != month) ProcessNewMonth(month, year);
llRegionSay(displayComsChannel, "Reset");
}//close process new day
string homeUri = osGetAvatarHomeURI(uuidToCheck);//get the avatars home grid
string newVisitor = cleanName + "," + homeUri; //this is the line we add to the visitors list
todaysVisitors += newVisitor;//add the line abive to todays visitors list. llMessageLinked(LINK_THIS, 93827334, uuidToCheck, NULL_KEY); //linked message to helpers llRegionSay(displayComsChannel, uuidToCheck);
if (debug) llOwnerSay("Debug:ProcessDetectedAvatars:" + newVisitor + "added to todays visitors list");
}//close if not on the list already
collision_start(integer total_number)
{
integer colliderIndex = 0; for (colliderIndex; colliderIndex < total_number; colliderIndex++) { integer detectedType = llDetectedType(0colliderIndex); if (detectedType == 1 || detectedType == 3 || detectedType == 5) { //only process avatars, no bots or physical objects key detectedUUID = llDetectedKey(0colliderIndex); if (detectedUUID != lastCollider) { //if this is the same avi just standing on the dector don't process them lastCollider = detectedUUID; ProcessDetectedAvatars(); }//close if not last collider }//close if detected type is an avatar }
}//close collision event
admins = [];
ReadConfigCards("Admin");
integer detectedIndex = 0;
key toucher = llDetectedKey(0);
if (~llListFindList(admins, (list)toucher))
DialogAdminMenu(toucher);
}//close if toucher is on list
//else llRegionSayTo(toucher, PUBLIC_CHANNEL, "Sorry you are not on the admin list and can not use this item.");
}//close touch start event
}//close timer
}//close state default
</syntaxhighlight>
 
==== Script - Display Board ====
* [https://github.com/Fire-And-Ice-Grid/LSL-And-OSSL-Script-Library/tree/main/VisitorCounterAdvanced Advanced Visitor Counter GitHub]
<syntaxhighlight lang="lsl" line>
integer displayComsChannel = -6827416;
integer displayComsChannelListen;
list todaysVisitors =[];
integer debug = FALSE;
 
SetUpListeners()
{//sets the coms channel and the random menu channel then turns the listeners on.
displayComsChannelListen = llListen(displayComsChannel, "", NULL_KEY, "");
llListenControl (displayComsChannelListen, TRUE);
}//close set up listeners
 
ApplyDynamicTexture(float rotationRAD, string text)
{ //sets the shape of the box and textures it rotating the arrow to the specified position
string sDynamicID = ""; // not implemented yet
string sContentType = "vector"; // vector = text/lines,etc. image = texture only
string sData = ""; // Storage for our drawing commands
string sExtraParams = "width:1024,height:512"; // optional parameters in the following format: [param]:[value],[param]:[value]
integer iTimer = 0; // timer is not implemented yet, leave @ 0
integer iAlpha = 100; // 0 = 100% Alpha, 255 = 100% Solid
// draw a rectangle
sData = osSetPenSize(sData, 3); // Set the pen width to 3 pixels
sData = osSetPenColor(sData, "Black"); // Set the pen color to red
sData = osMovePen(sData, 0, 0); // Upper left corner at <28,78>
sData = osDrawFilledRectangle(sData, 1024, 512); // 200 pixels by 100 pixels
// setup text to go in the drawn box
sData = osMovePen(sData, 30, 10); // place pen @ X,Y coordinates
sData = osSetFontName(sData, "Arial"); // Set the Fontname to use
sData = osSetFontSize(sData, 20); // Set the Font Size in pixels
sData = osSetPenColor(sData, "White"); // Set the pen color to Green
sData = osDrawText(sData, text); // The text to write
//do the draw multiple times so its actually black and not grey
osSetDynamicTextureDataBlend( sDynamicID, sContentType, sData, sExtraParams, iTimer, iAlpha ); // Now draw it out
osSetDynamicTextureDataBlend( sDynamicID, sContentType, sData, sExtraParams, iTimer, iAlpha ); // Now draw it out
osSetDynamicTextureDataBlend( sDynamicID, sContentType, sData, sExtraParams, iTimer, iAlpha ); // Now draw it out
}//close apply shape texture
 
SetBaseImage()
{
llSetLinkPrimitiveParamsFast(LINK_ROOT, [ PRIM_TEXTURE, ALL_SIDES, "802934bf-fcfb-4540-b7fa-b17585880d2b", <1,1,1>, <1,1,1>, 0 ]); //set the image
}
 
ProcessListenMessage(string message)
{
if (debug)
{
llOwnerSay("Debug:ProcessListenMessage:Entered");
}
if (message == "Reset")
{
if(debug)
{
llOwnerSay("Debug:ProcessListenMessage:Reset");
}
llResetScript();
}
else
{
if (debug)
{
llOwnerSay("Debug:ProcessListenMessage:UUID:" + message);
}
UpdateDisplay(message);
}
}
 
UpdateDisplay(string message)
{
string name = llKey2Name((key)message);
if(!(~llListFindList(todaysVisitors, (list)name)))
{
todaysVisitors += name;
UpdateDisplayText();
}
}
 
UpdateDisplayText()
{
string displayString = GenDisplayString();
SetBaseImage();
ApplyDynamicTexture(0, displayString);
}
 
string GenDisplayString ()
{
if (debug)
{
llOwnerSay("Debug:GenDisplayString:Entered");
}
string title = "Recent Visitors\n";
string display = title;
integer nameIndex = llGetListLength(todaysVisitors)-1;
for (nameIndex; nameIndex >= 0; nameIndex--)
{
display += llList2String(todaysVisitors, nameIndex);
display += "\n";
}
if (debug)
{
llOwnerSay("Debug:GenDisplayString:DisplayString: " + display);
}
return display;
}
 
default
{
state_entry()
{
SetUpListeners();
UpdateDisplayText();
}
 
listen(integer channel, string name, key id, string message)
{//listens on the set channels, then depending on the heard channel sends the message for processing.
if(debug)
{
llOwnerSay("Debug:Listen:Message: message");
}
if (llGetOwner() == llGetOwnerKey(id) && channel == displayComsChannel)
{
if (debug)
{
llOwnerSay("Debug:Listen:IsOwner And Correct Channel");
}
ProcessListenMessage(message);
} //close if sending object is owned by the same person
}//close listen
}
</syntaxhighlight>
 
==== Script - HelperMessages ====
* [https://github.com/Fire-And-Ice-Grid/LSL-And-OSSL-Script-Library/tree/main/VisitorCounterAdvanced Advanced Visitor Counter GitHub]
<syntaxhighlight lang="lsl" line>
list Helpers = [];
 
ProcessInstructionLine(string instruction, string data)
{
if (llToLower(instruction) == "helper")
{
Helpers += data;
}
}
 
string CleanUpString(string inputString)
 
{
 
string cleanString = llStringTrim( llToLower(inputString), STRING_TRIM );
 
return cleanString;
 
}
 
 
ReadConfigCards(string notecardName)
 
{ //Reads the named config card if it exists
 
if (llGetInventoryType(notecardName) == INVENTORY_NOTECARD)
 
{ //only come here if the name notecard actually exists, otherwise give the user an error
 
integer notecardLength = osGetNumberOfNotecardLines(notecardName); //gets the length of the notecard
 
integer index; //defines the index for the next line
 
for (index = 0; index < notecardLength; ++index)
 
{ //loops through the notecard line by line
 
string currentLine = osGetNotecardLine(notecardName,index); //contents of the current line exactly as it is in the notecard
 
string firstChar = llGetSubString(currentLine, 0,0); //gets the first character of this line
 
integer equalsIndex = llSubStringIndex(currentLine, "="); //gets the position of hte equals sign on this line if it exists
 
if (currentLine != "" && firstChar != "#" && equalsIndex != -1 )
 
{ //only come here if the line has content, it does not start with # and it contains an equal sign
 
string instruction = llGetSubString (currentLine, 0, equalsIndex-1); //everything before the equals sign
 
string data = llGetSubString(currentLine, equalsIndex+1, -1); //everything after the equals sign
 
instruction = CleanUpString (instruction); //sends the instruvtion to the cleanup method to remove white space and turn to lower case
 
data = CleanUpString (data); //sends the data to the cleanup method to remove white space and turn to lower case
 
ProcessInstructionLine(instruction, data); //sends the instruction and the data to the Process instruction method
 
}//close if the line is valid
 
else
 
{
 
if ( (currentLine != "") && (firstChar != "#") && (equalsIndex == -1))
 
{
 
llOwnerSay("Line number: " + (string)index + " is malformed. It is not blank, and does not begin with a #, yet it contains no equals sign.");
 
}
 
}
 
}
 
}//close if the notecard exists
 
else
 
{ //the named notecard does not exist, send an error to the user.
 
llOwnerSay ("The notecard called " + notecardName + " is missing, please address this");
 
}//close error the notecard does not exist
 
}//close read config card.
 
MessageHelpers(string aviUUID)
{
integer index;
for (index = 0; index < llGetListLength(Helpers); index++)
{
string pre = "hop://fireandicegrid.net:8002/app/agent/";
string tail = "/about";
string message = pre + aviUUID + tail + " has entered " + llGetRegionName() + " for the first time today";
llInstantMessage(llList2Key(Helpers, index), message);
}
}
 
default
 
{
changed(integer change)
{
if (change & CHANGED_INVENTORY) //note that it's & and not &&... it's bitwise!
{
llResetScript();
}
}
state_entry()
 
{ //main entry point of the script, this runs when the script starts
 
ReadConfigCards("Helpers"); //calls the read config card method passing the name of the card defined in the global variables above
 
}//close state entry
 
link_message(integer Sender, integer Number, string String, key Key) // This script is in the object too.
{
if (Number == 93827334)
{
MessageHelpers(String);
}
}
}//close default
</syntaxhighlight>
<syntaxhighlight lang="ini" line>
# Allowed Admins
 #Blank lines are ignored#Lines starting with # are ignored #Admin = 833a98e7-4574-4f07-9580-b06784759411lines should start with the word Admin, have an equals sign and then the UUID / Key of the avatar. #e.g. Admin = 8dbc01dccbd17d01-71c84a7e-4d88437a-b776ac57-8b8e827d745c0c8313508aae#If you wish to add the name as well, just put a hash tag on the line above or bellow the uuid with the name of the avatar.  
Admin = cbd17d01-4a7e-437a-ac57-0c8313508aae
</syntaxhighlight>
 
==== Ignore Notecard Sample ====
<syntaxhighlight lang="ini" line>
# IgnoreIgnored Avi's #Blank lines are ignored#Lines starting with # are ignored #Ignored avi entries should start with the word Ignore, then an equals sign followed by the UUID/Key of the avi to be ignored#E.g. Ignore = 833a98e7cbd17d01-45744a7e-4f07437a-9580ac57-b067847594110c8313508aae#If you wish to add the name as well, just put a hash tag on the line above or bellow the uuid with the name of the avatar.  
Ignore = cbd17d01-4a7e-437a-ac57-0c8313508aae
Ignore </syntaxhighlight> = 8dbc01dc=== Helpers Notecard Sample ====<syntaxhighlight lang="ini" line>#Helpers#All lines with a # at the start are ignored#List Helpers Avatars listed here will get a notification the first time someone arives in the region that day#Helper entries should start with the word Helper, then an equals sign, followed by the UUID/Key of the avatar#E.g. Helper = cbd17d01-4a7e-437a-ac57-0c8313508aae#If you wish to add the name as well, just put a hash tag on the line above or bellow the uuid with the name of the avatar.  Helper = cbd17d01-71c84a7e-4d88437a-b776ac57-8b8e827d745c0c8313508aae
</syntaxhighlight>

Navigation menu