def __delattr__(self, propname): """ Transparently deletes data from the typeclass or dbobj by first searching on the typeclass, secondly on the dbobj.db. Will not allow deletion of properties stored directly on dbobj. """ if propname in PROTECTED: string = "%s: '%s' is a protected attribute name." string += " (protected: [%s])" % (", ".join(PROTECTED)) log_errmsg(string % (self.name, propname)) return try: _DA(self, propname) except AttributeError: # not on typeclass, try to delete on db/ndb try: dbobj = _GA(self, 'dbobj') except AttributeError: log_trace("This is probably due to an unsafe reload.") return # ignore delete try: dbobj.del_attribute_raise(propname) except AttributeError: string = "Object: '%s' not found on %s(#%s), nor on its typeclass %s." raise AttributeError(string % (propname, dbobj, dbobj.dbid, dbobj.typeclass_path,))
def __getattribute__(self, propname): """ Change the normal property access to transparently include the properties on self.dbobj. Note that dbobj properties have priority, so if you define a same-named property on the class, it will NOT be accessible through getattr. """ if propname == 'dbobj': return _GA(self, 'dbobj') if propname.startswith('__') and propname.endswith('__'): # python specials are parsed as-is (otherwise things like # isinstance() fail to identify the typeclass) return _GA(self, propname) #print "get %s (dbobj:%s)" % (propname, type(dbobj)) try: return _GA(self, propname) except AttributeError: try: dbobj = _GA(self, 'dbobj') except AttributeError: log_trace("Typeclass CRITICAL ERROR! dbobj not found for Typeclass %s!" % self) raise try: return _GA(dbobj, propname) except AttributeError: try: #XXX deprecated return _GA(dbobj,"get_attribute_raise")(propname) except AttributeError: string = "Object: '%s' not found on %s(#%s), nor on its typeclass %s." raise AttributeError(string % (propname, dbobj, _GA(dbobj, "dbid"), _GA(dbobj, "typeclass_path")))
def _create_character(session, new_player, typeclass, start_location, home, permissions): """ Helper function, creates a character based on a player's name. This is meant for Guest and MULTISESSION_MODE < 2 situations. """ try: if not start_location: start_location = home # fallback new_character = create.create_object(typeclass, key=new_player.key, location=start_location, home=home, permissions=permissions) # set playable character list new_player.db._playable_characters.append(new_character) # allow only the character itself and the player to puppet this character (and Immortals). new_character.locks.add("puppet:id(%i) or pid(%i) or perm(Immortals) or pperm(Immortals)" % (new_character.id, new_player.id)) # If no description is set, set a default description if not new_character.db.desc: new_character.db.desc = "This is a Player." # We need to set this to have @ic auto-connect to this character new_player.db._last_puppet = new_character except Exception, e: session.msg("There was an error creating the Character:\n%s\n If this problem persists, contact an admin." % e) logger.log_trace() return False
def _get_local_obj_cmdsets(obj, obj_cmdset): "Object-level cmdsets" # Gather cmdsets from location, objects in location or carried local_obj_cmdsets = [None] try: location = obj.location except Exception: location = None if location and not obj_cmdset.no_objs: # Gather all cmdsets stored on objects in the room and # also in the caller's inventory and the location itself local_objlist = yield (location.contents_get(exclude=obj.dbobj) + obj.contents + [location]) for lobj in local_objlist: try: # call hook in case we need to do dynamic changing to cmdset _GA(lobj, "at_cmdset_get")() except Exception: logger.log_trace() # the call-type lock is checked here, it makes sure a player # is not seeing e.g. the commands on a fellow player (which is why # the no_superuser_bypass must be True) local_obj_cmdsets = \ yield [lobj.cmdset.current for lobj in local_objlist if (lobj.cmdset.current and lobj.locks.check(caller, 'call', no_superuser_bypass=True))] for cset in local_obj_cmdsets: #This is necessary for object sets, or we won't be able to # separate the command sets from each other in a busy room. cset.old_duplicates = cset.duplicates cset.duplicates = True returnValue(local_obj_cmdsets)
def create_help_entry(key, entrytext, category="General", locks=None): """ Create a static help entry in the help database. Note that Command help entries are dynamic and directly taken from the __doc__ entries of the command. The database-stored help entries are intended for more general help on the game, more extensive info, in-game setting information and so on. """ global _HelpEntry if not _HelpEntry: from src.help.models import HelpEntry as _HelpEntry try: new_help = _HelpEntry() new_help.key = key new_help.entrytext = entrytext new_help.help_category = category if locks: new_help.locks.add(locks) new_help.save() return new_help except IntegrityError: string = "Could not add help entry: key '%s' already exists." % key logger.log_errmsg(string) return None except Exception: logger.log_trace() return None
def __getattribute__(self, propname): """ Change the normal property access to transparently include the properties on self.dbobj. Note that dbobj properties have priority, so if you define a same-named property on the class, it will NOT be accessible through getattr. """ if propname.startswith('__') and propname.endswith('__'): # python specials are parsed as-is (otherwise things like # isinstance() fail to identify the typeclass) return _GA(self, propname) #print "get %s (dbobj:%s)" % (propname, type(dbobj)) try: return _GA(self, propname) except AttributeError: try: dbobj = _GA(self, 'dbobj') except AttributeError: log_trace( "Typeclass CRITICAL ERROR! dbobj not found for Typeclass %s!" % self) raise try: return _GA(dbobj, propname) except AttributeError: string = "Object: '%s' not found on %s(#%s), nor on its typeclass %s." raise AttributeError( string % (propname, dbobj, _GA( dbobj, "dbid"), _GA(dbobj, "typeclass_path")))
def dataReceived(self, string): """ Method called when data is coming in over the websocket connection. Type of data is identified by a 3-character prefix. OOB - This is an Out-of-band instruction. If so, the remaining string should be a json-packed string on the form {oobfuncname: [args, ], ...} any other prefix (or lack of prefix) is considered plain text data, to be treated like a game input command. """ if string[:3] == "OOB": string = string[3:] try: oobdata = json.loads(string) for (key, args) in oobdata.items(): #print "oob data in:", (key, args) self.data_in(text=None, oob=(key, make_iter(args))) except Exception: log_trace("Websocket malformed OOB request: %s" % string) else: # plain text input self.data_in(text=string)
def data_out(self, string='', data=None): """ Data Evennia -> Player access hook. data argument may be used depending on the client-server implementation. """ if data: # treat data? pass # string handling is similar to telnet try: string = utils.to_str(string, encoding=self.encoding) nomarkup = False raw = False if type(data) == dict: # check if we want escape codes to go through unparsed. raw = data.get("raw", False) # check if we want to remove all markup nomarkup = data.get("nomarkup", False) if raw: self.client.lineSend(self.suid, string) else: self.client.lineSend(self.suid, parse_html(string, strip_ansi=nomarkup)) return except Exception, e: logger.log_trace()
def dataReceived(self, data): """ This method will split the incoming data depending on if it starts with IAC (a telnet command) or not. All other data will be handled in line mode. Some clients also sends an erroneous line break after IAC, which we must watch out for. """ #print "dataRcv (%s):" % data, #try: # for b in data: # print ord(b), # print "" #except Exception, e: # print str(e) + ":", str(data) if data and data[0] == IAC or self.iaw_mode: try: #print "IAC mode" super(TelnetProtocol, self).dataReceived(data) if len(data) == 1: self.iaw_mode = True else: self.iaw_mode = False return except Exception: logger.log_trace() # if we get to this point the command must end with a linebreak. # We make sure to add it, to fix some clients messing this up. data = data.rstrip("\r\n") + "\n" #print "line data in:", repr(data) StatefulTelnetProtocol.dataReceived(self, data)
def dataReceived(self, data): """ This method will split the incoming data depending on if it starts with IAC (a telnet command) or not. All other data will be handled in line mode. Some clients also sends an erroneous line break after IAC, which we must watch out for. OOB protocols (MSDP etc) already intercept subnegotiations on their own, never entering this method. They will relay their parsed data directly to self.data_in. """ if data and data[0] == IAC or self.iaw_mode: try: #print "IAC mode" super(TelnetProtocol, self).dataReceived(data) if len(data) == 1: self.iaw_mode = True else: self.iaw_mode = False return except Exception, err1: conv = "" try: for b in data: conv += " " + repr(ord(b)) except Exception, err2: conv = str(err2) + ":", str(data) out = "Telnet Error (%s): %s (%s)" % (err1, data, conv) logger.log_trace(out) return
def __delattr__(self, propname): """ Transparently deletes data from the typeclass or dbobj by first searching on the typeclass, secondly on the dbobj.db. Will not allow deletion of properties stored directly on dbobj. """ if propname in PROTECTED: string = "%s: '%s' is a protected attribute name." string += " (protected: [%s])" % (", ".join(PROTECTED)) log_errmsg(string % (self.name, propname)) return try: _DA(self, propname) except AttributeError: # not on typeclass, try to delete on db/ndb try: dbobj = _GA(self, 'dbobj') except AttributeError: log_trace("This is probably due to an unsafe reload.") return # ignore delete try: dbobj.del_attribute(propname, raise_exception=True) except AttributeError: string = "Object: '%s' not found on %s(#%s), nor on its typeclass %s." raise AttributeError(string % ( propname, dbobj, dbobj.dbid, dbobj.typeclass_path, ))
def dataReceived(self, string): """ Method called when data is coming in over the websocket connection. Type of data is identified by a 3-character prefix. OOB - This is an Out-of-band instruction. If so, the remaining string should be a json-packed string on the form {oobfuncname: [[args], {kwargs}], ...} any other prefix (or lack of prefix) is considered plain text data, to be treated like a game input command. """ if string[:3] == "OOB": string = string[3:] try: oobdata = json.loads(string) for (key, argstuple) in oobdata.items(): args = argstuple[0] if argstuple else [] kwargs = argstuple[1] if len(argstuple) > 1 else {} self.data_in(oob=(key, args, kwargs)) except Exception: log_trace("Websocket malformed OOB request: %s" % string) else: # plain text input self.data_in(text=string)
def _step_task(self): "Step task. This groups error handling." try: return maybeDeferred(self._step_callback).addErrback( self._step_errback) except Exception: logger.log_trace()
def __setattr__(self, propname, value): """ Transparently save data to the dbobj object in all situations. Note that this does not necessarily mean storing it to the database unless data is stored into a propname corresponding to a field on ObjectDB model. """ #print "set %s -> %s" % (propname, value) if propname in PROTECTED: string = "%s: '%s' is a protected attribute name." string += " (protected: [%s])" % (", ".join(PROTECTED)) log_errmsg(string % (self.name, propname)) return try: dbobj = _GA(self, 'dbobj') except AttributeError: dbobj = None log_trace("This is probably due to an unsafe reload.") if dbobj: try: # only set value on propname if propname already exists # on dbobj. __getattribute__ will raise attribute error otherwise. _GA(dbobj, propname) _SA(dbobj, propname, value) except AttributeError: #XXX deprecated dbobj.set_attribute(propname, value) else: _SA(self, propname, value)
def _parse_lockstring(self, storage_lockstring): """ Helper function. This is normally only called when the lockstring is cached and does preliminary checking. locks are stored as a string 'atype:[NOT] lock()[[ AND|OR [NOT] lock()[...]];atype... """ locks = {} if not storage_lockstring: return locks duplicates = 0 elist = [] # errors wlist = [] # warnings for raw_lockstring in storage_lockstring.split(';'): lock_funcs = [] try: access_type, rhs = (part.strip() for part in raw_lockstring.split(':', 1)) except ValueError: logger.log_trace() return locks # parse the lock functions and separators funclist = _RE_FUNCS.findall(rhs) evalstring = rhs for pattern in ('AND', 'OR', 'NOT'): evalstring = re.sub(r"\b%s\b" % pattern, pattern.lower(), evalstring) nfuncs = len(funclist) for funcstring in funclist: funcname, rest = (part.strip().strip(')') for part in funcstring.split('(', 1)) func = _LOCKFUNCS.get(funcname, None) if not callable(func): elist.append(_("Lock: function '%s' is not available.") % funcstring) continue args = list(arg.strip() for arg in rest.split(',') if arg and not '=' in arg) kwargs = dict([arg.split('=', 1) for arg in rest.split(',') if arg and '=' in arg]) lock_funcs.append((func, args, kwargs)) evalstring = evalstring.replace(funcstring, '%s') if len(lock_funcs) < nfuncs: continue try: # purge the eval string of any superfluous items, then test it evalstring = " ".join(_RE_OK.findall(evalstring)) eval(evalstring % tuple(True for func in funclist), {}, {}) except Exception: elist.append(_("Lock: definition '%s' has syntax errors.") % raw_lockstring) continue if access_type in locks: duplicates += 1 wlist.append(_("Lock: access type '%(access_type)s' changed from '%(source)s' to '%(goal)s' " % \ {"access_type":access_type, "source":locks[access_type][2], "goal":raw_lockstring})) locks[access_type] = (evalstring, tuple(lock_funcs), raw_lockstring) if wlist and self.log_obj: # a warning text was set, it's not an error, so only report if log_obj is available. self._log_error("\n".join(wlist)) if elist: # an error text was set, raise exception. raise LockException("\n".join(elist)) # return the gathered locks in an easily executable form return locks
def _callback(self, oobhandler, sessions): "See original for more info" for key, (_, args, kwargs) in self.subscriptions.items(): session = sessions.session_from_sessid(kwargs.get("sessid")) try: oobhandler.execute_cmd(session, kwargs.get("func_key"), *args, **kwargs) except Exception: logger.log_trace()
def _stop_task(self): "stop task runner" try: #print "stopping twisted task:", id(self.ndb.twisted_task), self.obj if self.ndb.twisted_task and self.ndb.twisted_task.running: self.ndb.twisted_task.stop() except Exception: logger.log_trace()
def msdp_cmd_reset(self, arg): """ The reset command resets a variable to its initial state. """ try: MSDP_REPORTABLE[arg](reset=True) except Exception: logger.log_trace()
def _step_task(self): "step task" try: d = maybeDeferred(self._step_succ_callback) d.addErrback(self._step_err_callback) return d except Exception: logger.log_trace()
def save(): "Force save of time. This is called by server when shutting down/reloading." from src.scripts.models import ScriptDB try: script = ScriptDB.objects.get(db_key=GAMETIME_SCRIPT_NAME) script.at_repeat() except Exception: from src.utils import logger logger.log_trace()
def at_repeat(self): """ Loops through all subs, calling their given function """ for func, args, kwargs in self.subs: try: func(*args, **kwargs) except Exception: logger.log_trace()
def update(self, fieldname, new_value): """ Called by the field when it updates to a new value """ for tracker in self.tracktargets[fieldname].values(): try: tracker.update(new_value) except Exception: logger.log_trace()
def import_cmdset(python_path, cmdsetobj, emit_to_obj=None, no_logging=False): """ This helper function is used by the cmdsethandler to load a cmdset instance from a python module, given a python_path. It's usually accessed through the cmdsethandler's add() and add_default() methods. python_path - This is the full path to the cmdset object. cmdsetobj - the database object/typeclass on which this cmdset is to be assigned (this can be also channels and exits, as well as players but there will always be such an object) emit_to_obj - if given, error is emitted to this object (in addition to logging) no_logging - don't log/send error messages. This can be useful if import_cmdset is just used to check if this is a valid python path or not. function returns None if an error was encountered or path not found. """ try: try: #print "importing %s: _CACHED_CMDSETS=%s" % (python_path, _CACHED_CMDSETS) wanted_cache_key = python_path cmdsetclass = _CACHED_CMDSETS.get(wanted_cache_key, None) errstring = "" if not cmdsetclass: #print "cmdset '%s' not in cache. Reloading %s on %s." % (wanted_cache_key, python_path, cmdsetobj) # Not in cache. Reload from disk. modulepath, classname = python_path.rsplit('.', 1) module = __import__(modulepath, fromlist=[True]) cmdsetclass = module.__dict__[classname] _CACHED_CMDSETS[wanted_cache_key] = cmdsetclass #instantiate the cmdset (and catch its errors) if callable(cmdsetclass): cmdsetclass = cmdsetclass(cmdsetobj) return cmdsetclass except ImportError: errstring = _("Error loading cmdset: Couldn't import module '%s'.") errstring = errstring % modulepath raise except KeyError: errstring = _("Error in loading cmdset: No cmdset class '%(classname)s' in %(modulepath)s.") errstring = errstring % {"classname": classname, "modulepath": modulepath} raise except Exception: errstring = _("Compile/Run error when loading cmdset '%s'. Error was logged.") errstring = errstring % (python_path) raise except Exception: # returning an empty error cmdset if not no_logging: logger.log_trace(errstring) if emit_to_obj and not ServerConfig.objects.conf("server_starting_mode"): object.__getattribute__(emit_to_obj, "msg")(errstring) err_cmdset = _ErrorCmdSet() err_cmdset.errmessage = errstring return err_cmdset
def msdp_cmd_report(self, *arg): """ The report command instructs the server to start reporting a reportable variable to the client. """ try: MSDP_REPORTABLE[arg](report=True) except Exception: logger.log_trace()
def _callback(self): "See original for more info" for key, (_, args, kwargs) in self.subscriptions.items(): # args = (sessid, callback_function) session = SESSIONS.session_from_sessid(args[0]) try: # execute the oob callback yield args[1](OOB_HANDLER, session, *args[2:], **kwargs) except Exception: logger.log_trace()
def _get_cmdset(obj): "Get cmdset, triggering all hooks" try: yield obj.at_cmdset_get() except Exception: logger.log_trace() try: returnValue(obj.cmdset.current) except AttributeError: returnValue(None)
def at_post_login(self): """ This recovers the character again after having been "stoved away" at disconnect. """ global _CONNECT_CHANNEL if not _CONNECT_CHANNEL: try: _CONNECT_CHANNEL = Channel.objects.filter(db_key=settings.CHANNEL_CONNECTINFO[0])[0] except Exception, e: logger.log_trace()
def at_disconnect(self): """ We stove away the character when logging off, otherwise the character object will remain in the room also after the player logged off ("headless", so to say). """ global _CONNECT_CHANNEL if not _CONNECT_CHANNEL: try: _CONNECT_CHANNEL = Channel.objects.filter(db_key=settings.CHANNEL_CONNECTINFO[0])[0] except Exception, e: logger.log_trace()
def import_cmdset(path, cmdsetobj, emit_to_obj=None, no_logging=False): """ This helper function is used by the cmdsethandler to load a cmdset instance from a python module, given a python_path. It's usually accessed through the cmdsethandler's add() and add_default() methods. path - This is the full path to the cmdset object on python dot-form cmdsetobj - the database object/typeclass on which this cmdset is to be assigned (this can be also channels and exits, as well as players but there will always be such an object) emit_to_obj - if given, error is emitted to this object (in addition to logging) no_logging - don't log/send error messages. This can be useful if import_cmdset is just used to check if this is a valid python path or not. function returns None if an error was encountered or path not found. """ python_paths = [path] + [ "%s.%s" % (prefix, path) for prefix in _CMDSET_PATHS if not path.startswith(prefix) ] errstring = "" for python_path in python_paths: try: #print "importing %s: _CACHED_CMDSETS=%s" % (python_path, _CACHED_CMDSETS) wanted_cache_key = python_path cmdsetclass = _CACHED_CMDSETS.get(wanted_cache_key, None) errstring = "" if not cmdsetclass: #print "cmdset '%s' not in cache. Reloading %s on %s." % (wanted_cache_key, python_path, cmdsetobj) # Not in cache. Reload from disk. modulepath, classname = python_path.rsplit('.', 1) module = __import__(modulepath, fromlist=[True]) cmdsetclass = module.__dict__[classname] _CACHED_CMDSETS[wanted_cache_key] = cmdsetclass #instantiate the cmdset (and catch its errors) if callable(cmdsetclass): cmdsetclass = cmdsetclass(cmdsetobj) return cmdsetclass except ImportError, e: logger.log_trace() errstring += _("Error loading cmdset '%s': %s.") errstring = errstring % (modulepath, e) except KeyError: logger.log_trace() errstring += _( "Error in loading cmdset: No cmdset class '%(classname)s' in %(modulepath)s." ) errstring = errstring % { "classname": classname, "modulepath": modulepath }
def _create_player(session, playername, password, default_home, permissions, typeclass=None): """ Helper function, creates a player of the specified typeclass. """ try: new_player = create.create_player(playername, None, password, permissions=permissions, typeclass=typeclass) except Exception, e: session.msg("There was an error creating the Player:\n%s\n If this problem persists, contact an admin." % e) logger.log_trace() return False
def obj_set(self, value): "Setter. Allows for self.obj = value" global _TYPECLASS if not _TYPECLASS: from src.typeclasses.typeclass import TypeClass as _TYPECLASS if isinstance(value, _TYPECLASS): value = value.dbobj try: set_field_cache(self, "obj", value) except Exception: logger.log_trace() raise Exception("Cannot assign %s as a player object!" % value)
def msdp_cmd_send(self, arg): """ Request the server to send a particular variable to the client. arg - this is a list of variables the client wants. """ ret = [] for var in make_iter(arg): try: ret.append(MSDP_REPORTABLE[arg](send=True)) except Exception: logger.log_trace() return ret
def check_captcha(request): """ Google ReCaptcha validation process """ payload = { 'secret': ini.config('RECAPTCHA','recaptcha_secret_key'), 'response': request.form['g-recaptcha-response'], 'remoteip': request.remote_addr } resp = requests.post('https://www.google.com/recaptcha/api/siteverify', params=payload) data = json.loads(resp.text) if not data['success']: logger.log_trace("from validator: {0} may be a bot !".format(request.remote_addr)) return data['success']
def _send_to_connect_channel(self, message): "Helper method for loading the default comm channel" global _CONNECT_CHANNEL if not _CONNECT_CHANNEL: try: _CONNECT_CHANNEL = Channel.objects.filter(db_key=settings.CHANNEL_CONNECTINFO[0])[0] except Exception: logger.log_trace() now = datetime.datetime.now() now = "%02i-%02i-%02i(%02i:%02i)" % (now.year, now.month, now.day, now.hour, now.minute) if _CONNECT_CHANNEL: _CONNECT_CHANNEL.tempmsg("[%s, %s]: %s" % (_CONNECT_CHANNEL.key, now, message)) else: logger.log_infomsg("[%s]: %s" % (now, message))
def uptime(format=False): """ Get the actual time the server has been running since last downtime. """ try: script = ScriptDB.objects.get_all_scripts(GAME_TIME_SCRIPT)[0] except (KeyError, IndexError): logger.log_trace("GameTime script not found.") return # we return this as an integer (second-precision is good enough) up_time = int(script.attr("up_time")) if format: return realtime_format(up_time) return up_time
def msg(self, text=None, from_obj=None, sessid=0, **kwargs): """ Emits something to a session attached to the object. message (str): The message to send from_obj (obj): object that is sending. data (object): an optional data object that may or may not be used by the protocol. sessid (int): sessid to relay to, if any. If set to 0 (default), use either from_obj.sessid (if set) or self.sessid automatically If None, echo to all connected sessions When this message is called, from_obj.at_msg_send and self.at_msg_receive are called. """ global _SESSIONS if not _SESSIONS: from src.server.sessionhandler import SESSIONS as _SESSIONS text = to_str(text, force_string=True) if text else "" if "data" in kwargs: # deprecation warning logger.log_depmsg( "ObjectDB.msg(): 'data'-dict keyword is deprecated. Use **kwargs instead." ) data = kwargs.pop("data") if isinstance(data, dict): kwargs.update(data) if from_obj: # call hook try: _GA(from_obj, "at_msg_send")(text=text, to_obj=_GA(self, "typeclass"), **kwargs) except Exception: logger.log_trace() try: if not _GA(_GA(self, "typeclass"), "at_msg_receive")(text=text, **kwargs): # if at_msg_receive returns false, we abort message to this object return except Exception: logger.log_trace() sessions = _SESSIONS.session_from_sessid( [sessid] if sessid else make_iter(_GA(self, "sessid").get())) for session in sessions: session.msg(text=text, **kwargs)
def _send_to_connect_channel(self, message): "Helper method for loading the default comm channel" global _CONNECT_CHANNEL if not _CONNECT_CHANNEL: try: _CONNECT_CHANNEL = ChannelDB.objects.filter(db_key=settings.CHANNEL_CONNECTINFO[0])[0] except Exception: logger.log_trace() now = datetime.datetime.now() now = "%02i-%02i-%02i(%02i:%02i)" % (now.year, now.month, now.day, now.hour, now.minute) if _CONNECT_CHANNEL: _CONNECT_CHANNEL.tempmsg("[%s, %s]: %s" % (_CONNECT_CHANNEL.key, now, message)) else: logger.log_infomsg("[%s]: %s" % (now, message))
def unpause(self): """ Restart a paused script. This WILL call the at_start() hook. """ if self.db._paused_time: # only unpause if previously paused self.dbobj.is_active = True try: self.at_start() except Exception: logger.log_trace() self._start_task() return True
def remove(self, fieldname, trackerclass, *args, **kwargs): """ Remove identified tracker from TrackerHandler. Raises KeyError if tracker is not found. """ trackerkey = trackerclass.__name__ tracker = self.tracktargets[fieldname][trackerkey] try: tracker.at_remove(*args, **kwargs) except Exception: logger.log_trace() del self.tracktargets[fieldname][trackerkey] self.ntrackers -= 1 if self.ntrackers <= 0: # if there are no more trackers, clean this handler del self
def distribute_message(self, msg, online=False): """ Method for grabbing all listeners that a message should be sent to on this channel, and sending them a message. """ # get all players connected to this channel and send to them for player in self.dbobj.db_subscriptions.all(): player = player.typeclass try: # note our addition of the from_channel keyword here. This could be checked # by a custom player.msg() to treat channel-receives differently. player.msg(msg.message, from_obj=msg.senders, from_channel=self.id) except AttributeError, e: logger.log_trace("%s\nCannot send msg to player '%s'." % (e, player))
def execute_cmd(self, session, func_key, *args, **kwargs): """ Retrieve oobfunc from OOB_FUNCS and execute it immediately using *args and **kwargs """ try: #print "OOB execute_cmd:", session, func_key, args, kwargs, _OOB_FUNCS.keys() oobfunc = _OOB_FUNCS[func_key] # raise traceback if not found oobfunc(self, session, *args, **kwargs) except KeyError, e: errmsg = "OOB Error: function '%s' not recognized: %s" % (func_key, e) if _OOB_ERROR: _OOB_ERROR(self, session, errmsg, *args, **kwargs) else: logger.log_trace(errmsg) raise KeyError(errmsg)
def _callback(self): """ This will be called repeatedly every self.interval seconds. self.subscriptions contain tuples of (obj, args, kwargs) for each subscribing object. If overloading, this callback is expected to handle all subscriptions when it is triggered. It should not return anything and should not traceback on poorly designed hooks. The callback should ideally work under @inlineCallbacks so it can yield appropriately. """ for key, (obj, args, kwargs) in self.subscriptions.items(): hook_key = yield kwargs.get("hook_key", "at_tick") try: yield _GA(obj, hook_key)(*args, **kwargs) except Exception: log_trace()
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 of if it has started before. returns 0 or 1 to indicated the script has been started or not. Used in counting. """ #print "Script %s (%s) start (active:%s, force:%s) ..." % (self.key, id(self.dbobj), # self.is_active, force_restart) if self.dbobj.is_active and not force_restart: # script already runs and should not be restarted. return 0 obj = self.obj if obj: # check so the scripted object is valid and initalized try: _GA(obj.dbobj, 'cmdset') except AttributeError: # this means the object is not initialized. logger.log_trace() self.dbobj.is_active = False return 0 # try to restart a paused script if self.unpause(): return 1 # start the script from scratch self.dbobj.is_active = True try: self.at_start() except Exception: logger.log_trace() if self.dbobj.db_interval > 0: self._start_task() return 1
def execute_cmd(self, session, func_key, *args, **kwargs): """ Retrieve oobfunc from OOB_FUNCS and execute it immediately using *args and **kwargs """ oobfunc = _OOB_FUNCS.get(func_key, None) if not oobfunc: # function not found errmsg = "OOB Error: function '%s' not recognized." % func_key if _OOB_ERROR: _OOB_ERROR(self, session, errmsg, *args, **kwargs) logger.log_trace() else: logger.log_trace(errmsg) return # execute the found function try: #print "OOB execute_cmd:", session, func_key, args, kwargs, _OOB_FUNCS.keys() oobfunc(self, session, *args, **kwargs) except Exception, err: errmsg = "OOB Error: Exception in '%s'(%s, %s):\n%s" % ( func_key, args, kwargs, err) if _OOB_ERROR: _OOB_ERROR(self, session, errmsg, *args, **kwargs) logger.log_trace(errmsg) raise Exception(errmsg)
def data_out(self, text=None, **kwargs): """ Data Evennia -> Player access hook. webclient flags checked are raw=True - no parsing at all (leave ansi-to-html markers unparsed) nomarkup=True - clean out all ansi/html markers and tokens """ # string handling is similar to telnet try: text = utils.to_str(text if text else "", encoding=self.encoding) raw = kwargs.get("raw", False) nomarkup = kwargs.get("nomarkup", False) if raw: self.client.lineSend(self.suid, text) else: self.client.lineSend(self.suid, parse_html(text, strip_ansi=nomarkup)) return except Exception: logger.log_trace()
def __setattr__(self, propname, value): """ Transparently save data to the dbobj object in all situations. Note that this does not necessarily mean storing it to the database. """ #print "set %s -> %s" % (propname, value) if propname in PROTECTED: string = "%s: '%s' is a protected attribute name." string += " (protected: [%s])" % (", ".join(PROTECTED)) log_errmsg(string % (self.name, propname)) return try: dbobj = _GA(self, 'dbobj') except AttributeError: dbobj = None log_trace("This is probably due to an unsafe reload.") if dbobj: _SA(dbobj, propname, value) else: # only as a last resort do we save on the typeclass object _SA(self, propname, value)
def stop(self, kill=False): """ Called to stop the script from running. This also deletes the script. kill - don't call finishing hooks. """ #print "stopping script %s" % self.key #import pdb #pdb.set_trace() if not kill: try: self.at_stop() except Exception: logger.log_trace() self._stop_task() try: self.dbobj.delete() except AssertionError: logger.log_trace() return 0 return 1
def logerr(string=""): trc = traceback.format_exc() errstring = "%s%s" % (trc, string) logger.log_trace() _GA(self, "msg")(errstring)
def move_to(self, destination, quiet=False, emit_to_obj=None, use_destination=True, to_none=False): """ Moves this object to a new location. Moves this object to a new location. Note that if <destination> is an exit object (i.e. it has "destination"!=None), the move_to will happen to this destination and -not- into the exit object itself, unless use_destination=False. Note that no lock checks are done by this function, such things are assumed to have been handled before calling move_to. destination: (Object) Reference to the object to move to. This can also be an exit object, in which case the destination property is used as destination. quiet: (bool) If true, don't emit left/arrived messages. emit_to_obj: (Object) object to receive error messages use_destination (bool): Default is for objects to use the "destination" property of destinations as the target to move to. Turning off this keyword allows objects to move "inside" exit objects. to_none - allow destination to be None. Note that no hooks are run when moving to a None location. If you want to run hooks, run them manually (and make sure they can manage None locations). Returns True/False depending on if there were problems with the move. This method may also return various error messages to the emit_to_obj. """ def logerr(string=""): trc = traceback.format_exc() errstring = "%s%s" % (trc, string) logger.log_trace() _GA(self, "msg")(errstring) errtxt = _("Couldn't perform move ('%s'). Contact an admin.") if not emit_to_obj: emit_to_obj = self if not destination: if to_none: # immediately move to None. There can be no hooks called since # there is no destination to call them with. self.location = None return True emit_to_obj.msg(_("The destination doesn't exist.")) return if destination.destination and use_destination: # traverse exits destination = destination.destination # Before the move, call eventual pre-commands. try: if not self.at_before_move(_GA(destination, "typeclass")): return except Exception: logerr(errtxt % "at_before_move()") #emit_to_obj.msg(errtxt % "at_before_move()") #logger.log_trace() return False # Save the old location source_location = _GA(self, "location") if not source_location: # there was some error in placing this room. # we have to set one or we won't be able to continue if _GA(self, "home"): source_location = _GA(self, "home") else: default_home = ObjectDB.objects.get_id(settings.DEFAULT_HOME) source_location = default_home # Call hook on source location try: source_location.at_object_leave(_GA(self, "typeclass"), _GA(destination, "typeclass")) except Exception: logerr(errtxt % "at_object_leave()") #emit_to_obj.msg(errtxt % "at_object_leave()") #logger.log_trace() return False if not quiet: #tell the old room we are leaving try: self.announce_move_from(_GA(destination, "typeclass")) except Exception: logerr(errtxt % "at_announce_move()") #emit_to_obj.msg(errtxt % "at_announce_move()" ) #logger.log_trace() return False # Perform move try: #print "move_to location:", destination _SA(self, "location", destination) except Exception: emit_to_obj.msg(errtxt % "location change") logger.log_trace() return False if not quiet: # Tell the new room we are there. try: self.announce_move_to(_GA(source_location, "typeclass")) except Exception: logerr(errtxt % "announce_move_to()") #emit_to_obj.msg(errtxt % "announce_move_to()") #logger.log_trace() return False # Perform eventual extra commands on the receiving location # (the object has already arrived at this point) try: destination.at_object_receive(_GA(self, "typeclass"), _GA(source_location, "typeclass")) except Exception: logerr(errtxt % "at_object_receive()") #emit_to_obj.msg(errtxt % "at_object_receive()") #logger.log_trace() return False # Execute eventual extra commands on this object after moving it # (usually calling 'look') try: self.at_after_move(_GA(source_location, "typeclass")) except Exception: logerr(errtxt % "at_after_move") #emit_to_obj.msg(errtxt % "at_after_move()") #logger.log_trace() return False return True