Using llSensorRepeat as a second timer - SLUniverse Forums
Navigation » SLUniverse Forums > Development Discussion and Support > Scripting » Using llSensorRepeat as a second timer


Scripting Discuss scripting and programming for SL and other platforms

 
Reply
 
LinkBack Thread Tools Display Modes
Old 07-25-2012, 12:37 AM   #1 (permalink)
Senior Member
 
KT Kingsley's Avatar
Praying for intelligent life somewhere up in space, 'cause there's bugger all down here on Earth
 
Join Date: Jul 2011
Posts: 1,836
Using llSensorRepeat as a second timer

I'm finding myself using llSensorRepeat as an additional timer quite a lot recently.

While I realise I'm being lazy in not using something like llGetTime and coding my timer calls and events accordingly, I'm also not distributing any of my stuff, which tends to remain in a constant private beta state.

However, I would be interested to learn what parameters would make for the most efficient use of this hack.

I'm currently using
Code:
llSensorRepeat ("", "", AGENT, 0.001, 0.0, time);
(A zero range won't work.)
KT Kingsley is offline   Reply With Quote
Old 07-25-2012, 01:07 AM   #2 (permalink)
The Purple
 
Chalice Yao's Avatar
HEYOO!
 
Join Date: Dec 2007
Location: Somewhere purple, Germany
Posts: 7,773
My Mood:
SL Join Date: 20. January 2007
Client: NaCl
AAAAAAAAAAAAAAAAAARRRRRRRGH
__________________
"Have you ever noticed that anybody driving slower than you is an idiot, and anyone going faster than you is a maniac?" - George Carlin
Chalice Yao is online now   Reply With Quote
3 Users Laughed:
1 User Said Thanks:
1 User Agreed:
Old 07-25-2012, 01:23 AM   #3 (permalink)
Senior Member
 
KT Kingsley's Avatar
Praying for intelligent life somewhere up in space, 'cause there's bugger all down here on Earth
 
Join Date: Jul 2011
Posts: 1,836
Maybe I should mention that I'm doing that only for things that don't run continuously and which use a repeat time of several seconds – like dialog timeouts, and I'm scrupulously removing the sensor immediately in the no_sensor event!
KT Kingsley is offline   Reply With Quote
Old 07-25-2012, 03:32 AM   #4 (permalink)
Senior Member
 
Join Date: Apr 2012
Posts: 105
My Mood:
SL Join Date: March 2004
Quote:
Originally Posted by KT Kingsley View Post
Maybe I should mention that I'm doing that only for things that don't run continuously and which use a repeat time of several seconds – like dialog timeouts, and I'm scrupulously removing the sensor immediately in the no_sensor event!
If your using it for dialog timeouts, why not anchor it to a valid non-agent UUID? Should reduce lag.

Code:
llSensorRepeat ("", llGetKey(), AGENT, 0.001, 0.0, time);
Strife is offline   Reply With Quote
1 User Said Thanks:
Old 07-25-2012, 03:43 AM   #5 (permalink)
Banned
 
Join Date: Mar 2011
Location: Pennsylvania
Posts: 1,213
SL Join Date: Jan 2007
Linus Torvalds once said, "If it compiles, it is good; if it boots up, it is perfect."

I wouldn't worry about performance so long as you get it to do what you want. Just get the functionality working and then go back and optimize things like this later. You already know how to do it right, so no need to sweat the details if you find this easier to work with while developing your ideas.

Just please don't sell a million copies of something with a script like this in it.
bubblesort is offline   Reply With Quote
Old 07-25-2012, 10:03 AM   #6 (permalink)
That Bitch

*SLU Supporter*
 
Void's Avatar
Innocent as far as you know
 
Join Date: Nov 2011
Location: Online
Posts: 6,370
My Mood:
SL Join Date: late 04... that account is deleted now
when I use this method I always use the the objects key, and the set the type filter for agent, as Strife demonstrated. That's a guaranteed "no match / not found" and the agent filter probably cuts down on search complexity on the back end. You play catch in the no_sensor event, but you may need an empty sensor event for safety (not sure of the status on that bug)

I generally only use this when my timer is heavily scripted and under regular use, for other things of a transitory/asynchronous nature. to cut down overhead from multiplexing or continual flag checking in the actual timer event.

ETA:
and some people can scream all they want it actually works out cheap to the region if your timer is already bloated... I'm not sure that using it for dialog timers is a good idea though, since you often have to push those further out on successive dialog choices.
__________________
- These eyes can do more than see
Quote:
Originally Posted by Cajsa Lilliehook View Post
It's not enough to care about liberty if the only liberty you care about is your own.
Quote:
Originally Posted by Jupiter Firelyte View Post
Why doesn't anyone ever ask, "What is the real meaning of the winter solstice?"
Quote:
Originally Posted by Eboni Khan View Post
Thanks for being passive agressive.
Void is offline   Reply With Quote
Old 07-25-2012, 10:22 AM   #7 (permalink)
The Purple
 
Chalice Yao's Avatar
HEYOO!
 
Join Date: Dec 2007
Location: Somewhere purple, Germany
Posts: 7,773
My Mood:
SL Join Date: 20. January 2007
Client: NaCl
Quote:
Originally Posted by Void View Post
ETA:
and some people can scream all they want it actually works out cheap to the region if your timer is already bloated... I'm not sure that using it for dialog timers is a good idea though, since you often have to push those further out on successive dialog choices.
D:

AAAAAAAAAAAAAAAAAAARRRRGHHH
Chalice Yao is online now   Reply With Quote
1 User Laughed:
1 User Hugged You:
1 User Said Thanks:
Old 07-25-2012, 10:34 AM   #8 (permalink)
Senior Member
 
KT Kingsley's Avatar
Praying for intelligent life somewhere up in space, 'cause there's bugger all down here on Earth
 
Join Date: Jul 2011
Posts: 1,836
OK – so I heard your screams and howls of derisory laughter. (My thanks to those of you who offered words of comfort.)

So I went to work and came up with this, a system that will allow an unlimited number (well ok, memory-limited number) of different timer events with their individual timer intervals within a single script. Obviously it's way too scripty and list-processy for the pretty simple stuff I've done which really only needs to store a couple of time floats and do a simple test in the timer () event, but I thought I'd put it up here for comment and criticism anyway. This script includes the core functions and variable as well as example usage.

Code:
//Compound timer

//These three functions enable you to set up multiple timer events, each with their own interval, simultaneously
//(In this example you can trigger a simple dialog by clicking and holding for one second)

//list of timer events
list timer_events;//strided 3: next event due time, event id, interval between events

//store the returned key to identify this particular event in the timer () event
//specify the interval between triggering of the timer () event
key SetTimerEvent (float interval)
{
    //convert negative and zero intervals to immediate (use a seperate function to stop timer events)
    if (interval <= 0.0) interval = 0.01;
    //create a (hopefully) unique UUID for this event
    key id = (key) llInsertString (llInsertString (llInsertString (llInsertString (llMD5String (llGetTimestamp (), 0), 8, "-"), 13, "-"), 18, "-"), 23, "-");
    //add this event to the list and sort the list
    timer_events = llListSort ([llGetTime () + interval, id, interval] + timer_events, 3, TRUE);
    //calculate how long till the next event
    interval = llList2Float (timer_events, 0) - llGetTime ();
    //if we're already late for the next event do it immediately
    if (interval <= 0.0) interval = 0.01;
    //wait until the next event is due
    llSetTimerEvent (interval);
    return id;
}

//use a stored event key to specify it for removal
StopTimerEvent (key id)
{
    //find this event in the list
    integer index = llListFindList (timer_events, [id]);
    //if it's there...
    if (index > -1)
    {
        //remove this event from the list
        timer_events = llDeleteSubList (timer_events, index - 1, index + 1);
        //if there's no events left in the list stop the timer
        if (llGetListLength (timer_events) == 0) llSetTimerEvent (0.0);
        //if there are, and we've just removed the next scheduled event...
        else if (index == 1)
        {
            //calculate how long till the next event
            float interval = llList2Float (timer_events, 0) - llGetTime ();
            //if we're already late for it do it immediately
            if (interval <= 0.0) interval = 0.01;
            //wait until it's due
            llSetTimerEvent (interval);
        }
    }
}

//get the UUID of the current event in the timer () event to identify which event it is responding to
key GetTimerEventKey ()
{
    //get the UUID for the current event
    key id = llList2Key (timer_events, 1);
    //get the timer interval for this event
    float interval = llList2Float (timer_events, 2);
    //replace the current event with it's next ocurrence and sort the list
    timer_events = llListSort (llListReplaceList (timer_events, [llGetTime () + interval, id, interval], 0, 2), 3, TRUE);
    //calculate how long till the next event
    interval = llList2Float (timer_events, 0) - llGetTime ();
    //if we're already late for the next event do it immediately
    if (interval <= 0.0) interval = 0.01;
    //wait until the next event is due
    llSetTimerEvent (interval);
    return id;
}

//UUIDs of example timer events
key regular_timer;
key touch_timer;
key long_touch_timer;
key dialog_timeout;

//flag for when a long click-and-hold is encountered
integer long_touch;
//listener for dialog response
integer listener;

default
{
    state_entry ()
    {
        //set up a regular timer event (switchable on/off by dialog)
        regular_timer = SetTimerEvent (10.0);
    }
    touch_start (integer count)
    {
        if (llDetectedKey (0) == llGetOwner ())//ignore curious bystanders
        {
            //set up a timer to see if this is a long click-and-hold
            long_touch_timer = SetTimerEvent (1.0);
        }
    }
    touch_end (integer count)
    {
        if (llDetectedKey (0) == llGetOwner ())//ignore curious bystanders
        {
            //if this was a long click-and-hold reset the flag and do nothing else
            if (long_touch) long_touch = FALSE;
            //otherwise this was just a normal click...
            else
            {
                //stop waiting for a long click-and-hold
                StopTimerEvent (long_touch_timer);
                //precess the result of a normal click (in this case, trigger an event in 5s time)
                touch_timer = SetTimerEvent (5.0);
            }
        }
    }
    timer ()
    {
        //get the UUID of the current event
        key event_id = GetTimerEventKey ();
        //process the different events according to their UUID...
        if (event_id == regular_timer) llOwnerSay ("Regular 10s timer.");//the regular timer
        else if (event_id == touch_timer)//triggered 5s after a normal click
        {
            //stop further occurences of this event
            StopTimerEvent (touch_timer);
            //process the event
            llOwnerSay ("Touch triggered 5s timer.");
        }
        else if (event_id == long_touch_timer)//triggered 1s after a click that hasn't yet been released
        {
            //stop further occurences of this event
            StopTimerEvent (long_touch_timer);
            //set the flag so nothing happens in the touch_end () event
            long_touch = TRUE;
            //open a listener for the dialog
            listener = llListen (-5678, "", llGetOwner (), "");
            //initiate the dialog
            llDialog (llGetOwner (), "\nRegular timer:", llList2List (["Stop", "Start"], regular_timer == NULL_KEY, regular_timer == NULL_KEY) + ["CANCEL"], -5678);
            //create an event for a dialog timeout
            dialog_timeout = SetTimerEvent (60.0);
        }
        else if (event_id == dialog_timeout)//triggered 60s after a dialog has been initated but not responded to
        {
            //stop further occurences of this event
            StopTimerEvent (dialog_timeout);
            //remove the listener
            llListenRemove (listener);
            //kill the original dialog with a timeout info message (this works great in V2/3 viewers, maybe not no great elsewhere)
            llDialog (llGetOwner (), "\nDialog timeout", [], -999);
        }
        else
        {
            //this event hasn't been recognised so remove it from the list (you could try and do something about it, but here we'll just forget about it)
            //(in this example this can happen after multiple normal clicks, each overriding the previously stored UUID for a normal click)
            StopTimerEvent (event_id);
            //unnecessary spam
            llOwnerSay ("Unprocessed timer event.");
        }
    }
    listen (integer channel, string name, key id, string message)
    {
        //we've had a response to the dialog so we won't want a dialog timeout 
        StopTimerEvent (dialog_timeout);
        //remove the listener
        llListenRemove (listener);
        //process the dialog message...
        if (message == "Start")
        {
            //start a regular timer
            regular_timer = SetTimerEvent (10.0);
            //unnecessary spam
            llOwnerSay ("Starting regular timer.");
        }
        else if (message == "Stop")
        {
            //stop the regular timer
            StopTimerEvent (regular_timer);
            //specifically set NULL_KEY to simplify selecting which button to display in the dialog
            regular_timer = NULL_KEY;
            //unnecessary spam
            llOwnerSay ("Stopping regular timer.");
        }
        //do nothing: either the dialog has been cancelled deliberately, or a spurious message has managed to sneak in
        //unnecessary spam
        else llOwnerSay (message + " – dialog cancelled.");
    }
}

Last edited by KT Kingsley; 07-25-2012 at 10:40 AM.
KT Kingsley is offline   Reply With Quote
1 User Laughed:
1 User Hugged You:
Old 07-25-2012, 10:44 AM   #9 (permalink)
Senior Member

*SLU Supporter*
 
NeoBokrug Elytis's Avatar
post_count++;
 
Join Date: Sep 2007
Location: Austin, TX
Posts: 1,046
My Mood:
SL Join Date: 11/01/2005
Business: The Wastelands
Client: Official Newest
Juggle timestamps!

integer time_stamp_one;
integer time_stamp_two;

timer() {
integer unix_time = llGetUnixTime();
if (unix_time > time_stamp_one) {
// do stuff
time_stamp_one = unix_time + one_interval;
}
if (unix_time > time_stamp_two) {
// do different stuff
time_samp_two = unix_time + two_interval;
}
}
__________________
Tin Man Rant - Blog

Alright, I've been thinking. When life gives you lemons, don't make lemonade - make life take the lemons back! Get mad! I don't want your damn lemons, what am I supposed to do with these? Demand to see life's manager. Make life rue the day it thought it could give Cave Johnson lemons. Do you know who I am? I'm the man who's gonna burn your house down! With the lemons. I'm going to to get my engineers to invent a combustible lemon that burns your house down! -- Cave Johnson
NeoBokrug Elytis is offline   Reply With Quote
Old 07-25-2012, 10:46 AM   #10 (permalink)
The Purple
 
Chalice Yao's Avatar
HEYOO!
 
Join Date: Dec 2007
Location: Somewhere purple, Germany
Posts: 7,773
My Mood:
SL Join Date: 20. January 2007
Client: NaCl
Don't take my screams too seriously ;P LSL often requires tons of hacks to be more efficient, so whatever works for you is fine, as long as it doesn't take up much resources. Even if it's abuse of...the..sensor..for....f....fff..

Chalice Yao is online now   Reply With Quote
1 User Hugged You:
Old 07-25-2012, 10:48 AM   #11 (permalink)
Senior Member

*SLU Supporter*
 
NeoBokrug Elytis's Avatar
post_count++;
 
Join Date: Sep 2007
Location: Austin, TX
Posts: 1,046
My Mood:
SL Join Date: 11/01/2005
Business: The Wastelands
Client: Official Newest
Quote:
Originally Posted by KT Kingsley View Post
key id = (key) llInsertString (llInsertString (llInsertString (llInsertString (llMD5String (llGetTimestamp (), 0), 8, "-"), 13, "-"), 18, "-"), 23, "-");
I think an undocumented function got added in april: llGenerateKey();
NeoBokrug Elytis is offline   Reply With Quote
2 Users Said Thanks :
1 User Likes This:
Old 07-25-2012, 10:49 AM   #12 (permalink)
The Purple
 
Chalice Yao's Avatar
HEYOO!
 
Join Date: Dec 2007
Location: Somewhere purple, Germany
Posts: 7,773
My Mood:
SL Join Date: 20. January 2007
Client: NaCl
Quote:
Originally Posted by NeoBokrug Elytis View Post
I think an undocumented function got added in april: llGenerateKey();
LlGenerateKey - Second Life Wiki

Seems like there is at least some documentation..but yeah, I think there was no server release note about it

iiiinteresting.
Chalice Yao is online now   Reply With Quote
1 User Agreed:
Old 07-25-2012, 10:52 AM   #13 (permalink)
Senior Member

*SLU Supporter*
 
NeoBokrug Elytis's Avatar
post_count++;
 
Join Date: Sep 2007
Location: Austin, TX
Posts: 1,046
My Mood:
SL Join Date: 11/01/2005
Business: The Wastelands
Client: Official Newest
Quote:
Originally Posted by Chalice Yao View Post
Seems like there is at least some documentation..but yeah, I think there was no server release note about it

iiiinteresting.
That's what I meant. I really should drink caffeine in the morning.

Another thing to note it that even though the documentation says version 3 UUID, it's actually version 5

Last edited by NeoBokrug Elytis; 07-25-2012 at 10:53 AM. Reason: I really need caffeine.
NeoBokrug Elytis is offline   Reply With Quote
Old 07-25-2012, 10:53 AM   #14 (permalink)
Senior Member
 
KT Kingsley's Avatar
Praying for intelligent life somewhere up in space, 'cause there's bugger all down here on Earth
 
Join Date: Jul 2011
Posts: 1,836
llGenerateKey: much prettier - it fits on a single line of text!
KT Kingsley is offline   Reply With Quote
Old 07-25-2012, 11:48 AM   #15 (permalink)
Senior Member
 
KT Kingsley's Avatar
Praying for intelligent life somewhere up in space, 'cause there's bugger all down here on Earth
 
Join Date: Jul 2011
Posts: 1,836
Quote:
Originally Posted by NeoBokrug Elytis View Post
[…] Another thing to note it that even though the documentation says version 3 UUID, it's actually version 5
Strife is on the ball today! (It was corrected within minutes of your post!)
KT Kingsley is offline   Reply With Quote
Old 07-25-2012, 11:50 AM   #16 (permalink)
That Bitch

*SLU Supporter*
 
Void's Avatar
Innocent as far as you know
 
Join Date: Nov 2011
Location: Online
Posts: 6,370
My Mood:
SL Join Date: late 04... that account is deleted now
side note:
generate key is nice if you want psuedo-random and non repeating (as in the case of the md5 hack), but if you want actually random, spit out random numbers, convert them to hex and drop in your dashes).


the problem with timers is that there's multiple paradigms for them to work on... for instance, the continually delayed "push" used for most dialog and dataserver handling..... much simpler than running a faster timer with a timestamp that gets checked repeatedly, but it doesn't behave well when coupled with a simple frequency timer paradigm.

multiple frequency timers can be multiplexed together with a single counter and check... push timers can't unless you speed up the timer (to keep it roughly accurate) and check against multiple timestamps...

an lsl annoyance to be sure, but the lack of multiple independant timers kinda makes it necessary, and more painful than it should be. all we can really do is damage control.

Last edited by Void; 07-25-2012 at 11:56 AM.
Void is offline   Reply With Quote
Old 07-25-2012, 12:00 PM   #17 (permalink)
Senior Member
 
Join Date: Apr 2012
Posts: 105
My Mood:
SL Join Date: March 2004
Thanks for the heads up NeoBokrug, I've updated the docs (which is stupid since I've requested they do a rollback...)

It is true, it was never in the release notes. Drives me nuts when they do this and don't update the compiler in the client. *inspiration* I should read the tooltips from strings.xml!

Last edited by Strife; 07-26-2012 at 12:59 AM.
Strife is offline   Reply With Quote
1 User Said Thanks:
Old 07-25-2012, 12:05 PM   #18 (permalink)
Senior Member
 
Adeon Writer's Avatar
 
Join Date: Apr 2010
Posts: 6,183
Don't use sensor() as a timer!

no_sensor(), on the other hand...

;D
__________________
My mobile client puts the thread title at the top of my posts. I don't do it on purpose.
Adeon Writer is offline   Reply With Quote
Old 07-25-2012, 12:11 PM   #19 (permalink)
That Bitch

*SLU Supporter*
 
Void's Avatar
Innocent as far as you know
 
Join Date: Nov 2011
Location: Online
Posts: 6,370
My Mood:
SL Join Date: late 04... that account is deleted now
well yeah, I think that was assumed from the code =P


@chalice:
could be worse, people could use http as a timer =D
Void is offline   Reply With Quote
Old 07-25-2012, 12:23 PM   #20 (permalink)
Senior Member
 
KT Kingsley's Avatar
Praying for intelligent life somewhere up in space, 'cause there's bugger all down here on Earth
 
Join Date: Jul 2011
Posts: 1,836
Quote:
Originally Posted by Void View Post
[…] could be worse, people could use http as a timer =D
/me bookmarks this suggestion…
KT Kingsley is offline   Reply With Quote
1 User Laughed:
Old 07-25-2012, 12:36 PM   #21 (permalink)
Senior Member
 
Adeon Writer's Avatar
 
Join Date: Apr 2010
Posts: 6,183
Code:
changed(integer poot)
{
   if(poot & CHANGED_COLOR)
   {
      llSetColor(<llFrand(1), 0, 0>, 0);
      code();
   }
}
/waits for Chalice

Last edited by Adeon Writer; 07-25-2012 at 12:42 PM.
Adeon Writer is offline   Reply With Quote
3 Users Laughed:
1 User Likes This:
Old 07-25-2012, 01:32 PM   #22 (permalink)
That Bitch

*SLU Supporter*
 
Void's Avatar
Innocent as far as you know
 
Join Date: Nov 2011
Location: Online
Posts: 6,370
My Mood:
SL Join Date: late 04... that account is deleted now
I've actually done something close to that scary changed loop before =X

... granted I actually was changing something with it and it's ungodly fast

PS
don't use Frand, use a boolean switch, and ditch the (really bad) test =D
*I'm kidding, don't do that shit
Void is offline   Reply With Quote
Old 07-25-2012, 02:31 PM   #23 (permalink)
Senior Member
 
Darien Caldwell's Avatar
Mayan Time Lord
 
Join Date: Apr 2008
Location: Cali
Posts: 2,102
My Mood:
SL Join Date: 10/12/2006
Business: [H]arsh Styles
Client: Always changing, and too lazy to edit.
Quote:
Originally Posted by Void View Post
when I use this method I always use the the objects key, and the set the type filter for agent, as Strife demonstrated. That's a guaranteed "no match / not found" and the agent filter probably cuts down on search complexity on the back end. You play catch in the no_sensor event, but you may need an empty sensor event for safety (not sure of the status on that bug)

I generally only use this when my timer is heavily scripted and under regular use, for other things of a transitory/asynchronous nature. to cut down overhead from multiplexing or continual flag checking in the actual timer event.

ETA:
and some people can scream all they want it actually works out cheap to the region if your timer is already bloated... I'm not sure that using it for dialog timers is a good idea though, since you often have to push those further out on successive dialog choices.
Dialog timers are actually a waste in many instances, an open listen doesn't cause any measurable lag or overhead, it's the event that has the potential to. But if your listen is on a rarely used channel, and if your event discards very quickly, it's just about never going to be called, or only called for a negligibly short amount of time.

Dialog timers are a good idea if you're putting your listen on a busy channel like, um, 1. But I sure hope nobody is doing that.
__________________
[H]arsh Styles
Darien Caldwell is offline   Reply With Quote
Old 07-25-2012, 02:33 PM   #24 (permalink)
Senior Member
 
Darien Caldwell's Avatar
Mayan Time Lord
 
Join Date: Apr 2008
Location: Cali
Posts: 2,102
My Mood:
SL Join Date: 10/12/2006
Business: [H]arsh Styles
Client: Always changing, and too lazy to edit.
Quote:
Originally Posted by Strife View Post
*inspiration* I should read the tooltips from strings.xml!

Yeah except half the functions added over a year ago still aren't in there.
Darien Caldwell is offline   Reply With Quote
Old 07-25-2012, 03:27 PM   #25 (permalink)
Senior Member
 
Adeon Writer's Avatar
 
Join Date: Apr 2010
Posts: 6,183
I don't bother timing it out. My scripts just only have one listen open at a time. I don't time them out, I just use only one handle, which I llListenRemove before reusing it. I just close it on other events if it makes sense to.
Adeon Writer is offline   Reply With Quote
1 User Likes This:
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are On