From 857c6d53f251e202ab8a6982d24dbc1a444d09fb Mon Sep 17 00:00:00 2001 From: Andrew Bastien Date: Tue, 9 Apr 2019 23:42:46 -0400 Subject: [PATCH 1/4] Created basic GLOBAL_HANDLER for the Global Script API. --- evennia/__init__.py | 4 ++- evennia/scripts/globalhandler.py | 45 ++++++++++++++++++++++++++++++++ evennia/settings_default.py | 19 ++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 evennia/scripts/globalhandler.py diff --git a/evennia/__init__.py b/evennia/__init__.py index 080114f7a0..47a6273239 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_HANDLER = 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_HANDLER 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_HANDLER # initialize the doc string global __doc__ diff --git a/evennia/scripts/globalhandler.py b/evennia/scripts/globalhandler.py new file mode 100644 index 0000000000..3ac7e38d40 --- /dev/null +++ b/evennia/scripts/globalhandler.py @@ -0,0 +1,45 @@ +from django.conf import settings +from evennia.utils.utils import class_from_module + + +class GlobalHandler(object): + """ + Simple Handler object loaded by the Evennia API to contain and manage a game's Global Scripts. + + This is accessed like a dictionary. + + Example: + import evennia + evennia.GLOBAL_HANDLER['key'] + """ + + def __init__(self): + self.typeclass_storage = dict() + self.script_storage = dict() + for k, v in settings.GLOBAL_SCRIPTS.items(): + self.typeclass_storage[k] = class_from_module(v) + for k, v in self.typeclass_storage.items(): + found = v.objects.filter_family(db_key=k).first() + if not found: + found = v.create(key=k, typeclass=v, persistent=True) + self.script_storage[k] = found + + 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. + reloaded = self.typeclass_storage[item].create(key=item, typeclass=self.typeclass_storage[item], + persistent=True) + self.script_storage[item] = reloaded + return reloaded + + +# Create singleton of the GlobalHandler for the API. +GLOBAL_HANDLER = GlobalHandler() diff --git a/evennia/settings_default.py b/evennia/settings_default.py index 4e582b11e3..70ad3e8ba6 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -538,6 +538,25 @@ 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. + +# One limitation with this system is that each Script must be have a +# unique Typeclass. The 'key' is a way to quickly index them but is +# not necessarily the Script Typeclasss's key. + +GLOBAL_SCRIPTS = { + # 'key': 'typeclass.path.here', +} + ###################################################################### # Default Account setup and access ###################################################################### From f1c74716914b5c327c908c0f5e69ec15bf820507 Mon Sep 17 00:00:00 2001 From: Andrew Bastien Date: Thu, 11 Apr 2019 11:29:38 -0400 Subject: [PATCH 2/4] Renamed GLOBAL_HANDLER to GLOBAL_SCRIPTS and cleaned up to PEP8 --- evennia/__init__.py | 6 +++--- evennia/scripts/globalhandler.py | 21 ++++++++++++--------- evennia/settings_default.py | 5 ++--- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/evennia/__init__.py b/evennia/__init__.py index 47a6273239..139cda5e25 100644 --- a/evennia/__init__.py +++ b/evennia/__init__.py @@ -109,7 +109,7 @@ TASK_HANDLER = None TICKER_HANDLER = None MONITOR_HANDLER = None CHANNEL_HANDLER = None -GLOBAL_HANDLER = None +GLOBAL_SCRIPTS = None def _create_version(): @@ -153,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_HANDLER + global contrib, TICKER_HANDLER, MONITOR_HANDLER, SESSION_HANDLER, CHANNEL_HANDLER, TASK_HANDLER, GLOBAL_SCRIPTS global EvMenu, EvTable, EvForm, EvMore, EvEditor global ANSIString @@ -214,7 +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_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 index 3ac7e38d40..7b42086541 100644 --- a/evennia/scripts/globalhandler.py +++ b/evennia/scripts/globalhandler.py @@ -6,23 +6,23 @@ class GlobalHandler(object): """ Simple Handler object loaded by the Evennia API to contain and manage a game's Global Scripts. - This is accessed like a dictionary. + This is accessed like a dictionary. Alternatively you can access Properties on it. Example: import evennia - evennia.GLOBAL_HANDLER['key'] + evennia.GLOBAL_SCRIPTS['key'] """ def __init__(self): self.typeclass_storage = dict() self.script_storage = dict() - for k, v in settings.GLOBAL_SCRIPTS.items(): - self.typeclass_storage[k] = class_from_module(v) - for k, v in self.typeclass_storage.items(): - found = v.objects.filter_family(db_key=k).first() + for key, typeclass_path in settings.GLOBAL_SCRIPTS.items(): + self.typeclass_storage[key] = class_from_module(typeclass_path) + for key, typeclass in self.typeclass_storage.items(): + found = typeclass.objects.filter(db_key=key).first() if not found: - found = v.create(key=k, typeclass=v, persistent=True) - self.script_storage[k] = found + found = typeclass.create(key=key, typeclass=typeclass, persistent=True) + self.script_storage[key] = found def __getitem__(self, item): @@ -40,6 +40,9 @@ class GlobalHandler(object): self.script_storage[item] = reloaded return reloaded + def __getattr__(self, item): + return self[item] + # Create singleton of the GlobalHandler for the API. -GLOBAL_HANDLER = GlobalHandler() +GLOBAL_SCRIPTS = GlobalHandler() diff --git a/evennia/settings_default.py b/evennia/settings_default.py index 70ad3e8ba6..3987d10115 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -549,9 +549,8 @@ PROTOTYPEFUNC_MODULES = ["evennia.utils.prototypefuncs", # this for Scripts that absolutely MUST be running for your game as a # simple way to get them launched. -# One limitation with this system is that each Script must be have a -# unique Typeclass. The 'key' is a way to quickly index them but is -# not necessarily the Script Typeclasss's key. +# 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. GLOBAL_SCRIPTS = { # 'key': 'typeclass.path.here', From 1f246484cd174d4bca1c94565a7bd4d7e38570c7 Mon Sep 17 00:00:00 2001 From: Andrew Bastien Date: Sun, 14 Apr 2019 00:22:53 -0400 Subject: [PATCH 3/4] Refactored ScriptHandler into ScriptContainer. Now uses dictionaries with finer control for script launching. --- evennia/scripts/globalhandler.py | 49 +++++++++++++++++++++++--------- evennia/settings_default.py | 7 ++++- 2 files changed, 41 insertions(+), 15 deletions(-) diff --git a/evennia/scripts/globalhandler.py b/evennia/scripts/globalhandler.py index 7b42086541..8ccf672dcd 100644 --- a/evennia/scripts/globalhandler.py +++ b/evennia/scripts/globalhandler.py @@ -2,7 +2,7 @@ from django.conf import settings from evennia.utils.utils import class_from_module -class GlobalHandler(object): +class GlobalContainer(object): """ Simple Handler object loaded by the Evennia API to contain and manage a game's Global Scripts. @@ -14,15 +14,15 @@ class GlobalHandler(object): """ def __init__(self): - self.typeclass_storage = dict() + self.script_data = dict() self.script_storage = dict() - for key, typeclass_path in settings.GLOBAL_SCRIPTS.items(): - self.typeclass_storage[key] = class_from_module(typeclass_path) - for key, typeclass in self.typeclass_storage.items(): - found = typeclass.objects.filter(db_key=key).first() - if not found: - found = typeclass.create(key=key, typeclass=typeclass, persistent=True) - self.script_storage[key] = found + 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): @@ -35,14 +35,35 @@ class GlobalHandler(object): return self.script_storage[item] else: # Oops, something happened to our Global Script. Let's re-create it. - reloaded = self.typeclass_storage[item].create(key=item, typeclass=self.typeclass_storage[item], - persistent=True) - self.script_storage[item] = reloaded - return reloaded + 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 = 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 = GlobalHandler() +GLOBAL_SCRIPTS = GlobalContainer() diff --git a/evennia/settings_default.py b/evennia/settings_default.py index 3987d10115..67886cc21a 100644 --- a/evennia/settings_default.py +++ b/evennia/settings_default.py @@ -552,8 +552,13 @@ PROTOTYPEFUNC_MODULES = ["evennia.utils.prototypefuncs", # 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.path.here', + # 'key': {'typeclass': 'typeclass.path.here', + # 'repeats': -1, 'interval': 50, 'desc': 'Example script'}, } ###################################################################### From 3ae8234dad03ed6e3a49ceae95c08109c93dec2d Mon Sep 17 00:00:00 2001 From: Andrew Bastien Date: Sun, 14 Apr 2019 03:41:04 -0400 Subject: [PATCH 4/4] Fixed issue with creating new Scripts. Silly tuples! --- evennia/scripts/globalhandler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/evennia/scripts/globalhandler.py b/evennia/scripts/globalhandler.py index 8ccf672dcd..4cce262993 100644 --- a/evennia/scripts/globalhandler.py +++ b/evennia/scripts/globalhandler.py @@ -49,8 +49,8 @@ class GlobalContainer(object): desc = self.script_data[item].get('desc', '') if not found: - new_script = typeclass.create(key=item, persistent=True, interval=interval, start_delay=start_delay, - repeats=repeats, desc=desc) + 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