scheduler #99

Parent #74Owner #2Flags readSource RPG Core/rpgcore-patched.db

Aliases: scheduler

20 verbs · 33 properties · 0 children

Verbs

VerbSpecFlagsDefinerLines
init_for_corethis none thisrxd#9912
addthis none thisrxd#9916
insertthis none thisrxd#9911
assignthis none thisrxd#995
valid_taskthis none thisrxd#992
usable_bythis none thisrxd#997
kill_task*sthis none thisrxd#9922
job_batchthis none thisrxd#9917
dothis none thisrxd#9918
kill @unsched*uleany none nonerxd#9942
stop_startthis none thisrxd#9915
atrunthis none thisrxd#9932
look_selfthis none thisrxd#9925
get_task_displaythis none thisrxd#9945
@sched*ulernone none nonerxd#9934
is_runningthis none thisrxd#997
@resetthis any anyrd#9919
schedule schedule_at schedule_everythis none thisrxd#9927
do_checkpointthis none thisrxd#9945
@list-ch*eckpointsnone none nonerxd#9911

Properties

PropertyDefinerFlagsOwnerValue
lock#99rc#20
task#99rc#20
lock_timeout#99rc#2300
tasks#99rc#2{}
clearing#99rc#20
dump_interval#99rc#210800
dump_task#99rc#20
checkpoint_sizes#99rc#2{}
checkpoint_times#99rc#2{}
warehouse#74r#36<clear>
help_msg#74rc#2
list of 65{"Scheduler: The scheduler is designed as a process storage chamber. Verbs which execute with a long period (an hour, a day, etc.) can be stored on the scheduler, without filling up the queued task list. Verbs which need to happen with a certain number of iterations, or infinitely, can be handled by code in the scheduler, reducing the burden on the programmer. The scheduler also accounts for drift in lag, allowing a verb to run at a certain time, every time.", "", "Building Blocks:", "", ":schedule (rel_time,obj,verb[,args])", ":schedule_at (abs_time,obj,verb[,args])", ":schedule_every (rel_time,obj,verb[,args])", "", " \"rel_time\" indicates a time interval from the present moment, that is: a", " relative time, or \"x seconds from now\"", " \"abs_time\" indicates an absolute time, for example: 749069038", " \"obj\" indicates the object on which the verb you will call resides", " \"verb\" is the verb you will be calling", " \"args\" is/are the argument(s) you will use in the verb call.", "", " The \"rel_time\" is a number, given in seconds. The \"obj\" is an object", " number, like #1, the verb is a string, like \"tell\". The \"args\" is a list of", " arguments to be passed, and may be left off. If left off, no arguments will", " be passed.", "", "Examples:", "", ":schedule(35,#11,\"announce_all\",{\"I am here!\"})", " which is equivalent to:", " ;fork(35) #11:announce_all(\"I am here!\"); endfork", "", ":schedule_at(749069497,$fountain,\"start\")", " equals:", " ;fork(time()+6*24*3600) $fountain:start(); endfork", "", ":schedule_every(15,$puppet,\"action\",{\"move\",\"eat\",\"walk\"})", " is fairly close in meaning to:", " [verb code on $puppet]", " ...", " fork (15)", " this:(verb)(\"move\",\"eat\",\"walk\");", " endfork", "", "", "Extra Neat-o's:", "", "The \"object\" parameter in the verb calls above may be substituted with strings. The string will then be passed to the player's eval_cmd_str(), and must return an object number. If the code does not return a valid object number, the scheduled verb will not run.", "", "Also, the \"arguments\" parameter may be left as a simple value (integer, string, whatever), or left off entirely.", "", "Examples:", "", ":schedule_every(35,\"player.location\",\"announce_all\",{\"I am here!\"})", " Every 35 seconds, this verb will announce to the player's current location.", "", ":schedule(35,\"player\",\"tell\",\"Hello from me!\")", " Equivalent to :schedule(35,\"player\",\"tell\",{\"Hello from me!\"})", "", ":schedule(35,\"player\",\"tell\")", " Equivalent to :schedule(35,\"player\",\"tell\",{})", "", "", "Problems:", "", "This is a simplified version of Pascal's scheduler put together by Changeling (geocorona@aol.com). Contact that address with problems.", "Original author: (t_pascal@oxy.edu).", "", "FOR SERVERS COMPILED WITHOUT AUTOMATIC CHECKPOINTING:", ";$scheduler:schedule($scheduler.dump_interval, $scheduler, \"do_checkpoint\")", "====================================================="}
feature_verbs#74r#36{"@sched", "@unsched", "@reset", "@list-ch"}
feature_ok#74r#36<clear>
drop_failed_msg#5rc#2<clear>
drop_succeeded_msg#5rc#2<clear>
odrop_failed_msg#5rc#2<clear>
odrop_succeeded_msg#5rc#2<clear>
otake_succeeded_msg#5rc#2<clear>
otake_failed_msg#5rc#2<clear>
take_succeeded_msg#5rc#2<clear>
take_failed_msg#5rc#2<clear>
value_base#102r#2<clear>
damage_base#102r#2<clear>
x_loc#102r#36<clear>
y_loc#102r#36<clear>
ansi_title#102r#36<clear>
obvious#102r#36<clear>
build_help#102rc#2<clear>
key#1c#20
aliases#1rc#2{"scheduler"}
description#1rc#2"A feature object that can execute repetitive verbs, and verbs suspended for long periods."
object_size#1r#36{23893, -1090650497}
html#1rc#2<clear>

Ancestry

Ancestors (nearest first): #74 Generic Feature Object#5 generic thing#102 subthing#1 Root Class

Children: none

Call graph

calls n99_0 #99:init_for_core n74_8 #74:init_for_core n99_0->n74_8 n99_1 #99:add n63_9 #63:valid n99_1->n63_9 n99_2 #99:insert n99_2->n99_1 n99_10 #99:stop_start n99_2->n99_10 n99_11 #99:atrun n99_10->n99_11 n99_3 #99:assign n55_18 #55:iassoc n99_3->n55_18 n99_4 #99:valid_task n99_4->n55_18 n99_6 #99:kill_task*s n99_6->n99_10 n99_6->n99_4 n99_5 #99:usable_by n99_6->n99_5 n42_0 #42:controls n99_6->n42_0 n99_8 #99:do n69_0 #69:raise n99_8->n69_0 n99_9 #99:kill n99_9->n99_5 n99_9->n42_0 n6_18 #6:tell n99_9->n6_18 n56_4 #56:yes_or_no n99_9->n56_4 n99_11->n99_2 n99_11->n99_8 n99_11->n99_11 n55_16 #55:slice n99_11->n55_16 n99_7 #99:job_batch n99_11->n99_7 n99_12 #99:look_self n99_12->n99_5 n99_12->n42_0 n99_12->n6_18 n20_71 #20:redirect_ansi n99_12->n20_71 n20_48 #20:print n99_12->n20_48 n99_13 #99:get_task_display n99_13->n42_0 n99_13->n20_71 n99_13->n20_48 n99_15 #99:is_running n99_13->n99_15 n43_7 #43:english_time n99_13->n43_7 n20_59 #20:name_and_number n99_13->n20_59 n59_37 #59:task_valid n99_15->n59_37 n99_14 #99:@sched*uler n99_14->n6_18 n99_14->n99_13 n6_79 #6:tell_lines n99_14->n6_79 n99_16 #99:@reset n99_16->n99_10 n99_16->n6_18 n99_17 #99:schedule n99_17->n99_2 n99_17->n99_3 n99_17->n99_5 n99_18 #99:do_checkpoint n99_18->n99_4 n99_18->n43_7 n99_18->n99_17 n99_19 #99:@list-ch*eckpoints n99_19->n6_18 n99_19->n20_71 n20_26 #20:group_number n99_19->n20_26

Source

init_for_core

Spec this none thisFlags rxdOwner #2Definer #99

Referenced by

none

Source

1if (($code_utils:verb_location() == this) && caller_perms().wizard)
2this.task = 0;
3this.clearing = 0;
4this.lock = 0;
5this.lock_timeout = 300;
6this.tasks = {};
7this.dump_interval = 10800;
8this.dump_task = 0;
9this.checkpoint_sizes = {};
10this.checkpoint_times = {};
11endif
12pass(@args);

add

Spec this none thisFlags rxdOwner #2Definer #99

Referenced by

Source

1"  :add(time,t_id,data)  =>  inserts task on the task-list, in ascending order";
2if ((caller != this) && (!caller_perms().wizard))
3return E_PERM;
4endif
5if (length(args) < 3)
6return E_ARGS;
7elseif (!$recycler:valid(args[3][3]))
8return E_INVARG;
9endif
10time = call_function("tonum", args[1]);
11i = 1;
12len = length(tasks = this.tasks);
13while ((i <= len) && (this.tasks[i][1] <= time))
14i = i + 1;
15endwhile
16this.tasks = listinsert(tasks, args, i);

insert

Spec this none thisFlags rxdOwner #2Definer #99

Referenced by

Source

1"  :insert(time,t_id,data)  =>  Updates tasks in the list, starting :atrun if necessary";
2if ((caller != this) && (!caller_perms().wizard))
3return E_PERM;
4endif
5if (typeof(ret = this:add(@args)) == ERR)
6return ret;
7endif
8if (((call_function("tonum", args[1]) < this.lock) || (!(this.lock && this.task))) || (time() > (this.lock + this.lock_timeout)))
9this:stop_start();
10endif
11return ret;

assign

Spec this none thisFlags rxdOwner #2Definer #99

Referenced by

Source

1while ($list_utils:iassoc(n = random($maxint), this.tasks, 2))
2"Do nothing";
3endwhile
4"N is now unique..";
5return n;

valid_task

Spec this none thisFlags rxdOwner #2Definer #99

Referenced by

Source

1"    :valid_task(taskid)  =>  true if taskid is in the current task-list";
2return args ? $list_utils:iassoc(call_function("tonum", args[1]), this.tasks, 2) | E_ARGS;

usable_by

Spec this none thisFlags rxdOwner #2Definer #99

Referenced by

Source

1"    :usable_by(whom)  =>  1 | 0";
2"This verb should return true if who has permission to use this";
3if (args)
4return args[1].programmer;
5else
6return E_ARGS;
7endif

kill_task*s

Spec this none thisFlags rxdOwner #2Definer #99

Referenced by

none

Source

1"  :kill_task*s(t_id[s])  =>  returns number of tasks killed";
2if (!this:usable_by(caller_perms()))
3return E_PERM;
4endif
5if (args)
6t_ids = (typeof(args[1]) == LIST) ? args[1] | {args[1]};
7reset = 0;
8killed = 0;
9for t_id in (t_ids)
10if ((task = this:valid_task(call_function("tonum", t_id))) && $perm_utils:controls(caller_perms(), this.tasks[task][3][7]))
11this.tasks = listdelete(this.tasks, task);
12killed = killed + 1;
13endif
14reset = ((reset || task) == 1) ? 1 | 0;
15endfor
16if (reset)
17this:stop_start();
18endif
19return killed;
20else
21return E_ARGS;
22endif

job_batch

Spec this none thisFlags rxdOwner #2Definer #99

Referenced by

Source

1"  :job_batch(time)  =>  returns a list of tasks due for time, taking them off the queue.";
2if ((caller != this) && (!caller_perms().wizard))
3return E_PERM;
4endif
5if (args)
6time = call_function("tonum", args[1]);
7for x in [1..l = length(t = this.tasks)]
8if (t[x][1] > time)
9this.tasks = t[x..l];
10return t[1..x - 1];
11endif
12endfor
13this.tasks = {};
14return t;
15else
16return E_ARGS;
17endif

do

Spec this none thisFlags rxdOwner #2Definer #99

Referenced by

Source

1"Does the verb given args == {#obj,\"verb\",{args},#player,#permissions}";
2"The #obj argument may be given as a string which is then eval()'d";
3"This verb is a potential security hole!  Guard this one closely.";
4if ((caller == this) && caller_perms().wizard)
5if (length(args) < 5)
6return E_ARGS;
7else
8player = args[4];
9set_task_perms(args[5]);
10if (typeof(object = args[1]) == STR)
11e = player:eval_cmd_string(object)[1..2];
12object = (e[1] && (typeof(e[2]) == OBJ)) ? e[2] | $nothing;
13endif
14`object:(args[2])(@args[3]) ! E_VERBNF => "object must be garbage now"';
15endif
16else
17return $error:raise(E_PERM);
18endif

kill @unsched*ule

Spec any none noneFlags rxdOwner #2Definer #99

Referenced by

none

Source

1"kill [task_id]";
2"Unceremoniously kills the specified task. Wizards may also \"@unsched *\" (kill all tasks), or \"@unsched garbage\" (kill all tasks on recycled objects).";
3if (!this:usable_by(player))
4player:tell("Permission denied.");
5return;
6endif
7n = length(dobjstr);
8if (!n)
9player:tell("You must supply a task id to kill.");
10return;
11endif
12if ((dobjstr == "*") && player.wizard)
13if ($command_utils:yes_or_no("Kill all tasks?"))
14dobjstr = "&%&";
15n = 0;
16else
17player:tell("Kill aborted.");
18return;
19endif
20elseif (dobjstr == "*")
21player:tell("Only administrators may kill all tasks.");
22return;
23elseif ((dobjstr == "garbage") && player.wizard)
24ids = {};
25for task in (this.tasks)
26id = task[2];
27if ((parent(task[3][3]) == $garbage) || (!valid(task[3][3])))
28ids = listappend(ids, id);
29endif
30endfor
31killed = this:kill_tasks(ids);
32return player:tell("Killed ", tostr(killed), " task", (killed == 1) ? "." | "s.");
33endif
34ids = {};
35for task in (this.tasks)
36id = task[2];
37if ((dobjstr in {tostr(id), "&%&"}) && $perm_utils:controls(player, task[3][7]))
38ids = listappend(ids, id);
39endif
40endfor
41killed = this:kill_tasks(ids);
42player:tell("Killed ", tostr(killed), " task", (killed == 1) ? "." | "s.");

stop_start

Spec this none thisFlags rxdOwner #2Definer #99

Referenced by

Source

1"  :stop_start([seconds])  =>  Kill the old :atrun verb, and restart at the new time";
2"   Optional arg for length of time until restart. Defaults to 0 seconds.";
3if ((caller != this) && (!caller_perms().wizard))
4return E_PERM;
5endif
6`kill_task(this.task) ! E_INVARG';
7this.clearing = 1;
8delay = 0;
9if (args)
10delay = toint(args[1]);
11endif
12fork (delay)
13this.clearing = 0;
14this:atrun();
15endfork

atrun

Spec this none thisFlags rxdOwner #2Definer #99

Referenced by

Source

1"The guts of the scheduler.  Handles jobs.";
2if ((caller != this) && (!caller_perms().wizard))
3return E_PERM;
4elseif (this.clearing)
5return "wait a few seconds for multiple atruns to clear. See this:stop_start.";
6elseif ((this.task != task_id()) && (this.task in $list_utils:slice(queued_tasks())))
7kill_task(this.task);
8endif
9this.task = task_id();
10this.lock = time = time();
11for task in (this:job_batch(time))
12info = task[3];
13fork (0)
14this:do(@info[3..7]);
15endfork
16if ((freq = info[1]) > 1)
17freq = freq - 1;
18endif
19if (freq != 1)
20info[8][4] = time = time();
21this:insert((time + info[2]) - ((time - info[8][1]) % info[2]), task[2], info);
22endif
23endfor
24this.lock = (this.tasks && (time() < (this.lock + this.lock_timeout))) ? this.tasks[1][1] | 0;
25if (this.lock)
26fork task (max(0, this.lock - time()))
27this:atrun();
28endfork
29this.task = task;
30else
31this.task = 0;
32endif

look_self

Spec this none thisFlags rxdOwner #2Definer #99

Referenced by

none

Source

1if (!this:usable_by(player))
2return 0;
3endif
4tasks = this.tasks;
5if (tasks)
6su = $string_utils;
7player:tell("Job ID      Start Time            Player         Verb (* = forever)");
8player:tell(su:space(79, "-"));
9for task in (tasks)
10if ($perm_utils:controls(player, task[3][7]) || $perm_utils:controls(player, task[3][6]))
11temp = su:left(tostr(task[2]), 12, " ");
12temp = (temp + ctime(task[1])[5..24]) + "  ";
13temp = temp + su:left(task[3][6].name, 14, " ");
14if (task[3][1] < 1)
15temp = temp + "* ";
16endif
17temp = ((temp + tostr(task[3][3])) + ":") + task[3][4];
18temp = temp + su:print(task[3][5]);
19player:tell(temp);
20endif
21endfor
22player:tell(su:space(79, "-"));
23else
24player:tell("No jobs scheduled on ", this.name, ".");
25endif

get_task_display

Spec this none thisFlags rxdOwner #2Definer #99

Referenced by

Source

1":get_task_display()";
2"==> returns the output to be displayed by $scheduler:@sched.";
3"Written by Firesong (#337)@Weyrmount";
4su = $string_utils;
5running = this:is_running();
6line = su:space(79, "-");
7header = {line};
8header = {@header, "  Scheduler status       : " + tostr(running ? "The scheduler is currently running." | "The scheduler seems to have been stopped.")};
9header = {@header, "  Current system time    : " + tostr(ctime())};
10header = {@header, "  Tasks waiting in queue : " + tostr(length(this.tasks))};
11string = su:space(max(5, 79 - length(string = "Task running in.."))) + string;
12header = {@header, string};
13header = {@header, line};
14retval = {};
15for task in ($scheduler.tasks)
16if ($perm_utils:controls(player, task[3][7]) || $perm_utils:controls(player, task[3][6]))
17next_fire = task[1];
18task_id = task[2];
19interations = task[3][1];
20interval = task[3][2];
21object = task[3][3];
22verb = task[3][4];
23vargs = task[3][5];
24owner = task[3][6];
25task_started = task[3][8][1];
26perms = task[3][8][3];
27last_fired = task[3][8][4];
28"...";
29varg_str = (varg_str = su:print(vargs))[2..length(varg_str) - 1];
30time_str = $time_utils:english_time(next_fire - time());
31line1 = ((((("Verb  : " + tostr(object)) + ":") + tostr(verb)) + "(") + varg_str) + ")";
32spaces = max(5, 79 - (length(line1) + length(time_str)));
33line1 = (line1 + su:space(spaces)) + time_str;
34perm_str = "Perms : " + tostr((perms == $no_one) ? "$NO_ONE" | su:nn(perms));
35task_str = "Task ID : " + tostr(task_id);
36spaces = max(1, 50 - length(perm_str));
37line2 = (perm_str + su:space(spaces)) + task_str;
38owner_str = "Player: " + su:nn(owner);
39spaces = max(1, 50 - length(owner_str));
40line3 = (owner_str + su:space(spaces)) + (interval ? ("Interval: " + tostr(interval)) + " seconds" | "Interval: Will not run again");
41retval = {@retval, line1, line2, line3, line};
42((ticks_left() < 4000) || (seconds_left() < 2)) && suspend(5);
43endif
44endfor
45return {header, retval};

@sched*uler

Spec none none noneFlags rxdOwner #2Definer #99

Referenced by

none

Source

1":@sched*uler()   <-- A Feature Verb to diplay an alternate task list on the scheduler.";
2"";
3"Sample output:";
4"";
5"[SCHEDULER] Browse Mode";
6"";
7"The Scheduler is currently ticking away";
8"  Tasks waiting in queue : 31";
9"  Current system time    : Tue Apr  9 18:38:09 1996 HDT";
10"";
11"                                                                   Running in..";
12"-------------------------------------------------------------------------------";
13"Verb  : #280:DO_check_kids()                                          8 seconds";
14"Perms : Firesong (#337)                           Task ID : 1300241341";
15"Player: Firesong (#337)                           Interval: 60 seconds";
16"-------------------------------------------------------------------------------";
17"Done..";
18"";
19"Written by Firesong (#337)@Weyrmount";
20info = this:get_task_display();
21"...Display header info...";
22player:tell_lines(info[1]);
23"...Display task info...";
24if (info[2])
25for line in (info[2])
26player:tell(line);
27((ticks_left() < 4000) || (seconds_left() < 2)) && suspend(5);
28endfor
29player:tell("Done..");
30elseif (player.wizard)
31player:tell("There are no tasks running on the scheduler.");
32else
33player:tell("You don't have any tasks running on the scheduler.");
34endif

is_running

Spec this none thisFlags rxdOwner #2Definer #99

Referenced by

Source

1":is_running()   <-- Called by :get_task_display";
2"Returns:";
3"  --> 0 The scheduler is not running (no valid task)";
4"  --> 1 The scheduler's master firing task is currently running";
5cu = $code_utils;
6running = cu:task_valid(this.task);
7return running;

@reset

Spec this any anyFlags rdOwner #2Definer #99

Referenced by

none

Source

1"@reset <scheduler> [in <seconds>] => stops scheduler, the restarts it in so many seconds. Default is 5 seconds.";
2if (!player.wizard)
3player:tell("Permission denied.  Contact an administrator.");
4return;
5endif
6delay = 5;
7if (iobjstr)
8delay = toint(iobjstr);
9endif
10player:tell("Resetting in ", delay, " seconds.");
11for task in (queued_tasks())
12if (task[7] == "atrun")
13kill_task(task[1]);
14endif
15endfor
16this:stop_start(delay);
17fork (delay)
18player:tell("Done.");
19endfork

schedule schedule_at schedule_every

Spec this none thisFlags rxdOwner #2Definer #99

Referenced by

Source

1"  :schedule(interval,object,\"verb\"[,{[arguments]}[,player[,perms]])]";
2"  :schedule_at(time,object,\"verb\"[,{[arguments]}[,player[,perms]])]";
3"  :schedule_every(interval,object,\"verb\"[,{[arguments]}[,player[,perms]])]";
4"Schedules an event guarenteed to occur sometime after the interval has expired.  Returns a psuedo task id suitable for :kill_task() if successful, error otherwise.  Remember, the scheduler will try to adjust for drift.";
5"Example:  (at the end of a verb) fork (300) this:(verb)(x,y,z); endfork";
6"Becomes:  (outside the verb, probably from eval) :schedule_every(300,this,verb,{x,y,z})";
7if (!this:usable_by(caller_perms()))
8return E_PERM;
9elseif ((len = length(args)) < 3)
10return E_ARGS;
11elseif ((verb == "schedule_at") && (time() > args[1]))
12return E_INVARG;
13endif
14vargs = (len > 3) ? (typeof(args[4]) == LIST) ? args[4] | {args[4]} | {};
15if ((len > 4) && caller_perms().wizard)
16pl = args[5];
17perm = {@args, cp = caller_perms()}[6];
18else
19pl = player;
20perm = cp = caller_perms();
21endif
22tid = this:assign();
23time = (verb == "schedule_at") ? args[1] | (time() + args[1]);
24iters = (verb == "schedule_every") ? 0 | 1;
25INT = (verb == "schedule_every") ? args[1] | 0;
26this:insert(time, tid, {iters, INT, @args[2..3], vargs, pl, perm, {time(), caller, cp, 0}});
27return tid;

do_checkpoint

Spec this none thisFlags rxdOwner #2Definer #99

Referenced by

none

Source

1"Only use this if your server doesn't do automatic checkpoints";
2if ((!caller_perms().wizard) || (!player.wizard))
3raise(E_PERM);
4else
5if (this:valid_task(this.dump_task))
6this:kill_task(this.dump_task);
7endif
8this.dump_task = this:schedule(this.dump_interval, this, "do_checkpoint");
9this.checkpoint_times = (length(this.checkpoint_times) > 10) ? {@this.checkpoint_times[2..$], time()} | {@this.checkpoint_times, time()};
10starttime = time();
11for p in (connected_players())
12if (p.wizard)
13p:notify(("*** Checkpoint started " + ctime()) + ".");
14endif
15endfor
16dump_database();
17checks = 120;
18size = db_disk_size();
19try
20while (`db_disk_size() == size ! ANY => 1' && (checks > 1))
21checks = checks - 1;
22suspend(1);
23endwhile
24except v (ANY)
25"no biggie.";
26endtry
27try
28"This is a doublecheck that makes sure the db size has stabilized. If the first check was correct, only adds 2 seconds to the task.";
29size = db_disk_size();
30suspend(2);
31while (db_disk_size() != size)
32suspend(2);
33size = db_disk_size();
34endwhile
35except v (ANY)
36"no biggie.";
37endtry
38endtime = time() - starttime;
39for p in (connected_players())
40if (p.wizard)
41p:notify(((("*** Checkpoint finished " + ctime()) + ".  Elapsed time: ") + $time_utils:english_time(endtime)) + ".");
42endif
43endfor
44return this.checkpoint_sizes = (length(this.checkpoint_sizes) > 10) ? {@this.checkpoint_sizes[2..$], db_disk_size()} | {@this.checkpoint_sizes, db_disk_size()};
45endif

@list-ch*eckpoints

Spec none none noneFlags rxdOwner #2Definer #99

Referenced by

none

Source

1"Usage:  @list-checkpoints";
2"Lists the data saved for the last 10 checkpoints.";
3if (this.checkpoint_times)
4player:tell("     Time             Size");
5player:tell("  -----------       --------");
6for i in [1..length(this.checkpoint_times)]
7player:tell(ctime(this.checkpoint_times[i])[5..19], "   ", $string_utils:right($string_utils:group_number(this.checkpoint_sizes[i]), 11));
8endfor
9else
10player:tell("No checkpoint data.");
11endif