Difference between revisions of "Advanced Visitor Counter"
Admindiamond (talk | contribs) |
Admindiamond (talk | contribs) |
||
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
Contents
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
- Make a prim which covers the landing point of your region
- 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.
- 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.
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 <>