From 23e63111cc9ad0931c68d8706ff4df6651248de2 Mon Sep 17 00:00:00 2001 From: Griatch Date: Wed, 23 Sep 2015 18:51:29 +0200 Subject: [PATCH] Further work on stabilizing output across different situations. --- evennia/contrib/rpsystem.py | 157 +++++++++++++++++++---------------- evennia/locks/lockhandler.py | 2 + 2 files changed, 89 insertions(+), 70 deletions(-) diff --git a/evennia/contrib/rpsystem.py b/evennia/contrib/rpsystem.py index dc72b54b69..98c0a0f96f 100644 --- a/evennia/contrib/rpsystem.py +++ b/evennia/contrib/rpsystem.py @@ -108,6 +108,9 @@ _RE_REF = re.compile(r"\{+\#([0-9]+)\}+") # This regex is used to quickly reference one self in an emote. _RE_SELF_REF = re.compile(r"/me|@", _RE_FLAGS) +# regex for non-alphanumberic end of a string +_RE_CHAREND = re.compile(r"\W+$", _RE_FLAGS) + # reference markers for language _RE_REF_LANG = re.compile(r"\{+\##([0-9]+)\}+") # language says in the emote are on the form "..." or langname"..." (no spaces). @@ -262,7 +265,6 @@ def parse_language(speaker, emote): return emote, mapping - def parse_sdescs_and_recogs(sender, candidates, string, search_mode=False): """ Read a textraw emote and parse it into an intermediary @@ -379,7 +381,9 @@ def parse_sdescs_and_recogs(sender, candidates, string, search_mode=False): mapping[key] = obj if search_mode else (obj.db.sdesc or obj.key) else: refname = marker_match.group() - reflist = ["%s%s%s (%s)" % (inum+1, _NUM_SEP, _RE_PREFIX.sub("", refname), text) + reflist = ["%s%s%s (%s%s)" % (inum+1, _NUM_SEP, + _RE_PREFIX.sub("", refname), text, + " (%s)" % sender.key if sender == obj else "") for inum, (obj, text) in enumerate(bestmatches) if score == maxscore] errors.append(_EMOTE_MULTIMATCH_ERROR.format( ref=marker_match.group(), reflist="\n ".join(reflist))) @@ -401,50 +405,7 @@ def parse_sdescs_and_recogs(sender, candidates, string, search_mode=False): return string, mapping -def receive_emote(sender, receiver, emote, sdesc_mapping, language_mapping): - """ - Receive a pre-parsed emote. - - Args: - sender (Object): The object sending the emote. - receiver (Object): The object receiving (seeing) the emote. - emote (str): A pre-parsed emote string created with - `parse_emote`, with {#dbref} and {##nn} references for - objects and languages respectively. - sdesc_mapping (dict): A mapping between "#dbref" keys and - objects. - language_mapping (dict): A mapping "##dbref" and (langname, saytext). - - Returns: - finished_emote (str): The finished and ready-to-send emote - string, customized for receiver. - - Notes: - This function will translage all text back based both on sdesc - and recog mappings, but will give presedence to recog mappings. - """ - # we make a local copy that we can modify - mapping = copy(sdesc_mapping) - # overload mapping with receiver's recogs (which is on the same form) - try: - mapping.update(receiver.recog.ref2recog) - except AttributeError: - pass - # handle the language mapping, which always produce different keys ##nn - for key, (langname, saytext) in language_mapping.iteritems(): - # color say's white - mapping[key] = "{w%s{n" % _LANGUAGE_TRANSLATE(sender, receiver, langname, saytext) - # make sure receiver always sees their real name - rkey = "#%i" % receiver.id - if rkey in mapping: - mapping[rkey] = receiver.key - - #TODO - color handling - mapping = dict((key, "{b%s{n" % val) for key, val in mapping.iteritems()) - receiver.msg(emote.format(**mapping)) - - -def send_emote(sender, receivers, emote, no_anonymous=True): +def send_emote(sender, receivers, emote, anonymous_add="first"): """ Main access function for distribute an emote. @@ -454,10 +415,12 @@ def send_emote(sender, receivers, emote, no_anonymous=True): will also form the basis for which sdescs are 'valid' to use in the emote. emote (str): The raw emote string as input by emoter. - no_anonymous (bool, optional): Do not allow anonynous - emotes, that is, emotes without sender self-referencing, - but add an extra reference to the end of the emote - if so. + anonymous_add (str or None, optional): If `sender` is not + self-referencing in the emote, this will auto-add + `sender`'s data to the emote. Possible values are + - None: No auto-add at anonymous emote + - 'last': Add sender to the end of emote as [sender] + - 'first': Prepend sender to start of emote. """ try: @@ -468,15 +431,39 @@ def send_emote(sender, receivers, emote, no_anonymous=True): sender.msg(err.message) return - if no_anonymous and not "#%i" % sender.id in sdesc_mapping: + if anonymous_add and not "#%i" % sender.id in sdesc_mapping: # no self-reference in the emote - add to the end key = "#%i" % sender.id - emote = "%s [%s]" % (emote, "{%s}" % key) sdesc_mapping[key] = sender.sdesc.get() or sender.key + if anonymous_add == 'first': + possessive = "" if emote.startswith('\'') else " " + emote = "%s%s%s" % ("{%s}" % key, possessive, emote) + else: + emote = "%s [%s]" % (emote, "{%s}" % key) - # broadcast emote + # broadcast emote to everyone for receiver in receivers: - receive_emote(sender, receiver, emote, sdesc_mapping, language_mapping) + # we make a temporary copy that we can modify + mapping = copy(sdesc_mapping) + # overload mapping with receiver's recogs (which is on the same form) + try: + mapping.update(receiver.recog.ref2recog) + except AttributeError: + pass + # handle the language mapping, which always produce different keys ##nn + for key, (langname, saytext) in language_mapping.iteritems(): + # color say's white + mapping[key] = "{w%s{n" % _LANGUAGE_TRANSLATE(sender, receiver, langname, saytext) + # make sure receiver always sees their real name + rkey = "#%i" % receiver.id + if rkey in mapping: + mapping[rkey] = receiver.key + + #TODO - color handling + mapping = dict((key, "%s" % val) for key, val in mapping.iteritems()) + + # do the template replacement + receiver.msg(emote.format(**mapping)) #------------------------------------------------------------ @@ -524,9 +511,9 @@ class CmdEmote(RPCommand): # replaces the main emote # we also include ourselves here. emote = self.args targets = self.caller.location.contents - if not emote.endswith("."): + if not emote.endswith((".", "!")): emote = "%s." % emote - send_emote(self.caller, targets, emote, no_anonymous=True) + send_emote(self.caller, targets, emote, anonymous_add='first') class CmdSdesc(RPCommand): # set/look at own sdesc @@ -549,7 +536,9 @@ class CmdSdesc(RPCommand): # set/look at own sdesc caller.msg("Usage: sdesc ") return else: - sdesc = caller.sdesc.add(self.args) + # strip non-alfanum chars from end of sdesc + sdesc = _RE_CHAREND.sub("", self.args) + sdesc = caller.sdesc.add(sdesc) caller.msg("Your sdesc was set to '%s'." % sdesc) @@ -562,6 +551,8 @@ class CmdPose(Command): # set current pose and default pose pose default pose reset pose obj = + pose default obj = + pose reset obj = Examples: pose leans against the tree @@ -632,7 +623,7 @@ class CmdPose(Command): # set current pose and default pose caller.msg("Default pose is now '%s %s'." % (target_name, pose)) return else: - caller.db.pose = pose + target.db.pose = pose caller.msg("Pose will read '%s %s'." % (target_name, pose)) @@ -675,13 +666,17 @@ class CmdRecog(Command): # assign personal alias to object in room if nmatches == 0: caller.msg(_EMOTE_NOMATCH_ERROR.format(ref=sdesc)) elif nmatches > 1: - reflist = ["%s%s%s (%s)" % (inum+1, _NUM_SEP, _RE_PREFIX.sub("", sdesc), obj.sdesc.get()) + reflist = ["%s%s%s (%s%s)" % (inum+1, _NUM_SEP, + _RE_PREFIX.sub("", sdesc), caller.recog.get(obj), + " (%s)" % caller.key if caller == obj else "") for inum, obj in enumerate(matches)] caller.msg(_EMOTE_MULTIMATCH_ERROR.format(ref=sdesc,reflist="\n ".join(reflist))) else: # we have all we need, add the recog alias + obj = matches[0] + sdesc = obj.sdesc.get() if hasattr(obj, "sdesc") else obj.key alias = caller.recog.add(obj, alias) - caller.msg("You will now remember {w%s{n as {w%s{n." % (obj.db.sdesc, alias)) + caller.msg("You will now remember {w%s{n as {w%s{n." % (sdesc, alias)) class CmdLanguage(Command): # list available languages @@ -871,10 +866,11 @@ class RecogHandler(object): # mapping #dbref:obj key = "#%i" % obj.id - self.db._ref2recog[key] = recog - self.db._obj2recog[obj] = recog + print "self.obj:", self.obj, self.obj.db._ref2recog + self.obj.db._recog_ref2recog[key] = recog + self.obj.db._recog_obj2recog[obj] = recog regex = ordered_permutation_regex(cleaned_recog) - self.db._obj2regex[obj] = regex + self.obj.db._recog_obj2regex[obj] = regex # local caching self.ref2recog[key] = recog self.obj2recog[obj] = recog @@ -883,14 +879,16 @@ class RecogHandler(object): def get(self, obj): """ - Get recog replacement string, if one exists. + Get recog replacement string, if one exists, otherwise + get sdesc and as a last resort, the object's key. Args: obj (Object): The object, whose sdesc to replace Returns: recog (str): The replacement string to use. """ - return self.obj2recog.get(obj) + return self.obj2recog.get(obj, obj.sdesc.get() + if hasattr(obj, "sdesc") else obj.key) def remove(self, obj): """ @@ -900,9 +898,9 @@ class RecogHandler(object): obj (Object): The object for which to remove recog. """ if obj in self.db.obj2recog: - del self.db.obj2recog[obj] - del self.db.obj2regex[obj] - del self.db.ref2regex["#%i" % obj.id] + del self.db._recog_obj2recog[obj] + del self.db._recog_obj2regex[obj] + del self.db._recog_ref2regex["#%i" % obj.id] self._cache() def get_regex_tuple(self, obj): @@ -953,17 +951,36 @@ class RPObject(DefaultObject): if (isinstance(searchdata, basestring) and not (kwargs.get("global_search") or kwargs.get("candidates"))): - matches = parse_sdescs_and_recogs(self, self.location.contents, + # searchdata is a string; common self-references + if searchdata.lower() in ("here", ): + return [self.location] if "quiet" in kwargs else self.location + if searchdata.lower() in ("me", "self",): + return [self] if "quiet" in kwargs else self + if searchdata.lower() == self.key.lower(): + return [self] if "quiet" in kwargs else self + + # sdesc/recog matching + candidates = self.location.contents + matches = parse_sdescs_and_recogs(self, candidates, _PREFIX + searchdata, search_mode=True) nmatches = len(matches) if nmatches == 1: return matches[0] elif nmatches > 1: # multimatch - reflist = ["%s%s%s (%s)" % (inum+1, _NUM_SEP, searchdata, obj.sdesc.get()) + reflist = ["%s%s%s (%s%s)" % (inum+1, _NUM_SEP, searchdata, self.recog.get(obj), + " (%s)" % self.key if self == obj else "") for inum, obj in enumerate(matches)] self.msg(_EMOTE_MULTIMATCH_ERROR.format(ref=searchdata,reflist="\n ".join(reflist))) return + + if not self.locks.check_lockstring(self, "perm(Builders)"): + # we block lookup unless we have access to continue + if "nofound_string" in kwargs: + self.msg(kwargs["nofound_string"]) + else: + self.msg("There is nothing here called '%s'." % searchdata) + return # fall back to normal search return super(RPObject, self).search(searchdata, **kwargs) diff --git a/evennia/locks/lockhandler.py b/evennia/locks/lockhandler.py index 6df388e26e..463cc7598b 100644 --- a/evennia/locks/lockhandler.py +++ b/evennia/locks/lockhandler.py @@ -503,6 +503,8 @@ class LockHandler(object): or (hasattr(accessing_obj, 'player') and hasattr(accessing_obj.player, 'is_superuser') and accessing_obj.player.is_superuser) or (hasattr(accessing_obj, 'get_player') and (not accessing_obj.get_player() or accessing_obj.get_player().is_superuser))): return True + if not ":" in lockstring: + lockstring = "%s:%s" % ("_dummy", lockstring) locks = self._parse_lockstring(lockstring)