def execute_cmd(self, raw_string, sessid=None): """ Do something as this object. This method is a copy of the execute_ cmd method on the session. This is never called normally, it's only used when wanting specifically to let an object be the caller of a command. It makes use of nicks of eventual connected players as well. Argument: raw_string (string) - raw command input sessid (int) - optional session id to return results to Returns Deferred - this is an asynchronous Twisted object that will not fire until the command has actually finished executing. To overload this one needs to attach callback functions to it, with addCallback(function). This function will be called with an eventual return value from the command execution. This return is not used at all by Evennia by default, but might be useful for coders intending to implement some sort of nested command structure. """ # nick replacement - we require full-word matching. # do text encoding conversion raw_string = to_unicode(raw_string) raw_string = self.nicks.nickreplace(raw_string, categories=("inputline", "channel"), include_player=True) return cmdhandler.cmdhandler(_GA(self, "typeclass"), raw_string, callertype="object", sessid=sessid)
def __new__(cls, *args, **kwargs): """ When creating a new ANSIString, you may use a custom parser that has the same attributes as the standard one, and you may declare the string to be handled as already decoded. It is important not to double decode strings, as escapes can only be respected once. """ string = args[0] if not isinstance(string, basestring): string = to_str(string, force_string=True) parser = kwargs.get('parser', ANSI_PARSER) decoded = kwargs.get('decoded', False) or hasattr(string, '_raw_string') if not decoded: # Completely new ANSI String clean_string = to_unicode(parser.parse_ansi(string, strip_ansi=True)) string = parser.parse_ansi(string) elif hasattr(string, '_clean_string'): # It's already an ANSIString clean_string = string._clean_string string = string._raw_string else: # It's a string that has been pre-ansi decoded. clean_string = parser.strip_raw_codes(string) if not isinstance(string, unicode): string = string.decode('utf-8') else: # Do this to prevent recursive ANSIStrings. string = unicode(string) ansi_string = super(ANSIString, cls).__new__(ANSIString, to_str(clean_string), "utf-8") ansi_string._raw_string = string ansi_string._clean_string = clean_string return ansi_string
def reload(self, filename=None, form=None, **kwargs): """ Creates the form from a stored file name """ # clean kwargs (these cannot be overridden) kwargs.pop("enforce_size", None) kwargs.pop("width", None) kwargs.pop("height", None) if form or self.input_form_dict: datadict = form if form else self.input_form_dict self.input_form_dict = datadict elif filename or self.filename: filename = filename if filename else self.filename datadict = all_from_module(filename) self.filename = filename else: datadict = {} cellchar = to_str(datadict.get("FORMCHAR", "x")) self.cellchar = to_str(cellchar[0] if len(cellchar) > 1 else cellchar) tablechar = datadict.get("TABLECHAR", "c") self.tablechar = tablechar[0] if len(tablechar) > 1 else tablechar # split into a list of list of lines. Form can be indexed with form[iy][ix] self.raw_form = to_unicode(datadict.get("FORM", "")).split("\n") # strip first line self.raw_form = self.raw_form[1:] if self.raw_form else self.raw_form self.options.update(kwargs) # parse and replace self.mapping = self._parse_rectangles(self.cellchar, self.tablechar, self.raw_form, **kwargs) self.form = self._populate_form(self.raw_form, self.mapping)
def get_objs_with_db_property_value(self, property_name, property_value, candidates=None, typeclasses=None): """ Returns all objects having a given db field property. candidates - list of objects to search typeclasses - list of typeclass-path strings to restrict matches with """ if isinstance(property_value, basestring): property_value = to_unicode(property_value) if isinstance(property_name, basestring): if not property_name.startswith('db_'): property_name = "db_%s" % property_name if hasattr(property_value, 'dbobj'): property_value = property_value.dbobj querykwargs = {property_name: property_value} cand_restriction = candidates != None and Q( pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q() type_restriction = typeclasses and Q( db_typeclass_path__in=make_iter(typeclasses)) or Q() try: return list( self.filter(cand_restriction & type_restriction & Q(**querykwargs))) except exceptions.FieldError: return [] except ValueError: from src.utils import logger logger.log_errmsg( "The property '%s' does not support search criteria of the type %s." % (property_name, type(property_value))) return []
def reload(self, filename=None, form=None, **kwargs): """ Creates the form from a stored file name """ # clean kwargs (these cannot be overridden) kwargs.pop("enforce_size", None) kwargs.pop("width", None) kwargs.pop("height", None) if form or self.input_form_dict: datadict = form if form else self.input_form_dict self.input_form_dict = datadict elif filename or self.filename: filename = filename if filename else self.filename datadict = all_from_module(filename) self.filename = filename else: datadict = {} cellchar = to_str(datadict.get("FORMCHAR", "x")) self.cellchar = to_str(cellchar[0] if len(cellchar) > 1 else cellchar) tablechar = datadict.get("TABLECHAR", "c") self.tablechar = tablechar[0] if len(tablechar) > 1 else tablechar # split into a list of list of lines. Form can be indexed with form[iy][ix] self.raw_form = _to_ansi(to_unicode(datadict.get("FORM", "")).split("\n")) # strip first line self.raw_form = self.raw_form[1:] if self.raw_form else self.raw_form self.options.update(kwargs) # parse and replace self.mapping = self._parse_rectangles(self.cellchar, self.tablechar, self.raw_form, **kwargs) self.form = self._populate_form(self.raw_form, self.mapping)
def execute_cmd(self, raw_string, sessid=None): """ Do something as this player. This method is never called normally, but only when the player object itself is supposed to execute the command. It does not take nicks on eventual puppets into account. raw_string - raw command input coming from the command line. """ # nick replacement - we require full-word matching. raw_string = utils.to_unicode(raw_string) raw_list = raw_string.split(None) raw_list = [" ".join(raw_list[:i + 1]) for i in range(len(raw_list)) if raw_list[:i + 1]] # get the nick replacement data directly from the database to be # able to use db_category__in nicks = self.db_attributes.filter(db_category__in=("nick_inputline", "nick_channel")) for nick in nicks: if nick.db_key in raw_list: raw_string = raw_string.replace(nick.db_key, nick.db_strvalue, 1) break if not sessid and _MULTISESSION_MODE in (0, 1): # in this case, we should either have only one sessid, or the sessid # should not matter (since the return goes to all of them we can # just use the first one as the source) sessid = self.get_all_sessions()[0].sessid return cmdhandler.cmdhandler(self.typeclass, raw_string, callertype="player", sessid=sessid)
def execute_cmd(self, raw_string, sessid=None, **kwargs): """ Do something as this player. This method is never called normally, but only when the player object itself is supposed to execute the command. It takes player nicks into account, but not nicks of eventual puppets. raw_string - raw command input coming from the command line. sessid - the optional session id to be responsible for the command-send **kwargs - other keyword arguments will be added to the found command object instace as variables before it executes. This is unused by default Evennia but may be used to set flags and change operating paramaters for commands at run-time. """ raw_string = utils.to_unicode(raw_string) raw_string = self.nicks.nickreplace(raw_string, categories=("inputline", "channel"), include_player=False) if not sessid and _MULTISESSION_MODE in (0, 1): # in this case, we should either have only one sessid, or the sessid # should not matter (since the return goes to all of them we can # just use the first one as the source) try: sessid = self.get_all_sessions()[0].sessid except IndexError: # this can happen for bots sessid = None return cmdhandler.cmdhandler(self.typeclass, raw_string, callertype="player", sessid=sessid, **kwargs)
def data_out(self, session, text="", **kwargs): """ Sending data Server -> Portal """ text = text and to_str(to_unicode(text), encoding=session.encoding) self.server.amp_protocol.call_remote_MsgServer2Portal( sessid=session.sessid, msg=text, data=kwargs)
def get_objs_with_db_property_value(self, property_name, property_value, candidates=None, typeclasses=None): """ Returns all objects having a given db field property. candidates - list of objects to search typeclasses - list of typeclass-path strings to restrict matches with """ if isinstance(property_value, basestring): property_value = to_unicode(property_value) if isinstance(property_name, basestring): if not property_name.startswith("db_"): property_name = "db_%s" % property_name if hasattr(property_value, "dbobj"): property_value = property_value.dbobj querykwargs = {property_name: property_value} cand_restriction = ( candidates != None and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q() ) type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q() try: return list(self.filter(cand_restriction & type_restriction & Q(**querykwargs))) except exceptions.FieldError: return [] except ValueError: from src.utils import logger logger.log_errmsg( "The property '%s' does not support search criteria of the type %s." % (property_name, type(property_value)) ) return []
def execute_cmd(self, raw_string, sessid=None): """ Do something as this player. This method is never called normally, but only when the player object itself is supposed to execute the command. It takes player nicks into account, but not nicks of eventual puppets. raw_string - raw command input coming from the command line. """ raw_string = utils.to_unicode(raw_string) raw_string = self.nicks.nickreplace(raw_string, categories=("inputline", "channel"), include_player=False) if not sessid and _MULTISESSION_MODE in (0, 1): # in this case, we should either have only one sessid, or the sessid # should not matter (since the return goes to all of them we can # just use the first one as the source) try: sessid = self.get_all_sessions()[0].sessid except IndexError: # this can happen for bots sessid = None return cmdhandler.cmdhandler(self.typeclass, raw_string, callertype="player", sessid=sessid)
def get_object_with_player(self, ostring, exact=True, candidates=None): """ Search for an object based on its player's name or dbref. This search is sometimes initiated by appending a * to the beginning of the search criterion (e.g. in local_and_global_search). search_string: (string) The name or dbref to search for. """ ostring = to_unicode(ostring).lstrip("*") # simplest case - search by dbref dbref = self.dbref(ostring) if dbref: return dbref # not a dbref. Search by name. cand_restriction = ( candidates != None and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q() ) if exact: return self.filter(cand_restriction & Q(db_player__username__iexact=ostring)) else: # fuzzy matching ply_cands = self.filter(cand_restriction & Q(playerdb__username__istartswith=ostring)).values_list( "db_key", flat=True ) if candidates: index_matches = string_partial_matching(ply_cands, ostring, ret_index=True) return [obj for ind, obj in enumerate(make_iter(candidates)) if ind in index_matches] else: return string_partial_matching(ply_cands, ostring, ret_index=False)
def execute_cmd(self, raw_string): """ Do something as this object. This command transparently lets its typeclass execute the command. Evennia also calls this method whenever the player sends a command on the command line. Argument: raw_string (string) - raw command input Returns Deferred - this is an asynchronous Twisted object that will not fire until the command has actually finished executing. To overload this one needs to attach callback functions to it, with addCallback(function). This function will be called with an eventual return value from the command execution. This return is not used at all by Evennia by default, but might be useful for coders intending to implement some sort of nested command structure. """ # nick replacement - we require full-word matching. # do text encoding conversion raw_string = to_unicode(raw_string) raw_list = raw_string.split(None) raw_list = [" ".join(raw_list[:i+1]) for i in range(len(raw_list)) if raw_list[:i+1]] nicks = ObjectNick.objects.filter(db_obj=self, db_type__in=("inputline", "channel")) if self.has_player: nicks = list(nicks) + list(PlayerNick.objects.filter(db_obj=self.db_player, db_type__in=("inputline","channel"))) for nick in nicks: if nick.db_nick in raw_list: raw_string = raw_string.replace(nick.db_nick, nick.db_real, 1) break return cmdhandler.cmdhandler(_GA(self, "typeclass"), raw_string)
def data_out(self, session, text="", **kwargs): """ Sending data Server -> Portal """ text = text and to_str(to_unicode(text), encoding=session.encoding) self.server.amp_protocol.call_remote_MsgServer2Portal(sessid=session.sessid, msg=text, data=kwargs)
def _to_ansi(obj, regexable=False): "convert to ANSIString" if isinstance(obj, dict): return dict((key, _to_ansi(value, regexable=regexable)) for key, value in obj.items()) elif hasattr(obj, "__iter__"): return [_to_ansi(o) for o in obj] else: return ANSIString(to_unicode(obj), regexable=regexable)
def data_in(self, sessid, text="", **kwargs): """ Data Portal -> Server """ session = self.sessions.get(sessid, None) if session: text = text and to_unicode(strip_control_sequences(text), encoding=session.encoding) session.data_in(text=text, **kwargs)
def __new__(cls, *args, **kwargs): """ When creating a new ANSIString, you may use a custom parser that has the same attributes as the standard one, and you may declare the string to be handled as already decoded. It is important not to double decode strings, as escapes can only be respected once. Internally, ANSIString can also passes itself precached code/character indexes and clean strings to avoid doing extra work when combining ANSIStrings. """ string = args[0] if not isinstance(string, basestring): string = to_str(string, force_string=True) parser = kwargs.get('parser', ANSI_PARSER) decoded = kwargs.get('decoded', False) or hasattr( string, '_raw_string') code_indexes = kwargs.pop('code_indexes', None) char_indexes = kwargs.pop('char_indexes', None) clean_string = kwargs.pop('clean_string', None) # All True, or All False, not just one. checks = map(lambda x: x is None, [code_indexes, char_indexes, clean_string]) if not len(set(checks)) == 1: raise ValueError("You must specify code_indexes, char_indexes, " "and clean_string together, or not at all.") if not all(checks): decoded = True if not decoded: # Completely new ANSI String clean_string = to_unicode( parser.parse_ansi(string, strip_ansi=True)) string = parser.parse_ansi(string) elif clean_string is not None: # We have an explicit clean string. pass elif hasattr(string, '_clean_string'): # It's already an ANSIString clean_string = string._clean_string code_indexes = string._code_indexes char_indexes = string._char_indexes string = string._raw_string else: # It's a string that has been pre-ansi decoded. clean_string = parser.strip_raw_codes(string) if not isinstance(string, unicode): string = string.decode('utf-8') ansi_string = super(ANSIString, cls).__new__(ANSIString, to_str(clean_string), "utf-8") ansi_string._raw_string = string ansi_string._clean_string = clean_string ansi_string._code_indexes = code_indexes ansi_string._char_indexes = char_indexes return ansi_string
def forwards(self, orm): "Write your forwards methods here." for attr in orm.ScriptAttribute.objects.all(): try: # repack attr into new format, and reimport val = pickle.loads(to_str(attr.db_value)) attr.db_value = to_unicode(pickle.dumps(to_str(to_attr(from_attr(attr, val))))) attr.save() except TypeError, RuntimeError: pass
def forwards(self, orm): "Write your forwards methods here." for attr in orm.ObjAttribute.objects.all(): # repack attr into new format, and reimport try: val = pickle.loads(to_str(attr.db_value)) attr.db_value = to_unicode(pickle.dumps(to_str(to_attr(from_attr(attr, val))))) attr.save() except TypeError, RuntimeError: pass
def get_objs_with_db_property_value(self, property_name, property_value, candidates=None): """ Returns all objects having a given db field property """ if isinstance(property_value, basestring): property_value = to_unicode(property_value) property_name = "db_%s" % property_name.lstrip('db_') cand_restriction = candidates and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q() try: return self.filter(cand_restriction & Q(property_name=property_value)) except exceptions.FieldError: return []
def __new__(cls, *args, **kwargs): """ When creating a new ANSIString, you may use a custom parser that has the same attributes as the standard one, and you may declare the string to be handled as already decoded. It is important not to double decode strings, as escapes can only be respected once. Internally, ANSIString can also passes itself precached code/character indexes and clean strings to avoid doing extra work when combining ANSIStrings. """ string = args[0] if not isinstance(string, basestring): string = to_str(string, force_string=True) parser = kwargs.get('parser', ANSI_PARSER) decoded = kwargs.get('decoded', False) or hasattr(string, '_raw_string') code_indexes = kwargs.pop('code_indexes', None) char_indexes = kwargs.pop('char_indexes', None) clean_string = kwargs.pop('clean_string', None) # All True, or All False, not just one. checks = map(lambda x: x is None, [code_indexes, char_indexes, clean_string]) if not len(set(checks)) == 1: raise ValueError("You must specify code_indexes, char_indexes, " "and clean_string together, or not at all.") if not all(checks): decoded = True if not decoded: # Completely new ANSI String clean_string = to_unicode(parser.parse_ansi(string, strip_ansi=True)) string = parser.parse_ansi(string) elif clean_string is not None: # We have an explicit clean string. pass elif hasattr(string, '_clean_string'): # It's already an ANSIString clean_string = string._clean_string code_indexes = string._code_indexes char_indexes = string._char_indexes string = string._raw_string else: # It's a string that has been pre-ansi decoded. clean_string = parser.strip_raw_codes(string) if not isinstance(string, unicode): string = string.decode('utf-8') ansi_string = super(ANSIString, cls).__new__(ANSIString, to_str(clean_string), "utf-8") ansi_string._raw_string = string ansi_string._clean_string = clean_string ansi_string._code_indexes = code_indexes ansi_string._char_indexes = char_indexes return ansi_string
def forwards(self, orm): "Write your forwards methods here." for attr in orm['players.PlayerAttribute'].objects.all(): try: # repack attr into new format, and reimport val = pickle.loads(to_str(attr.db_value)) if hasattr(val, '__iter__'): val = ("iter", val) elif type(val) == PackedDBobject: val = ("dbobj", val) else: val = ("simple", val) attr.db_value = to_unicode(pickle.dumps(to_str(to_attr(from_attr(attr, val))))) attr.save() except TypeError, RuntimeError: pass
def forwards(self, orm): "Write your forwards methods here." for attr in orm.PlayerAttribute.objects.all(): try: # repack attr into new format, and reimport val = pickle.loads(to_str(attr.db_value)) if hasattr(val, '__iter__'): val = ("iter", val) elif type(val) == PackedDBobject: val = ("dbobj", val) else: val = ("simple", val) attr.db_value = to_unicode(pickle.dumps(to_str(to_attr(from_attr(attr, val))))) attr.save() except TypeError, RuntimeError: pass
def execute_cmd(self, raw_string): """ Do something as this player. This command transparently lets its typeclass execute the command. raw_string - raw command input coming from the command line. """ # nick replacement - we require full-word matching. raw_string = utils.to_unicode(raw_string) raw_list = raw_string.split(None) raw_list = [" ".join(raw_list[:i+1]) for i in range(len(raw_list)) if raw_list[:i+1]] for nick in PlayerNick.objects.filter(db_obj=self, db_type__in=("inputline","channel")): if nick.db_nick in raw_list: raw_string = raw_string.replace(nick.db_nick, nick.db_real, 1) break return cmdhandler.cmdhandler(self.typeclass, raw_string)
def data_in(self, text=None, **kwargs): """ Send User->Evennia. This will in effect execute a command string on the server. Especially handled keywords: oob - this should hold a dictionary of oob command calls from the oob-supporting protocol. """ if text: # this is treated as a command input text = to_unicode(text) # handle the 'idle' command if text.strip() == IDLE_COMMAND: self.update_session_counters(idle=True) return if self.player: # nick replacement puppet = self.player.get_puppet(self.sessid) if puppet: text = puppet.nicks.nickreplace(text, categories=("inputline", "channel"), include_player=True) else: text = self.player.nicks.nickreplace( text, categories=("inputline", "channels"), include_player=False) cmdhandler.cmdhandler(self, text, callertype="session", sessid=self.sessid) self.update_session_counters() if "oob" in kwargs: # handle oob instructions global _OOB_HANDLER if not _OOB_HANDLER: from src.server.oobhandler import OOB_HANDLER as _OOB_HANDLER oobstruct = self.sessionhandler.oobstruct_parser( kwargs.pop("oob", None)) #print "session.data_in: oobstruct:",oobstruct for (funcname, args, kwargs) in oobstruct: if funcname: _OOB_HANDLER.execute_cmd(self, funcname, *args, **kwargs)
def execute_cmd(self, raw_string, sessid=None): """ Do something as this player. This command transparently lets its typeclass execute the command. raw_string - raw command input coming from the command line. """ # nick replacement - we require full-word matching. raw_string = utils.to_unicode(raw_string) raw_list = raw_string.split(None) raw_list = [" ".join(raw_list[: i + 1]) for i in range(len(raw_list)) if raw_list[: i + 1]] for nick in PlayerNick.objects.filter(db_obj=self, db_type__in=("inputline", "channel")): if nick.db_nick in raw_list: raw_string = raw_string.replace(nick.db_nick, nick.db_real, 1) break if not sessid and _MULTISESSION_MODE in (0, 1): # in this case, we should either have only one sessid, or the sessid # should not matter (since the return goes to all of them we can just # use the first one as the source) sessid = self.get_all_sessions()[0].sessid return cmdhandler.cmdhandler(self.typeclass, raw_string, sessid=sessid)
def execute_cmd(self, raw_string, sessid=None): """ Do something as this object. This method is a copy of the execute_ cmd method on the session. This is never called normally, it's only used when wanting specifically to let an object be the caller of a command. It makes use of nicks of eventual connected players as well. Argument: raw_string (string) - raw command input sessid (int) - optional session id to return results to Returns Deferred - this is an asynchronous Twisted object that will not fire until the command has actually finished executing. To overload this one needs to attach callback functions to it, with addCallback(function). This function will be called with an eventual return value from the command execution. This return is not used at all by Evennia by default, but might be useful for coders intending to implement some sort of nested command structure. """ # nick replacement - we require full-word matching. # do text encoding conversion raw_string = to_unicode(raw_string) raw_list = raw_string.split(None) raw_list = [" ".join(raw_list[:i + 1]) for i in range(len(raw_list)) if raw_list[:i + 1]] # fetch the nick data efficiently nicks = self.db_attributes.filter(db_category__in=("nick_inputline", "nick_channel")) if self.has_player: # attach player nicks as well, but after the object-level nicks nicks = list(nicks) + list(self.player.db_attributes.filter(db_category__in=("nick_inputline", "nick_channel"))) for nick in nicks: if nick.db_key in raw_list: raw_string = raw_string.replace(nick.db_key, nick.db_strvalue, 1) break return cmdhandler.cmdhandler(_GA(self, "typeclass"), raw_string, callertype="object", sessid=sessid)
def data_in(self, text=None, **kwargs): """ Send User->Evennia. This will in effect execute a command string on the server. Especially handled keywords: oob - this should hold a dictionary of oob command calls from the oob-supporting protocol. """ if text: # this is treated as a command input text = to_unicode(text) # handle the 'idle' command if text.strip() == IDLE_COMMAND: self.update_session_counters(idle=True) return if self.player: # nick replacement puppet = self.player.get_puppet(self.sessid) if puppet: text = puppet.nicks.nickreplace(text, categories=("inputline", "channel"), include_player=True) else: text = self.player.nicks.nickreplace( text, categories=("inputline", "channels"), include_player=False ) cmdhandler(self, text, callertype="session", sessid=self.sessid) self.update_session_counters() if "oob" in kwargs: # handle oob instructions global _OOB_HANDLER if not _OOB_HANDLER: from src.server.oobhandler import OOB_HANDLER as _OOB_HANDLER oobstruct = self.sessionhandler.oobstruct_parser(kwargs.pop("oob", None)) # print "session.data_in: oobstruct:",oobstruct for (funcname, args, kwargs) in oobstruct: if funcname: _OOB_HANDLER.execute_cmd(self, funcname, *args, **kwargs)
def __new__(cls, *args, **kwargs): """ When creating a new ANSIString, you may use a custom parser that has the same attributes as the standard one, and you may declare the string to be handled as already decoded. It is important not to double decode strings, as escapes can only be respected once. """ string = args[0] if not isinstance(string, basestring): string = to_str(string, force_string=True) parser = kwargs.get('parser', ANSI_PARSER) decoded = kwargs.get('decoded', False) or hasattr( string, '_raw_string') if not decoded: # Completely new ANSI String clean_string = to_unicode( parser.parse_ansi(string, strip_ansi=True)) string = parser.parse_ansi(string) elif hasattr(string, '_clean_string'): # It's already an ANSIString clean_string = string._clean_string string = string._raw_string else: # It's a string that has been pre-ansi decoded. clean_string = parser.strip_raw_codes(string) if not isinstance(string, unicode): string = string.decode('utf-8') else: # Do this to prevent recursive ANSIStrings. string = unicode(string) ansi_string = super(ANSIString, cls).__new__(ANSIString, to_str(clean_string), "utf-8") ansi_string._raw_string = string ansi_string._clean_string = clean_string return ansi_string
def get_object_with_player(self, ostring, exact=True, candidates=None): """ Search for an object based on its player's name or dbref. This search is sometimes initiated by appending a * to the beginning of the search criterion (e.g. in local_and_global_search). search_string: (string) The name or dbref to search for. """ ostring = to_unicode(ostring).lstrip('*') # simplest case - search by dbref dbref = self.dbref(ostring) if dbref: return dbref # not a dbref. Search by name. cand_restriction = candidates != None and Q( pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q() if exact: return self.filter(cand_restriction & Q(db_player__username__iexact=ostring)) else: # fuzzy matching ply_cands = self.filter(cand_restriction & Q( playerdb__username__istartswith=ostring)).values_list( "db_key", flat=True) if candidates: index_matches = string_partial_matching(ply_cands, ostring, ret_index=True) return [ obj for ind, obj in enumerate(make_iter(candidates)) if ind in index_matches ] else: return string_partial_matching(ply_cands, ostring, ret_index=False)
Custom manager for Objects. """ try: import cPickle as pickle except ImportError: import pickle from django.db.models import Q from django.conf import settings #from django.contrib.auth.models import User from django.db.models.fields import exceptions from src.typeclasses.managers import TypedObjectManager from src.typeclasses.managers import returns_typeclass, returns_typeclass_list from src.utils import utils from src.utils.utils import to_unicode, make_iter, string_partial_matching, to_str __all__ = ("ObjectManager",) _GA = object.__getattribute__ _DUMPS = lambda inp: to_unicode(pickle.dumps(inp)) # Try to use a custom way to parse id-tagged multimatches. _AT_MULTIMATCH_INPUT = utils.variable_from_module(*settings.SEARCH_AT_MULTIMATCH_INPUT.rsplit('.', 1)) class ObjectManager(TypedObjectManager): """ This ObjectManager implementes methods for searching and manipulating Objects directly from the database. Evennia-specific search methods (will return Typeclasses or lists of Typeclasses, whereas Django-general methods will return Querysets or database objects). dbref (converter)
def create_object(typeclass=None, key=None, location=None, home=None, permissions=None, locks=None, aliases=None, destination=None, report_to=None, nohome=False): """ Create a new in-game object. Any game object is a combination of a database object that stores data persistently to the database, and a typeclass, which on-the-fly 'decorates' the database object into whataver different type of object it is supposed to be in the game. See src.objects.managers for methods to manipulate existing objects in the database. src.objects.objects holds the base typeclasses and src.objects.models hold the database model. report_to is an optional object for reporting errors to in string form. If report_to is not set, errors will be raised as en Exception containing the error message. If set, this method will return None upon errors. nohome - this allows the creation of objects without a default home location; this only used when creating default location itself or during unittests """ global _Object, _ObjectDB if not _Object: from src.objects.objects import Object as _Object if not _ObjectDB: from src.objects.models import ObjectDB as _ObjectDB # input validation if not typeclass: typeclass = settings.BASE_OBJECT_TYPECLASS elif isinstance(typeclass, _ObjectDB): # this is already an objectdb instance, extract its typeclass typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Object) or utils.inherits_from(typeclass, _Object): # this is already an object typeclass, extract its path typeclass = typeclass.path # handle eventual #dbref input location = handle_dbref(location, _ObjectDB) home = handle_dbref(home, _ObjectDB) destination = handle_dbref(destination, _ObjectDB) report_to = handle_dbref(report_to, _ObjectDB) # create new database object new_db_object = _ObjectDB() # assign the typeclass typeclass = utils.to_unicode(typeclass) new_db_object.typeclass_path = typeclass # the name/key is often set later in the typeclass. This # is set here as a failsafe. if key: new_db_object.key = key else: new_db_object.key = "#%i" % new_db_object.dbid # this will either load the typeclass or the default one new_object = new_db_object.typeclass if not _GA(new_object, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input and it still # gave us a default SharedMemoryModel.delete(new_db_object) if report_to: _GA(report_to, "msg")("Error creating %s (%s):\n%s" % (new_db_object.key, typeclass, _GA(new_db_object, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_object, "typeclass_last_errmsg")) # from now on we can use the typeclass object # as if it was the database object. new_object.destination = destination # call the hook method. This is where all at_creation # customization happens as the typeclass stores custom # things on its database object. new_object.basetype_setup() # setup the basics of Exits, Characters etc. new_object.at_object_creation() # custom-given perms/locks overwrite hooks if permissions: new_object.permissions.add(permissions) if locks: new_object.locks.add(locks) if aliases: new_object.aliases.add(aliases) if home: new_object.home = home else: # we shouldn't need to handle dbref here (home handler should fix it), but some have # reported issues here (issue 446). try: new_object.home = handle_dbref(settings.DEFAULT_HOME, _ObjectDB) if not nohome else None except _ObjectDB.DoesNotExist: raise _ObjectDB.DoesNotExist("settings.DEFAULT_HOME (= '%s') does not exist, or the setting is malformed." % settings.DEFAULT_HOME) # perform a move_to in order to display eventual messages. if location: new_object.move_to(location, quiet=True) else: # rooms would have location=None. new_object.location = None # post-hook setup (mainly used by Exits) new_object.basetype_posthook_setup() new_object.save() return new_object
def create_player(key, email, password, typeclass=None, is_superuser=False, locks=None, permissions=None, report_to=None): """ This creates a new player. key - the player's name. This should be unique. email - email on valid [email protected] form. password - password in cleartext is_superuser - wether or not this player is to be a superuser locks - lockstring permission - list of permissions report_to - an object with a msg() method to report errors to. If not given, errors will be logged. Will return the Player-typeclass or None/raise Exception if the Typeclass given failed to load. Concerning is_superuser: Usually only the server admin should need to be superuser, all other access levels can be handled with more fine-grained permissions or groups. A superuser bypasses all lock checking operations and is thus not suitable for play-testing the game. """ global _PlayerDB, _Player if not _PlayerDB: from src.players.models import PlayerDB as _PlayerDB if not _Player: from src.players.player import Player as _Player if not email: email = "*****@*****.**" if _PlayerDB.objects.filter(username__iexact=key): raise ValueError("A Player with the name '%s' already exists." % key) # this handles a given dbref-relocate to a player. report_to = handle_dbref(report_to, _PlayerDB) try: # create the correct Player object if is_superuser: new_db_player = _PlayerDB.objects.create_superuser(key, email, password) else: new_db_player = _PlayerDB.objects.create_user(key, email, password) if not typeclass: typeclass = settings.BASE_PLAYER_TYPECLASS elif isinstance(typeclass, _PlayerDB): # this is an PlayerDB instance, extract its typeclass path typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Player) or utils.inherits_from(typeclass, _Player): # this is Player object typeclass, extract its path typeclass = typeclass.path # assign the typeclass typeclass = utils.to_unicode(typeclass) new_db_player.typeclass_path = typeclass # this will either load the typeclass or the default one new_player = new_db_player.typeclass if not _GA(new_db_player, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input # and it still gave us a default SharedMemoryModel.delete(new_db_player) if report_to: _GA(report_to, "msg")("Error creating %s (%s):\n%s" % (new_db_player.key, typeclass, _GA(new_db_player, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_player, "typeclass_last_errmsg")) new_player.basetype_setup() # setup the basic locks and cmdset # call hook method (may override default permissions) new_player.at_player_creation() # custom given arguments potentially overrides the hook if permissions: new_player.permissions.add(permissions) elif not new_player.permissions: new_player.permissions.add(settings.PERMISSION_PLAYER_DEFAULT) if locks: new_player.locks.add(locks) return new_player except Exception: # a failure in creating the player; we try to clean # up as much as we can logger.log_trace() try: new_player.delete() except Exception: pass try: del new_player except Exception: pass raise
def create_script(typeclass, key=None, obj=None, player=None, locks=None, interval=None, start_delay=None, repeats=None, persistent=None, autostart=True, report_to=None): """ Create a new script. All scripts are a combination of a database object that communicates with the database, and an typeclass that 'decorates' the database object into being different types of scripts. It's behaviour is similar to the game objects except scripts has a time component and are more limited in scope. Argument 'typeclass' can be either an actual typeclass object or a python path to such an object. Only set key here if you want a unique name for this particular script (set it in config to give same key to all scripts of the same type). Set obj to tie this script to a particular object. See src.scripts.manager for methods to manipulate existing scripts in the database. report_to is an obtional object to receive error messages. If report_to is not set, an Exception with the error will be raised. If set, this method will return None upon errors. """ global _Script, _ScriptDB if not _Script: from src.scripts.scripts import Script as _Script if not _ScriptDB: from src.scripts.models import ScriptDB as _ScriptDB if not typeclass: typeclass = settings.BASE_SCRIPT_TYPECLASS elif isinstance(typeclass, _ScriptDB): # this is already an scriptdb instance, extract its typeclass typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Script) or utils.inherits_from(typeclass, _Script): # this is already an object typeclass, extract its path typeclass = typeclass.path # create new database script new_db_script = _ScriptDB() # assign the typeclass typeclass = utils.to_unicode(typeclass) new_db_script.typeclass_path = typeclass # the name/key is often set later in the typeclass. This # is set here as a failsafe. if key: new_db_script.key = key else: new_db_script.key = "#%i" % new_db_script.id # this will either load the typeclass or the default one new_script = new_db_script.typeclass if not _GA(new_db_script, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input and it still # gave us a default SharedMemoryModel.delete(new_db_script) if report_to: _GA(report_to, "msg")("Error creating %s (%s): %s" % (new_db_script.key, typeclass, _GA(new_db_script, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_script, "typeclass_last_errmsg")) if obj: new_script.obj = obj if player: new_script.player = player # call the hook method. This is where all at_creation # customization happens as the typeclass stores custom # things on its database object. new_script.at_script_creation() # custom-given variables override the hook if key: new_script.key = key if locks: new_script.locks.add(locks) if interval is not None: new_script.interval = interval if start_delay is not None: new_script.start_delay = start_delay if repeats is not None: new_script.repeats = repeats if persistent is not None: new_script.persistent = persistent # a new created script should usually be started. if autostart: new_script.start() new_db_script.save() return new_script
def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sessid=None, **kwargs): """ This is the main function to handle any string sent to the engine. called_by - object on which this was called from. This is either a Session, a Player or an Object. raw_string - the command string given on the command line _testing - if we should actually execute the command or not. if True, the command instance will be returned instead. callertype - this is one of "session", "player" or "object", in decending order. So when the Session is the caller, it will merge its own cmdset into cmdsets from both Player and eventual puppeted Object (and cmdsets in its room etc). A Player will only include its own cmdset and the Objects and so on. Merge order is the same order, so that Object cmdsets are merged in last, giving them precendence for same-name and same-prio commands. sessid - Relevant if callertype is "player" - the session id will help retrieve the correct cmdsets from puppeted objects. **kwargs - other keyword arguments will be assigned as named variables on the retrieved command object *before* it is executed. This is unuesed in default Evennia but may be used by code to set custom flags or special operating conditions for a command as it executes. Note that this function returns a deferred! """ raw_string = to_unicode(raw_string, force_string=True) session, player, obj = None, None, None if callertype == "session": session = called_by player = session.player if player: obj = yield _GA(player.dbobj, "get_puppet")(session.sessid) elif callertype == "player": player = called_by if sessid: obj = yield _GA(player.dbobj, "get_puppet")(sessid) elif callertype == "object": obj = called_by else: raise RuntimeError("cmdhandler: callertype %s is not valid." % callertype) # the caller will be the one to receive messages and excert its permissions. # we assign the caller with preference 'bottom up' caller = obj or player or session try: # catch bugs in cmdhandler itself try: # catch special-type commands cmdset = yield get_and_merge_cmdsets(caller, session, player, obj, callertype, sessid) if not cmdset: # this is bad and shouldn't happen. raise NoCmdSets unformatted_raw_string = raw_string raw_string = raw_string.strip() if not raw_string: # Empty input. Test for system command instead. syscmd = yield cmdset.get(CMD_NOINPUT) sysarg = "" raise ExecSystemCommand(syscmd, sysarg) # Parse the input string and match to available cmdset. # This also checks for permissions, so all commands in match # are commands the caller is allowed to call. matches = yield _COMMAND_PARSER(raw_string, cmdset, caller) # Deal with matches if len(matches) > 1: # We have a multiple-match syscmd = yield cmdset.get(CMD_MULTIMATCH) sysarg = _("There were multiple matches.") if syscmd: # use custom CMD_MULTIMATCH syscmd.matches = matches else: # fall back to default error handling sysarg = yield at_multimatch_cmd(caller, matches) raise ExecSystemCommand(syscmd, sysarg) if len(matches) == 1: # We have a unique command match. But it may still be invalid. match = matches[0] cmdname, args, cmd = match[0], match[1], match[2] # check if we allow this type of command if cmdset.no_channels and hasattr( cmd, "is_channel") and cmd.is_channel: matches = [] if cmdset.no_exits and hasattr(cmd, "is_exit") and cmd.is_exit: matches = [] if not matches: # No commands match our entered command syscmd = yield cmdset.get(CMD_NOMATCH) if syscmd: # use custom CMD_NOMATH command sysarg = raw_string else: # fallback to default error text sysarg = _("Command '%s' is not available.") % raw_string suggestions = string_suggestions( raw_string, cmdset.get_all_cmd_keys_and_aliases(caller), cutoff=0.7, maxnum=3) if suggestions: sysarg += _( " Maybe you meant %s?") % utils.list_to_string( suggestions, _('or'), addquote=True) else: sysarg += _(" Type \"help\" for help.") raise ExecSystemCommand(syscmd, sysarg) # Check if this is a Channel-cmd match. if hasattr(cmd, 'is_channel') and cmd.is_channel: # even if a user-defined syscmd is not defined, the # found cmd is already a system command in its own right. syscmd = yield cmdset.get(CMD_CHANNEL) if syscmd: # replace system command with custom version cmd = syscmd cmd.sessid = session.sessid if session else None sysarg = "%s:%s" % (cmdname, args) raise ExecSystemCommand(cmd, sysarg) # A normal command. # Assign useful variables to the instance cmd.caller = caller cmd.cmdstring = cmdname cmd.args = args cmd.cmdset = cmdset cmd.sessid = session.sessid if session else sessid cmd.session = session cmd.player = player cmd.raw_string = unformatted_raw_string #cmd.obj # set via on-object cmdset handler for each command, # since this may be different for every command when # merging multuple cmdsets if hasattr(cmd, 'obj') and hasattr(cmd.obj, 'scripts'): # cmd.obj is automatically made available by the cmdhandler. # we make sure to validate its scripts. yield cmd.obj.scripts.validate() if _testing: # only return the command instance returnValue(cmd) # assign custom kwargs to found cmd object for key, val in kwargs.items(): setattr(cmd, key, val) # pre-command hook abort = yield cmd.at_pre_cmd() if abort: # abort sequence returnValue(abort) # Parse and execute yield cmd.parse() # (return value is normally None) ret = yield cmd.func() # post-command hook yield cmd.at_post_cmd() if cmd.save_for_next: # store a reference to this command, possibly # accessible by the next command. caller.ndb.last_cmd = yield copy(cmd) else: caller.ndb.last_cmd = None # Done! This returns a deferred. By default, Evennia does # not use this at all. returnValue(ret) except ExecSystemCommand, exc: # Not a normal command: run a system command, if available, # or fall back to a return string. syscmd = exc.syscmd sysarg = exc.sysarg if syscmd: syscmd.caller = caller syscmd.cmdstring = syscmd.key syscmd.args = sysarg syscmd.cmdset = cmdset syscmd.sessid = session.sessid if session else None syscmd.raw_string = unformatted_raw_string if hasattr(syscmd, 'obj') and hasattr(syscmd.obj, 'scripts'): # cmd.obj is automatically made available. # we make sure to validate its scripts. yield syscmd.obj.scripts.validate() if _testing: # only return the command instance returnValue(syscmd) # parse and run the command yield syscmd.parse() yield syscmd.func() elif sysarg: # return system arg caller.msg(exc.sysarg) except NoCmdSets: # Critical error. string = "No command sets found! This is a sign of a critical bug.\n" string += "The error was logged.\n" string += "If logging out/in doesn't solve the problem, try to " string += "contact the server admin through some other means " string += "for assistance." caller.msg(_(string)) logger.log_errmsg("No cmdsets found: %s" % caller) except Exception: # We should not end up here. If we do, it's a programming bug. string = "%s\nAbove traceback is from an untrapped error." string += " Please file a bug report." logger.log_trace(_(string)) caller.msg(string % format_exc())
def cmdhandler(called_by, raw_string, _testing=False, callertype="session", sessid=None, **kwargs): """ This is the main function to handle any string sent to the engine. called_by - object on which this was called from. This is either a Session, a Player or an Object. raw_string - the command string given on the command line _testing - if we should actually execute the command or not. if True, the command instance will be returned instead. callertype - this is one of "session", "player" or "object", in decending order. So when the Session is the caller, it will merge its own cmdset into cmdsets from both Player and eventual puppeted Object (and cmdsets in its room etc). A Player will only include its own cmdset and the Objects and so on. Merge order is the same order, so that Object cmdsets are merged in last, giving them precendence for same-name and same-prio commands. sessid - Relevant if callertype is "player" - the session id will help retrieve the correct cmdsets from puppeted objects. **kwargs - other keyword arguments will be assigned as named variables on the retrieved command object *before* it is executed. This is unuesed in default Evennia but may be used by code to set custom flags or special operating conditions for a command as it executes. Note that this function returns a deferred! """ raw_string = to_unicode(raw_string, force_string=True) session, player, obj = None, None, None if callertype == "session": session = called_by player = session.player if player: obj = yield _GA(player.dbobj, "get_puppet")(session.sessid) elif callertype == "player": player = called_by if sessid: obj = yield _GA(player.dbobj, "get_puppet")(sessid) elif callertype == "object": obj = called_by else: raise RuntimeError("cmdhandler: callertype %s is not valid." % callertype) # the caller will be the one to receive messages and excert its permissions. # we assign the caller with preference 'bottom up' caller = obj or player or session try: # catch bugs in cmdhandler itself try: # catch special-type commands cmdset = yield get_and_merge_cmdsets(caller, session, player, obj, callertype, sessid) if not cmdset: # this is bad and shouldn't happen. raise NoCmdSets unformatted_raw_string = raw_string raw_string = raw_string.strip() if not raw_string: # Empty input. Test for system command instead. syscmd = yield cmdset.get(CMD_NOINPUT) sysarg = "" raise ExecSystemCommand(syscmd, sysarg) # Parse the input string and match to available cmdset. # This also checks for permissions, so all commands in match # are commands the caller is allowed to call. matches = yield _COMMAND_PARSER(raw_string, cmdset, caller) # Deal with matches if len(matches) > 1: # We have a multiple-match syscmd = yield cmdset.get(CMD_MULTIMATCH) sysarg = _("There were multiple matches.") if syscmd: # use custom CMD_MULTIMATCH syscmd.matches = matches else: # fall back to default error handling sysarg = yield at_multimatch_cmd(caller, matches) raise ExecSystemCommand(syscmd, sysarg) if len(matches) == 1: # We have a unique command match. But it may still be invalid. match = matches[0] cmdname, args, cmd = match[0], match[1], match[2] # check if we allow this type of command if cmdset.no_channels and hasattr(cmd, "is_channel") and cmd.is_channel: matches = [] if cmdset.no_exits and hasattr(cmd, "is_exit") and cmd.is_exit: matches = [] if not matches: # No commands match our entered command syscmd = yield cmdset.get(CMD_NOMATCH) if syscmd: # use custom CMD_NOMATH command sysarg = raw_string else: # fallback to default error text sysarg = _("Command '%s' is not available.") % raw_string suggestions = string_suggestions(raw_string, cmdset.get_all_cmd_keys_and_aliases(caller), cutoff=0.7, maxnum=3) if suggestions: sysarg += _(" Maybe you meant %s?") % utils.list_to_string(suggestions, _('or'), addquote=True) else: sysarg += _(" Type \"help\" for help.") raise ExecSystemCommand(syscmd, sysarg) # Check if this is a Channel-cmd match. if hasattr(cmd, 'is_channel') and cmd.is_channel: # even if a user-defined syscmd is not defined, the # found cmd is already a system command in its own right. syscmd = yield cmdset.get(CMD_CHANNEL) if syscmd: # replace system command with custom version cmd = syscmd cmd.sessid = session.sessid if session else None sysarg = "%s:%s" % (cmdname, args) raise ExecSystemCommand(cmd, sysarg) # A normal command. # Assign useful variables to the instance cmd.caller = caller cmd.cmdstring = cmdname cmd.args = args cmd.cmdset = cmdset cmd.sessid = session.sessid if session else sessid cmd.session = session cmd.player = player cmd.raw_string = unformatted_raw_string #cmd.obj # set via on-object cmdset handler for each command, # since this may be different for every command when # merging multuple cmdsets if hasattr(cmd, 'obj') and hasattr(cmd.obj, 'scripts'): # cmd.obj is automatically made available by the cmdhandler. # we make sure to validate its scripts. yield cmd.obj.scripts.validate() if _testing: # only return the command instance returnValue(cmd) # assign custom kwargs to found cmd object for key, val in kwargs.items(): setattr(cmd, key, val) # pre-command hook abort = yield cmd.at_pre_cmd() if abort: # abort sequence returnValue(abort) # Parse and execute yield cmd.parse() # (return value is normally None) ret = yield cmd.func() # post-command hook yield cmd.at_post_cmd() if cmd.save_for_next: # store a reference to this command, possibly # accessible by the next command. caller.ndb.last_cmd = yield copy(cmd) else: caller.ndb.last_cmd = None # Done! This returns a deferred. By default, Evennia does # not use this at all. returnValue(ret) except ExecSystemCommand, exc: # Not a normal command: run a system command, if available, # or fall back to a return string. syscmd = exc.syscmd sysarg = exc.sysarg if syscmd: syscmd.caller = caller syscmd.cmdstring = syscmd.key syscmd.args = sysarg syscmd.cmdset = cmdset syscmd.sessid = session.sessid if session else None syscmd.raw_string = unformatted_raw_string if hasattr(syscmd, 'obj') and hasattr(syscmd.obj, 'scripts'): # cmd.obj is automatically made available. # we make sure to validate its scripts. yield syscmd.obj.scripts.validate() if _testing: # only return the command instance returnValue(syscmd) # parse and run the command yield syscmd.parse() yield syscmd.func() elif sysarg: # return system arg caller.msg(exc.sysarg) except NoCmdSets: # Critical error. string = "No command sets found! This is a sign of a critical bug.\n" string += "The error was logged.\n" string += "If logging out/in doesn't solve the problem, try to " string += "contact the server admin through some other means " string += "for assistance." caller.msg(_(string)) logger.log_errmsg("No cmdsets found: %s" % caller) except Exception: # We should not end up here. If we do, it's a programming bug. string = "%s\nAbove traceback is from an untrapped error." string += " Please file a bug report." logger.log_trace(_(string)) caller.msg(string % format_exc())
def create_object(typeclass, key=None, location=None, home=None, player=None, permissions=None, locks=None, aliases=None, destination=None, report_to=None): """ Create a new in-game object. Any game object is a combination of a database object that stores data persistently to the database, and a typeclass, which on-the-fly 'decorates' the database object into whataver different type of object it is supposed to be in the game. See src.objects.managers for methods to manipulate existing objects in the database. src.objects.objects holds the base typeclasses and src.objects.models hold the database model. report_to is an optional object for reporting errors to in string form. If report_to is not set, errors will be raised as en Exception containing the error message. If set, this method will return None upon errors. """ global _Object, _ObjectDB if not _Object: from src.objects.objects import Object as _Object if not _ObjectDB: from src.objects.models import ObjectDB as _ObjectDB if not typeclass: typeclass = settings.BASE_OBJECT_TYPECLASS elif isinstance(typeclass, _ObjectDB): # this is already an objectdb instance, extract its typeclass typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Object) or utils.inherits_from(typeclass, _Object): # this is already an object typeclass, extract its path typeclass = typeclass.path # create new database object new_db_object = _ObjectDB() # assign the typeclass typeclass = utils.to_unicode(typeclass) new_db_object.typeclass_path = typeclass # the name/key is often set later in the typeclass. This # is set here as a failsafe. if key: new_db_object.key = key else: new_db_object.key = "#%i" % new_db_object.dbid # this will either load the typeclass or the default one new_object = new_db_object.typeclass if not _GA(new_object, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input and it still gave us a default SharedMemoryModel.delete(new_db_object) if report_to: _GA(report_to, "msg")("Error creating %s (%s):\n%s" % (new_db_object.key, typeclass, _GA(new_db_object, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_object, "typeclass_last_errmsg")) # from now on we can use the typeclass object # as if it was the database object. if player: # link a player and the object together new_object.player = player player.obj = new_object new_object.destination = destination # call the hook method. This is where all at_creation # customization happens as the typeclass stores custom # things on its database object. new_object.basetype_setup() # setup the basics of Exits, Characters etc. new_object.at_object_creation() # custom-given perms/locks overwrite hooks if permissions: new_object.permissions = permissions if locks: new_object.locks.add(locks) if aliases: new_object.aliases = aliases # perform a move_to in order to display eventual messages. if home: new_object.home = home else: new_object.home = settings.CHARACTER_DEFAULT_HOME if location: new_object.move_to(location, quiet=True) else: # rooms would have location=None. new_object.location = None # post-hook setup (mainly used by Exits) new_object.basetype_posthook_setup() new_object.save() return new_object
def create_object(typeclass=None, key=None, location=None, home=None, permissions=None, locks=None, aliases=None, destination=None, report_to=None, nohome=False): """ Create a new in-game object. Any game object is a combination of a database object that stores data persistently to the database, and a typeclass, which on-the-fly 'decorates' the database object into whataver different type of object it is supposed to be in the game. See src.objects.managers for methods to manipulate existing objects in the database. src.objects.objects holds the base typeclasses and src.objects.models hold the database model. report_to is an optional object for reporting errors to in string form. If report_to is not set, errors will be raised as en Exception containing the error message. If set, this method will return None upon errors. nohome - this allows the creation of objects without a default home location; this only used when creating the default location itself or during unittests """ global _Object, _ObjectDB if not _Object: from src.objects.objects import Object as _Object if not _ObjectDB: from src.objects.models import ObjectDB as _ObjectDB # input validation if not typeclass: typeclass = settings.BASE_OBJECT_TYPECLASS elif isinstance(typeclass, _ObjectDB): # this is already an objectdb instance, extract its typeclass typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Object) or utils.inherits_from(typeclass, _Object): # this is already an object typeclass, extract its path typeclass = typeclass.path typeclass = utils.to_unicode(typeclass) # Setup input for the create command location = handle_dbref(location, _ObjectDB) destination = handle_dbref(destination, _ObjectDB) home = handle_dbref(home, _ObjectDB) if not home: try: home = handle_dbref(settings.DEFAULT_HOME, _ObjectDB) if not nohome else None except _ObjectDB.DoesNotExist: raise _ObjectDB.DoesNotExist("settings.DEFAULT_HOME (= '%s') does not exist, or the setting is malformed." % settings.DEFAULT_HOME) # create new database object all in one go new_db_object = _ObjectDB(db_key=key, db_location=location, db_destination=destination, db_home=home, db_typeclass_path=typeclass) if not key: # the object should always have a key, so if not set we give a default new_db_object.key = "#%i" % new_db_object.dbid # this will either load the typeclass or the default one (will also save object) new_object = new_db_object.typeclass if not _GA(new_object, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input and it still # gave us a default try: SharedMemoryModel.delete(new_db_object) except AssertionError: # this happens if object was never created pass if report_to: report_to = handle_dbref(report_to, _ObjectDB) _GA(report_to, "msg")("Error creating %s (%s).\n%s" % (new_db_object.key, typeclass, _GA(new_db_object, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_object, "typeclass_last_errmsg")) # from now on we can use the typeclass object # as if it was the database object. # call the hook methods. This is where all at_creation # customization happens as the typeclass stores custom # things on its database object. # note - this may override input keys, locations etc! new_object.basetype_setup() # setup the basics of Exits, Characters etc. new_object.at_object_creation() # we want the input to override that set in the hooks, so # we re-apply those if needed if new_object.key != key: new_object.key = key if new_object.location != location: new_object.location = location if new_object.home != home: new_object.home = home if new_object.destination != destination: new_object.destination = destination # custom-given perms/locks do overwrite hooks if permissions: new_object.permissions.add(permissions) if locks: new_object.locks.add(locks) if aliases: new_object.aliases.add(aliases) # trigger relevant move_to hooks in order to display messages. if location: location.at_object_receive(new_object, None) new_object.at_after_move(None) # post-hook setup (mainly used by Exits) new_object.basetype_posthook_setup() return new_object
def __str__(self): "print table" return to_unicode("\n".join([line for line in self._generate_lines()]))
def create_object(typeclass=None, key=None, location=None, home=None, permissions=None, locks=None, aliases=None, destination=None, report_to=None, nohome=False): """ Create a new in-game object. Any game object is a combination of a database object that stores data persistently to the database, and a typeclass, which on-the-fly 'decorates' the database object into whataver different type of object it is supposed to be in the game. See src.objects.managers for methods to manipulate existing objects in the database. src.objects.objects holds the base typeclasses and src.objects.models hold the database model. report_to is an optional object for reporting errors to in string form. If report_to is not set, errors will be raised as en Exception containing the error message. If set, this method will return None upon errors. nohome - this allows the creation of objects without a default home location; this only used when creating the default location itself or during unittests """ global _Object, _ObjectDB if not _Object: from src.objects.objects import Object as _Object if not _ObjectDB: from src.objects.models import ObjectDB as _ObjectDB # input validation if not typeclass: typeclass = settings.BASE_OBJECT_TYPECLASS elif isinstance(typeclass, _ObjectDB): # this is already an objectdb instance, extract its typeclass typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Object) or utils.inherits_from( typeclass, _Object): # this is already an object typeclass, extract its path typeclass = typeclass.path typeclass = utils.to_unicode(typeclass) # Setup input for the create command location = handle_dbref(location, _ObjectDB) destination = handle_dbref(destination, _ObjectDB) home = handle_dbref(home, _ObjectDB) if not home: try: home = handle_dbref(settings.DEFAULT_HOME, _ObjectDB) if not nohome else None except _ObjectDB.DoesNotExist: raise _ObjectDB.DoesNotExist( "settings.DEFAULT_HOME (= '%s') does not exist, or the setting is malformed." % settings.DEFAULT_HOME) # create new database object all in one go new_db_object = _ObjectDB(db_key=key, db_location=location, db_destination=destination, db_home=home, db_typeclass_path=typeclass) if not key: # the object should always have a key, so if not set we give a default new_db_object.key = "#%i" % new_db_object.dbid # this will either load the typeclass or the default one (will also save object) new_object = new_db_object.typeclass if not _GA(new_object, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input and it still # gave us a default try: SharedMemoryModel.delete(new_db_object) except AssertionError: # this happens if object was never created pass if report_to: report_to = handle_dbref(report_to, _ObjectDB) _GA(report_to, "msg")("Error creating %s (%s).\n%s" % (new_db_object.key, typeclass, _GA(new_db_object, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_object, "typeclass_last_errmsg")) # from now on we can use the typeclass object # as if it was the database object. # call the hook methods. This is where all at_creation # customization happens as the typeclass stores custom # things on its database object. # note - this may override input keys, locations etc! new_object.basetype_setup() # setup the basics of Exits, Characters etc. new_object.at_object_creation() # we want the input to override that set in the hooks, so # we re-apply those if needed if new_object.key != key: new_object.key = key if new_object.location != location: new_object.location = location if new_object.home != home: new_object.home = home if new_object.destination != destination: new_object.destination = destination # custom-given perms/locks do overwrite hooks if permissions: new_object.permissions.add(permissions) if locks: new_object.locks.add(locks) if aliases: new_object.aliases.add(aliases) # trigger relevant move_to hooks in order to display messages. if location: new_object.at_object_receive(new_object, None) new_object.at_after_move(new_object) # post-hook setup (mainly used by Exits) new_object.basetype_posthook_setup() return new_object
def create_player(key, email, password, typeclass=None, is_superuser=False, locks=None, permissions=None, report_to=None): """ This creates a new player. key - the player's name. This should be unique. email - email on valid [email protected] form. password - password in cleartext is_superuser - wether or not this player is to be a superuser locks - lockstring permission - list of permissions report_to - an object with a msg() method to report errors to. If not given, errors will be logged. Will return the Player-typeclass or None/raise Exception if the Typeclass given failed to load. Concerning is_superuser: Usually only the server admin should need to be superuser, all other access levels can be handled with more fine-grained permissions or groups. A superuser bypasses all lock checking operations and is thus not suitable for play-testing the game. """ global _PlayerDB, _Player if not _PlayerDB: from src.players.models import PlayerDB as _PlayerDB if not _Player: from src.players.player import Player as _Player if not email: email = "*****@*****.**" if _PlayerDB.objects.filter(username__iexact=key): raise ValueError("A Player with the name '%s' already exists." % key) # this handles a given dbref-relocate to a player. report_to = handle_dbref(report_to, _PlayerDB) try: # create the correct Player object if is_superuser: new_db_player = _PlayerDB.objects.create_superuser( key, email, password) else: new_db_player = _PlayerDB.objects.create_user(key, email, password) if not typeclass: typeclass = settings.BASE_PLAYER_TYPECLASS elif isinstance(typeclass, _PlayerDB): # this is an PlayerDB instance, extract its typeclass path typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Player) or utils.inherits_from( typeclass, _Player): # this is Player object typeclass, extract its path typeclass = typeclass.path # assign the typeclass typeclass = utils.to_unicode(typeclass) new_db_player.typeclass_path = typeclass # this will either load the typeclass or the default one new_player = new_db_player.typeclass if not _GA(new_db_player, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input # and it still gave us a default SharedMemoryModel.delete(new_db_player) if report_to: _GA(report_to, "msg")("Error creating %s (%s):\n%s" % (new_db_player.key, typeclass, _GA(new_db_player, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_player, "typeclass_last_errmsg")) new_player.basetype_setup() # setup the basic locks and cmdset # call hook method (may override default permissions) new_player.at_player_creation() # custom given arguments potentially overrides the hook if permissions: new_player.permissions.add(permissions) elif not new_player.permissions: new_player.permissions.add(settings.PERMISSION_PLAYER_DEFAULT) if locks: new_player.locks.add(locks) return new_player except Exception: # a failure in creating the player; we try to clean # up as much as we can logger.log_trace() try: new_player.delete() except Exception: pass try: del new_player except Exception: pass raise
def create_script(typeclass, key=None, obj=None, player=None, locks=None, interval=None, start_delay=None, repeats=None, persistent=None, autostart=True, report_to=None): """ Create a new script. All scripts are a combination of a database object that communicates with the database, and an typeclass that 'decorates' the database object into being different types of scripts. It's behaviour is similar to the game objects except scripts has a time component and are more limited in scope. Argument 'typeclass' can be either an actual typeclass object or a python path to such an object. Only set key here if you want a unique name for this particular script (set it in config to give same key to all scripts of the same type). Set obj to tie this script to a particular object. See src.scripts.manager for methods to manipulate existing scripts in the database. report_to is an obtional object to receive error messages. If report_to is not set, an Exception with the error will be raised. If set, this method will return None upon errors. """ global _Script, _ScriptDB if not _Script: from src.scripts.scripts import Script as _Script if not _ScriptDB: from src.scripts.models import ScriptDB as _ScriptDB if not typeclass: typeclass = settings.BASE_SCRIPT_TYPECLASS elif isinstance(typeclass, _ScriptDB): # this is already an scriptdb instance, extract its typeclass typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Script) or utils.inherits_from( typeclass, _Script): # this is already an object typeclass, extract its path typeclass = typeclass.path # create new database script new_db_script = _ScriptDB() # assign the typeclass typeclass = utils.to_unicode(typeclass) new_db_script.typeclass_path = typeclass # the name/key is often set later in the typeclass. This # is set here as a failsafe. if key: new_db_script.key = key else: new_db_script.key = "#%i" % new_db_script.id # this will either load the typeclass or the default one new_script = new_db_script.typeclass if not _GA(new_db_script, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input and it still # gave us a default SharedMemoryModel.delete(new_db_script) if report_to: _GA(report_to, "msg")("Error creating %s (%s): %s" % (new_db_script.key, typeclass, _GA(new_db_script, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_script, "typeclass_last_errmsg")) if obj: new_script.obj = obj if player: new_script.player = player # call the hook method. This is where all at_creation # customization happens as the typeclass stores custom # things on its database object. new_script.at_script_creation() # custom-given variables override the hook if key: new_script.key = key if locks: new_script.locks.add(locks) if interval is not None: new_script.interval = interval if start_delay is not None: new_script.start_delay = start_delay if repeats is not None: new_script.repeats = repeats if persistent is not None: new_script.persistent = persistent # a new created script should usually be started. if autostart: new_script.start() new_db_script.save() return new_script
def _to_ansi(obj): "convert to ANSIString" if hasattr(obj, "__iter__"): return [_to_ansi(o) for o in obj] else: return ANSIString(to_unicode(obj))
def create_object(typeclass=None, key=None, location=None, home=None, permissions=None, locks=None, aliases=None, destination=None, report_to=None, nohome=False): """ Create a new in-game object. Any game object is a combination of a database object that stores data persistently to the database, and a typeclass, which on-the-fly 'decorates' the database object into whataver different type of object it is supposed to be in the game. See src.objects.managers for methods to manipulate existing objects in the database. src.objects.objects holds the base typeclasses and src.objects.models hold the database model. report_to is an optional object for reporting errors to in string form. If report_to is not set, errors will be raised as en Exception containing the error message. If set, this method will return None upon errors. nohome - this allows the creation of objects without a default home location; this only used when creating default location itself or during unittests """ global _Object, _ObjectDB if not _Object: from src.objects.objects import Object as _Object if not _ObjectDB: from src.objects.models import ObjectDB as _ObjectDB # input validation if not typeclass: typeclass = settings.BASE_OBJECT_TYPECLASS elif isinstance(typeclass, _ObjectDB): # this is already an objectdb instance, extract its typeclass typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Object) or utils.inherits_from( typeclass, _Object): # this is already an object typeclass, extract its path typeclass = typeclass.path # handle eventual #dbref input location = handle_dbref(location, _ObjectDB) home = handle_dbref(home, _ObjectDB) destination = handle_dbref(destination, _ObjectDB) report_to = handle_dbref(report_to, _ObjectDB) # create new database object new_db_object = _ObjectDB() # assign the typeclass typeclass = utils.to_unicode(typeclass) new_db_object.typeclass_path = typeclass # the name/key is often set later in the typeclass. This # is set here as a failsafe. if key: new_db_object.key = key else: new_db_object.key = "#%i" % new_db_object.dbid # this will either load the typeclass or the default one new_object = new_db_object.typeclass if not _GA(new_object, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input and it still # gave us a default SharedMemoryModel.delete(new_db_object) if report_to: _GA(report_to, "msg")("Error creating %s (%s):\n%s" % (new_db_object.key, typeclass, _GA(new_db_object, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_object, "typeclass_last_errmsg")) # from now on we can use the typeclass object # as if it was the database object. new_object.destination = destination # call the hook method. This is where all at_creation # customization happens as the typeclass stores custom # things on its database object. new_object.basetype_setup() # setup the basics of Exits, Characters etc. new_object.at_object_creation() # custom-given perms/locks overwrite hooks if permissions: new_object.permissions.add(permissions) if locks: new_object.locks.add(locks) if aliases: new_object.aliases.add(aliases) if home: new_object.home = home else: # we shouldn't need to handle dbref here (home handler should fix it), but some have # reported issues here (issue 446). try: new_object.home = handle_dbref(settings.DEFAULT_HOME, _ObjectDB) if not nohome else None except _ObjectDB.DoesNotExist: raise _ObjectDB.DoesNotExist( "settings.DEFAULT_HOME (= '%s') does not exist, or the setting is malformed." % settings.DEFAULT_HOME) # perform a move_to in order to display eventual messages. if location: new_object.move_to(location, quiet=True) else: # rooms would have location=None. new_object.location = None # post-hook setup (mainly used by Exits) new_object.basetype_posthook_setup() new_object.save() return new_object
def create_player(name, email, password, user=None, typeclass=None, is_superuser=False, locks=None, permissions=None, create_character=True, character_typeclass=None, character_location=None, character_home=None, player_dbobj=None, report_to=None): """ This creates a new player, handling the creation of the User object and its associated Player object. If player_dbobj is given, this player object is used instead of creating a new one. This is called by the admin interface since it needs to create the player object in order to relate it automatically to the user. If create_character is True, a game player object with the same name as the User/Player will also be created. Its typeclass and base properties can also be given. Returns the new game character, or the Player obj if no character is created. For more info about the typeclass argument, see create_objects() above. Note: if user is supplied, it will NOT be modified (args name, email, passw and is_superuser will be ignored). Change those properties directly on the User instead. If no permissions are given (None), the default permission group as defined in settings.PERMISSION_PLAYER_DEFAULT will be assigned. If permissions are given, no automatic assignment will occur. Concerning is_superuser: A superuser should have access to everything in the game and on the server/web interface. The very first user created in the database is always a superuser (that's using django's own creation, not this one). Usually only the server admin should need to be superuser, all other access levels can be handled with more fine-grained permissions or groups. Since superuser overrules all permissions, we don't set any in this case. """ # The system should already have checked so the name/email # isn't already registered, and that the password is ok before # getting here. global _PlayerDB, _Player if not _PlayerDB: from src.players.models import PlayerDB as _PlayerDB if not _Player: from src.players.player import Player as _Player if not email: email = "*****@*****.**" if user: new_user = user email = user.email else: if is_superuser: new_user = User.objects.create_superuser(name, email, password) else: new_user = User.objects.create_user(name, email, password) try: if not typeclass: typeclass = settings.BASE_PLAYER_TYPECLASS elif isinstance(typeclass, _PlayerDB): # this is already an objectdb instance, extract its typeclass typeclass = typeclass.typeclass.path elif isinstance(typeclass, _Player) or utils.inherits_from(typeclass, _Player): # this is already an object typeclass, extract its path typeclass = typeclass.path if player_dbobj: try: _GA(player_dbobj, "dbobj") new_db_player = player_dbobj.dbobj except AttributeError: new_db_player = player_dbobj # use the typeclass from this object typeclass = new_db_player.typeclass_path else: new_db_player = _PlayerDB(db_key=name, user=new_user) new_db_player.save() # assign the typeclass typeclass = utils.to_unicode(typeclass) new_db_player.typeclass_path = typeclass # this will either load the typeclass or the default one new_player = new_db_player.typeclass if not _GA(new_db_player, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input and it still gave us a default SharedMemoryModel.delete(new_db_player) if report_to: _GA(report_to, "msg")("Error creating %s (%s):\n%s" % (new_db_player.key, typeclass, _GA(new_db_player, "typeclass_last_errmsg"))) return None else: raise Exception(_GA(new_db_player, "typeclass_last_errmsg")) new_player.basetype_setup() # setup the basic locks and cmdset # call hook method (may override default permissions) new_player.at_player_creation() # custom given arguments potentially overrides the hook if permissions: new_player.permissions = permissions elif not new_player.permissions: new_player.permissions = settings.PERMISSION_PLAYER_DEFAULT if locks: new_player.locks.add(locks) # create *in-game* 'player' object if create_character: if not character_typeclass: character_typeclass = settings.BASE_CHARACTER_TYPECLASS # creating the object automatically links the player # and object together by player.obj <-> obj.player new_character = create_object(character_typeclass, key=name, location=character_location, home=character_location, permissions=permissions, player=new_player, report_to=report_to) return new_character return new_player except Exception, e: # a failure in creating the character if not user: # in there was a failure we clean up everything we can logger.log_trace() try: new_user.delete() except Exception: pass try: new_player.delete() except Exception: pass try: del new_character except Exception: pass raise e