def run_init_hooks(self): """ Called every server start """ from evennia.objects.models import ObjectDB #from evennia.players.models import PlayerDB #update eventual changed defaults self.update_defaults() #print "run_init_hooks:", ObjectDB.get_all_cached_instances() [o.at_init() for o in ObjectDB.get_all_cached_instances()] [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 evennia.server.oobhandler import OOB_HANDLER OOB_HANDLER.restore() from evennia.scripts.tickerhandler import TICKER_HANDLER TICKER_HANDLER.restore() # call correct server hook based on start file value if mode in ('True', 'reload'): # True was the old reload flag, kept for compatibilty self.at_server_reload_start() elif mode in ('reset', 'shutdown'): self.at_server_cold_start() # clear eventual lingering session storages ObjectDB.objects.clear_all_sessids() # always call this regardless of start type self.at_server_start()
def data_in(self, sessid, text="", **kwargs): """ Data Portal -> Server. We also intercept OOB communication here. Args: sessid (int): Session id. Kwargs: text (str): Text from protocol. kwargs (any): Other data from protocol. """ #from evennia.server.profiling.timetrace import timetrace #text = timetrace(text, "ServerSessionHandler.data_in") session = self.sessions.get(sessid, None) if session: text = text and to_unicode(strip_control_sequences(text), encoding=session.encoding) if "oob" in kwargs: # incoming data is always on the form (cmdname, args, kwargs) global _OOB_HANDLER if not _OOB_HANDLER: from evennia.server.oobhandler import OOB_HANDLER as _OOB_HANDLER funcname, args, kwargs = kwargs.pop("oob") #print "OOB session.data_in:", funcname, args, kwargs if funcname: _OOB_HANDLER.execute_cmd(session, funcname, *args, **kwargs) # pass the rest off to the session session.data_in(text=text, **kwargs)
def oob_unreport(session, *args, **kwargs): """ This removes tracking for the given data. Args: session (Session): Session controling this command. """ obj = session.get_puppet_or_player() if obj: for name in (a.upper() for a in args if a): propname = OOB_REPORTABLE.get(name, None) if not propname: oob_error( session, "No Un-Reportable property '%s'. Use LIST REPORTABLE_VARIABLES." % propname) elif propname.startswith("db_"): OOB_HANDLER.remove_field_monitor(obj, session, propname, "oob_return_field_report") else: # assume attribute OOB_HANDLER.remove_attribute_monitor( obj, session, propname, "oob_return_attribute_report") else: oob_error(session, "You must log in first.")
def data_in(self, sessid, text="", **kwargs): """ Data Portal -> Server. We also intercept OOB communication here. Args: sessid (int): Session id. Kwargs: text (str): Text from protocol. kwargs (any): Other data from protocol. """ session = self.sessions.get(sessid, None) if session: text = text and to_unicode(strip_control_sequences(text), encoding=session.encoding) if "oob" in kwargs: # incoming data is always on the form (cmdname, args, kwargs) global _OOB_HANDLER if not _OOB_HANDLER: from evennia.server.oobhandler import OOB_HANDLER as _OOB_HANDLER funcname, args, kwargs = kwargs.pop("oob") #print "OOB session.data_in:", funcname, args, kwargs if funcname: _OOB_HANDLER.execute_cmd(session, funcname, *args, **kwargs) # pass the rest off to the session session.data_in(text=text, **kwargs)
def run_init_hooks(self): """ Called every server start """ from evennia.objects.models import ObjectDB #from evennia.players.models import PlayerDB #update eventual changed defaults self.update_defaults() [o.at_init() for o in ObjectDB.get_all_cached_instances()] [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 evennia.server.oobhandler import OOB_HANDLER OOB_HANDLER.restore() from evennia.scripts.tickerhandler import TICKER_HANDLER TICKER_HANDLER.restore() # call correct server hook based on start file value if mode in ('True', 'reload'): # True was the old reload flag, kept for compatibilty self.at_server_reload_start() elif mode == 'reset': # only run hook, don't purge sessions self.at_server_cold_start() elif mode in ('reset', 'shutdown'): self.at_server_cold_start() # clear eventual lingering session storages ObjectDB.objects.clear_all_sessids() # always call this regardless of start type self.at_server_start()
def oob_report(session, *args, **kwargs): """ Called with the `REPORT PROPNAME` MSDP command. Monitors the changes of given property name. Assumes reporting happens on an object controlled by the session. Args: session (Session): The Session doing the monitoring. The property is assumed to sit on the entity currently controlled by the Session. If puppeting, this is an Object, otherwise the object will be the Player the Session belongs to. args (str or list): One or more property names to monitor changes in. If a name starts with `db_`, the property is assumed to be a field, otherwise an Attribute of the given name will be monitored (if it exists). Notes: When the property updates, the monitor will send a MSDP_ARRAY to the session of the form `(SEND, fieldname, new_value)` Examples: ("REPORT", "CHARACTER_NAME") ("MSDP_TABLE", "CHARACTER_NAME", "Amanda") """ obj = session.get_puppet_or_player() if obj: ret = [] for name in args: propname = OOB_REPORTABLE.get(name, None) if not propname: oob_error( session, "No Reportable property '%s'. Use LIST REPORTABLE_VARIABLES." % propname) # the field_monitors require an oob function as a callback when they report a change. elif propname.startswith("db_"): OOB_HANDLER.add_field_monitor(obj, session.sessid, propname, "return_field_report") ret.append(to_str(_GA(obj, propname), force_string=True)) else: OOB_HANDLER.add_attribute_monitor(obj, session.sessid, propname, "return_attribute_report") ret.append(_GA(obj, "db_value")) #print "ret:", ret session.msg(oob=("MSDP_ARRAY", ret)) else: oob_error(session, "You must log in first.")
def oob_unreport(session, *args, **kwargs): """ This removes tracking for the given data. """ obj = session.get_puppet_or_player() if obj: for name in (a.upper() for a in args if a): propname = OOB_REPORTABLE.get(name, None) if not propname: oob_error(session, "No Un-Reportable property '%s'. Use LIST REPORTABLE_VARIABLES." % propname) elif propname.startswith("db_"): OOB_HANDLER.remove_field_monitor(obj, session.sessid, propname, "oob_return_field_report") else: # assume attribute OOB_HANDLER.remove_attribute_monitor(obj, session.sessid, propname, "oob_return_attribute_report") else: oob_error(session, "You must log in first.")
def oob_unrepeat(session, oobfuncname, interval): """ Called with UNREPEAT <oobfunc> <interval> Disable repeating callback. Args: session (Session): Session controlling the repeater oobfuncname (str): OOB function called every interval seconds interval (int): Interval of repeater, in seconds. Notes: The command checks so that it cannot repeat itself. """ obj = session.get_puppet_or_player() if obj: OOB_HANDLER.remove_repeater(obj, session.sessid, oobfuncname, interval)
def oob_unrepeat(session, oobfuncname, interval): """ Called with UNREPEAT <oobfunc> <interval> Disable repeating callback. Args: session (Session): Session controlling the repeater oobfuncname (str): OOB function called every interval seconds interval (int): Interval of repeater, in seconds. Notes: The command checks so that it cannot repeat itself. """ obj = session.get_puppet_or_player() if obj: OOB_HANDLER.remove_repeater(obj, session, oobfuncname, interval)
def oob_report(session, *args, **kwargs): """ Called with the `REPORT PROPNAME` MSDP command. Monitors the changes of given property name. Assumes reporting happens on an object controlled by the session. Args: session (Session): The Session doing the monitoring. The property is assumed to sit on the entity currently controlled by the Session. If puppeting, this is an Object, otherwise the object will be the Player the Session belongs to. args (str or list): One or more property names to monitor changes in. If a name starts with `db_`, the property is assumed to be a field, otherwise an Attribute of the given name will be monitored (if it exists). Notes: When the property updates, the monitor will send a MSDP_ARRAY to the session of the form `(SEND, fieldname, new_value)` Examples: ("REPORT", "CHARACTER_NAME") ("MSDP_TABLE", "CHARACTER_NAME", "Amanda") """ obj = session.get_puppet_or_player() if obj: ret = [] for name in args: propname = OOB_REPORTABLE.get(name, None) if not propname: oob_error(session, "No Reportable property '%s'. Use LIST REPORTABLE_VARIABLES." % propname) # the field_monitors require an oob function as a callback when they report a change. elif propname.startswith("db_"): OOB_HANDLER.add_field_monitor(obj, session.sessid, propname, "return_field_report") ret.append(to_str(_GA(obj, propname), force_string=True)) else: OOB_HANDLER.add_attribute_monitor(obj, session.sessid, propname, "return_attribute_report") ret.append(_GA(obj, "db_value")) #print "ret:", ret session.msg(oob=("MSDP_ARRAY", ret)) else: oob_error(session, "You must log in first.")
def data_in(self, sessid, text="", **kwargs): """ Data Portal -> Server. We also intercept OOB communication here. """ session = self.sessions.get(sessid, None) if session: text = text and to_unicode(strip_control_sequences(text), encoding=session.encoding) if "oob" in kwargs: # incoming data is always on the form (cmdname, args, kwargs) global _OOB_HANDLER if not _OOB_HANDLER: from evennia.server.oobhandler import OOB_HANDLER as _OOB_HANDLER funcname, args, kwargs = kwargs.pop("oob") #print "OOB session.data_in:", funcname, args, kwargs if funcname: _OOB_HANDLER.execute_cmd(session, funcname, *args, **kwargs) # pass the rest off to the session session.data_in(text=text, **kwargs)
def oob_repeat(session, oobfuncname, interval, *args, **kwargs): """ Called as REPEAT <oobfunc> <interval> <args> Repeats a given OOB command with a certain frequency. Args: session (Session): Session creating the repeat oobfuncname (str): OOB function called every interval seconds interval (int): Interval of repeat, in seconds. Notes: The command checks so that it cannot repeat itself. """ if not oobfuncname: oob_error(session, "Usage: REPEAT <oobfuncname>, <interval>") return # limit repeat actions to minimum 5 seconds interval interval = 20 if not interval else (max(5, interval)) obj = session.get_puppet_or_player() if obj and oobfuncname != "REPEAT": OOB_HANDLER.add_repeater(obj, session.sessid, oobfuncname, interval, *args, **kwargs)
def oob_repeat(session, oobfuncname, interval, *args, **kwargs): """ Called as REPEAT <oobfunc> <interval> <args> Repeats a given OOB command with a certain frequency. Args: session (Session): Session creating the repeat oobfuncname (str): OOB function called every interval seconds interval (int): Interval of repeat, in seconds. Notes: The command checks so that it cannot repeat itself. """ if not oobfuncname: oob_error(session, "Usage: REPEAT <oobfuncname>, <interval>") return # limit repeat actions to minimum 5 seconds interval interval = 20 if not interval else (max(5, interval)) obj = session.get_puppet_or_player() if obj and oobfuncname != "REPEAT": OOB_HANDLER.add_repeater(obj, session, oobfuncname, interval, *args, **kwargs)
def oob_list(session, mode, *args, **kwargs): """ Called with the `LIST <MODE>` MSDP command. Args: session (Session): The Session asking for the information mode (str): The available properties. One of "COMMANDS" Request an array of commands supported by the server. "LISTS" Request an array of lists supported by the server. "CONFIGURABLE_VARIABLES" Request an array of variables the client can configure. "REPORTABLE_VARIABLES" Request an array of variables the server will report. "REPORTED_VARIABLES" Request an array of variables currently being reported. "SENDABLE_VARIABLES" Request an array of variables the server will send. Examples: oob in: LIST COMMANDS oob out: (COMMANDS, (SEND, REPORT, LIST, ...) """ mode = mode.upper() if mode == "COMMANDS": session.msg(oob=("COMMANDS", ("LIST", "REPORT", "UNREPORT", # "RESET", "SEND"))) elif mode == "REPORTABLE_VARIABLES": session.msg(oob=("REPORTABLE_VARIABLES", tuple(key for key in OOB_REPORTABLE.keys()))) elif mode == "REPORTED_VARIABLES": # we need to check so as to use the right return value depending on if it is # an Attribute (identified by tracking the db_value field) or a normal database field # reported is a list of tuples (obj, propname, args, kwargs) reported = OOB_HANDLER.get_all_monitors(session.sessid) reported = [rep[0].key if rep[1] == "db_value" else rep[1] for rep in reported] session.msg(oob=("REPORTED_VARIABLES", reported)) elif mode == "SENDABLE_VARIABLES": session.msg(oob=("SENDABLE_VARIABLES", tuple(key for key in OOB_REPORTABLE.keys()))) elif mode == "CONFIGURABLE_VARIABLES": # Not implemented (game specific) oob_error(session, "Not implemented (game specific)") else: # mode == "LISTS" or not given session.msg(oob=("LISTS",("REPORTABLE_VARIABLES", "REPORTED_VARIABLES", # "CONFIGURABLE_VARIABLES", "SENDABLE_VARIABLES")))
def oob_list(session, mode, *args, **kwargs): """ Called with the `LIST <MODE>` MSDP command. Args: session (Session): The Session asking for the information mode (str): The available properties. One of "COMMANDS" Request an array of commands supported by the server. "LISTS" Request an array of lists supported by the server. "CONFIGURABLE_VARIABLES" Request an array of variables the client can configure. "REPORTABLE_VARIABLES" Request an array of variables the server will report. "REPORTED_VARIABLES" Request an array of variables currently being reported. "SENDABLE_VARIABLES" Request an array of variables the server will send. Examples: oob in: LIST COMMANDS oob out: (COMMANDS, (SEND, REPORT, LIST, ...) """ mode = mode.upper() if mode == "COMMANDS": session.msg(oob=("COMMANDS", ("LIST", "REPORT", "UNREPORT", # "RESET", "SEND"))) elif mode == "REPORTABLE_VARIABLES": session.msg(oob=("REPORTABLE_VARIABLES", tuple(key for key in OOB_REPORTABLE.keys()))) elif mode == "REPORTED_VARIABLES": # we need to check so as to use the right return value depending on if it is # an Attribute (identified by tracking the db_value field) or a normal database field # reported is a list of tuples (obj, propname, args, kwargs) reported = OOB_HANDLER.get_all_monitors(session) reported = [rep[0].key if rep[1] == "db_value" else rep[1] for rep in reported] session.msg(oob=("REPORTED_VARIABLES", reported)) elif mode == "SENDABLE_VARIABLES": session.msg(oob=("SENDABLE_VARIABLES", tuple(key for key in OOB_REPORTABLE.keys()))) elif mode == "CONFIGURABLE_VARIABLES": # Not implemented (game specific) oob_error(session, "Not implemented (game specific)") else: # mode == "LISTS" or not given session.msg(oob=("LISTS",("REPORTABLE_VARIABLES", "REPORTED_VARIABLES", # "CONFIGURABLE_VARIABLES", "SENDABLE_VARIABLES")))
def shutdown(self, mode=None, _reactor_stopping=False): """ Shuts down the server from inside it. mode - sets the server restart mode. 'reload' - server restarts, no "persistent" scripts are stopped, at_reload hooks called. 'reset' - server restarts, non-persistent scripts stopped, at_shutdown hooks called. 'shutdown' - like reset, but server will not auto-restart. None - keep currently set flag from flag file. _reactor_stopping - this is set if server is stopped by a kill command OR this method was already called once - in both cases the reactor is dead/stopping already. """ if _reactor_stopping and hasattr(self, "shutdown_complete"): # this means we have already passed through this method # once; we don't need to run the shutdown procedure again. defer.returnValue(None) mode = self.set_restart_mode(mode) # call shutdown hooks on all cached objects from evennia.objects.models import ObjectDB #from evennia.players.models import PlayerDB from evennia.server.models import ServerConfig if mode == 'reload': # call restart hooks yield [ o.at_server_reload() for o in ObjectDB.get_all_cached_instances() ] yield [ p.at_server_reload() for p in PlayerDB.get_all_cached_instances() ] yield [(s.pause(), s.at_server_reload()) for s in ScriptDB.get_all_cached_instances()] yield self.sessions.all_sessions_portal_sync() ServerConfig.objects.conf("server_restart_mode", "reload") from evennia.server.oobhandler import OOB_HANDLER OOB_HANDLER.save() from evennia.scripts.tickerhandler import TICKER_HANDLER TICKER_HANDLER.save() self.at_server_reload_stop() else: if mode == 'reset': # don't unset the is_connected flag on reset, otherwise # same as shutdown yield [ o.at_server_shutdown() for o in ObjectDB.get_all_cached_instances() ] yield [ p.at_server_shutdown() for p in PlayerDB.get_all_cached_instances() ] else: # shutdown yield [ _SA(p, "is_connected", False) for p in PlayerDB.get_all_cached_instances() ] yield [ o.at_server_shutdown() for o in ObjectDB.get_all_cached_instances() ] yield [(p.unpuppet_all(), p.at_server_shutdown()) for p in PlayerDB.get_all_cached_instances()] yield [ s.at_server_shutdown() for s in ScriptDB.get_all_cached_instances() ] yield ObjectDB.objects.clear_all_sessids() ServerConfig.objects.conf("server_restart_mode", "reset") self.at_server_cold_stop() self.at_server_stop() # if _reactor_stopping is true, reactor does not need to # be stopped again. if os.name == 'nt' and os.path.exists(SERVER_PIDFILE): # for Windows we need to remove pid files manually os.remove(SERVER_PIDFILE) if not _reactor_stopping: # this will also send a reactor.stop signal, so we set a # flag to avoid loops. self.shutdown_complete = True reactor.callLater(0, reactor.stop)
def shutdown(self, mode=None, _reactor_stopping=False): """ Shuts down the server from inside it. mode - sets the server restart mode. 'reload' - server restarts, no "persistent" scripts are stopped, at_reload hooks called. 'reset' - server restarts, non-persistent scripts stopped, at_shutdown hooks called but sessions will not be disconnected. 'shutdown' - like reset, but server will not auto-restart. None - keep currently set flag from flag file. _reactor_stopping - this is set if server is stopped by a kill command OR this method was already called once - in both cases the reactor is dead/stopping already. """ if _reactor_stopping and hasattr(self, "shutdown_complete"): # this means we have already passed through this method # once; we don't need to run the shutdown procedure again. defer.returnValue(None) mode = self.set_restart_mode(mode) from evennia.objects.models import ObjectDB #from evennia.players.models import PlayerDB from evennia.server.models import ServerConfig if mode == 'reload': # call restart hooks ServerConfig.objects.conf("server_restart_mode", "reload") yield [o.at_server_reload() for o in ObjectDB.get_all_cached_instances()] yield [p.at_server_reload() for p in PlayerDB.get_all_cached_instances()] yield [(s.pause(), s.at_server_reload()) for s in ScriptDB.get_all_cached_instances()] yield self.sessions.all_sessions_portal_sync() self.at_server_reload_stop() # only save OOB state on reload, not on shutdown/reset from evennia.server.oobhandler import OOB_HANDLER OOB_HANDLER.save() else: if mode == 'reset': # like shutdown but don't unset the is_connected flag and don't disconnect sessions yield [o.at_server_shutdown() for o in ObjectDB.get_all_cached_instances()] yield [p.at_server_shutdown() for p in PlayerDB.get_all_cached_instances()] if self.amp_protocol: yield self.sessions.all_sessions_portal_sync() else: # shutdown yield [_SA(p, "is_connected", False) for p in PlayerDB.get_all_cached_instances()] yield [o.at_server_shutdown() for o in ObjectDB.get_all_cached_instances()] yield [(p.unpuppet_all(), p.at_server_shutdown()) for p in PlayerDB.get_all_cached_instances()] yield ObjectDB.objects.clear_all_sessids() yield [(s.pause(), s.at_server_reload()) for s in ScriptDB.get_all_cached_instances()] ServerConfig.objects.conf("server_restart_mode", "reset") self.at_server_cold_stop() # tickerhandler state should always be saved. from evennia.scripts.tickerhandler import TICKER_HANDLER TICKER_HANDLER.save() # always called, also for a reload self.at_server_stop() # if _reactor_stopping is true, reactor does not need to # be stopped again. if os.name == 'nt' and os.path.exists(SERVER_PIDFILE): # for Windows we need to remove pid files manually os.remove(SERVER_PIDFILE) if not _reactor_stopping: # this will also send a reactor.stop signal, so we set a # flag to avoid loops. self.shutdown_complete = True # kill the server reactor.callLater(0, reactor.stop)