Timeout-Scheduler

From Second Life Wiki
Revision as of 14:32, 18 November 2010 by Ochi Wolfe (talk | contribs)
Jump to navigation Jump to search
KBwarning.png Warning: This page and the script are currently under development and are not yet finished. Please use it with caution and check back later for updates.

What it is

Timeout-Scheduler is a function which provides a very versatile tool for handling multiple independent timer events, optionally supplemented with arbitrary data.

Some key ideas

  • Easy handling of multiple independent, asynchronous timeout events (for example dialog timeouts for multiple users).
  • One central function (in conjunction with a timer event) for getting, setting, modifying and removing timeout events.
  • Timeout events can be supplemented with additional data which is returned for example when the respective timeout occurs.
  • Hierarchical conditional selection of events, offering many possibilities to do things with very few function calls.

Short overview of the function

The sched() function takes a few arguments, of which some can be left empty depending on the use case.

  • base and cond, the first two parameters of the function, are used to give the timeout one or more names which can be used to look up this timeout event later, for instance to retrieve data about it or to remove it manually. The base paramter must usually be non-empty; the cond list takes up to two additional names for this timeout (see below on how to use the cond parameter for doing cool stuff).
  • time can take three different kinds of values with different meanings:
    • Positive values are used for setting new timeouts. The value is the number of seconds after which the event times out and the hander in the timer event is triggered.
    • A value of 0 is used to remove an existing event (and fetching that event's data), see below.
    • A value of -1 is used to retrieve the data associated with an existing event without deleting the event.
  • data is a list of additional data to associate with the timeout event. This data cannot be used to look up events, but it is returned in addition to the other timeout data when a timeout event is retrieved, removed or triggered.

Creating simple timeout events

Let's start by creating simple timeout events. We'll only use the first parameter base to give the timeouts a name and data to assign some additional data. Try this:

<lsl> sched("timeout3", [], 3, []); sched("timeout2", [], 2, ["SomeData0", "yay"]); sched("timeout1", [], 1, ["SomeData0", "woah", "SomeData1", "moah"]); </lsl>

This should trigger the three timeouts in the correct chronological order.

Implementation

<lsl> ////////// NOTES ///////////////////////

// Timeout-Scheduler v0.1.1-Dev (2010-11) by Ochi Wolfe

// You may use, change and distribute this code as you wish. // When distributing it in source form, it might still be desirable // to include a note where it is from and what you have changed.

////////// VARIABLES ///////////////////

list schedule = [];

////////// FUNCTIONS ///////////////////

string get(list d, string k, string r) {

   integer i = llListFindList(llList2ListStrided(d, 0, -1, 2), [k]);
   if (~i) return llList2String(d, 2*i+1);
   return r;

}

list sched(key base, list cond, integer time, list data) {

   list    res;
   integer idx = -1;
   integer now = llGetUnixTime();

   if (base) { // Select by conditions
       idx = llListFindList(schedule, [base] + cond);
   } else { // Select next due timeout
       integer til = llList2Integer(schedule, 0);
       if (til && til <= now) idx = 1;
   }

   if (~idx) { // There already exists a timeout
       res = llParseStringKeepNulls(llList2String(schedule, idx+3), ["\n"], []);
       if (llGetListEntryType(schedule, idx+2) != TYPE_INTEGER) res = ["_2", llList2String(schedule, idx+2)] + res;
       if (llGetListEntryType(schedule, idx+1) != TYPE_INTEGER) res = ["_1", llList2String(schedule, idx+1)] + res;
       res = ["_0", llList2String(schedule, idx)] + res;
       
       if (!time) { // Delete existing timeout only if time == 0
           schedule = llDeleteSubList(schedule, idx-1, idx+3);
       }
   }

   if (time > 0) { // If positive time is given, insert new timeout
       while (llGetListLength(cond) < 2) cond += [FALSE];
       schedule = llListSort([now+time, base] + cond + [llDumpList2String(data, "\n")] + schedule, 5, TRUE);
   }

   // Adjust timer if necessary
   integer til = llList2Integer(schedule, 0);
   if (!til || til > now) llSetTimerEvent((!!til) * (til-now));

   return res;

}

////////// STATES //////////////////////

default {

   state_entry() {
       sched("timeout", [], 3, []);
   }

   timer() {
       list tData;
       while (tData = sched("", [], 0, [])) {
           llOwnerSay("Base: "      + get(tData, "_0", ""));
           llOwnerSay("Cond1: "     + get(tData, "_1", "(not set)"));
           llOwnerSay("Cond2: "     + get(tData, "_2", "(not set)"));
           llOwnerSay("SomeData0: " + get(tData, "SomeData0", "(not set)"));
           llOwnerSay("SomeData1: " + get(tData, "SomeData1", "(not set)"));
       }
   }

} </lsl>