Make the ContribRPObject.search() fully accept all kwargs of normal obj.search. Resolves #1017.
This commit is contained in:
parent
f5ba4f6204
commit
89fbc44d15
1 changed files with 132 additions and 48 deletions
|
|
@ -74,11 +74,13 @@ from builtins import object
|
||||||
import re
|
import re
|
||||||
from re import escape as re_escape
|
from re import escape as re_escape
|
||||||
import itertools
|
import itertools
|
||||||
from evennia import DefaultObject, DefaultCharacter
|
from django.conf import settings
|
||||||
|
from evennia import DefaultObject, DefaultCharacter, ObjectDB
|
||||||
from evennia import Command, CmdSet
|
from evennia import Command, CmdSet
|
||||||
from evennia import ansi
|
from evennia import ansi
|
||||||
from evennia.utils.utils import lazy_property
|
from evennia.utils.utils import lazy_property, make_iter, variable_from_module
|
||||||
|
|
||||||
|
_AT_SEARCH_RESULT = variable_from_module(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
# Emote parser
|
# Emote parser
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
|
|
@ -1056,67 +1058,149 @@ class ContribRPObject(DefaultObject):
|
||||||
self.db.pose = ""
|
self.db.pose = ""
|
||||||
self.db.pose_default = "is here."
|
self.db.pose_default = "is here."
|
||||||
|
|
||||||
def search(self, searchdata, **kwargs):
|
def search(self, searchdata,
|
||||||
|
global_search=False,
|
||||||
|
use_nicks=True,
|
||||||
|
typeclass=None,
|
||||||
|
location=None,
|
||||||
|
attribute_name=None,
|
||||||
|
quiet=False,
|
||||||
|
exact=False,
|
||||||
|
candidates=None,
|
||||||
|
nofound_string=None,
|
||||||
|
multimatch_string=None,
|
||||||
|
use_dbref=None):
|
||||||
"""
|
"""
|
||||||
This version of search will pre-parse searchdata for eventual
|
Returns an Object matching a search string/condition, taking
|
||||||
matches against recogs and sdescs of candidates in the same
|
sdescs into account.
|
||||||
location.
|
|
||||||
|
Perform a standard object search in the database, handling
|
||||||
|
multiple results and lack thereof gracefully. By default, only
|
||||||
|
objects in the current `location` of `self` or its inventory are searched for.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
searchdata (str): Search string.
|
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 `searchdata`.
|
||||||
|
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 or list): Specify a location or multiple locations
|
||||||
|
to search. Note that this is used to query the *contents* of a
|
||||||
|
location and will not match for the location itself -
|
||||||
|
if you want that, don't set this or use `candidates` to specify
|
||||||
|
exactly which objects should be searched.
|
||||||
|
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 - this tells the
|
||||||
|
search method that the user wants to handle all errors
|
||||||
|
themselves. It also changes the return value type, see
|
||||||
|
below.
|
||||||
|
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.
|
||||||
|
candidates (list of objects): this is an optional custom list of objects
|
||||||
|
to search (filter) between. It is ignored if `global_search`
|
||||||
|
is given. If not set, this list will automatically be defined
|
||||||
|
to include the location, the contents of location and the
|
||||||
|
caller's contents (inventory).
|
||||||
|
nofound_string (str): optional custom string for not-found error message.
|
||||||
|
multimatch_string (str): optional custom string for multimatch error header.
|
||||||
|
use_dbref (bool or None): If None, only turn off use_dbref if we are of a lower
|
||||||
|
permission than Builders. Otherwise, honor the True/False value.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
match (Object, None or list): will return an Object/None if `quiet=False`,
|
||||||
|
otherwise it will return a list of 0, 1 or more matches.
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
Recog/sdesc matching is always turned off if the keyword
|
To find Players, use eg. `evennia.player_search`. If
|
||||||
`global_search` is set or `candidates` are given.
|
`quiet=False`, error messages will be handled by
|
||||||
|
`settings.SEARCH_AT_RESULT` and echoed automatically (on
|
||||||
|
error, return will be `None`). If `quiet=True`, the error
|
||||||
|
messaging is assumed to be handled by the caller.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if (isinstance(searchdata, basestring) and not
|
is_string = isinstance(searchdata, basestring)
|
||||||
(kwargs.get("global_search") or
|
|
||||||
kwargs.get("candidates"))):
|
if is_string:
|
||||||
# searchdata is a string; common self-references
|
# searchdata is a string; wrap some common self-references
|
||||||
if searchdata.lower() in ("here", ):
|
if searchdata.lower() in ("here", ):
|
||||||
return [self.location] if "quiet" in kwargs else self.location
|
return [self.location] if quiet else self.location
|
||||||
if searchdata.lower() in ("me", "self",):
|
if searchdata.lower() in ("me", "self",):
|
||||||
return [self] if "quiet" in kwargs else self
|
return [self] if quiet else self
|
||||||
if searchdata.lower() == self.key.lower():
|
|
||||||
return [self] if "quiet" in kwargs else self
|
|
||||||
|
|
||||||
# sdesc/recog matching
|
|
||||||
candidates = self.location.contents + self.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%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
|
|
||||||
|
|
||||||
# No matches. At this point we can't pass this on to the
|
if use_nicks:
|
||||||
# normal search mechanism just like that, since that will lead to a
|
# do nick-replacement on search
|
||||||
# security hole in the sdesc lookup: The normal search
|
searchdata = self.nicks.nickreplace(searchdata, categories=("object", "player"), include_player=True)
|
||||||
# mechanism will search by key+alias, so that means if we
|
|
||||||
# were to guess a Character's key (or #dbref), their
|
|
||||||
# object would be returned regardless of their sdesc. So
|
|
||||||
# we limit the access to the parent search to builders.
|
|
||||||
# A side effect of this is that all objects searchable
|
|
||||||
# with this mechanism must be possible to search by sdesc.
|
|
||||||
|
|
||||||
if not self.locks.check_lockstring(self, "perm(Builders)"):
|
if(global_search or (is_string and searchdata.startswith("#") and
|
||||||
# we block lookup unless we have access to continue
|
len(searchdata) > 1 and searchdata[1:].isdigit())):
|
||||||
if "nofound_string" in kwargs:
|
# only allow exact matching if searching the entire database
|
||||||
self.msg(kwargs["nofound_string"])
|
# or unique #dbrefs
|
||||||
|
exact = True
|
||||||
|
elif not candidates:
|
||||||
|
# no custom candidates given - get them automatically
|
||||||
|
if location:
|
||||||
|
# location(s) were given
|
||||||
|
candidates = []
|
||||||
|
for obj in make_iter(location):
|
||||||
|
candidates.extend(obj.contents)
|
||||||
|
else:
|
||||||
|
# local search. Candidates are taken from
|
||||||
|
# self.contents, self.location and
|
||||||
|
# self.location.contents
|
||||||
|
location = self.location
|
||||||
|
candidates = self.contents
|
||||||
|
if location:
|
||||||
|
candidates = candidates + [location] + location.contents
|
||||||
else:
|
else:
|
||||||
self.msg("There is no '%s' here." % searchdata)
|
# normally we don't need this since we are
|
||||||
return
|
# included in location.contents
|
||||||
|
candidates.append(self)
|
||||||
|
|
||||||
# fall back to normal search
|
# the sdesc-related substitution
|
||||||
return super(ContribRPObject, self).search(searchdata, **kwargs)
|
if use_dbref is None:
|
||||||
|
use_dbref = self.locks.check_lockstring(self, "perm(Builders)")
|
||||||
|
|
||||||
|
if candidates:
|
||||||
|
candidates = parse_sdescs_and_recogs(self, candidates,
|
||||||
|
_PREFIX + searchdata, search_mode=True)
|
||||||
|
results = []
|
||||||
|
for candidate in candidates:
|
||||||
|
results.extend(ObjectDB.objects.object_search(candidate.key,
|
||||||
|
attribute_name=attribute_name,
|
||||||
|
typeclass=typeclass,
|
||||||
|
candidates=candidates,
|
||||||
|
exact=exact,
|
||||||
|
use_dbref=use_dbref))
|
||||||
|
else:
|
||||||
|
results = ObjectDB.objects.object_search(searchdata,
|
||||||
|
attribute_name=attribute_name,
|
||||||
|
typeclass=typeclass,
|
||||||
|
candidates=candidates,
|
||||||
|
exact=exact,
|
||||||
|
use_dbref=use_dbref)
|
||||||
|
if quiet:
|
||||||
|
return results
|
||||||
|
return _AT_SEARCH_RESULT(results, self, query=searchdata,
|
||||||
|
nofound_string=nofound_string, multimatch_string=multimatch_string)
|
||||||
|
|
||||||
def get_display_name(self, looker, **kwargs):
|
def get_display_name(self, looker, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue