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 get_objs_with_attr_value(self, attribute_name, attribute_value, candidates=None, typeclasses=None): """ Returns all objects having the valid attrname set to the given value. candidates - list of candidate objects to search typeclasses - list of typeclass-path strings to restrict matches with This uses the Attribute's PickledField to transparently search the database by matching the internal representation. This is reasonably effective but since Attribute values cannot be indexed, searching by Attribute key is to be preferred whenever possible. """ 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() ## This doesn't work if attribute_value is an object. Workaround below if isinstance(attribute_value, (basestring, int, float, bool, long)): return self.filter( cand_restriction & type_restriction & Q(db_attributes__db_key=attribute_name, db_attributes__db_value=attribute_value) ) else: # We have to loop for safety since the referenced lookup gives deepcopy error if attribute value is an object. global _ATTR if not _ATTR: from src.typeclasses.models import Attribute as _ATTR cands = list(self.filter(cand_restriction & type_restriction & Q(db_attributes__db_key=attribute_name))) results = [ attr.objectdb_set.all() for attr in _ATTR.objects.filter(objectdb__in=cands, db_value=attribute_value) ] return chain(*results)
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 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 __init__(self, senders=None, receivers=None, channels=None, message="", header="", type="", lockstring="", hide_from=None): self.senders = senders and make_iter(senders) or [] self.receivers = receivers and make_iter(receivers) or [] self.channels = channels and make_iter(channels) or [] self.type = type self.header = header self.message = message self.lock_storage = lockstring self.hide_from = hide_from and make_iter(hide_from) or [] self.date_sent = datetime.now()
def __init__(self, senders=None, receivers=None, channels=None, message="", header="", type="", lockstring="", hide_from=None): self.senders = senders and make_iter(senders) or [] self.receivers = receivers and make_iter(receivers) or [] self.channels = channels and make_iter(channels) or [] self.type = type self.header = header self.message = message self.lock_storage = lockstring self.locks = LazyLoadHandler(self, "locks", LockHandler) self.hide_from = hide_from and make_iter(hide_from) or [] self.date_sent = datetime.now()
def func(self): "Implement function" caller = self.caller # all channels we have available to listen to channels = [chan for chan in ChannelDB.objects.get_all_channels() if chan.access(caller, "listen")] # print channels if not channels: self.msg("No channels available.") return # all channel we are already subscribed to subs = ChannelDB.objects.get_subscriptions(caller) # print subs if self.cmdstring == "comlist": # just display the subscribed channels with no extra info comtable = prettytable.PrettyTable(["{wchannel", "{wmy aliases", "{wdescription"]) for chan in subs: clower = chan.key.lower() nicks = caller.nicks.get(category="channel") comtable.add_row( [ "%s%s" % (chan.key, chan.aliases.all() and "(%s)" % ",".join(chan.aliases.all()) or ""), "%s".join(nick for nick in make_iter(nicks) if nick and nick.lower() == clower), chan.db.desc, ] ) caller.msg( "\n{wChannel subscriptions{n (use {w@channels{n to list all, {waddcom{n/{wdelcom{n to sub/unsub):{n\n%s" % comtable ) else: # full listing (of channels caller is able to listen to) comtable = prettytable.PrettyTable(["{wsub", "{wchannel", "{wmy aliases", "{wlocks", "{wdescription"]) for chan in channels: clower = chan.key.lower() nicks = caller.nicks.get(category="channel") nicks = nicks or [] comtable.add_row( [ chan in subs and "{gYes{n" or "{rNo{n", "%s%s" % (chan.key, chan.aliases.all() and "(%s)" % ",".join(chan.aliases.all()) or ""), "%s".join(nick for nick in make_iter(nicks) if nick.lower() == clower), str(chan.locks), chan.db.desc, ] ) caller.msg( "\n{wAvailable channels{n (use {wcomlist{n,{waddcom{n and {wdelcom{n to manage subscriptions):\n%s" % comtable )
def get_objs_with_key_or_alias(self, ostring, exact=True, candidates=None, typeclasses=None): """ Returns objects based on key or alias match. Will also do fuzzy matching based on the utils.string_partial_matching function. candidates - list of candidate objects to restrict on typeclasses - list of typeclass path strings to restrict on """ if not isinstance(ostring, basestring): if hasattr(ostring, "key"): ostring = ostring.key else: return [] if is_iter(candidates) and not len(candidates): # if candidates is an empty iterable there can be no matches # Exit early. return [] # build query objects candidates_id = [_GA(obj, "id") for obj in make_iter(candidates) if obj] cand_restriction = candidates != None and Q(pk__in=make_iter(candidates_id)) or Q() type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q() if exact: # exact match - do direct search return self.filter( cand_restriction & type_restriction & ( Q(db_key__iexact=ostring) | Q(db_tags__db_key__iexact=ostring) & Q(db_tags__db_category__iexact="objectalias") ) ).distinct() elif candidates: # fuzzy with candidates key_candidates = self.filter(cand_restriction & type_restriction) else: # fuzzy without supplied candidates - we select our own candidates key_candidates = self.filter( type_restriction & (Q(db_key__istartswith=ostring) | Q(db_tags__db_key__istartswith=ostring)) ).distinct() candidates_id = [_GA(obj, "id") for obj in key_candidates] # fuzzy matching key_strings = key_candidates.values_list("db_key", flat=True) index_matches = string_partial_matching(key_strings, ostring, ret_index=True) if index_matches: return [obj for ind, obj in enumerate(key_candidates) if ind in index_matches] else: alias_candidates = self.filter(id__in=candidates_id, db_tags__db_category__iexact="objectalias") # print alias_candidates alias_strings = alias_candidates.values_list("db_key", flat=True) index_matches = string_partial_matching(alias_strings, ostring, ret_index=True) if index_matches: return [alias.db_obj for ind, alias in enumerate(alias_candidates) if ind in index_matches] return []
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 cmdset_storage_set(self, value): """ Setter. Allows for self.name = value. Stores as a comma-separated string. """ _SA(self, "db_cmdset_storage", ",".join(str(val).strip() for val in make_iter(value))) _GA(self, "save")()
def remove_receiver(self, obj): "Remove a sender or a list of senders" for o in make_iter(obj): try: self.senders.remove(o) except ValueError: pass # nothing to remove
def create_tag(self, key=None, category=None, data=None, model="objects.objectdb", tagtype=None): """ Create a tag. This makes sure the create case-insensitive tags. Note that if the exact same tag configuration (key+category+model+tagtype) exists, it will be re-used. A data keyword will overwrite existing data on a tag (it is not part of what makes the tag unique). """ data = str(data) if data is not None else None tag = self.get_tag(key=key, category=category, model=model, tagtype=tagtype) if tag and data is not None: tag.db_data = data tag.save() elif not tag: tag = self.create( db_key=key.lower().strip() if key is not None else None, db_category=category.lower().strip() if category and key is not None else None, db_data=str(data) if data is not None else None, db_model=model, db_tagtype=tagtype) tag.save() return make_iter(tag)[0]
def get_objs_with_key_or_alias(self, ostring, exact=True, candidates=None): """ Returns objects based on key or alias match. Will also do fuzzy matching based on the utils.string_partial_matching function. """ # build query objects candidates_id = [_GA(obj, "id") for obj in make_iter(candidates) if obj] cand_restriction = candidates and Q(pk__in=candidates_id) or Q() if exact: # exact match - do direct search return self.filter(cand_restriction & (Q(db_key__iexact=ostring) | Q(alias__db_key__iexact=ostring))).distinct() elif candidates: # fuzzy with candidates key_candidates = self.filter(cand_restriction) else: # fuzzy without supplied candidates - we select our own candidates key_candidates = self.filter(Q(db_key__istartswith=ostring) | Q(alias__db_key__istartswith=ostring)).distinct() candidates_id = [_GA(obj, "id") for obj in key_candidates] # fuzzy matching key_strings = key_candidates.values_list("db_key", flat=True) index_matches = string_partial_matching(key_strings, ostring, ret_index=True) if index_matches: return [obj for ind, obj in enumerate(key_candidates) if ind in index_matches] else: alias_candidates = self.model.alias_set.related.model.objects.filter(db_obj__pk__in=candidates_id) alias_strings = alias_candidates.values_list("db_key", flat=True) index_matches = string_partial_matching(alias_strings, ostring, ret_index=True) if index_matches: return [alias.db_obj for ind, alias in enumerate(alias_candidates) if ind in index_matches] return []
def create_tag(self, key=None, category=None, data=None, tagtype=None): """ Create a new Tag of the base type associated with this typedobject. This makes sure to create case-insensitive tags. If the exact same tag configuration (key+category+tagtype) exists on the model, a new tag will not be created, but an old one returned. A data keyword is not part of the uniqueness of the tag and setting one on an existing tag will overwrite the old data field. """ data = str(data) if data is not None else None # try to get old tag tag = self.get_tag(key=key, category=category, tagtype=tagtype) if tag and data is not None: # overload data on tag tag.db_data = data tag.save() elif not tag: # create a new tag global _Tag if not _Tag: from src.typeclasses.models import Tag as _Tag tag = _Tag.objects.create( db_key=key.strip().lower() if key is not None else None, db_category=category.strip().lower() if category and key is not None else None, db_data=data, db_tagtype=tagtype.strip().lower() if tagtype is not None else None) tag.save() return make_iter(tag)[0]
def get_objs_with_key_and_typeclass(self, oname, otypeclass_path, candidates=None): """ Returns objects based on simultaneous key and typeclass match. """ cand_restriction = ( candidates != None and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q() ) return self.filter(cand_restriction & Q(db_key__iexact=oname, db_typeclass_path__exact=otypeclass_path))
def func(self, *args, **kwargs): "decorator. Returns result or None." self.__doc__ = method.__doc__ matches = method(self, *args, **kwargs) dbobj = matches and make_iter(matches)[0] or None if dbobj: return (hasattr(dbobj, "typeclass") and dbobj.typeclass) or dbobj return None
def no_look_target(self): "Hook method for default look without a specified target" # caller is always a player at this point. player = self.player sessid = self.sessid # get all our characters and sessions characters = player.db._playable_characters if None in characters: # clean up list if character object was deleted in between characters = [character for character in characters if character] player.db._playable_characters = characters sessions = player.get_all_sessions() is_su = player.is_superuser # text shown when looking in the ooc area string = "Account {g%s{n (you are Out-of-Character)" % (player.key) nsess = len(sessions) string += nsess == 1 and "\n\n{wConnected session:{n" or "\n\n{wConnected sessions (%i):{n" % nsess for isess, sess in enumerate(sessions): csessid = sess.sessid addr = "%s (%s)" % (sess.protocol_key, isinstance(sess.address, tuple) and str(sess.address[0]) or str(sess.address)) string += "\n %s %s" % (sessid == csessid and "{w%s{n" % (isess + 1) or (isess + 1), addr) string += "\n\n {whelp{n - more commands" string += "\n {wooc <Text>{n - talk on public channel" if is_su or len(characters) < MAX_NR_CHARACTERS: if not characters: string += "\n\n You don't have any characters yet. See {whelp @charcreate{n for creating one." else: string += "\n {w@charcreate <name> [=description]{n - create new character" if characters: string_s_ending = len(characters) > 1 and "s" or "" string += "\n {w@ic <character>{n - enter the game ({w@ooc{n to get back here)" if is_su: string += "\n\nAvailable character%s (%i/unlimited):" % (string_s_ending, len(characters)) else: string += "\n\nAvailable character%s%s:" % (string_s_ending, MAX_NR_CHARACTERS > 1 and " (%i/%i)" % (len(characters), MAX_NR_CHARACTERS) or "") for char in characters: csessid = char.sessid.get() if csessid: # character is already puppeted sessi = player.get_session(csessid) for sess in utils.make_iter(sessi): sid = sess in sessions and sessions.index(sess) + 1 if sess and sid: string += "\n - {G%s{n [%s] (played by you in session %i)" % (char.key, ", ".join(char.permissions.all()), sid) else: string += "\n - {R%s{n [%s] (played by someone else)" % (char.key, ", ".join(char.permissions.all())) else: # character is "free to puppet" string += "\n - %s [%s]" % (char.key, ", ".join(char.permissions.all())) string = ("-" * 68) + "\n" + string + "\n" + ("-" * 68) self.msg(string)
def create_message(senderobj, message, channels=None, receivers=None, locks=None, header=None): """ Create a new communication message. Msgs are used for all player-to-player communication, both between individual players and over channels. senderobj - the player sending the message. This must be the actual object. message - text with the message. Eventual headers, titles etc should all be included in this text string. Formatting will be retained. channels - a channel or a list of channels to send to. The channels may be actual channel objects or their unique key strings. receivers - a player to send to, or a list of them. May be Player objects or playernames. locks - lock definition string header - mime-type or other optional information for the message The Comm system is created very open-ended, so it's fully possible to let a message both go to several channels and to several receivers at the same time, it's up to the command definitions to limit this as desired. """ global _Msg if not _Msg: from src.comms.models import Msg as _Msg if not message: # we don't allow empty messages. return new_message = _Msg(db_message=message) new_message.save() for sender in make_iter(senderobj): new_message.senders = sender new_message.header = header for channel in make_iter(channels): new_message.channels = channel for receiver in make_iter(receivers): new_message.receivers = receiver if locks: new_message.locks.add(locks) new_message.save() return new_message
def get_contents(self, location, excludeobj=None): """ Get all objects that has a location set to this one. excludeobj - one or more object keys to exclude from the match """ exclude_restriction = Q(pk__in=[_GA(obj, "id") for obj in make_iter(excludeobj)]) if excludeobj else Q() return self.filter(db_location=location).exclude(exclude_restriction)
def msg(self, msgobj, header=None, senders=None, sender_strings=None, persistent=False, online=False, emit=False, external=False): """ Send the given message to all players connected to channel. Note that no permission-checking is done here; it is assumed to have been done before calling this method. The optional keywords are not used if persistent is False. msgobj - a Msg/TempMsg instance or a message string. If one of the former, the remaining keywords will be ignored. If a string, this will either be sent as-is (if persistent=False) or it will be used together with header and senders keywords to create a Msg instance on the fly. senders - an object, player or a list of objects or players. Optional if persistent=False. sender_strings - Name strings of senders. Used for external connections where the sender is not a player or object. When this is defined, external will be assumed. external - Treat this message agnostic of its sender. persistent (default False) - ignored if msgobj is a Msg or TempMsg. If True, a Msg will be created, using header and senders keywords. If False, other keywords will be ignored. online (bool) - If this is set true, only messages people who are online. Otherwise, messages all players connected. This can make things faster, but may not trigger listeners on players that are offline. emit (bool) - Signals to the message formatter that this message is not to be directly associated with a name. """ if senders: senders = make_iter(senders) else: senders = [] if isinstance(msgobj, basestring): # given msgobj is a string msg = msgobj if persistent and self.db.keep_log: msgobj = Msg() msgobj.save() else: # Use TempMsg, so this message is not stored. msgobj = TempMsg() msgobj.header = header msgobj.message = msg msgobj.channels = [self.dbobj] # add this channel if not msgobj.senders: msgobj.senders = senders msgobj = self.pre_send_message(msgobj) if not msgobj: return False msgobj = self.message_transform(msgobj, emit=emit, sender_strings=sender_strings, external=external) self.distribute_message(msgobj, online=online) self.post_send_message(msgobj) return True
def func(self): "Create the nickname" caller = self.caller switches = self.switches nicks = caller.nicks.get(return_obj=True) if 'list' in switches: table = prettytable.PrettyTable( ["{wNickType", "{wNickname", "{wTranslates-to"]) for nick in utils.make_iter(nicks): table.add_row( [nick.db_category, nick.db_key, nick.db_strvalue]) string = "{wDefined Nicks:{n\n%s" % table caller.msg(string) return if 'clearall' in switches: caller.nicks.clear() caller.msg("Cleared all aliases.") return if not self.args or not self.lhs: caller.msg("Usage: nick[/switches] nickname = [realname]") return nick = self.lhs real = self.rhs if real == nick: caller.msg( "No point in setting nick same as the string to replace...") return # check so we have a suitable nick type if not any(True for switch in switches if switch in ("object", "player", "inputline")): switches = ["inputline"] string = "" for switch in switches: oldnick = caller.nicks.get(key=nick, category=switch) #oldnick = Nick.objects.filter(db_obj=caller.dbobj, db_nick__iexact=nick, db_type__iexact=switch) if not real: # removal of nick if oldnick: # clear the alias string += "\nNick '%s' (= '%s') was cleared." % (nick, oldnick) caller.nicks.delete(nick, category=switch) else: string += "\nNo nick '%s' found, so it could not be removed." % nick else: # creating new nick if oldnick: string += "\nNick %s changed from '%s' to '%s'." % ( nick, oldnick, real) else: string += "\nNick set: '%s' = '%s'." % (nick, real) caller.nicks.add(nick, real, category=switch) caller.msg(string)
def delete_script(self, dbref): """ This stops and deletes a specific script directly from the script database. This might be needed for global scripts not tied to a specific game object. """ scripts = self.get_id(dbref) for script in make_iter(scripts): script.stop()
def get_objs_with_attr(self, attribute_name, candidates=None): """ Returns all objects having the given attribute_name defined at all. Location should be a valid location object. """ cand_restriction = ( candidates != None and Q(db_attributes__db_obj__pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q() ) return list(self.filter(cand_restriction & Q(db_attributes__db_key=attribute_name)))
def get_contents(self, location, excludeobj=None): """ Get all objects that has a location set to this one. excludeobj - one or more object keys to exclude from the match """ exclude_restriction = Q( pk__in=[_GA(obj, "id") for obj in make_iter(excludeobj)]) if excludeobj else Q() return self.filter(db_location=location).exclude(exclude_restriction)
def get_objs_with_attr_value(self, attribute_name, attribute_value, candidates=None, typeclasses=None): """ Returns all objects having the valid attrname set to the given value. candidates - list of candidate objects to search typeclasses - list of typeclass-path strings to restrict matches with This uses the Attribute's PickledField to transparently search the database by matching the internal representation. This is reasonably effective but since Attribute values cannot be indexed, searching by Attribute key is to be preferred whenever possible. """ 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() ## This doesn't work if attribute_value is an object. Workaround below if isinstance(attribute_value, (basestring, int, float, bool, long)): return self.filter(cand_restriction & type_restriction & Q(db_attributes__db_key=attribute_name, db_attributes__db_value=attribute_value)) else: # We have to loop for safety since the referenced lookup gives deepcopy error if attribute value is an object. global _ATTR if not _ATTR: from src.typeclasses.models import Attribute as _ATTR cands = list( self.filter(cand_restriction & type_restriction & Q(db_attributes__db_key=attribute_name))) results = [ attr.objectdb_set.all() for attr in _ATTR.objects.filter(objectdb__in=cands, db_value=attribute_value) ] return chain(*results)
def contents_get(self, exclude=None): """ Returns the contents of this object, i.e. all objects that has this object set as its location. This should be publically available. exclude is one or more objects to not return """ if exclude: exclude = [obj.dbobj for obj in make_iter(exclude)] return ObjectDB.objects.get_contents(self, excludeobj=exclude) return ObjectDB.objects.get_contents(self)
def get_objs_with_attr(self, attribute_name, candidates=None): """ Returns all objects having the given attribute_name defined at all. Location should be a valid location object. """ cand_restriction = candidates != None and Q( db_attributes__db_obj__pk__in=[ _GA(obj, "id") for obj in make_iter(candidates) if obj ]) or Q() return list( self.filter(cand_restriction & Q(db_attributes__db_key=attribute_name)))
def get_objs_with_key_and_typeclass(self, oname, otypeclass_path, candidates=None): """ Returns objects based on simultaneous key and typeclass match. """ cand_restriction = candidates != None and Q( pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q() return self.filter(cand_restriction & Q( db_key__iexact=oname, db_typeclass_path__exact=otypeclass_path))
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 func(self): "Create the nickname" caller = self.caller switches = self.switches nicks = caller.nicks.get(return_obj=True) if 'list' in switches: table = prettytable.PrettyTable(["{wNickType", "{wNickname", "{wTranslates-to"]) for nick in utils.make_iter(nicks): table.add_row([nick.db_category, nick.db_key, nick.db_strvalue]) string = "{wDefined Nicks:{n\n%s" % table caller.msg(string) return if 'clearall' in switches: caller.nicks.clear() caller.msg("Cleared all aliases.") return if not self.args or not self.lhs: caller.msg("Usage: nick[/switches] nickname = [realname]") return nick = self.lhs real = self.rhs if real == nick: caller.msg("No point in setting nick same as the string to replace...") return # check so we have a suitable nick type if not any(True for switch in switches if switch in ("object", "player", "inputline")): switches = ["inputline"] string = "" for switch in switches: oldnick = caller.nicks.get(key=nick, category=switch) #oldnick = Nick.objects.filter(db_obj=caller.dbobj, db_nick__iexact=nick, db_type__iexact=switch) if not real: # removal of nick if oldnick: # clear the alias string += "\nNick '%s' (= '%s') was cleared." % (nick, oldnick) caller.nicks.delete(nick, category=switch) else: string += "\nNo nick '%s' found, so it could not be removed." % nick else: # creating new nick if oldnick: string += "\nNick %s changed from '%s' to '%s'." % (nick, oldnick, real) else: string += "\nNick set: '%s' = '%s'." % (nick, real) caller.nicks.add(nick, real, category=switch) caller.msg(string)
def get_objs_with_db_property(self, property_name, candidates=None): """ Returns all objects having a given db field property. property_name = search string candidates - list of candidate objects to search """ 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).exclude(Q(property_name=None)) except exceptions.FieldError: return []
def __receivers_set(self, value): "Setter. Allows for self.receivers = value. This appends a new receiver to the message." for val in (v for v in make_iter(value) if v): obj, typ = identify_object(val) if typ == 'player': self.db_receivers_players.add(obj) elif typ == 'object': self.db_receivers_objects.add(obj) elif not obj: return else: raise ValueError self.save()
def msg_contents(self, message, exclude=None, from_obj=None, **kwargs): """ Emits something to all objects inside an object. exclude is a list of objects not to send to. See self.msg() for more info. """ contents = _GA(self, "contents") if exclude: exclude = make_iter(exclude) contents = [obj for obj in contents if obj not in exclude] for obj in contents: obj.msg(message, from_obj=from_obj, **kwargs)
def remove_sender(self, value): "Remove a single sender or a list of senders" for val in make_iter(value): obj, typ = identify_object(val) if typ == 'player': self.db_sender_players.remove(obj) elif typ == 'object': self.db_sender_objects.remove(obj) elif isinstance(obj, basestring): self.db_sender_external = obj else: raise ValueError(obj) self.save()
def contents_get(self, exclude=None): """ Returns the contents of this object, i.e. all objects that has this object set as its location. This should be publically available. exclude is one or more objects to not return """ cont = get_prop_cache(self, "_contents") exclude = make_iter(exclude) if cont == None: cont = _GA(self, "contents_update")() return [obj for obj in cont if obj not in exclude]
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 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 _get_prototype(dic, prot, protparents): """ Recursively traverse a prototype dictionary, including multiple inheritance. Use _validate_prototype before this, we don't check for infinite recursion here. """ if "prototype" in dic: # move backwards through the inheritance for prototype in make_iter(dic["prototype"]): # Build the prot dictionary in reverse order, overloading new_prot = _get_prototype(protparents.get(prototype, {}), prot, protparents) prot.update(new_prot) prot.update(dic) prot.pop("prototype", None) # we don't need this anymore return prot
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 __senders_set(self, value): "Setter. Allows for self.sender = value" for val in (v for v in make_iter(value) if v): obj, typ = identify_object(val) if typ == 'player': self.db_sender_players.add(obj) elif typ == 'object': self.db_sender_objects.add(obj) elif isinstance(typ, basestring): self.db_sender_external = obj elif not obj: return else: raise ValueError(obj) self.save()
def _validate_prototype(key, prototype, protparents, visited): "Run validation on a prototype, checking for inifinite regress" assert isinstance(prototype, dict) if id(prototype) in visited: raise RuntimeError("%s has infinite nesting of prototypes." % key or prototype) visited.append(id(prototype)) protstrings = prototype.get("prototype") if protstrings: for protstring in make_iter(protstrings): if key is not None and protstring == key: raise RuntimeError("%s tries to prototype itself." % key or prototype) protparent = protparents.get(protstring) if not protparent: raise RuntimeError("%s's prototype '%s' was not found." % (key or prototype, protstring)) _validate_prototype(protstring, protparent, protparents, visited)
def __receivers_set(self, value): """ Setter. Allows for self.receivers = value. This appends a new receiver to the message. """ for val in (v for v in make_iter(value) if v): obj, typ = identify_object(val) if typ == 'player': self.db_receivers_players.add(obj) elif typ == 'object': self.db_receivers_objects.add(obj) elif not obj: return else: raise ValueError self.save()
def get_objs_with_db_property(self, property_name, candidates=None): """ Returns all objects having a given db field property. property_name = search string candidates - list of candidate objects to search """ property_name = "db_%s" % property_name.lstrip('db_') cand_restriction = candidates != None and Q( pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q() querykwargs = {property_name: None} try: return list( self.filter(cand_restriction).exclude(Q(**querykwargs))) except exceptions.FieldError: return []
def msg(self, text=None, from_obj=None, sessid=None, **kwargs): """ Evennia -> User This is the main route for sending data back to the user from the server. outgoing_string (string) - text data to send from_obj (Object/Player) - source object of message to send. Its at_msg_send() hook will be called. sessid - the session id of the session to send to. If not given, return to all sessions connected to this player. This is usually only relevant when using msg() directly from a player-command (from a command on a Character, the character automatically stores and handles the sessid). Can also be a list of sessids. kwargs (dict) - All other keywords are parsed as extra data. """ if "data" in kwargs: # deprecation warning logger.log_depmsg( "PlayerDB:msg() 'data'-dict keyword is deprecated. Use **kwargs instead." ) data = kwargs.pop("data") if isinstance(data, dict): kwargs.update(data) text = to_str(text, force_string=True) if text else "" if from_obj: # call hook try: _GA(from_obj, "at_msg_send")(text=text, to_obj=_GA(self, "typeclass"), **kwargs) except Exception: pass sessions = _MULTISESSION_MODE > 1 and sessid and _GA( self, "get_session")(sessid) or None if sessions: for session in make_iter(sessions): obj = session.puppet if obj and not obj.at_msg_receive(text=text, **kwargs): # if hook returns false, cancel send continue session.msg(text=text, **kwargs) else: # if no session was specified, send to them all for sess in _GA(self, 'get_all_sessions')(): sess.msg(text=text, **kwargs)
def func(self): "Implementing the command. " caller = self.caller player = caller if not self.args: self.msg("Usage: delcom <alias or channel>") return ostring = self.args.lower() channel = find_channel(caller, ostring, silent=True, noaliases=True) if channel: # we have given a channel name - unsubscribe if not channel.has_connection(player): self.msg("You are not listening to that channel.") return chkey = channel.key.lower() # find all nicks linked to this channel and delete them for nick in [ nick for nick in make_iter( caller.nicks.get(category="channel", return_obj=True)) if nick and nick.strvalue.lower() == chkey ]: nick.delete() disconnect = channel.disconnect(player) if disconnect: self.msg( "You stop listening to channel '%s'. Eventual aliases were removed." % channel.key) return else: # we are removing a channel nick channame = caller.nicks.get(key=ostring, category="channel") channel = find_channel(caller, channame, silent=True) if not channel: self.msg("No channel with alias '%s' was found." % ostring) else: if caller.nicks.get(ostring, category="channel"): caller.nicks.remove(ostring, category="channel") self.msg("Your alias '%s' for channel %s was cleared." % (ostring, channel.key)) else: self.msg("You had no such alias defined for this channel.")
def _get_prototype(dic, prot, protparents, visited): """ Recursively traverse a prototype dictionary, including multiple inheritance and self-reference detection """ visited.append(id(dic)) if "prototype" in dic: # move backwards through the inheritance for prototype in make_iter(dic["prototype"]): if id(prototype) in visited: # a loop was detected. Don't self-reference. continue # Build the prot dictionary in reverse order, overloading new_prot = _get_prototype(protparents.get(prototype, {}), prot, protparents, visited) prot.update(new_prot) prot.update(dic) prot.pop("prototype", None) # we don't need this anymore return prot
def func(self, *args, **kwargs): "decorator. Returns a list." self.__doc__ = method.__doc__ matches = make_iter(method(self, *args, **kwargs)) return [(hasattr(dbobj, "typeclass") and dbobj.typeclass) or dbobj for dbobj in make_iter(matches)]
def search( self, searchdata, global_search=False, use_nicks=True, # should this default to off? typeclass=None, location=None, attribute_name=None, quiet=False, exact=False): """ Returns the typeclass of an Object matching a search string/condition Perform a standard object search in the database, handling multiple results and lack thereof gracefully. By default, only objects in self's current location or inventory is searched. Note: to find Players, use eg. ev.player_search. Inputs: searchdata (str or obj): Primary search criterion. Will be matched against object.key (with object.aliases second) unless the keyword attribute_name specifies otherwise. Special strings: #<num> - search by unique dbref. This is always a global search. me,self - self-reference to this object <num>-<string> - can be used to differentiate between multiple same-named matches global_search (bool): Search all objects globally. This is overruled by "location" keyword. use_nicks (bool): Use nickname-replace (nicktype "object") on the search string typeclass (str or Typeclass, or list of either): Limit search only to Objects with this typeclass. May be a list of typeclasses for a broader search. location (Object): Specify a location to search, if different from the self's given location plus its contents. This can also be a list of locations. attribute_name (str): Define which property to search. If set, no key+alias search will be performed. This can be used to search database fields (db_ will be automatically appended), and if that fails, it will try to return objects having Attributes with this name and value equal to searchdata. A special use is to search for "key" here if you want to do a key-search without including aliases. quiet (bool) - don't display default error messages - return multiple matches as a list and no matches as None. If not set (default), will echo error messages and return None. exact (bool) - if unset (default) - prefers to match to beginning of string rather than not matching at all. If set, requires exact mathing of entire string. Returns: quiet=False (default): no match or multimatch: auto-echoes errors to self.msg, then returns None (results are handled by settings.SEARCH_AT_RESULT and settings.SEARCH_AT_MULTIMATCH_INPUT) match: a unique object match quiet=True: no match or multimatch: returns None or list of multi-matches match: a unique object match """ is_string = isinstance(searchdata, basestring) if use_nicks: # do nick-replacement on search searchdata = self.nicks.nickreplace(searchdata, categories=("object", "player"), include_player=True) candidates = None if (global_search or (is_string and searchdata.startswith("#") and len(searchdata) > 1 and searchdata[1:].isdigit())): # only allow exact matching if searching the entire database # or unique #dbrefs exact = True elif location: # location(s) were given candidates = [] for obj in make_iter(location): candidates.extend([o.dbobj for o in obj.contents]) else: # local search. Candidates are self.contents, self.location # and self.location.contents location = self.location candidates = self.contents if location: candidates = candidates + [location] + location.contents else: # normally we are included in location.contents candidates.append(self) # db manager expects database objects candidates = [obj.dbobj for obj in candidates] results = ObjectDB.objects.object_search(searchdata, attribute_name=attribute_name, typeclass=typeclass, candidates=candidates, exact=exact) if quiet: return results return _AT_SEARCH_RESULT(self, searchdata, results, global_search)