evennia/src/commands/search.py
Griatch 8074617285 Largely rewrote and refactored the help system.
The help entry database structure has changed! You have to resync or purge
your database or your will get problems!

New features:
* Help entry access now fully controlled by evennia permissions
* Categories for each help entry
* All entries are created dynamically, with a See also: footer calculated
  after the current state of the database.
* Indexes and topic list calculated on the fly (alphabetically/after category)
* Added auto-help help entries for all default commands.
* Only shows commands _actually implemented_ - MUX help db moved into 'MUX' category
  which is not shown by default.
* More powerful auto-help markup - supports categories and permissions (and inheritance).
* Global on/off switch for auto-help, when entering production
* Auto_help_override switch for selectively activating auto-help when developing
  new commands (like the old system).
* Refactored State help system; no more risk of overwriting global help entries.
* State help now defers to main help db when no match found; makes system more transparent.
* State help entries also support categories/permissions (state categories are not
  used much though).

Other updates:
* Added more commands to the batch processor
* Many bug-fixes.

/Griatch
2009-10-14 18:15:15 +00:00

241 lines
9.7 KiB
Python

"""
Implementation of the @search command that resembles MUX2.
"""
from django.db.models import Q
from src.objects.models import Object
from src import defines_global
from src.cmdtable import GLOBAL_CMD_TABLE
def _parse_restriction_split(source_object, restriction_split, search_low_dbnum,
search_high_dbnum):
"""
Parses a split restriction string and sets some needed variables.
Returns a tuple in the form of: (low dbnum, high dbnum)
"""
restriction_size = len(restriction_split)
if restriction_size >= 2:
try:
search_low_dbnum = int(restriction_split[1].strip())
except ValueError:
source_object.emit_to("Invalid value for low dbref limit.")
return False
if restriction_size >= 3:
try:
search_high_dbnum = int(restriction_split[2].strip())
except ValueError:
source_object.emit_to("Invalid value for high dbref limit.")
return False
return search_low_dbnum, search_high_dbnum
def display_results(source_object, search_query):
"""
Display the results to the searcher.
"""
# Lists to hold results by type. There may be a better way to do this
thing_list = []
room_list = []
exit_list = []
player_list = []
for obj in search_query:
if obj.is_thing():
thing_list.append(obj)
elif obj.is_room():
room_list.append(obj)
elif obj.is_exit():
exit_list.append(obj)
elif obj.is_player():
player_list.append(obj)
# Render each section for different object types
if thing_list:
source_object.emit_to("\n\rTHINGS:")
for thing in thing_list:
source_object.emit_to(thing.get_name(show_dbref=True, show_flags=True))
if exit_list:
source_object.emit_to("\n\rEXITS:")
for exit in exit_list:
source_object.emit_to(exit.get_name(show_dbref=True, show_flags=True))
if room_list:
source_object.emit_to("\n\rROOMS:")
for room in room_list:
source_object.emit_to(room.get_name(show_dbref=True, show_flags=True))
if player_list:
source_object.emit_to("\n\rPLAYER:")
for player in player_list:
source_object.emit_to(player.get_name(show_dbref=True, show_flags=True))
# Show the total counts by type
source_object.emit_to("\n\rFound: Rooms...%d Exits...%d Things...%d Players...%d" % (
len(room_list),
len(exit_list),
len(thing_list),
len(player_list)))
def build_query(source_object, search_query, search_player, search_type,
search_restriction, search_low_dbnum, search_high_dbnum):
"""
Builds and returns a QuerySet object, or None if an error occurs.
"""
# Look up an Object matching the player search query
if search_player:
# Replace the string variable with an Object reference
search_player = source_object.search_for_object(search_player)
# Use standard_objsearch to handle duplicate/nonexistant results
if not search_player:
return None
# Searching by player, chain filter
search_query = search_query.filter(owner=search_player)
# Check to ensure valid search types
if search_type == "type":
if search_restriction == "room":
search_query = search_query.filter(type=defines_global.OTYPE_ROOM)
elif search_restriction == "thing":
search_query = search_query.filter(type=defines_global.OTYPE_THING)
elif search_restriction == "exit":
search_query = search_query.filter(type=defines_global.OTYPE_EXIT)
elif search_restriction == "player":
search_query = search_query.filter(type=defines_global.OTYPE_PLAYER)
else:
source_object.emit_to("Invalid class. See 'help SEARCH CLASSES'.")
return None
elif search_type == "parent":
search_query = search_query.filter(script_parent__iexact=search_restriction)
elif search_type == "object" or search_type == "thing":
search_query = search_query.filter(name__icontains=search_restriction,
type=defines_global.OTYPE_THING)
elif search_type == "rooms":
search_query = search_query.filter(name__icontains=search_restriction,
type=defines_global.OTYPE_ROOM)
elif search_type == "exits":
search_query = search_query.filter(name__icontains=search_restriction,
type=defines_global.OTYPE_EXIT)
elif search_type == "players":
search_query = search_query.filter(name__icontains=search_restriction,
type=defines_global.OTYPE_PLAYER)
elif search_type == "zone":
zone_obj = source_object.search_for_object(search_restriction)
# Use search_for_object to handle duplicate/nonexistant results.
if not zone_obj:
return None
search_query = search_query.filter(zone=zone_obj)
elif search_type == "power":
# TODO: Need this once we have powers implemented.
source_object.emit_to("To be implemented...")
return None
elif search_type == "flags":
flag_list = search_restriction.split()
#source_object.emit_to("restriction: %s" % flag_list)
for flag in flag_list:
search_query = search_query.filter(Q(flags__icontains=flag) | Q(nosave_flags__icontains=flag))
if search_low_dbnum:
search_query = search_query.filter(id__gte=search_low_dbnum)
if search_high_dbnum:
search_query = search_query.filter(id__lte=search_high_dbnum)
return search_query
def cmd_search(command):
"""
search
Usage:
search <name>
Searches for owned objects as per MUX2.
"""
source_object = command.source_object
search_player = None
search_type = None
search_restriction = None
search_low_dbnum = None
search_high_dbnum = None
if not command.command_argument:
search_player = "#" + str(source_object.id)
else:
first_check_split = command.command_argument.split(' ', 1)
if '=' in first_check_split[0]:
# @search class=restriction...
eq_split = command.command_argument.split('=', 1)
search_type = eq_split[0]
restriction_split = eq_split[1].split(',')
search_restriction = restriction_split[0].strip()
#source_object.emit_to("@search class=restriction")
#source_object.emit_to("eq_split: %s" % eq_split)
#source_object.emit_to("restriction_split: %s" % restriction_split)
try:
search_low_dbnum, search_high_dbnum = _parse_restriction_split(source_object,
restriction_split,
search_low_dbnum,
search_high_dbnum)
except TypeError:
return
else:
# @search player
if len(first_check_split) == 1:
#source_object.emit_to("@search player")
#source_object.emit_to(first_check_split)
search_player = first_check_split[0]
else:
#source_object.emit_to("@search player class=restriction")
#source_object.emit_to(first_check_split)
search_player = first_check_split[0]
eq_split = first_check_split[1].split('=', 1)
search_type = eq_split[0]
#source_object.emit_to("eq_split: %s" % eq_split)
restriction_split = eq_split[1].split(',')
search_restriction = restriction_split[0]
#source_object.emit_to("restriction_split: %s" % restriction_split)
try:
search_low_dbnum, search_high_dbnum = _parse_restriction_split(source_object,
restriction_split,
search_low_dbnum,
search_high_dbnum)
except TypeError:
return
search_query = Object.objects.all()
#source_object.emit_to("search_player: %s" % search_player)
#source_object.emit_to("search_type: %s" % search_type)
#source_object.emit_to("search_restriction: %s" % search_restriction)
#source_object.emit_to("search_lowdb: %s" % search_low_dbnum)
#source_object.emit_to("search_highdb: %s" % search_high_dbnum)
# Clean up these variables for comparisons.
try:
search_type = search_type.strip().lower()
except AttributeError:
pass
try:
search_restriction = search_restriction.strip().lower()
except AttributeError:
pass
# Build the search query.
search_query = build_query(source_object, search_query, search_player, search_type,
search_restriction, search_low_dbnum,
search_high_dbnum)
# Something bad happened in query construction, die here.
if search_query is None:
return
display_results(source_object, search_query)
GLOBAL_CMD_TABLE.add_command("@search", cmd_search,
priv_tuple=("objects.info",),
help_category="Building")