Difference between revisions of "Advanced Visitor Counter"

From Fire And Ice Grid
Jump to navigation Jump to search
 
Line 23: Line 23:
 
# Create a new script inside the prim you created
 
# Create a new script inside the prim you created
 
# Copy-paste the script below into the one you just created and save.  
 
# Copy-paste the script below into the one you just created and save.  
 +
 +
== Admin List ==
 +
Any avi on the admin list will be able to click the counter to get a folder with all notecards currently held inside the visitor counter.
 +
 +
== 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.
  
 
==== Licence ====
 
==== Licence ====

Revision as of 18:57, 18 October 2020


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.

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.

Instructions

  1. Make a prim which covers the landing point of your region
  2. 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.
  3. 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.
  4. Add the two notecards you just created to the prim
  5. Create a new script inside the prim you created
  6. Copy-paste the script below into the one you just created and save.

Admin List

Any avi on the admin list will be able to click the counter to get a folder with all notecards currently held inside the visitor counter.

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.

Licence

 1 BSD 3-Clause License
 2 Copyright (c) 2020, Sara Payne
 3 All rights reserved.
 4 Redistribution and use in source and binary forms, with or without
 5 modification, are permitted provided that the following conditions are met:
 6 1. Redistributions of source code must retain the above copyright notice, this
 7    list of conditions and the following disclaimer.
 8 2. Redistributions in binary form must reproduce the above copyright notice,
 9    this list of conditions and the following disclaimer in the documentation
10    and/or other materials provided with the distribution.
11 3. Neither the name of the copyright holder nor the names of its
12    contributors may be used to endorse or promote products derived from
13    this software without specific prior written permission.
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Script

  1 list todaysVisitors; //list contains names and grid uri as CSV (uniquire visits in the day)
  2 list todaysVisitorsUUIDs;//list contains all unique UUIDS detected today. 
  3 key lastCollider;//uuid of the last avi to collide with this object
  4 integer lastDay; //day of the month at the last point we checked
  5 integer lastMonth; //month at the year at the last point we checked
  6 integer lastYear; //year at the last point we checked
  7 list daysOfMonthNotecards;//used while processing change of month
  8 list monthsOfYearNotecards; //used while processing change of year
  9 integer totalVisitorsCalculation; //used while processing change of month
 10 list lastPeriodsVisitors; //used while processing change of month 
 11 list admins;//list of people allowed to access the counters menu
 12 list ignore;//list of people who will not be counted by the visitor counter. 
 13 integer menuChannel; //channel the menu listens on
 14 integer menuChannelListen; //handle to turn the listener on and off
 15 key lastAdmin; //uuid of the last admin to use the menu, used to send time out warning
 16 integer timeInterval = 30; //how frequently the sim is checked for visitors
 17 integer menuListen; //used to aid in tracking the listener...shouldn't be needed working aorund OS bugs
 18 list notecardsToProcess; //used when processing a new month or year, temp storage of notecard names
 19 integer debug = TRUE;
 20   
 21 integer GetDate (string dayMonthYear) 
 22 {   //fetches the date, and breaks it down into component parts returning the requested prt
 23     list dateComponents = llParseString2List(llGetDate(), ["-"], []);
 24     integer toReturn;
 25     if (dayMonthYear == "Day") toReturn = llList2Integer(dateComponents, 2);//day of month
 26     else if (dayMonthYear == "Month") toReturn =  llList2Integer(dateComponents, 1); //month of year
 27     else if (dayMonthYear == "Year") toReturn =  llList2Integer(dateComponents, 0); //year
 28     return toReturn; 
 29 } //close GetDate
 30   
 31 CheckDate()
 32 {   //checks to see if the day, month or year has changed form the last check, calling appropirate methods if it has
 33     integer year = GetDate("Year");
 34     integer month = GetDate("Month");
 35     integer day = GetDate("Day");
 36     if (day != lastDay) ProcessNewDay(day, month, year);
 37 }//close check the date 
 38 
 39 ProcessNewDay(integer day, integer month, integer year)
 40 {   //makes yesterdays visitors note card then resets the lists for today
 41     totalVisitorsCalculation = 0; //reset total visitors calc to 0 ready for next time
 42     ProcessLastPeriodVisitors("DayOfMonth");
 43     GenerateNewNoteCard("DayOfMonth");
 44     lastDay = day; //make last day equal today ready for tomorrow
 45     todaysVisitors =  []; //clear todays visitors list. 
 46     todaysVisitorsUUIDs = []; //clear the list of visitors uuid's
 47     if (lastMonth != month) ProcessNewMonth(month, year);
 48 }//close process new day
 49  
 50 ProcessNewMonth(integer month, integer year)
 51 {
 52     totalVisitorsCalculation = 0; //reset total visitors calc to 0 ready for next time
 53     PopulateDaysAndMonthsNoteardLists("ProcessNewMonth");//clear lists and generate new ones to work from
 54     ProcessLastPeriodVisitors("MonthOfYear");
 55     GenerateNewNoteCard("MonthOfYear");
 56     lastMonth = month; //make last month this month ready for next month
 57     lastPeriodsVisitors = []; //clear to keep memory down while not processing
 58     totalVisitorsCalculation = 0; //reset total visitors calc to 0 ready for next time
 59     daysOfMonthNotecards = []; //clear list to keep memory use down
 60     if (year != lastYear) ProcessNewYear(year);
 61     else monthsOfYearNotecards = [];//change of year has not occured so this is not needed, clear to keep memory use down
 62 }//close process new month
 63 
 64 ProcessNewYear(integer year)
 65 {
 66     totalVisitorsCalculation = 0; //reset total visitors calc to 0 ready for next time
 67     PopulateDaysAndMonthsNoteardLists("ProcessNewYear");//clear lists and generate new ones to work from
 68     ProcessLastPeriodVisitors("Year");
 69     GenerateNewNoteCard("Year");
 70     lastYear = year;
 71     lastPeriodsVisitors = []; //clear to keep memory down while not processing
 72     totalVisitorsCalculation = 0; //reset total visitors calc to 0 ready for next time
 73     monthsOfYearNotecards = [];//change of year has not occured so this is not needed, clear to keep memory use down
 74 }//close process new year
 75 
 76 ProcessLastPeriodVisitors(string type)
 77 {
 78     notecardsToProcess = [];
 79     if (type == "DayOfMonth")
 80     { 
 81         list yesterdaysVisitors = todaysVisitors;
 82         string visitorsUnique = "*Unique Visitors = " + (string)llGetListLength(yesterdaysVisitors);
 83         string visitorsAll = "*All Visitors = " + (string)llGetListLength(yesterdaysVisitors);
 84         yesterdaysVisitors += visitorsUnique; //adds the line above to the list
 85         yesterdaysVisitors += visitorsAll; //adds the line above to the list
 86         if (llGetInventoryType("Yesterday") == INVENTORY_NOTECARD) llRemoveInventory("Yesterday");
 87         osMakeNotecard("Yesterday", yesterdaysVisitors); //save the notecard
 88         EnsureNotecardWritten("Yesterday"); 
 89         notecardsToProcess += "Yesterday";
 90     }
 91     else if (type == "MonthOfYear")
 92     {
 93         notecardsToProcess = daysOfMonthNotecards;
 94         daysOfMonthNotecards = []; //clear to keep memory use down
 95     }
 96     else if (type == "Year")
 97     {
 98         notecardsToProcess = monthsOfYearNotecards;
 99         monthsOfYearNotecards = [];//clear to keep memory down
100     }
101     lastPeriodsVisitors = []; //ensure the list is clear at the start 
102     integer numberOfNotecardsToProcess = llGetListLength(notecardsToProcess);
103     integer noteCardIndex;
104     totalVisitorsCalculation = 0;
105     for (noteCardIndex = numberOfNotecardsToProcess-1; noteCardIndex >= 0; noteCardIndex--)
106     {
107         string notecardName = llList2String(notecardsToProcess, noteCardIndex);
108         ProcessVisitorsNotecard(notecardName); //adds contentents to the period list and total visitors figures preventing duplicates in the list
109         llRemoveInventory(notecardName);
110     } 
111 } 
112  
113 ProcessVisitorsNotecard(string notecardName)
114 {   //loops through the named notecard, adding the total visitors together and adding new uninque visitors to a period list
115     string currentLine;
116     integer notecardLength = osGetNumberOfNotecardLines(notecardName);
117     integer lineIndex;
118     for (lineIndex = 0; lineIndex < notecardLength; lineIndex++)
119     {   //loops through the selected notecard
120         currentLine = osGetNotecardLine(notecardName, lineIndex);
121         string firstTwoChars = llGetSubString(currentLine, 0, 1);
122         if (currentLine != "")
123         {
124             if (firstTwoChars == "*A" || firstTwoChars == "*U") //process this line as a total for notecard
125             {   //do this the long way, assume people are idiots and manually change an auto generated notecard. 
126                 if (firstTwoChars == "*A")
127                 {   //only process the all figures when adding together. 
128                     integer equalsIndex = llSubStringIndex (currentLine, "="); //get the position of the equals sign
129                     string strVisitors = llGetSubString(currentLine, equalsIndex+1, -1); //everything after the equals sign
130                     strVisitors = llStringTrim(strVisitors, STRING_TRIM); //remove any white space
131                     integer visitors = (integer) strVisitors; //convert to an integer
132                     totalVisitorsCalculation += visitors; //add value to total visitors calc figure      
133                 }   //close if first two charas are *A
134             }//close if first char is an *
135             else 
136             { 
137                 if (!(~llListFindList(lastPeriodsVisitors, (list)currentLine)))
138                 {   //if this visitor is not the last periods list add them
139                     currentLine = osGetNotecardLine(notecardName, lineIndex);
140                     lastPeriodsVisitors += currentLine;
141                 }//close if not on list
142             }//close if line does not start with an asterix
143         }//close if line is not blank
144     }//close loop through notecard
145 }//close process visitors notecard
146 
147 GenerateNewNoteCard(string notecardType)
148 {   //saves yesterdays vistors, clears the lists and sets last day to todays day ;
149     integer lastTimePeriod; 
150     if (notecardType == "DayOfMonth") lastTimePeriod = lastDay;
151     else if (notecardType == "MonthOfYear") lastTimePeriod = lastMonth;
152     else if (notecardType == "Year") lastTimePeriod = lastYear;
153     string visitorsUnique = "*Unique Visitors = " + (string)llGetListLength(lastPeriodsVisitors);
154     string visitorsAll = "*All Visitors = " + (string)totalVisitorsCalculation;
155     lastPeriodsVisitors += visitorsUnique; //adds the line above to the list
156     lastPeriodsVisitors += visitorsAll; //adds the line above to the list
157     string tail; 
158     if (lastTimePeriod < 10) tail = "0" + (string)lastTimePeriod; //keep the tail to always be 2 characters 
159     else tail = (string)lastTimePeriod; //set the tail string based on the day of the month yesterday
160     string notecardName = notecardType + "-" + tail;
161     if (llGetInventoryType(notecardName) == INVENTORY_NOTECARD) llRemoveInventory(notecardName);
162     osMakeNotecard(notecardName, lastPeriodsVisitors); //save the notecard
163     EnsureNotecardWritten(notecardName);
164     lastPeriodsVisitors = [];
165 }//close process new day 
166 
167 PopulateDaysAndMonthsNoteardLists(string callingMethod)
168 {   //goes through the inventory making lists of the notecard names for days of the month and months of the year
169     daysOfMonthNotecards = []; //ensure the list starts empty
170     monthsOfYearNotecards = []; //ensure the list starts empty
171     integer totalNotecards = llGetInventoryNumber(INVENTORY_NOTECARD);
172     integer notecardIndex;
173     for (notecardIndex = 0; notecardIndex < totalNotecards; notecardIndex++)
174     {   //loops through all notecards and makes a list of the day of the month notecards
175         string notecardName = llGetInventoryName(INVENTORY_NOTECARD, notecardIndex);
176         integer hyphenIndex = llSubStringIndex(notecardName, "-");
177         if (hyphenIndex >= 0)
178         {   //only come here if the name contains a hypen, otherwise ignore as its not part of the system
179             string notecardType = llGetSubString(notecardName, 0, hyphenIndex-1); //everything before the hypen
180             if (notecardType == "DayOfMonth") 
181             {
182                 daysOfMonthNotecards += notecardName; //add this card to the days of the month list
183             }
184             else if (notecardType == "MonthOfYear") 
185             {
186                 monthsOfYearNotecards += notecardName; //add this card to the months of the year list
187             }
188             //no else as its not part of the system so gets ignored
189         }//close if its a notecard belonging to the ones we need to processs
190     }//close loop through all notecards
191 }//populate days and months lists.  
192 
193 string ParseName(string detectedName)
194 { // parse name so both local and hg visitors are displayed nicely
195 //hypergrid name example firstName.LastName@SomeGrid.com:8002
196 string firstName;
197 string lastName;
198 string cleanName;
199 integer atIndex = llSubStringIndex(detectedName, "@"); //get the index position of the "@" symbol if present
200 integer periodIndex = llSubStringIndex(detectedName, ".");//get the index position of the "." if present
201 list nameSegments;
202 if ((periodIndex >= 0) && (atIndex >= 0))
203     {   //the detected name contains both an "@"" and "." so this avi is a hypergrid visitor
204         nameSegments = llParseString2List(detectedName,[" "],["@"]);//split the dected name into two list elements
205         string hGGridName = llList2String(nameSegments,0); //everything before the @ 
206         nameSegments = llParseStringKeepNulls(hGGridName, [" "], ["."]); //split the hg name into two list elements
207         firstName = llList2String(nameSegments,0); //retrieve the first name from the 1st index in the list
208         lastName = llList2String(nameSegments,2); //retrieve  the last name form the 2nd index in the list
209         cleanName = firstName + " " + lastName; //combines the names to look like a local visitors name
210     }//close if hg visitor
211 else
212     {   //this is a local visitor the name is already clean
213         cleanName = detectedName;
214     }//close if local visitor
215 return cleanName; //returns the cleaned name to the calling method
216 }//close parse name
217 
218 SetUpListeners()
219 {//sets the coms channel and the random menu channel then turns the listeners on.
220     menuChannel = (integer)(llFrand(-1000000000.0) - 1000000000.0); //generates random main menu channel
221     menuChannelListen = llListen(menuChannel, "", NULL_KEY, "");//sets up main menu listen integer
222     llListenControl (menuChannelListen, FALSE); //turns off listeners for main menu channel
223 }//close set up listeners
224 
225 DialogAdminMenu(key aviUUID)
226 {   //deliver the menu to the admin provided
227     list buttons = ["Visitors", "Done"]; //list of buttons on the menu
228     string message = "Will deliver a folder with the visitors details in it."; //message on the menu
229     llDialog(aviUUID, message, buttons, menuChannel); //delivers the actual menu
230 }//close deliver dialog menu
231 
232 ShowVisitors (key aviUUID)
233 {   //adds an extra card to show todays visitors then delivers a folder of all visitor details. 
234     list notecardToMake = todaysVisitors;
235     integer numberOfVisitorsToday = llGetListLength(notecardToMake);
236     string notecardName = "Todays-Visitors";
237     string visitorsUnique = "*Unique Visitors = " + (string)numberOfVisitorsToday;
238     string visitorsAll = "*All Visitors = " + (string)numberOfVisitorsToday;
239     notecardToMake += visitorsUnique; //adds the line above to the list
240     notecardToMake += visitorsAll; //adds the line above to the list
241     if (llGetInventoryType(notecardName) != -1)
242     {   //if this notecard already exists delete it
243         llRemoveInventory(notecardName);
244     }//close if notecard already exists
245     osMakeNotecard(notecardName, notecardToMake); //save the notecard
246     list itemsToDeliver = [];
247     integer notecardIndex;
248     for (notecardIndex = 0; notecardIndex < llGetInventoryNumber(INVENTORY_NOTECARD); notecardIndex++)
249     {   //loops through all notecards in the inventory. 
250         string notecardToProcess = llGetInventoryName(INVENTORY_NOTECARD, notecardIndex);
251         integer hyphenIndex = llSubStringIndex(notecardToProcess, "-");
252         if (hyphenIndex != -1)
253         {   //ignore all notecards which do not have a hyphen in them
254             string notecardType  = llGetSubString(notecardToProcess, 0, hyphenIndex-1);
255             if (notecardType == "DayOfMonth" || notecardType == "MonthOfYear" || notecardType == "Year" || notecardType == "Todays")
256             {   //only process notecards starting with "DayOfMonth, MonthOfYear or Year
257                 itemsToDeliver += notecardToProcess;
258             }//close if name matechs our criteria
259         }//close if there is a hypen
260     }//close loop through all notecards in the inventory. 
261     llGiveInventoryList(aviUUID, llGetObjectName(), itemsToDeliver);
262     llListenControl (menuChannelListen, FALSE); //turns off listeners for main menu channel
263     menuListen = FALSE;
264     llRemoveInventory(notecardName);
265     CleanTodaysVisitorsList(); //clean up pass by reference mess    
266 }//close show visitors.
267 
268 CleanTodaysVisitorsList()
269 {   //this list is passed by refernece earlier, either we clean it now or we do a loop copy earlier
270     integer index = llGetListLength(todaysVisitors)-1;
271     for (; index >=0; index--)
272     {
273         string toTest = llList2String(todaysVisitors,index);
274         if (llGetSubString(toTest,0,0) == "*")
275         {   //removes unique visitos and all visitors lines which get added earlier.
276             todaysVisitors = llDeleteSubList(todaysVisitors, index,index);
277         }
278     }
279 }//close clean todays visitors list. 
280 
281 ProcessInstructionLine(string instruction, string data, string notecardName)
282 {   //we only need the data, add it to the admins list
283     if (notecardName == "Admin") 
284     {
285         if (!(~llListFindList(admins, (list)data)))
286         {
287             admins += data;
288         }
289     }
290     else if (notecardName == "Ignore") 
291     {
292         if (!(~llListFindList(ignore, (list)data)))
293         {
294             ignore +=data;
295         }
296     }
297 }//close process instruction line
298 
299 string CleanUpString(string inputString)
300 {   //takes in the string provided by the sending method, removes white space and converts it to lower case then returns the string to the sending method 
301     string cleanString = llStringTrim( llToLower(inputString), STRING_TRIM ); //does the clean up
302     return cleanString; //returns the string to the sending method now its cleaned up  
303 }//close clean up string. 
304 
305 ReadConfigCards(string notecardName)
306 {   //Reads the named config card if it exists
307     if (llGetInventoryType(notecardName) == INVENTORY_NOTECARD)
308     {   //only come here if the name notecard actually exists, otherwise give the user an error
309         integer notecardLength = osGetNumberOfNotecardLines(notecardName); //gets the length of the notecard
310         integer index; //defines the index for the next line
311         for (index = 0; index < notecardLength; ++index)
312         {    //loops through the notecard line by line  
313             string currentLine = osGetNotecardLine(notecardName,index); //contents of the current line exactly as it is in the notecard
314             string firstChar = llGetSubString(currentLine, 0,0); //gets the first character of this line
315             integer equalsIndex = llSubStringIndex(currentLine, "="); //gets the position of hte equals sign on this line if it exists
316             if (currentLine != "" && firstChar != "#" && equalsIndex != -1 )
317             {   //only come here if the line has content, it does not start with # and it contains an equal sign
318                 string instruction = llGetSubString (currentLine, 0, equalsIndex-1); //everything before the equals sign
319                 string data = llGetSubString(currentLine, equalsIndex+1, -1); //everything after the equals sign    
320                 instruction = CleanUpString (instruction); //sends the instruvtion to the cleanup method to remove white space and turn to lower case
321                 data = CleanUpString (data); //sends the data to the cleanup method to remove white space and turn to lower case
322                 ProcessInstructionLine(instruction, data, notecardName); //sends the instruction and the data to the Process instruction method
323             }//close if the line is valid
324             else
325             {   //come here if the above condition is not met
326                 if ( (currentLine != "") && (firstChar != "#") && (equalsIndex == -1))
327                 {   // if the line is not blank and it does not begin with a #, and there is no = sign send an error telling the user which line is invalid. 
328                     llOwnerSay("Line number: " + (string)index + " is malformed. It is not blank, and does not begin with a #, yet it contains no equals sign.");
329                 }//close line is invalid
330             }//close invalid line
331         }
332     }//close if the notecard exists
333     else 
334     {   //the named notecard does not exist, send an error to the user. 
335         //llOwnerSay ("The notecard called " + notecardName + " is missing, auto generating one with just the owner added");
336         GenerateMissingConfigCard(notecardName);
337         
338     }//close error the notecard does not exist
339 }//close read config card.
340 
341 GenerateMissingConfigCard(string notecardName)
342 {
343     string dataToAdd = notecardName + " = " + (string)llGetOwner();
344     string title = "# " + notecardName + "'s" ;
345     list newNotecardContents = [title, dataToAdd];
346     osMakeNotecard(notecardName, newNotecardContents); //save the notecard
347 } 
348 
349 ProcessDetectedAvatars()
350 {   //processes avatars detected by either the region list or collission event. 
351     list avatarsInRegion = llGetAgentList(AGENT_LIST_REGION, []); //generates a list of all avatar uuids in the region
352     integer avatarIndex;
353     for (avatarIndex = 0; avatarIndex < llGetListLength(avatarsInRegion); avatarIndex++)
354     {   //loop through all detected avis
355         key uuidToCheck = llList2Key(avatarsInRegion, avatarIndex); //avi we are currently dealing with
356         string aviName = llKey2Name(uuidToCheck);
357         string cleanName = ParseName (aviName); //get avi name without hg stuff if present
358         if (llDetectedType(avatarIndex) != 0)
359         {
360             if (!(~llListFindList(ignore, (list)uuidToCheck)))
361             {   //if the avi is not on the ignore list come here
362                 if (debug) llOwnerSay("Debug:ProcessDetectedAvis: " + uuidToCheck + " is not on the ignore list"); 
363                 if (!(~llListFindList(todaysVisitorsUUIDs, (list)uuidToCheck)))
364                 {   //if avi has not already visited today add them to both daily visitors and UUID lists
365                     todaysVisitorsUUIDs += uuidToCheck; //add this uuid to the list of visitors today, has to be uuid as names could match with hg visitors
366                     string homeUri = osGetAvatarHomeURI(uuidToCheck);//get the avatars home grid
367                     string newVisitor = cleanName + "," + homeUri; //this is the line we add to the visitors list
368                     todaysVisitors += newVisitor;//add the line abive to todays visitors list. 
369                     if (debug) llOwnerSay("Debug:ProcessDetectedAvatars:" + newVisitor + "added to todays visitors list");
370                 }//close if not on the list already
371             } 
372         }
373         
374     }//close loop through detected list
375 }//close process avatars in region 
376 
377 EnsureNotecardWritten(string notecardName)
378 {   //holds the scrit in a loop untill the card is written
379     integer notecardWritten = FALSE;
380     while (!notecardWritten)
381     {   //if the status is not written come here
382         if (llGetInventoryType(notecardName) == INVENTORY_NOTECARD) notecardWritten = TRUE; //change to true if its written
383     }  //close while not written 
384 }//close ensure notecard is written. 
385 
386 default
387 {
388     changed( integer change )
389     {   //if we have been moved to a new region or changed owne reset the script
390         if (change & (CHANGED_OWNER | CHANGED_REGION)) llResetScript();
391     }//close changed
392 
393     state_entry()
394     {
395         osVolumeDetect(TRUE); //makes item volumetric
396         SetUpListeners();
397         //start fake test data
398         //==========================
399         //lastYear = 2018;
400         //lastMonth = 11;
401         //lastDay = 22;
402         //==========================
403         //end fake test data
404         lastYear = GetDate("Year");
405         lastMonth = GetDate("Month");
406         lastDay = GetDate("Day");
407         ReadConfigCards("Admin");
408         ReadConfigCards("Ignore");
409         llSetTimerEvent(timeInterval); //every 30 mins
410     }//close state entry
411 
412     collision_start(integer total_number)
413     {
414         integer detectedType = llDetectedType(0);
415         if (detectedType == 1 || detectedType == 3 || detectedType == 5)
416         {   //only process avatars, no bots or physical objects
417             key detectedUUID = llDetectedKey(0);
418             if (detectedUUID != lastCollider)
419             {   //if this is the same avi just standing on the dector don't process them
420                 lastCollider = detectedUUID;
421                 ProcessDetectedAvatars();
422             }//close if not last collider
423         }//close if detected type is an avatar
424     }//close collision event
425 
426     touch_start(integer num_detected)
427     {   //come here any time the object is clicked
428          admins = [];
429          ReadConfigCards("Admin");
430          key toucher = llDetectedKey(0);
431          if (~llListFindList(admins, (list)toucher))
432          {  //if the toucher is on the admin list deliver the menu
433              lastAdmin = toucher; //store the last admin toucher incase of a time out. 
434              llListenControl (menuChannelListen, TRUE); //turns on listeners for main menu channel
435              menuListen = TRUE;
436              DialogAdminMenu(toucher);
437          }//close if toucher is on list
438          else llRegionSayTo(toucher, PUBLIC_CHANNEL, "Sorry you are not on the admin list and can not use this item.");
439     }//close touch start event 
440 
441     listen( integer channel, string name, key id, string message )
442     {
443         if (channel == menuChannel)
444         {   //come here if the channel is the menu channel
445             if (~llListFindList(admins, (list)id))
446             {   //if avi sending the message is on the admins list send them the menu
447                 if (message == "Visitors") ShowVisitors(id);
448             }//close if found on admins list
449         }//close channel is the menu channel
450     }//close listen
451  
452     timer()
453     {   //come here based on the timer event time 
454         if (menuListen)
455         {   //come here if the menu listener is on
456             menuListen = FALSE;//set listener tracker to false
457             llRegionSayTo(lastAdmin, PUBLIC_CHANNEL, "Menu timed out, please click again"); //warn the last user
458             llListenControl (menuChannelListen, FALSE); //turns on listeners for main menu channel
459         }//close if menu listener is on
460         ProcessDetectedAvatars(); //scan the sim and process all found avis
461         CheckDate(); //check the date to see if its a new day, if it is process the changes (includes month/year if they also changed)
462     }//close timer
463 }//close state default

Admin Notecard Sample

1 # Allowed Admins
2 Admin = 833a98e7-4574-4f07-9580-b06784759411
3 Admin = 8dbc01dc-71c8-4d88-b776-8b8e827d745c
4 Admin = cbd17d01-4a7e-437a-ac57-0c8313508aae


Ignore Notecard Sample

1 # Ignore's
2 Ignore = 833a98e7-4574-4f07-9580-b06784759411
3 Ignore = cbd17d01-4a7e-437a-ac57-0c8313508aae
4 Ignore = 8dbc01dc-71c8-4d88-b776-8b8e827d745c


Syntax Highlighting

GeShi syntax highlighting is enabled on this wiki. <be>

When using the tabs described in the link, change the language part to "lsl". Eg.
syntaxhighlight lang="lsl" line
inside angled brackets <>