mirror of
https://github.com/evennia/evennia.git
synced 2026-03-23 08:16:30 +01:00
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
|
||||
from re import escape as re_escape
|
||||
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 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
|
||||
#------------------------------------------------------------
|
||||
|
|
@ -1056,67 +1058,149 @@ class ContribRPObject(DefaultObject):
|
|||
self.db.pose = ""
|
||||
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
|
||||
matches against recogs and sdescs of candidates in the same
|
||||
location.
|
||||
Returns an Object matching a search string/condition, taking
|
||||
sdescs into account.
|
||||
|
||||
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:
|
||||
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:
|
||||
Recog/sdesc matching is always turned off if the keyword
|
||||
`global_search` is set or `candidates` are given.
|
||||
To find Players, use eg. `evennia.player_search`. If
|
||||
`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
|
||||
(kwargs.get("global_search") or
|
||||
kwargs.get("candidates"))):
|
||||
# searchdata is a string; common self-references
|
||||
is_string = isinstance(searchdata, basestring)
|
||||
|
||||
if is_string:
|
||||
# searchdata is a string; wrap some common self-references
|
||||
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",):
|
||||
return [self] if "quiet" in kwargs else self
|
||||
if searchdata.lower() == self.key.lower():
|
||||
return [self] if "quiet" in kwargs else self
|
||||
return [self] if quiet 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
|
||||
# normal search mechanism just like that, since that will lead to a
|
||||
# security hole in the sdesc lookup: The normal search
|
||||
# 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 use_nicks:
|
||||
# do nick-replacement on search
|
||||
searchdata = self.nicks.nickreplace(searchdata, categories=("object", "player"), include_player=True)
|
||||
|
||||
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"])
|
||||
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 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:
|
||||
self.msg("There is no '%s' here." % searchdata)
|
||||
return
|
||||
# normally we don't need this since we are
|
||||
# included in location.contents
|
||||
candidates.append(self)
|
||||
|
||||
# fall back to normal search
|
||||
return super(ContribRPObject, self).search(searchdata, **kwargs)
|
||||
# the sdesc-related substitution
|
||||
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):
|
||||
"""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue