Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Letting an Avatar click once every 24hrs

Billy Fieschi
Registered User
Join date: 21 Jul 2006
Posts: 9
02-13-2008 06:13
I want to script a prim that will allow an avatar to click once and then not be allowed to click again for 24hrs, this needs to be the same for all avatars and at the same time.

I am thinking llsettimerevent, can this be applied to just one uuid, there will have to be some kind of list of the avatars that have clicked for the script to reference.

Anyone got any ideas?

Is this possible?
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
02-13-2008 09:57
You can keep such a list, but it will probably run you out of memory unless you sacrifice a tiny bit of accuracy and put a maximum on the number of entries stored. Of course, it is likely you won't actually have enough clickers to cause this to be a problem unless your object is very popular. Heh. And the memory problem will become far less of a concern when we get Mono.

Note: this code has not yet been compiled or tested.
CODE

float LOCKOUT_PERIOD = 86400; // 60*60*24 seconds
integer MAX_CLICKERS = 80;

// Parallel lists. Each key in clickers is matched by a llGetTime() time in
// clickTimes. Entries are added in order of increasing click time.
list clickers = [];
list clickTimes = [];
integer nClickers = 0;

cleanupClickers()
{
float currTime = llGetTime();
float windowStart = currTime-LOCKOUT_PERIOD;

integer i;
for (i = 0; i < nClickers; ++i)
{
if (llList2Float(clickTimes, i) > windowStart)
{
jump break1;
}
} @break1;

if (i > 0)
{
// Entries before i are before the lockout period and can be forgotten.

clickers = llDeleteSubList((clickers=[])+clickers, 0, i-1);
clickTimes = llDeleteSubList((clickTimes=[])+clickTimes, 0, i-1);
nClickers -= i;
}
}

integer hasAlreadyClicked(key resident)
{
return llListFindList(clickers, [ resident ]) >= 0;
}

integer addClicker(key resident)
{
if (nClickers >= MAX_CLICKERS)
{
clickers = llDeleteSubList((clickers=[])+clickers, 0, 0);
clickTimes = llDeleteSubList((clickTimes=[])+clickTimes, 0, 0);
--nClickers;
}

clickers = (clickers=[])+clickers+[ resident ];
clickTimes = (clickTimes=[])+clickTimes+[ llGetTime() ];
++nClickers;
}

default
{
touch_start(integer numDetected)
{
cleanupClickers();

integer i;
for (i = 0; i < numDetected; ++i)
{
key clicker = llDetectedKey(i);
if (!hasAlreadyClicked(clicker))
{
addClicker();

// Do stuff for this click
}
}
}
}
Ravenhurst Xeno
Consiracy with no purpose
Join date: 20 Jan 2007
Posts: 147
02-13-2008 09:59
From: Billy Fieschi
I want to script a prim that will allow an avatar to click once and then not be allowed to click again for 24hrs, this needs to be the same for all avatars and at the same time.

I am thinking llsettimerevent, can this be applied to just one uuid, there will have to be some kind of list of the avatars that have clicked for the script to reference.

Anyone got any ideas?

Is this possible?


Yes it is possible but llSetTimerEvent isn't really appropriate for this as each script can only have one timer event active at any given time. To do this, the script will have to keep a list of avs that have clicked it and the last time they clicked it. Then when it gets another touch event, check the list to see if it is someone that has already clicked it and when. Because of lsl memory limits, you will only be able to track a hundred or two avs without getting really tricky or using out of world data storage.
Renee Roundfield
Registered User
Join date: 10 Mar 2006
Posts: 278
02-13-2008 15:16
I did something very similar for a Christmas Advent calendar. If you can send me an IM in game to remind me, I can look at that script. I divided the list among 10 scripts sorting by a digit in the UUID of the avatar, so it had fair capacity. But that does make it scripty. And it's helpful if the time can be midnight GMT.
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
02-13-2008 15:47
if avatar is not found in your saved list, add it and the time it was added
if avatar is found, do not process the click
every hour process the front of the list to remove an av/timecode combo that has been in for 24+ hours.

llGetTime can be used for the timestamp, then check if it's 24hrs in seconds later on the hourly check.

if you cap the list make sure the cap keeps the end that has the newest info.
_____________________
|
| . "Cat-Like Typing Detected"
| . This post may contain errors in logic, spelling, and
| . grammar known to the SL populace to cause confusion
|
| - Please Use PHP tags when posting scripts/code, Thanks.
| - Can't See PHP or URL Tags Correctly? Check Out This Link...
| -
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
02-13-2008 22:11
From: Void Singer
if avatar is not found in your saved list, add it and the time it was added
if avatar is found, do not process the click
every hour process the front of the list to remove an av/timecode combo that has been in for 24+ hours.

llGetTime can be used for the timestamp, then check if it's 24hrs in seconds later on the hourly check.

if you cap the list make sure the cap keeps the end that has the newest info.

No way! :-P
Billy Fieschi
Registered User
Join date: 21 Jul 2006
Posts: 9
02-14-2008 02:59
Thanks all for your input,
Hewee, I will try it out and let you know.
Renee, I will IM you in world.
Kahiro Watanabe
Registered User
Join date: 28 Sep 2007
Posts: 572
02-14-2008 05:42
Originally Posted by Void Singer
if avatar is not found in your saved list, add it and the time it was added
if avatar is found, do not process the click
every hour process the front of the list to remove an av/timecode combo that has been in for 24+ hours.

llGetTime can be used for the timestamp, then check if it's 24hrs in seconds later on the hourly check.

if you cap the list make sure the cap keeps the end that has the newest info.

From: Hewee Zetkin
No way! :-P


Actually...Way!. I was going to post same Singer's solution. That way you can save a lot of memory because you use only one list. Imagine that you have 100 ppl on list.

Your way you will have 2 lists with 100 elements.

Singer's way: 1 List

And this is what I thougt: Each field of the list should be a CSV string with key,timestamp.
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
02-14-2008 08:06
From: Hewee Zetkin
No way! :-P

don't get me wrong, I know it's very similar to the way you posted, and I've even done it as a double list just as you did, but I like the timmered variation better than the click variation. I didn't post code because your's could be easily adapted to use the timer method

the reason I like the timer method is that the list gets cleared constantly, even in low traffic, in high traffic, it doesn't process the list on every click, saving a few cycles.

two lists probably is optimal for search/process time since you only have names in one, which makes it search values faster, and only times in the other, which makes processing out old entries faster. though it could be done in strides, that means an extra memory hit for conversion. not so sure about csv'ing the name/time since that requires extra proccessing, and search slows down because there is no partial matching in list find list.

as an optimization, you could search through the list of times for the first index that's less than 24 hrs and then kill all previous entries, instead of deleting them one at a time.

something like

while (index < list_length && time < 24hrs) ++index
then
timelist = list2list( timelist, index, -1 )

assuming you were adding new entries to the tail end.

another speed up would be to add 24hrs to the initial timecode, and then just compare < or > to speed up the garbage collection (since you won't have to tweak it later, possibly multiple times as it's processed)
_____________________
|
| . "Cat-Like Typing Detected"
| . This post may contain errors in logic, spelling, and
| . grammar known to the SL populace to cause confusion
|
| - Please Use PHP tags when posting scripts/code, Thanks.
| - Can't See PHP or URL Tags Correctly? Check Out This Link...
| -
Archie Goodman
Registered User
Join date: 19 May 2006
Posts: 1
02-14-2008 14:43
Sounds great guys, but I am a complete novice so, Void, if you could post the code it would be great.

thanks
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
02-14-2008 15:09
From: Archie Goodman
Sounds great guys, but I am a complete novice so, Void, if you could post the code it would be great.

See above. If you want to go with the suggestion of only cleaning up the list every so often, move the call to 'cleanupClickers()' to an appropriate event or control statement. Otherwise everything Void mentioned is implemented in my script.
Wildefire Walcott
Heartbreaking
Join date: 8 Nov 2005
Posts: 2,156
02-14-2008 16:01
From: Hewee Zetkin
And the memory problem will become far less of a concern when we get Mono.

Mono? Speak for yourself! :p
_____________________
Desperation Isle Estates: Great prices, great neighbors, great service!
http://desperationisle.blogspot.com/

New Desperation Isle: The prettiest BDSM Playground and Fetish Mall in SL!
http://desperationisle.com/

Desperation Isle Productions: Skyboxes for lots (and budgets) of all sizes!
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
02-14-2008 17:14
included as a excercise in the difference of how two people code the same thing. plus I know Heewee's example was made to be more readable/understandable to the beginer, so I kept the same essential variables and conventions from that example.
CODE

float LOCKOUT_PERIOD = 86400; // 60*60*24 seconds
float CLEANUP_RATE = 3600; //-- 60*60sec = 1hr
integer MAX_CLICKERS = 160;

// Parallel lists. Each key in clickers is matched by a llGetTime() time in
// clickTimes. Entries are added in order of increasing click time.
list clickers = [];
list clickTimes = [];
integer index;

default{
state_entry(){
llSetTimerEvent( CLEANUP_RATE );
}

touch_start(integer numDetected){
do{
key clicked = llDetectedKey( --numDetected );

//-- condensed from function call
if (!~llListFindList( clickers, (list)clicked )){
//-- condensed from function call
clickers = (list)clicked + llList2List( (clickers = []) + clickers, 0, MAX_CLICKERS - 1 );
clickTimes = (list)(llGetTime() + LOCKOUT_PERIOD) + llList2List( (clickTimes = []) + clickTimes, 0, MAX_CLICKERS - 1 );

// Do stuff for this click
}
}while (numDetected);
}

timer(){
//-- moved from user function and tweaked.
if (index = llGetListLength( clickTimes )){
float windowStart = llGetTime();

@Loop;
if (llList2Float( clickTimes, --index ) < windowStart){
if (index){
jump Loop;
}else{
clickers = [];
clickTimes = [];
}
}

// Entries after index are before the lockout period and can be forgotten.
clickers = llList2List( (clickers = []) + clickers, 0, index );
clickTimes = llList2List( (clickTimes = []) + clickTimes, 0, index );
}
}
}
_____________________
|
| . "Cat-Like Typing Detected"
| . This post may contain errors in logic, spelling, and
| . grammar known to the SL populace to cause confusion
|
| - Please Use PHP tags when posting scripts/code, Thanks.
| - Can't See PHP or URL Tags Correctly? Check Out This Link...
| -