diff --git a/evennia/__init__.py b/evennia/__init__.py index 080114f7a0..139cda5e25 100644 --- a/evennia/__init__.py +++ b/evennia/__init__.py @@ -109,6 +109,7 @@ TASK_HANDLER = None TICKER_HANDLER = None MONITOR_HANDLER = None CHANNEL_HANDLER = None +GLOBAL_SCRIPTS = None def _create_version(): @@ -152,7 +153,7 @@ def _init(): global search_object, search_script, search_account, search_channel, search_help, search_tag, search_message global create_object, create_script, create_account, create_channel, create_message, create_help_entry global settings, lockfuncs, logger, utils, gametime, ansi, spawn, managers - global contrib, TICKER_HANDLER, MONITOR_HANDLER, SESSION_HANDLER, CHANNEL_HANDLER, TASK_HANDLER + global contrib, TICKER_HANDLER, MONITOR_HANDLER, SESSION_HANDLER, CHANNEL_HANDLER, TASK_HANDLER, GLOBAL_SCRIPTS global EvMenu, EvTable, EvForm, EvMore, EvEditor global ANSIString @@ -213,6 +214,7 @@ def _init(): from .server.sessionhandler import SESSION_HANDLER from .comms.channelhandler import CHANNEL_HANDLER from .scripts.monitorhandler import MONITOR_HANDLER + from .scripts.globalhandler import GLOBAL_SCRIPTS # initialize the doc string global __doc__ diff --git a/evennia/scripts/globalhandler.py b/evennia/scripts/globalhandler.py new file mode 100644 index 0000000000..4cce262993 --- /dev/null +++ b/evennia/scripts/globalhandler.py @@ -0,0 +1,69 @@ +from django.conf import settings +from evennia.utils.utils import class_from_module + + +class GlobalContainer(object): + """ + Simple Handler object loaded by the Evennia API to contain and manage a game's Global Scripts. + + This is accessed like a dictionary. Alternatively you can access Properties on it. + + Example: + import evennia + evennia.GLOBAL_SCRIPTS['key'] + """ + + def __init__(self): + self.script_data = dict() + self.script_storage = dict() + self.script_data.update(settings.GLOBAL_SCRIPTS) + self.typeclass_storage = dict() + + for key, data in settings.GLOBAL_SCRIPTS.items(): + self.typeclass_storage[key] = class_from_module(data['typeclass']) + for key in self.script_data.keys(): + self._load_script(key) + + def __getitem__(self, item): + + # Likely to only reach this if someone called the API wrong. + if item not in self.typeclass_storage: + return None + + # The most common outcome next! + if self.script_storage[item]: + return self.script_storage[item] + else: + # Oops, something happened to our Global Script. Let's re-create it. + return self._load_script(item) + + def __getattr__(self, item): + return self[item] + + def _load_script(self, item): + typeclass = self.typeclass_storage[item] + found = typeclass.objects.filter(db_key=item).first() + interval = self.script_data[item].get('interval', None) + start_delay = self.script_data[item].get('start_delay', None) + repeats = self.script_data[item].get('repeats', 0) + desc = self.script_data[item].get('desc', '') + + if not found: + new_script, errors = typeclass.create(key=item, persistent=True, interval=interval, start_delay=start_delay, + repeats=repeats, desc=desc) + new_script.start() + self.script_storage[item] = new_script + return new_script + + if (found.interval != interval) or (found.start_delay != start_delay) or (found.repeats != repeats): + found.restart(interval=interval, start_delay=start_delay, repeats=repeats) + if found.desc != desc: + found.desc = desc + self.script_storage[item] = found + return found + + + + +# Create singleton of the GlobalHandler for the API. +GLOBAL_SCRIPTS = GlobalContainer() diff --git a/evennia/settings_default.py b/evennia/settings_default.py index 4e582b11e3..67886cc21a 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -538,6 +538,29 @@ INLINEFUNC_MODULES = ["evennia.utils.inlinefuncs", PROTOTYPEFUNC_MODULES = ["evennia.utils.prototypefuncs", "server.conf.prototypefuncs"] +###################################################################### +# Global Scripts +###################################################################### + +# While any script that is not attached to any object is considered +# Global, any listed here will be started by Evennia during boot +# and attached to its API for an easy-lookup. This ensures the Script +# is always accessible, and re-created if it is somehow deleted. Use +# this for Scripts that absolutely MUST be running for your game as a +# simple way to get them launched. + +# The 'key' is a way to quickly index them, and it will also be the +# Script Typeclasss's key so it can be quickly retrieved. + +# Values are a dictionary that uses the example format. Available keys +# are typeclass (required), interval, repeats, start_delay, and desc +# only typeclass is required. + +GLOBAL_SCRIPTS = { + # 'key': {'typeclass': 'typeclass.path.here', + # 'repeats': -1, 'interval': 50, 'desc': 'Example script'}, +} + ###################################################################### # Default Account setup and access ######################################################################