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