#include <kernel/kernel.h> #include <phantasmal/timed.h> #include <phantasmal/log.h> #include <phantasmal/lpc_names.h> #include <type.h> mapping* per_queue; mixed* per_call_out; /*********************************************************************** * TIMED handles call_outs on behalf of MUD mobiles and objects. * There is a small maximum total number of call_outs available, and * this uses them sparingly. TimeD also gives a heartbeat function * interface, which is more familiar to long-time LPC users. ***********************************************************************/ private mixed* delay_tab; /* Prototypes */ void upgraded(varargs int clone); private void priv_start_call_out(int how_often); private void priv_stop_call_out(int how_often); static void create(void) { upgraded(); } void upgraded(varargs int clone) { mixed *tmp_queue, *tmp_call_outs; int size, ctr; if(!SYSTEM() && !COMMON()) return; /* Allocate or reallocate the queue of periodic call_outs and the call_out numbers if necessary. */ if(!per_queue || sizeof(per_queue) != TIMED_HIGHEST) { tmp_queue = allocate(TIMED_HIGHEST); tmp_call_outs = allocate(TIMED_HIGHEST); if(per_queue && (sizeof(per_queue) < TIMED_HIGHEST)) { size = sizeof(per_queue); } else if(per_queue) { size = TIMED_HIGHEST; } else { size = 0; } for(ctr = 0; ctr < size; ctr++) { tmp_queue[ctr] = per_queue[ctr]; tmp_call_outs[ctr] = per_call_out[ctr]; } /* Initialize any extra slots as empty */ for(ctr = size; ctr < TIMED_HIGHEST; ctr++) { tmp_queue[ctr] = ([ ]); tmp_call_outs[ctr] = 0; } per_queue = tmp_queue; per_call_out = tmp_call_outs; } /* Hardcode a MUD minute to 20 real seconds right now, just to test. */ delay_tab = allocate(TIMED_HIGHEST); delay_tab[TIMED_HALF_MINUTE] = 30; delay_tab[TIMED_TEN_MINUTES] = 600; delay_tab[TIMED_ONE_HOUR] = 3600; delay_tab[TIMED_ONE_DAY] = 3600 * 24; } void set_heart_beat(int how_often, string funcname, mixed args...) { if(!SYSTEM() && !COMMON() && !GAME()) return; if((how_often >= TIMED_HIGHEST) || (how_often <= 0)) { error("Illegal value for how_often in TIMED::periodic_call_out!"); } if(per_queue[how_often][object_name(previous_object())]) { error("Already have a heart_beat registered for " + object_name(previous_object()) + "!\n" + "Unregister it first!"); } LOGD->write_syslog("Setting up periodic call_out in TIMED", LOG_VERBOSE); per_queue[how_often][object_name(previous_object())] = ({ funcname, args }); if(per_call_out[how_often] <= 0) { priv_start_call_out(how_often); } } private void stop_object_call_out(int how_often, string objname) { per_queue[how_often][objname] = nil; if(map_sizeof(per_queue[how_often]) == 0) { priv_stop_call_out(how_often); } } void stop_heart_beat(int how_often) { if(!SYSTEM() && !COMMON() && !GAME()) return; stop_object_call_out(how_often, object_name(previous_object())); } private void priv_start_call_out(int how_often) { if(per_call_out[how_often] > 0) { LOGD->write_syslog("Call_out #" + how_often + " is already started in TIMED::priv_start_call_out!", LOG_WARNING); return; } if(delay_tab[how_often] && delay_tab[how_often] > 0) { per_call_out[how_often] = call_out("__priv_co_hook", delay_tab[how_often], how_often); } else { LOGD->write_syslog("Trying to schedule zero-time callout!", LOG_ERR); } if(per_call_out[how_often] <= 0) { LOGD->write_syslog("Can't schedule call_out # " + how_often + " in TIMED::priv_start_call_out!", LOG_ERROR); per_call_out[how_often] = 0; } } private void priv_stop_call_out(int how_often) { int ret; if(per_call_out[how_often] <= 0) { LOGD->write_syslog("Call_out #" + how_often + " is already stopped in TIMED::priv_stop_call_out!", LOG_WARNING); return; } ret = remove_call_out(per_call_out[how_often]); if(ret < 0) { LOGD->write_syslog("Call_out #" + how_often + ", handle #" + per_call_out[how_often] + " doesn't exist in TIMED::priv_stop_call_out!", LOG_WARNING); } per_call_out[how_often] = 0; } void __priv_co_hook(int how_often) { int ctr; mixed *keys, *tmp; object call_obj; if(!KERNEL()) { error("TIMED::__priv_co_hook can be called only by KERNEL code!"); } /* Schedule the next call */ per_call_out[how_often] = 0; priv_start_call_out(how_often); keys = map_indices(per_queue[how_often]); for(ctr = 0; ctr < sizeof(keys); ctr++) { tmp = per_queue[how_often][keys[ctr]]; call_obj = find_object(keys[ctr]); if(call_obj) { call_other(call_obj, tmp[0], tmp[1]...); } else { LOGD->write_syslog("Can't find object " + keys[ctr] + " to call!", LOG_WARN); stop_object_call_out(how_often, keys[ctr]); } } }