Added working report functionality for db-fields. Not tested for Attributes yet. Also working oob-repeat functionality, but still a traceback at reload.

This commit is contained in:
Griatch 2013-10-16 23:39:04 +02:00
parent bdcc8de5bc
commit 46c2e372bf
4 changed files with 144 additions and 169 deletions

View file

@ -28,7 +28,7 @@ from src.server.models import ServerConfig
from src.server.sessionhandler import SESSIONS from src.server.sessionhandler import SESSIONS
from src.scripts.scripts import Script from src.scripts.scripts import Script
from src.utils.create import create_script from src.utils.create import create_script
from src.utils.dbserialize import dbserialize, dbunserialize, pack_dbobj from src.utils.dbserialize import dbserialize, dbunserialize, pack_dbobj, unpack_dbobj
from src.utils import logger from src.utils import logger
from src.utils.utils import all_from_module, to_str, is_iter, make_iter from src.utils.utils import all_from_module, to_str, is_iter, make_iter
@ -57,25 +57,27 @@ class TrackerHandler(object):
# initiate store only with valid on-object fieldnames # initiate store only with valid on-object fieldnames
self.tracktargets = dict((key, {}) for key in _GA(_GA(self.obj, "_meta"), "get_all_field_names")()) self.tracktargets = dict((key, {}) for key in _GA(_GA(self.obj, "_meta"), "get_all_field_names")())
def add(self, fieldname, trackerkey, trackerobj): def add(self, fieldname, tracker):
""" """
Add tracker to the handler. Raises KeyError if fieldname Add tracker to the handler. Raises KeyError if fieldname
does not exist. does not exist.
""" """
self.tracktargets[fieldname][trackerkey] = trackerobj trackerkey = tracker.__class__.__name__
self.tracktargets[fieldname][trackerkey] = tracker
self.ntrackers += 1 self.ntrackers += 1
def remove(self, fieldname, trackerkey, *args, **kwargs): def remove(self, fieldname, trackerclass, *args, **kwargs):
""" """
Remove tracker from handler. Raises KeyError if tracker Remove tracker from handler. Raises KeyError if tracker
is not found. is not found.
""" """
oobobj = self.tracktargets[fieldname][trackerkey] trackerkey = trackerclass.__name__
tracker = self.tracktargets[fieldname][trackerkey]
try: try:
oobobj.at_delete(*args, **kwargs) tracker.at_delete(*args, **kwargs)
except Exception: except Exception:
logger.log_trace() logger.log_trace()
del oobobj del tracker
self.ntrackers -= 1 self.ntrackers -= 1
if self.ntrackers <= 0: if self.ntrackers <= 0:
# if there are no more trackers, clean this handler # if there are no more trackers, clean this handler
@ -85,9 +87,9 @@ class TrackerHandler(object):
""" """
Called by the field when it updates to a new value Called by the field when it updates to a new value
""" """
for trackerobj in self.tracktargets[fieldname].values(): for tracker in self.tracktargets[fieldname].values():
try: try:
trackerobj.update(fieldname, new_value) tracker.update(new_value)
except Exception: except Exception:
logger.log_trace() logger.log_trace()
@ -104,82 +106,61 @@ class TrackerBase(object):
"Called when tracker is removed" "Called when tracker is removed"
pass pass
# Default tracker OOB class class _RepeaterScript(Script):
class OOBTracker(TrackerBase):
""" """
A OOB object that passively sends data to a stored sessid whenever Repeating and subscription-enabled script for triggering OOB
a named database field changes. functions. Maintained in a _RepeaterPool.
""" """
def __init__(self, fieldname, sessid, *args, **kwargs): def at_script_creation(self):
""" "Called when script is initialized"
name - name of entity to track, such as "db_key" self.key = "oob_func"
track_type - one of "field", "prop" or "attr" for Database fields, self.desc = "OOB functionality script"
non-database Property or Attribute self.persistent = False #oob scripts should always be non-persistent
sessid - sessid of session to report to self.ndb.subscriptions = {}
"""
self.fieldname = fieldname
self.sessid = sessid
def update(self, new_value, *args, **kwargs): def at_repeat(self):
"Called by cache when updating the tracked entitiy" """
SESSIONS.session_from_sessid(self.sessid).msg(oob=("trackreturn", Calls subscriptions every self.interval seconds
(self.fieldname, new_value))) """
for (func_key, obj, session, interval, args, kwargs) in self.ndb.subscriptions.values():
OOB_HANDLER.execute_cmd(session, func_key, *args, **kwargs)
def subscribe(self, store_key, obj, session, func_key, interval, *args, **kwargs):
"""
Sign up a subscriber to this oobfunction. Subscriber is
a database object with a dbref.
"""
self.ndb.subscriptions[store_key] = (func_key, obj, session, interval, args, kwargs)
def unsubscribe(self, store_key):
"""
Unsubscribe from oobfunction. Returns True if removal was
successful, False otherwise
"""
self.ndb.subscriptions.pop(store_key, None)
class _RepeaterPool(object): class _RepeaterPool(object):
""" """
This maintains a pool of _RepeaterScript scripts, ordered one per interval. It This maintains a pool of _RepeaterScript scripts, ordered one per interval. It
will automatically cull itself once a given interval's script has no more will automatically cull itself once a given interval's script has no more
subscriptions. subscriptions.
This is used and accessed from oobhandler.repeat/unrepeat
""" """
class _RepeaterScript(Script):
"""
Repeating script for triggering OOB functions. Maintained in the pool.
"""
def at_script_creation(self):
"Called when script is initialized"
self.key = "oob_func"
self.desc = "OOB functionality script"
self.persistent = False #oob scripts should always be non-persistent
self.ndb.subscriptions = {}
def at_repeat(self):
"""
Calls subscriptions every self.interval seconds
"""
for (func_key, caller, interval, args, kwargs) in self.ndb.subscriptions.values():
try:
_OOB_FUNCS[func_key](caller, *args, **kwargs)
except Exception:
logger.log_trace()
def subscribe(self, store_key, caller, func_key, interval, *args, **kwargs):
"""
Sign up a subscriber to this oobfunction. Subscriber is
a database object with a dbref.
"""
self.ndb.subscriptions[store_key] = (func_key, caller, interval, args, kwargs)
def unsubscribe(self, store_key):
"""
Unsubscribe from oobfunction. Returns True if removal was
successful, False otherwise
"""
self.ndb.subscriptions.pop(store_key, None)
def __init__(self): def __init__(self):
self.scripts = {} self.scripts = {}
def add(self, store_key, caller, func_key, interval, *args, **kwargs): def add(self, store_key, obj, sessid, func_key, interval, *args, **kwargs):
""" """
Add a new tracking Add a new tracking
""" """
if interval not in self.scripts: if interval not in self.scripts:
# if no existing interval exists, create new script to fill the gap # if no existing interval exists, create new script to fill the gap
new_tracker = create_script(self._RepeaterScript, key="oob_repeater_%is" % interval, interval=interval) new_tracker = create_script(_RepeaterScript, key="oob_repeater_%is" % interval, interval=interval)
self.scripts[interval] = new_tracker self.scripts[interval] = new_tracker
self.scripts[interval].subscribe(store_key, caller, func_key, interval, *args, **kwargs) session = SESSIONS.session_from_sessid(sessid)
self.scripts[interval].subscribe(store_key, obj, session, func_key, interval, *args, **kwargs)
def remove(self, store_key, interval): def remove(self, store_key, interval):
""" """
@ -215,8 +196,10 @@ class OOBHandler(object):
ServerConf field ServerConf field
""" """
if self.oob_tracker_storage: if self.oob_tracker_storage:
print "saved tracker_storage:", self.oob_tracker_storage
ServerConfig.objects.conf(key="oob_tracker_storage", value=dbserialize(self.oob_tracker_storage)) ServerConfig.objects.conf(key="oob_tracker_storage", value=dbserialize(self.oob_tracker_storage))
if self.oob_repeat_storage: if self.oob_repeat_storage:
print "saved repeat_storage:", self.oob_repeat_storage
ServerConfig.objects.conf(key="oob_repeat_storage", value=dbserialize(self.oob_repeat_storage)) ServerConfig.objects.conf(key="oob_repeat_storage", value=dbserialize(self.oob_repeat_storage))
def restore(self): def restore(self):
@ -228,17 +211,23 @@ class OOBHandler(object):
tracker_storage = ServerConfig.objects.conf(key="oob_tracker_storage") tracker_storage = ServerConfig.objects.conf(key="oob_tracker_storage")
if tracker_storage: if tracker_storage:
self.oob_tracker_storage = dbunserialize(tracker_storage) self.oob_tracker_storage = dbunserialize(tracker_storage)
for tracker_key, (obj, sessid, fieldname, args, kwargs) in self.oob_tracker_storage.items(): print "recovered from tracker_storage:", self.oob_tracker_storage
self.track(obj, sessid, fieldname, tracker_key, *args, **kwargs) for (obj, sessid, fieldname, trackerclass, args, kwargs) in self.oob_tracker_storage.values():
self.track(unpack_dbobj(obj), sessid, fieldname, trackerclass, *args, **kwargs)
# make sure to purce the storage
ServerConfig.objects.conf(key="oob_tracker_storage", delete=True)
repeat_storage = ServerConfig.objects.conf(key="oob_repeat_storage") repeat_storage = ServerConfig.objects.conf(key="oob_repeat_storage")
if repeat_storage: if repeat_storage:
self.oob_repeat_storage = dbunserialize(repeat_storage) self.oob_repeat_storage = dbunserialize(repeat_storage)
for func_key, (caller, func_key, interval, args, kwargs) in self.oob_repeat_storage.items(): print "recovered from repeat_storage:", self.oob_repeat_storage
self.repeat(caller, func_key, interval, *args, **kwargs) for (obj, sessid, func_key, interval, args, kwargs) in self.oob_repeat_storage.values():
self.repeat(unpack_dbobj(obj), sessid, func_key, interval, *args, **kwargs)
# make sure to purge the storage
ServerConfig.objects.conf(key="oob_repeat_storage", delete=True)
def track(self, obj, sessid, fieldname, oobclass, *args, **kwargs): def track(self, obj, sessid, fieldname, trackerclass, *args, **kwargs):
""" """
Create an OOB obj of class _oob_MAPPING[tracker_key] on obj. args, Create an OOB obj of class _oob_MAPPING[tracker_key] on obj. args,
kwargs will be used to initialize the OOB hook before adding kwargs will be used to initialize the OOB hook before adding
@ -247,46 +236,59 @@ class OOBHandler(object):
will be used as the property name when assigning the OOB to will be used as the property name when assigning the OOB to
obj, otherwise tracker_key is ysed as the property name. obj, otherwise tracker_key is ysed as the property name.
""" """
oobclass = _OOB_TRACKERS[tracker_key] # raise traceback if not found try:
obj = obj.dbobj
except AttributeError:
pass
if not "_trackerhandler" in _GA(obj, "__dict__"): if not "_trackerhandler" in _GA(obj, "__dict__"):
# assign trackerhandler to object # assign trackerhandler to object
_SA(obj, "_trackerhandler", TrackerHandler(obj)) _SA(obj, "_trackerhandler", TrackerHandler(obj))
# initialize object # initialize object
oob = oobclass(obj, sessid, fieldname, *args, **kwargs) tracker = trackerclass(self, fieldname, sessid, *args, **kwargs)
_GA(obj, "_trackerhandler").add(oob, fieldname) _GA(obj, "_trackerhandler").add(fieldname, tracker)
# store calling arguments as a pickle for retrieval later # store calling arguments as a pickle for retrieval later
storekey = (pack_dbobj(obj), sessid, fieldname) obj_packed = pack_dbobj(obj)
stored = (obj, sessid, fieldname, args, kwargs) storekey = (obj_packed, sessid, fieldname)
stored = (obj_packed, sessid, fieldname, trackerclass, args, kwargs)
self.oob_tracker_storage[storekey] = stored self.oob_tracker_storage[storekey] = stored
def untrack(self, obj, sessid, fieldname, tracker_key, *args, **kwargs): def untrack(self, obj, sessid, fieldname, trackerclass, *args, **kwargs):
""" """
Remove the OOB from obj. If oob implements an Remove the OOB from obj. If oob implements an
at_delete hook, this will be called with args, kwargs at_delete hook, this will be called with args, kwargs
""" """
try:
obj = obj.dbobj
except AttributeError:
pass
try: try:
# call at_delete hook # call at_delete hook
_GA(obj, "_trackerhandler").remove(fieldname, tracker_key, *args, **kwargs) _GA(obj, "_trackerhandler").remove(fieldname, trackerclass, *args, **kwargs)
except AttributeError: except AttributeError:
pass pass
# remove the pickle from storage # remove the pickle from storage
store_key = (pack_dbobj(obj), sessid, fieldname) store_key = (pack_dbobj(obj), sessid, fieldname)
self.oob_tracker_storage.pop(store_key, None) self.oob_tracker_storage.pop(store_key, None)
def track_field(self, obj, sessid, field_name, tracker_key="oobtracker"): def track_field(self, obj, sessid, field_name, trackerclass):
""" """
Shortcut wrapper method for specifically tracking a database field. Shortcut wrapper method for specifically tracking a database field.
Uses OOBTracker by default (change tracker_key to redirect) Takes the tracker class as argument.
Will create a tracker with a property name that the field cache
expects
""" """
# all database field names starts with db_* # all database field names starts with db_*
field_name = field_name if field_name.startswith("db_") else "db_%s" % field_name field_name = field_name if field_name.startswith("db_") else "db_%s" % field_name
oob_tracker_name = "_track_%s_change" % field_name # field cache looks for name on this form self.track(obj, sessid, field_name, trackerclass)
self.track(obj, tracker_key, field_name, sessid, property_name=oob_tracker_name)
def track_attribute(self, obj, sessid, attr_name, tracker_key="oobtracker"): def untrack_field(self, obj, sessid, field_name):
"""
Shortcut for untracking a database field. Uses OOBTracker by defualt
"""
field_name = field_name if field_name.startswith("db_") else "db_%s" % field_name
self.untrack(obj, sessid, field_name)
def track_attribute(self, obj, sessid, attr_name, trackerclass):
""" """
Shortcut wrapper method for specifically tracking the changes of an Shortcut wrapper method for specifically tracking the changes of an
Attribute on an object. Will create a tracker on the Attribute Object and Attribute on an object. Will create a tracker on the Attribute Object and
@ -295,10 +297,17 @@ class OOBHandler(object):
# get the attribute object if we can # get the attribute object if we can
attrobj = _GA(obj, "attributes").get(attr_name, return_obj=True) attrobj = _GA(obj, "attributes").get(attr_name, return_obj=True)
if attrobj: if attrobj:
oob_tracker_name = "_track_db_value_change" self.track(attrobj, sessid, attr_name, trackerclass)
self.track(attrobj, tracker_key, attr_name, sessid, property_name=oob_tracker_name)
def repeat(self, caller, func_key, interval=20, *args, **kwargs): def untrack_attribute(self, obj, sessid, attr_name, tracker_key="oobtracker"):
"""
Shortcut for deactivating tracking for a given attribute.
"""
attrobj = _GA(obj, "attributes").get(attr_name, return_obj=True)
if attrobj:
self.untrack(attrobj, sessid, attr_name)
def repeat(self, obj, sessid, func_key, interval=20, *args, **kwargs):
""" """
Start a repeating action. Every interval seconds, Start a repeating action. Every interval seconds,
the oobfunc corresponding to func_key is called with the oobfunc corresponding to func_key is called with
@ -306,22 +315,32 @@ class OOBHandler(object):
""" """
if not func_key in _OOB_FUNCS: if not func_key in _OOB_FUNCS:
raise KeyError("%s is not a valid OOB function name.") raise KeyError("%s is not a valid OOB function name.")
store_key = (pack_dbobj(caller), func_key, interval) try:
obj = obj.dbobj
except AttributeError:
pass
store_obj = pack_dbobj(obj)
store_key = (store_obj, sessid, func_key, interval)
# prepare to store # prepare to store
self.oob_repeat_storage[store_key] = (caller, func_key, interval, args, kwargs) self.oob_repeat_storage[store_key] = (store_obj, sessid, func_key, interval, args, kwargs)
self.oob_tracker_pool.add(store_key, caller, func_key, interval, *args, **kwargs) self.oob_tracker_pool.add(store_key, obj, sessid, func_key, interval, *args, **kwargs)
def unrepeat(self, caller, func_key, interval=20): def unrepeat(self, obj, sessid, func_key, interval=20):
""" """
Stop a repeating action Stop a repeating action
""" """
store_key = (pack_dbobj(caller), func_key, interval) try:
obj = obj.dbobj
except AttributeError:
pass
store_key = (pack_dbobj(obj), sessid, func_key, interval)
self.oob_tracker_pool.remove(store_key, interval) self.oob_tracker_pool.remove(store_key, interval)
self.oob_repeat_storage.pop(store_key, None) self.oob_repeat_storage.pop(store_key, None)
def msg(self, sessid, funcname, *args, **kwargs): def msg(self, sessid, funcname, *args, **kwargs):
"Shortcut to relay oob data back to portal" "Shortcut to relay oob data back to portal"
session = self.sessionhandler.session_from_sessid(sessid) session = self.sessionhandler.session_from_sessid(sessid)
print "oobhandler msg:", sessid, session, funcname, args, kwargs
if session: if session:
session.msg(oob=(funcname, args, kwargs)) session.msg(oob=(funcname, args, kwargs))
@ -331,6 +350,7 @@ class OOBHandler(object):
using *args and **kwargs using *args and **kwargs
""" """
try: try:
print "OOB execute_cmd:", session, func_key, args, kwargs, _OOB_FUNCS.keys()
oobfunc = _OOB_FUNCS[func_key] # raise traceback if not found oobfunc = _OOB_FUNCS[func_key] # raise traceback if not found
oobfunc(self, session, *args, **kwargs) oobfunc(self, session, *args, **kwargs)
except KeyError: except KeyError:

View file

@ -45,69 +45,6 @@ MSDP_COMMANDS_CUSTOM = {}
# this maps MSDP command names to Evennia commands found in OOB_FUNC_MODULE. It # this maps MSDP command names to Evennia commands found in OOB_FUNC_MODULE. It
# is up to these commands to return data on proper form. This is overloaded if # is up to these commands to return data on proper form. This is overloaded if
# OOB_REPORTABLE is defined in the custom OOB module below. # OOB_REPORTABLE is defined in the custom OOB module below.
MSDP_REPORTABLE = {
# General
"CHARACTER_NAME": "get_character_name",
"SERVER_ID": "get_server_id",
"SERVER_TIME": "get_server_time",
# Character
"AFFECTS": "char_affects",
"ALIGNMENT": "char_alignment",
"EXPERIENCE": "char_experience",
"EXPERIENCE_MAX": "char_experience_max",
"EXPERIENCE_TNL": "char_experience_tnl",
"HEALTH": "char_health",
"HEALTH_MAX": "char_health_max",
"LEVEL": "char_level",
"RACE": "char_race",
"CLASS": "char_class",
"MANA": "char_mana",
"MANA_MAX": "char_mana_max",
"WIMPY": "char_wimpy",
"PRACTICE": "char_practice",
"MONEY": "char_money",
"MOVEMENT": "char_movement",
"MOVEMENT_MAX": "char_movement_max",
"HITROLL": "char_hitroll",
"DAMROLL": "char_damroll",
"AC": "char_ac",
"STR": "char_str",
"INT": "char_int",
"WIS": "char_wis",
"DEX": "char_dex",
"CON": "char_con",
# Combat
"OPPONENT_HEALTH": "opponent_health",
"OPPONENT_HEALTH_MAX":"opponent_health_max",
"OPPONENT_LEVEL": "opponent_level",
"OPPONENT_NAME": "opponent_name",
# World
"AREA_NAME": "area_name",
"ROOM_EXITS": "area_room_exits",
"ROOM_NAME": "room_name",
"ROOM_VNUM": "room_dbref",
"WORLD_TIME": "world_time",
# Configurable variables
"CLIENT_ID": "client_id",
"CLIENT_VERSION": "client_version",
"PLUGIN_ID": "plugin_id",
"ANSI_COLORS": "ansi_colours",
"XTERM_256_COLORS": "xterm_256_colors",
"UTF_8": "utf_8",
"SOUND": "sound",
"MXP": "mxp",
# GUI variables
"BUTTON_1": "button1",
"BUTTON_2": "button2",
"BUTTON_3": "button3",
"BUTTON_4": "button4",
"BUTTON_5": "button5",
"GAUGE_1": "gauge1",
"GAUGE_2": "gauge2",
"GAUGE_3": "gauge3",
"GAUGE_4": "gauge4",
"GAUGE_5": "gauge5"}
MSDP_SENDABLE = MSDP_REPORTABLE
# try to load custom OOB module # try to load custom OOB module
OOB_MODULE = None#mod_import(settings.OOB_FUNC_MODULE) OOB_MODULE = None#mod_import(settings.OOB_FUNC_MODULE)
@ -156,10 +93,13 @@ class Msdp(object):
converted to a string), a list (will be converted to an MSDP_ARRAY), converted to a string), a list (will be converted to an MSDP_ARRAY),
or a dictionary (will be converted to MSDP_TABLE). or a dictionary (will be converted to MSDP_TABLE).
Obs - this normally only returns tables and lists (var val val ...) rather than OBS - there is no actual use of arrays and tables in the MSDP
arrays. It will convert *args to lists and **kwargs to tables and specification or default commands -- are returns are implemented
if both are given to this method, this will result in a list followed as simple lists or named lists (our name for them here, these
by a table, both having the same names. un-bounded structures are not named in the specification). So for
now, this routine will not explicitly create arrays nor tables,
although there are helper methods ready should it be needed in
the future.
""" """
def make_table(name, **kwargs): def make_table(name, **kwargs):
@ -173,7 +113,7 @@ class Msdp(object):
else: else:
string += MSDP_VAR + force_str(key) + MSDP_VAL + force_str(val) string += MSDP_VAR + force_str(key) + MSDP_VAL + force_str(val)
string += MSDP_TABLE_CLOSE string += MSDP_TABLE_CLOSE
return string return stringk
def make_array(name, *args): def make_array(name, *args):
"build a array. Arrays may not nest tables by definition." "build a array. Arrays may not nest tables by definition."
@ -188,8 +128,17 @@ class Msdp(object):
string += MSDP_VAL.join(force_str(arg) for arg in args) string += MSDP_VAL.join(force_str(arg) for arg in args)
return string return string
def make_named_list(name, **kwargs):
"build a named list - a table without start/end markers"
string = MSDP_VAR + force_str(name)
for key, val in kwargs.items():
string += MSDP_VAR + force_str(key) + MSDP_VAL + force_str(val)
return string
# Default MSDP commands # Default MSDP commands
print "MSDP outgoing:", cmdname, args, kwargs
cupper = cmdname.upper() cupper = cmdname.upper()
if cupper == "LIST": if cupper == "LIST":
self.data_out(make_list("LIST", *args)) self.data_out(make_list("LIST", *args))
@ -200,15 +149,14 @@ class Msdp(object):
elif cupper == "RESET": elif cupper == "RESET":
self.data_out(make_list("RESET", *args)) self.data_out(make_list("RESET", *args))
elif cupper == "SEND": elif cupper == "SEND":
self.data_out(make_list("SEND", *args)) self.data_out(make_named_list("SEND", **kwargs))
else: else:
# return list or tables. If both arg/kwarg is given, return one array and one table, both # return list or named lists.
# with the same name.
msdp_string = "" msdp_string = ""
if args: if args:
msdp_string += make_list(cupper, *args) msdp_string += make_list(cupper, *args)
if kwargs: if kwargs:
msdp_string += make_table(cupper, **kwargs) msdp_string += make_named_list(cupper, **kwargs)
self.data_out(msdp_string) self.data_out(msdp_string)
def msdp_to_evennia(self, data): def msdp_to_evennia(self, data):

View file

@ -214,10 +214,14 @@ class Evennia(object):
[(o.typeclass, o.at_init()) for o in ObjectDB.get_all_cached_instances()] [(o.typeclass, o.at_init()) for o in ObjectDB.get_all_cached_instances()]
[(p.typeclass, p.at_init()) for p in PlayerDB.get_all_cached_instances()] [(p.typeclass, p.at_init()) for p in PlayerDB.get_all_cached_instances()]
with open(SERVER_RESTART, 'r') as f:
mode = f.read()
if mode in ('True', 'reload'):
from src.server.oobhandler import OOB_HANDLER
OOB_HANDLER.restore()
if SERVER_STARTSTOP_MODULE: if SERVER_STARTSTOP_MODULE:
# call correct server hook based on start file value # call correct server hook based on start file value
with open(SERVER_RESTART, 'r') as f:
mode = f.read()
if mode in ('True', 'reload'): if mode in ('True', 'reload'):
# True was the old reload flag, kept for compatibilty # True was the old reload flag, kept for compatibilty
SERVER_STARTSTOP_MODULE.at_server_reload_start() SERVER_STARTSTOP_MODULE.at_server_reload_start()
@ -280,6 +284,9 @@ class Evennia(object):
yield self.sessions.all_sessions_portal_sync() yield self.sessions.all_sessions_portal_sync()
ServerConfig.objects.conf("server_restart_mode", "reload") ServerConfig.objects.conf("server_restart_mode", "reload")
from src.server.oobhandler import OOB_HANDLER
OOB_HANDLER.save()
if SERVER_STARTSTOP_MODULE: if SERVER_STARTSTOP_MODULE:
SERVER_STARTSTOP_MODULE.at_server_reload_stop() SERVER_STARTSTOP_MODULE.at_server_reload_stop()

View file

@ -196,7 +196,7 @@ def pack_dbobj(item):
# build the internal representation as a tuple ("__packed_dbobj__", key, creation_time, id) # build the internal representation as a tuple ("__packed_dbobj__", key, creation_time, id)
return natural_key and ('__packed_dbobj__', natural_key, _TO_DATESTRING(obj), _GA(obj, "id")) or item return natural_key and ('__packed_dbobj__', natural_key, _TO_DATESTRING(obj), _GA(obj, "id")) or item
def _unpack_dbobj(item): def unpack_dbobj(item):
""" """
Check and convert internal representations back to Django database models. Check and convert internal representations back to Django database models.
The fact that item is a packed dbobj should be checked before this call. The fact that item is a packed dbobj should be checked before this call.
@ -267,7 +267,7 @@ def from_pickle(data, db_obj=None):
return item return item
elif _IS_PACKED_DBOBJ(item): elif _IS_PACKED_DBOBJ(item):
# this must be checked before tuple # this must be checked before tuple
return _unpack_dbobj(item) return unpack_dbobj(item)
elif dtype == tuple: elif dtype == tuple:
return tuple(process_item(val) for val in item) return tuple(process_item(val) for val in item)
elif dtype == dict: elif dtype == dict:
@ -289,7 +289,7 @@ def from_pickle(data, db_obj=None):
return item return item
elif _IS_PACKED_DBOBJ(item): elif _IS_PACKED_DBOBJ(item):
# this must be checked before tuple # this must be checked before tuple
return _unpack_dbobj(item) return unpack_dbobj(item)
elif dtype == tuple: elif dtype == tuple:
return tuple(process_tree(val) for val in item) return tuple(process_tree(val) for val in item)
elif dtype == list: elif dtype == list: