2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
This module contains the base Script class that all
|
|
|
|
|
scripts are inheriting from.
|
|
|
|
|
|
2012-03-31 15:09:22 +02:00
|
|
|
It also defines a few common scripts.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
|
2012-03-31 15:09:22 +02:00
|
|
|
from time import time
|
2014-02-13 13:25:46 +01:00
|
|
|
from twisted.internet.defer import maybeDeferred, Deferred
|
2011-07-03 21:01:06 +00:00
|
|
|
from twisted.internet.task import LoopingCall
|
2012-04-28 00:37:36 +02:00
|
|
|
from django.conf import settings
|
2013-11-14 19:31:17 +01:00
|
|
|
from django.utils.translation import ugettext as _
|
2010-08-29 18:46:58 +00:00
|
|
|
from src.typeclasses.typeclass import TypeClass
|
|
|
|
|
from src.scripts.models import ScriptDB
|
2012-03-31 15:09:22 +02:00
|
|
|
from src.comms import channelhandler
|
2013-11-14 19:31:17 +01:00
|
|
|
from src.utils import logger
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2013-11-14 19:31:17 +01:00
|
|
|
__all__ = ["Script", "DoNothing", "CheckSessions",
|
|
|
|
|
"ValidateScripts", "ValidateChannelHandler"]
|
2012-04-28 00:37:36 +02:00
|
|
|
|
2013-02-10 11:52:31 +01:00
|
|
|
_SESSIONS = None
|
2013-11-14 19:31:17 +01:00
|
|
|
# attr-cache size in MB
|
|
|
|
|
_ATTRIBUTE_CACHE_MAXSIZE = settings.ATTRIBUTE_CACHE_MAXSIZE
|
|
|
|
|
|
2012-03-31 15:09:22 +02:00
|
|
|
|
2014-02-13 13:25:46 +01:00
|
|
|
def test():
|
|
|
|
|
print "Called: %s " % time()
|
|
|
|
|
|
|
|
|
|
class ExtendedLoopingCall(LoopingCall):
|
|
|
|
|
"""
|
|
|
|
|
LoopingCall that can start at a delay different
|
|
|
|
|
than self.interval.
|
|
|
|
|
"""
|
|
|
|
|
start_delay = None
|
|
|
|
|
|
|
|
|
|
def start(self, interval, now=True, start_delay=None):
|
|
|
|
|
"""
|
|
|
|
|
Start running function every interval seconds.
|
|
|
|
|
|
|
|
|
|
This overloads the LoopingCall default by offering
|
|
|
|
|
the start_delay keyword.
|
|
|
|
|
|
|
|
|
|
start_delay: The number of seconds before starting.
|
|
|
|
|
If None, wait interval seconds. Only
|
|
|
|
|
valid is now is False.
|
|
|
|
|
"""
|
|
|
|
|
assert not self.running, ("Tried to start an already running "
|
|
|
|
|
"LoopingCall.")
|
|
|
|
|
if interval < 0:
|
|
|
|
|
raise ValueError, "interval must be >= 0"
|
|
|
|
|
self.running = True
|
|
|
|
|
d = self.deferred = Deferred()
|
|
|
|
|
self.starttime = self.clock.seconds()
|
|
|
|
|
self._lastTime = self.starttime
|
|
|
|
|
self.interval = interval
|
|
|
|
|
if now:
|
|
|
|
|
self()
|
|
|
|
|
elif start_delay is not None and start_delay >= 0:
|
|
|
|
|
self.interval = start_delay
|
|
|
|
|
self._reschedule()
|
|
|
|
|
# this is set after the _reshedule call to make
|
|
|
|
|
# next_call find it until next reshedule.
|
|
|
|
|
self.start_delay = start_delay
|
|
|
|
|
self.interval = interval
|
|
|
|
|
else:
|
|
|
|
|
self._reschedule()
|
|
|
|
|
return d
|
|
|
|
|
|
|
|
|
|
def _reschedule(self):
|
|
|
|
|
"Handle delayed call so next_call get it right"
|
|
|
|
|
self.start_delay = None
|
|
|
|
|
super(ExtendedLoopingCall, self)._reschedule()
|
|
|
|
|
|
|
|
|
|
def reset(self, force_call=True):
|
|
|
|
|
"""
|
|
|
|
|
Reset the loop timer. The task must already be started.
|
|
|
|
|
|
|
|
|
|
force_call - trigger the callback function
|
|
|
|
|
"""
|
|
|
|
|
assert self.running, ("Tried to reset a LoopingCall that was "
|
|
|
|
|
"not running.")
|
|
|
|
|
if self.call is not None:
|
|
|
|
|
self.call.cancel()
|
|
|
|
|
if force_call:
|
|
|
|
|
self()
|
|
|
|
|
else:
|
|
|
|
|
self._reschedule()
|
|
|
|
|
|
|
|
|
|
def next_call_time(self):
|
|
|
|
|
"""
|
|
|
|
|
Return the time in seconds until the next call. This takes
|
|
|
|
|
start_delay into account.
|
|
|
|
|
"""
|
|
|
|
|
currentTime = self.clock.seconds()
|
|
|
|
|
if self.start_delay is not None:
|
|
|
|
|
# take start_delay into account
|
|
|
|
|
untilNextTime = (self._lastTime - currentTime) % self.start_delay
|
|
|
|
|
return max(self._lastTime + self.start_delay, currentTime + untilNextTime)
|
|
|
|
|
else:
|
|
|
|
|
untilNextTime = (self._lastTime - currentTime) % self.interval
|
|
|
|
|
return max(self._lastTime + self.interval, currentTime + untilNextTime)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
#
|
2012-03-31 15:09:22 +02:00
|
|
|
# Base script, inherit from Script below instead.
|
2010-08-29 18:46:58 +00:00
|
|
|
#
|
|
|
|
|
class ScriptClass(TypeClass):
|
|
|
|
|
"""
|
2013-11-14 19:31:17 +01:00
|
|
|
Base class for scripts. Don't inherit from this, inherit
|
|
|
|
|
from the class 'Script' instead.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2012-03-31 15:09:22 +02:00
|
|
|
# private methods
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
def __eq__(self, other):
|
|
|
|
|
"""
|
|
|
|
|
This has to be located at this level, having it in the
|
|
|
|
|
parent doesn't work.
|
|
|
|
|
"""
|
2011-07-03 21:01:06 +00:00
|
|
|
try:
|
2012-04-26 17:47:25 +02:00
|
|
|
return other.dbid == self.dbid
|
2011-07-03 21:01:06 +00:00
|
|
|
except Exception:
|
2012-03-31 15:09:22 +02:00
|
|
|
return False
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2011-09-03 10:22:19 +00:00
|
|
|
def _start_task(self, start_now=True):
|
2011-07-03 21:01:06 +00:00
|
|
|
"start task runner"
|
2011-09-03 10:22:19 +00:00
|
|
|
|
2011-07-03 21:01:06 +00:00
|
|
|
self.ndb.twisted_task = LoopingCall(self._step_task)
|
2011-09-03 10:22:19 +00:00
|
|
|
if self.ndb._paused_time:
|
|
|
|
|
# we had paused the script, restarting
|
|
|
|
|
#print " start with paused time:", self.key, self.ndb._paused_time
|
|
|
|
|
self.ndb.twisted_task.start(self.ndb._paused_time, now=False)
|
|
|
|
|
else:
|
2012-03-31 15:09:22 +02:00
|
|
|
# starting script anew.
|
2011-09-03 10:22:19 +00:00
|
|
|
#print "_start_task: self.interval:", self.key, self.dbobj.interval
|
2013-11-14 19:31:17 +01:00
|
|
|
self.ndb.twisted_task.start(self.dbobj.interval,
|
|
|
|
|
now=start_now and not self.start_delay)
|
2012-03-31 15:09:22 +02:00
|
|
|
self.ndb.time_last_called = int(time())
|
|
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def _stop_task(self):
|
2011-07-03 21:01:06 +00:00
|
|
|
"stop task runner"
|
|
|
|
|
try:
|
2011-08-11 21:16:35 +00:00
|
|
|
#print "stopping twisted task:", id(self.ndb.twisted_task), self.obj
|
2011-09-07 15:44:13 +00:00
|
|
|
if self.ndb.twisted_task and self.ndb.twisted_task.running:
|
2012-03-31 15:09:22 +02:00
|
|
|
self.ndb.twisted_task.stop()
|
2011-07-03 21:01:06 +00:00
|
|
|
except Exception:
|
2011-08-11 21:16:35 +00:00
|
|
|
logger.log_trace()
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2011-07-03 21:01:06 +00:00
|
|
|
def _step_err_callback(self, e):
|
|
|
|
|
"callback for runner errors"
|
|
|
|
|
cname = self.__class__.__name__
|
2012-06-14 02:43:35 +02:00
|
|
|
estring = _("Script %(key)s(#%(dbid)i) of type '%(cname)s': at_repeat() error '%(err)s'.") % \
|
2013-11-14 19:31:17 +01:00
|
|
|
{"key": self.key, "dbid": self.dbid, "cname": cname,
|
|
|
|
|
"err": e.getErrorMessage()}
|
2011-07-03 21:01:06 +00:00
|
|
|
try:
|
|
|
|
|
self.dbobj.db_obj.msg(estring)
|
|
|
|
|
except Exception:
|
|
|
|
|
pass
|
|
|
|
|
logger.log_errmsg(estring)
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2011-07-03 21:01:06 +00:00
|
|
|
def _step_succ_callback(self):
|
|
|
|
|
"step task runner. No try..except needed due to defer wrap."
|
2010-08-29 18:46:58 +00:00
|
|
|
if not self.is_valid():
|
|
|
|
|
self.stop()
|
2012-03-31 15:09:22 +02:00
|
|
|
return
|
2011-07-03 21:01:06 +00:00
|
|
|
self.at_repeat()
|
|
|
|
|
repeats = self.dbobj.db_repeats
|
|
|
|
|
if repeats <= 0:
|
2013-11-14 19:31:17 +01:00
|
|
|
pass # infinite repeat
|
2011-07-03 21:01:06 +00:00
|
|
|
elif repeats == 1:
|
|
|
|
|
self.stop()
|
2012-03-31 15:09:22 +02:00
|
|
|
return
|
2011-07-03 21:01:06 +00:00
|
|
|
else:
|
|
|
|
|
self.dbobj.db_repeats -= 1
|
|
|
|
|
self.ndb.time_last_called = int(time())
|
|
|
|
|
self.save()
|
2011-09-03 10:22:19 +00:00
|
|
|
|
|
|
|
|
if self.ndb._paused_time:
|
2013-11-14 19:31:17 +01:00
|
|
|
# this means we were running an unpaused script, for the
|
|
|
|
|
# time remaining after the pause. Now we start a normal-running
|
|
|
|
|
# timer again.
|
|
|
|
|
# print "switching to normal run:", self.key
|
2011-09-03 10:22:19 +00:00
|
|
|
del self.ndb._paused_time
|
|
|
|
|
self._stop_task()
|
|
|
|
|
self._start_task(start_now=False)
|
|
|
|
|
|
2011-07-03 21:01:06 +00:00
|
|
|
def _step_task(self):
|
|
|
|
|
"step task"
|
2012-03-31 15:09:22 +02:00
|
|
|
try:
|
2011-07-03 21:01:06 +00:00
|
|
|
d = maybeDeferred(self._step_succ_callback)
|
2012-03-31 15:09:22 +02:00
|
|
|
d.addErrback(self._step_err_callback)
|
2011-07-03 21:01:06 +00:00
|
|
|
return d
|
2010-08-29 18:46:58 +00:00
|
|
|
except Exception:
|
2012-03-31 15:09:22 +02:00
|
|
|
logger.log_trace()
|
|
|
|
|
|
|
|
|
|
# Public methods
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
def time_until_next_repeat(self):
|
|
|
|
|
"""
|
|
|
|
|
Returns the time in seconds until the script will be
|
2012-03-31 15:09:22 +02:00
|
|
|
run again. If this is not a stepping script, returns None.
|
2010-08-29 18:46:58 +00:00
|
|
|
This is not used in any way by the script's stepping
|
|
|
|
|
system; it's only here for the user to be able to
|
2012-03-31 15:09:22 +02:00
|
|
|
check in on their scripts and when they will next be run.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2011-07-03 21:01:06 +00:00
|
|
|
try:
|
2011-09-03 10:22:19 +00:00
|
|
|
if self.ndb._paused_time:
|
|
|
|
|
return max(0, (self.ndb.time_last_called + self.ndb._paused_time) - int(time()))
|
|
|
|
|
else:
|
|
|
|
|
return max(0, (self.ndb.time_last_called + self.dbobj.db_interval) - int(time()))
|
2011-07-03 21:01:06 +00:00
|
|
|
except Exception:
|
2012-03-31 15:09:22 +02:00
|
|
|
return None
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
def start(self, force_restart=False):
|
|
|
|
|
"""
|
|
|
|
|
Called every time the script is started (for
|
|
|
|
|
persistent scripts, this is usually once every server start)
|
|
|
|
|
|
|
|
|
|
force_restart - if True, will always restart the script, regardless
|
2012-03-31 15:09:22 +02:00
|
|
|
of if it has started before.
|
|
|
|
|
|
2013-11-14 19:31:17 +01:00
|
|
|
returns 0 or 1 to indicated the script has been started or not.
|
|
|
|
|
Used in counting.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
2012-03-31 15:09:22 +02:00
|
|
|
#print "Script %s (%s) start (active:%s, force:%s) ..." % (self.key, id(self.dbobj),
|
|
|
|
|
# self.is_active, force_restart)
|
2011-08-11 21:16:35 +00:00
|
|
|
|
|
|
|
|
if self.dbobj.is_active and not force_restart:
|
|
|
|
|
# script already runs and should not be restarted.
|
2012-03-31 15:09:22 +02:00
|
|
|
return 0
|
2011-08-11 21:16:35 +00:00
|
|
|
|
|
|
|
|
obj = self.obj
|
2012-03-31 15:09:22 +02:00
|
|
|
if obj:
|
|
|
|
|
# check so the scripted object is valid and initalized
|
2010-08-29 18:46:58 +00:00
|
|
|
try:
|
2013-11-28 14:11:18 +01:00
|
|
|
object.__getattribute__(obj.dbobj, 'cmdset')
|
2010-08-29 18:46:58 +00:00
|
|
|
except AttributeError:
|
2011-07-03 21:01:06 +00:00
|
|
|
# this means the object is not initialized.
|
2013-11-28 14:11:18 +01:00
|
|
|
logger.log_trace()
|
2011-08-11 21:16:35 +00:00
|
|
|
self.dbobj.is_active = False
|
2012-03-31 15:09:22 +02:00
|
|
|
return 0
|
2011-09-03 10:22:19 +00:00
|
|
|
|
2012-03-31 15:09:22 +02:00
|
|
|
# try to restart a paused script
|
2011-09-03 10:22:19 +00:00
|
|
|
if self.unpause():
|
|
|
|
|
return 1
|
|
|
|
|
|
2012-03-31 15:09:22 +02:00
|
|
|
# try to start the script from scratch
|
|
|
|
|
try:
|
2011-08-11 21:16:35 +00:00
|
|
|
self.dbobj.is_active = True
|
2011-07-03 21:01:06 +00:00
|
|
|
self.at_start()
|
|
|
|
|
if self.dbobj.db_interval > 0:
|
2010-08-29 18:46:58 +00:00
|
|
|
self._start_task()
|
2011-07-03 21:01:06 +00:00
|
|
|
return 1
|
|
|
|
|
except Exception:
|
|
|
|
|
logger.log_trace()
|
2012-03-31 15:09:22 +02:00
|
|
|
self.dbobj.is_active = False
|
2011-07-03 21:01:06 +00:00
|
|
|
return 0
|
|
|
|
|
|
2011-06-26 14:35:02 +00:00
|
|
|
def stop(self, kill=False):
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
Called to stop the script from running.
|
2012-03-31 15:09:22 +02:00
|
|
|
This also deletes the script.
|
2011-06-26 14:35:02 +00:00
|
|
|
|
2012-03-31 15:09:22 +02:00
|
|
|
kill - don't call finishing hooks.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
#print "stopping script %s" % self.key
|
2011-08-11 21:16:35 +00:00
|
|
|
#import pdb
|
|
|
|
|
#pdb.set_trace()
|
2011-06-26 14:35:02 +00:00
|
|
|
if not kill:
|
|
|
|
|
try:
|
|
|
|
|
self.at_stop()
|
|
|
|
|
except Exception:
|
|
|
|
|
logger.log_trace()
|
2011-07-03 21:01:06 +00:00
|
|
|
if self.dbobj.db_interval > 0:
|
2010-08-29 18:46:58 +00:00
|
|
|
try:
|
|
|
|
|
self._stop_task()
|
2012-04-28 00:37:36 +02:00
|
|
|
except Exception:
|
2012-04-26 17:47:25 +02:00
|
|
|
logger.log_trace("Stopping script %s(%s)" % (self.key, self.dbid))
|
2010-08-29 18:46:58 +00:00
|
|
|
pass
|
|
|
|
|
try:
|
2011-07-03 21:01:06 +00:00
|
|
|
self.dbobj.delete()
|
2010-08-29 18:46:58 +00:00
|
|
|
except AssertionError:
|
2011-08-11 21:16:35 +00:00
|
|
|
logger.log_trace()
|
2011-03-20 19:45:56 +00:00
|
|
|
return 0
|
|
|
|
|
return 1
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2011-09-03 10:22:19 +00:00
|
|
|
def pause(self):
|
|
|
|
|
"""
|
|
|
|
|
This stops a running script and stores its active state.
|
|
|
|
|
"""
|
|
|
|
|
#print "pausing", self.key, self.time_until_next_repeat()
|
|
|
|
|
dt = self.time_until_next_repeat()
|
2013-11-14 19:31:17 +01:00
|
|
|
if dt is None:
|
2012-03-31 15:09:22 +02:00
|
|
|
return
|
|
|
|
|
self.db._paused_time = dt
|
2011-09-03 10:22:19 +00:00
|
|
|
self._stop_task()
|
2012-03-31 15:09:22 +02:00
|
|
|
|
2011-09-03 10:22:19 +00:00
|
|
|
def unpause(self):
|
|
|
|
|
"""
|
2012-03-31 15:09:22 +02:00
|
|
|
Restart a paused script. This WILL call at_start().
|
2011-09-03 10:22:19 +00:00
|
|
|
"""
|
|
|
|
|
#print "unpausing", self.key, self.db._paused_time
|
2012-03-31 15:09:22 +02:00
|
|
|
dt = self.db._paused_time
|
2013-11-14 19:31:17 +01:00
|
|
|
if dt is None:
|
2011-09-03 10:22:19 +00:00
|
|
|
return False
|
|
|
|
|
try:
|
|
|
|
|
self.dbobj.is_active = True
|
|
|
|
|
self.at_start()
|
2012-03-31 15:09:22 +02:00
|
|
|
self.ndb._paused_time = dt
|
2011-09-03 10:22:19 +00:00
|
|
|
self._start_task(start_now=False)
|
|
|
|
|
del self.db._paused_time
|
2012-04-28 00:37:36 +02:00
|
|
|
except Exception:
|
2011-09-03 10:22:19 +00:00
|
|
|
logger.log_trace()
|
|
|
|
|
self.dbobj.is_active = False
|
|
|
|
|
return False
|
2012-03-31 15:09:22 +02:00
|
|
|
return True
|
2011-09-03 10:22:19 +00:00
|
|
|
|
2011-07-03 21:01:06 +00:00
|
|
|
# hooks
|
|
|
|
|
def at_script_creation(self):
|
|
|
|
|
"placeholder"
|
|
|
|
|
pass
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def is_valid(self):
|
|
|
|
|
"placeholder"
|
|
|
|
|
pass
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def at_start(self):
|
|
|
|
|
"placeholder."
|
2012-03-31 15:09:22 +02:00
|
|
|
pass
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def at_stop(self):
|
|
|
|
|
"placeholder"
|
|
|
|
|
pass
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def at_repeat(self):
|
|
|
|
|
"placeholder"
|
|
|
|
|
pass
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2011-10-01 22:36:55 +02:00
|
|
|
def at_init(self):
|
|
|
|
|
"called when typeclass re-caches. Usually not used for scripts."
|
|
|
|
|
pass
|
2012-03-31 15:09:22 +02:00
|
|
|
|
2011-07-03 21:01:06 +00:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
#
|
|
|
|
|
# Base Script - inherit from this
|
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
class Script(ScriptClass):
|
|
|
|
|
"""
|
|
|
|
|
This is the class you should inherit from, it implements
|
|
|
|
|
the hooks called by the script machinery.
|
|
|
|
|
"""
|
|
|
|
|
|
2012-03-24 23:02:45 +01:00
|
|
|
def __init__(self, dbobj):
|
|
|
|
|
"""
|
2013-11-14 19:31:17 +01:00
|
|
|
This is the base TypeClass for all Scripts. Scripts describe events,
|
|
|
|
|
timers and states in game, they can have a time component or describe
|
|
|
|
|
a state that changes under certain conditions.
|
2012-03-24 23:02:45 +01:00
|
|
|
|
|
|
|
|
Script API:
|
|
|
|
|
|
|
|
|
|
* Available properties (only available on initiated Typeclass objects)
|
|
|
|
|
|
2012-03-31 15:09:22 +02:00
|
|
|
key (string) - name of object
|
2012-03-24 23:02:45 +01:00
|
|
|
name (string)- same as key
|
2013-11-14 19:31:17 +01:00
|
|
|
aliases (list of strings) - aliases to the object. Will be saved to
|
|
|
|
|
database as AliasDB entries but returned as strings.
|
2012-03-24 23:02:45 +01:00
|
|
|
dbref (int, read-only) - unique #id-number. Also "id" can be used.
|
2013-11-14 19:31:17 +01:00
|
|
|
dbobj (Object, read-only) - link to database model. dbobj.typeclass
|
|
|
|
|
points back to this class
|
|
|
|
|
typeclass (Object, read-only) - this links back to this class as an
|
|
|
|
|
identified only. Use self.swap_typeclass() to switch.
|
2012-03-24 23:02:45 +01:00
|
|
|
date_created (string) - time stamp of object creation
|
2012-03-31 15:09:22 +02:00
|
|
|
permissions (list of strings) - list of permission strings
|
2012-03-24 23:02:45 +01:00
|
|
|
|
|
|
|
|
desc (string) - optional description of script, shown in listings
|
2013-11-14 19:31:17 +01:00
|
|
|
obj (Object) - optional object that this script is connected to
|
|
|
|
|
and acts on (set automatically
|
|
|
|
|
by obj.scripts.add())
|
|
|
|
|
interval (int) - how often script should run, in seconds.
|
|
|
|
|
<=0 turns off ticker
|
|
|
|
|
start_delay (bool) - if the script should start repeating right
|
|
|
|
|
away or wait self.interval seconds
|
|
|
|
|
repeats (int) - how many times the script should repeat before
|
|
|
|
|
stopping. <=0 means infinite repeats
|
2012-03-24 23:02:45 +01:00
|
|
|
persistent (bool) - if script should survive a server shutdown or not
|
2012-03-31 15:09:22 +02:00
|
|
|
is_active (bool) - if script is currently running
|
2012-03-24 23:02:45 +01:00
|
|
|
|
|
|
|
|
* Handlers
|
|
|
|
|
|
|
|
|
|
locks - lock-handler: use locks.add() to add new lock strings
|
2013-11-14 19:31:17 +01:00
|
|
|
db - attribute-handler: store/retrieve database attributes on this
|
|
|
|
|
self.db.myattr=val, val=self.db.myattr
|
|
|
|
|
ndb - non-persistent attribute handler: same as db but does not
|
|
|
|
|
create a database entry when storing data
|
2012-03-24 23:02:45 +01:00
|
|
|
|
2012-03-31 15:09:22 +02:00
|
|
|
* Helper methods
|
2012-03-24 23:02:45 +01:00
|
|
|
|
2013-11-14 19:31:17 +01:00
|
|
|
start() - start script (this usually happens automatically at creation
|
|
|
|
|
and obj.script.add() etc)
|
2012-03-24 23:02:45 +01:00
|
|
|
stop() - stop script, and delete it
|
2013-11-14 19:31:17 +01:00
|
|
|
pause() - put the script on hold, until unpause() is called. If script
|
|
|
|
|
is persistent, the pause state will survive a shutdown.
|
|
|
|
|
unpause() - restart a previously paused script. The script will
|
|
|
|
|
continue as if it was never paused.
|
|
|
|
|
time_until_next_repeat() - if a timed script (interval>0), returns
|
|
|
|
|
time until next tick
|
2012-03-24 23:02:45 +01:00
|
|
|
|
2012-03-31 15:09:22 +02:00
|
|
|
* Hook methods
|
2012-03-24 23:02:45 +01:00
|
|
|
|
|
|
|
|
at_script_creation() - called only once, when an object of this
|
|
|
|
|
class is first created.
|
|
|
|
|
is_valid() - is called to check if the script is valid to be running
|
2013-11-14 19:31:17 +01:00
|
|
|
at the current time. If is_valid() returns False, the
|
|
|
|
|
running script is stopped and removed from the game. You
|
|
|
|
|
can use this to check state changes (i.e. an script
|
|
|
|
|
tracking some combat stats at regular intervals is only
|
|
|
|
|
valid to run while there is actual combat going on).
|
|
|
|
|
at_start() - Called every time the script is started, which for
|
|
|
|
|
persistent scripts is at least once every server start.
|
|
|
|
|
Note that this is unaffected by self.delay_start, which
|
|
|
|
|
only delays the first call to at_repeat().
|
|
|
|
|
at_repeat() - Called every self.interval seconds. It will be called
|
|
|
|
|
immediately upon launch unless self.delay_start is True,
|
|
|
|
|
which will delay the first call of this method by
|
|
|
|
|
self.interval seconds. If self.interval<=0, this method
|
|
|
|
|
will never be called.
|
|
|
|
|
at_stop() - Called as the script object is stopped and is about to
|
|
|
|
|
be removed from the game, e.g. because is_valid()
|
|
|
|
|
returned False or self.stop() was called manually.
|
|
|
|
|
at_server_reload() - Called when server reloads. Can be used to save
|
|
|
|
|
temporary variables you want should survive a reload.
|
2012-03-31 15:09:22 +02:00
|
|
|
at_server_shutdown() - called at a full server shutdown.
|
2012-03-24 23:02:45 +01:00
|
|
|
|
2012-03-31 15:09:22 +02:00
|
|
|
|
|
|
|
|
"""
|
2012-03-24 23:02:45 +01:00
|
|
|
super(Script, self).__init__(dbobj)
|
2012-03-24 18:25:32 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def at_script_creation(self):
|
|
|
|
|
"""
|
|
|
|
|
Only called once, by the create function.
|
|
|
|
|
"""
|
2012-03-31 15:09:22 +02:00
|
|
|
self.key = "<unnamed>"
|
2010-08-29 18:46:58 +00:00
|
|
|
self.desc = ""
|
2013-11-14 19:31:17 +01:00
|
|
|
self.interval = 0 # infinite
|
2010-08-29 18:46:58 +00:00
|
|
|
self.start_delay = False
|
2011-07-03 21:01:06 +00:00
|
|
|
self.repeats = 0 # infinite
|
2012-03-31 15:09:22 +02:00
|
|
|
self.persistent = False
|
|
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def is_valid(self):
|
|
|
|
|
"""
|
2012-03-31 15:09:22 +02:00
|
|
|
Is called to check if the script is valid to run at this time.
|
2010-08-29 18:46:58 +00:00
|
|
|
Should return a boolean. The method is assumed to collect all needed
|
|
|
|
|
information from its related self.obj.
|
|
|
|
|
"""
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
def at_start(self):
|
|
|
|
|
"""
|
|
|
|
|
Called whenever the script is started, which for persistent
|
2012-03-31 15:09:22 +02:00
|
|
|
scripts is at least once every server start. It will also be called
|
2011-09-03 10:22:19 +00:00
|
|
|
when starting again after a pause (such as after a server reload)
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def at_repeat(self):
|
|
|
|
|
"""
|
|
|
|
|
Called repeatedly if this Script is set to repeat
|
2012-03-31 15:09:22 +02:00
|
|
|
regularly.
|
2010-08-29 18:46:58 +00:00
|
|
|
"""
|
|
|
|
|
pass
|
2012-03-31 15:09:22 +02:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def at_stop(self):
|
|
|
|
|
"""
|
|
|
|
|
Called whenever when it's time for this script to stop
|
|
|
|
|
(either because is_valid returned False or )
|
|
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
2011-09-03 10:22:19 +00:00
|
|
|
def at_server_reload(self):
|
|
|
|
|
"""
|
2013-11-14 19:31:17 +01:00
|
|
|
This hook is called whenever the server is shutting down for
|
|
|
|
|
restart/reboot. If you want to, for example, save non-persistent
|
|
|
|
|
properties across a restart, this is the place to do it.
|
2011-09-03 10:22:19 +00:00
|
|
|
"""
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
def at_server_shutdown(self):
|
|
|
|
|
"""
|
2013-11-14 19:31:17 +01:00
|
|
|
This hook is called whenever the server is shutting down fully
|
|
|
|
|
(i.e. not for a restart).
|
2011-09-03 10:22:19 +00:00
|
|
|
"""
|
|
|
|
|
pass
|
2011-07-03 21:01:06 +00:00
|
|
|
|
|
|
|
|
|
2012-03-31 15:09:22 +02:00
|
|
|
# Some useful default Script types used by Evennia.
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
class DoNothing(Script):
|
2012-03-31 15:09:22 +02:00
|
|
|
"An script that does nothing. Used as default fallback."
|
|
|
|
|
def at_script_creation(self):
|
2013-11-14 19:31:17 +01:00
|
|
|
"Setup the script"
|
|
|
|
|
self.key = "sys_do_nothing"
|
|
|
|
|
self.desc = _("This is an empty placeholder script.")
|
|
|
|
|
|
2012-03-31 15:09:22 +02:00
|
|
|
|
2013-01-03 09:18:49 +01:00
|
|
|
class Store(Script):
|
|
|
|
|
"Simple storage script"
|
|
|
|
|
def at_script_creation(self):
|
|
|
|
|
"Setup the script"
|
|
|
|
|
self.key = "sys_storage"
|
|
|
|
|
self.desc = _("This is a generic storage container.")
|
|
|
|
|
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
class CheckSessions(Script):
|
|
|
|
|
"Check sessions regularly."
|
|
|
|
|
def at_script_creation(self):
|
|
|
|
|
"Setup the script"
|
|
|
|
|
self.key = "sys_session_check"
|
2012-06-14 02:43:35 +02:00
|
|
|
self.desc = _("Checks sessions so they are live.")
|
2012-03-31 15:09:22 +02:00
|
|
|
self.interval = 60 # repeat every 60 seconds
|
|
|
|
|
self.persistent = True
|
2010-08-29 18:46:58 +00:00
|
|
|
|
|
|
|
|
def at_repeat(self):
|
|
|
|
|
"called every 60 seconds"
|
2013-02-10 11:52:31 +01:00
|
|
|
global _SESSIONS
|
|
|
|
|
if not _SESSIONS:
|
|
|
|
|
from src.server.sessionhandler import SESSIONS as _SESSIONS
|
2010-08-29 18:46:58 +00:00
|
|
|
#print "session check!"
|
2010-09-19 06:57:08 +00:00
|
|
|
#print "ValidateSessions run"
|
2013-02-10 11:52:31 +01:00
|
|
|
_SESSIONS.validate_sessions()
|
2010-08-29 18:46:58 +00:00
|
|
|
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
class ValidateScripts(Script):
|
2012-03-31 15:09:22 +02:00
|
|
|
"Check script validation regularly"
|
2010-08-29 18:46:58 +00:00
|
|
|
def at_script_creation(self):
|
|
|
|
|
"Setup the script"
|
|
|
|
|
self.key = "sys_scripts_validate"
|
2012-06-14 02:43:35 +02:00
|
|
|
self.desc = _("Validates all scripts regularly.")
|
2013-11-14 19:31:17 +01:00
|
|
|
self.interval = 3600 # validate every hour.
|
2010-08-29 18:46:58 +00:00
|
|
|
self.persistent = True
|
|
|
|
|
|
|
|
|
|
def at_repeat(self):
|
2012-03-31 15:09:22 +02:00
|
|
|
"called every hour"
|
2010-10-31 08:10:02 +00:00
|
|
|
#print "ValidateScripts run."
|
2010-08-29 18:46:58 +00:00
|
|
|
ScriptDB.objects.validate()
|
|
|
|
|
|
2013-11-14 19:31:17 +01:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
class ValidateChannelHandler(Script):
|
2012-03-31 15:09:22 +02:00
|
|
|
"Update the channelhandler to make sure it's in sync."
|
2010-08-29 18:46:58 +00:00
|
|
|
def at_script_creation(self):
|
|
|
|
|
"Setup the script"
|
|
|
|
|
self.key = "sys_channels_validate"
|
2012-06-14 02:43:35 +02:00
|
|
|
self.desc = _("Updates the channel handler")
|
2013-11-14 19:31:17 +01:00
|
|
|
self.interval = 3700 # validate a little later than ValidateScripts
|
2010-08-29 18:46:58 +00:00
|
|
|
self.persistent = True
|
2012-03-31 15:09:22 +02:00
|
|
|
|
2010-08-29 18:46:58 +00:00
|
|
|
def at_repeat(self):
|
|
|
|
|
"called every hour+"
|
2010-10-31 08:10:02 +00:00
|
|
|
#print "ValidateChannelHandler run."
|
2010-08-29 18:46:58 +00:00
|
|
|
channelhandler.CHANNELHANDLER.update()
|
2012-03-31 15:09:22 +02:00
|
|
|
|
2013-10-21 21:17:32 +02:00
|
|
|
#class ClearAttributeCache(Script):
|
|
|
|
|
# "Clear the attribute cache."
|
|
|
|
|
# def at_script_creation(self):
|
|
|
|
|
# "Setup the script"
|
|
|
|
|
# self.key = "sys_cache_clear"
|
|
|
|
|
# self.desc = _("Clears the Attribute Cache")
|
|
|
|
|
# self.interval = 3600 * 2
|
|
|
|
|
# self.persistent = True
|
|
|
|
|
# def at_repeat(self):
|
|
|
|
|
# "called every 2 hours. Sets a max attr-cache limit to 100 MB." # enough for normal usage?
|
|
|
|
|
# if is_pypy:
|
|
|
|
|
# # pypy don't support get_size, so we have to skip out here.
|
|
|
|
|
# return
|
|
|
|
|
# attr_cache_size, _, _ = caches.get_cache_sizes()
|
|
|
|
|
# if attr_cache_size > _ATTRIBUTE_CACHE_MAXSIZE:
|
|
|
|
|
# caches.flush_attr_cache()
|