Looking through our command code after a long hiatus, I realized that it was pretty much awful. So here's part 1 of the command interpreter overhaul.

- The command handler has been drastically simplified. We were doing way too much processing in the handler that should have been done in the individual command functions themselves.
- The 'cdat' dict we were previously passing around has been replaced with a Command object that has useful methods for performing some of the parsing command functions will probably want to do from time to time.
- All commands were updated to use the new Command object, tested, and cleaned up in general.
- A lot of formatting was cleaned up.
- A lot of previously un-found bugs and limitations were fixed.
- The 'page' command has been broken out into its own file, since it's going to have a number of functions that would otherwise clutter commands/general.py.

Expect a commit (probably later today) that will clean up the second half of cmdhandler.py.
This commit is contained in:
Greg Taylor 2008-12-14 20:21:02 +00:00
parent 37d66093cc
commit d58f4eb517
16 changed files with 818 additions and 698 deletions

View file

@ -75,9 +75,11 @@ class ObjectManager(models.Manager):
else:
o_query = self.filter(name__icontains=ostring)
return o_query.exclude(type=defines_global.OTYPE_GARBAGE)
return o_query.exclude(type__in=[defines_global.OTYPE_GARBAGE,
defines_global.OTYPE_GOING])
def list_search_object_namestr(self, searchlist, ostring, dbref_only=False, limit_types=False, match_type="fuzzy"):
def list_search_object_namestr(self, searchlist, ostring, dbref_only=False,
limit_types=False, match_type="fuzzy"):
"""
Iterates through a list of objects and returns a list of
name matches.
@ -98,7 +100,9 @@ class ObjectManager(models.Manager):
return [prospect for prospect in searchlist if prospect.name_match(ostring, match_type=match_type)]
def standard_plr_objsearch(self, session, ostring, search_contents=True, search_location=True, dbref_only=False, limit_types=False):
def standard_plr_objsearch(self, session, ostring, search_contents=True,
search_location=True, dbref_only=False,
limit_types=False):
"""
Perform a standard object search via a player session, handling multiple
results and lack thereof gracefully.
@ -107,7 +111,11 @@ class ObjectManager(models.Manager):
ostring: (str) The string to match object names against.
"""
pobject = session.get_pobject()
results = self.local_and_global_search(pobject, ostring, search_contents=search_contents, search_location=search_location, dbref_only=dbref_only, limit_types=limit_types)
results = self.local_and_global_search(pobject, ostring,
search_contents=search_contents,
search_location=search_location,
dbref_only=dbref_only,
limit_types=limit_types)
if len(results) > 1:
session.msg("More than one match found (please narrow target):")
@ -136,14 +144,14 @@ class ObjectManager(models.Manager):
def player_alias_search(self, searcher, ostring):
"""
Search players by alias. Returns a list of objects whose "ALIAS" attribute
exactly (not case-sensitive) matches ostring.
Search players by alias. Returns a list of objects whose "ALIAS"
attribute exactly (not case-sensitive) matches ostring.
searcher: (Object) The object doing the searching.
ostring: (string) The alias string to search for.
"""
search_query = ''.join(ostring)
Attribute = ContentType.objects.get(app_label="objects", model="attribute").get_model()
Attribute = ContentType.objects.get(app_label="objects",
model="attribute").model_class()
results = Attribute.objects.select_related().filter(attr_name__exact="ALIAS").filter(attr_value__iexact=ostring)
return [prospect.get_object() for prospect in results if prospect.get_object().is_player()]
@ -171,11 +179,17 @@ class ObjectManager(models.Manager):
except IndexError:
return None
def is_dbref(self, dbstring):
"""
Is the input a well-formed dbref number?
"""
util_object.is_dbref(dbstring)
def dbref_search(self, dbref_string, limit_types=False):
"""
Searches for a given dbref.
dbref_number: (string) The dbref to search for
dbref_number: (string) The dbref to search for. With # sign.
limit_types: (list of int) A list of Object type numbers to filter by.
"""
if not util_object.is_dbref(dbref_string):
@ -192,7 +206,9 @@ class ObjectManager(models.Manager):
except IndexError:
return None
def local_and_global_search(self, searcher, ostring, search_contents=True, search_location=True, dbref_only=False, limit_types=False):
def local_and_global_search(self, searcher, ostring, search_contents=True,
search_location=True, dbref_only=False,
limit_types=False):
"""
Searches an object's location then globally for a dbref or name match.
@ -203,14 +219,13 @@ class ObjectManager(models.Manager):
dbref_only: (bool) Only compare dbrefs.
limit_types: (list of int) A list of Object type numbers to filter by.
"""
search_query = ''.join(ostring)
search_query = ostring
# This is a global dbref search. Not applicable if we're only searching
# searcher's contents/locations, dbref comparisons for location/contents
# searches are handled by list_search_object_namestr() below.
if util_object.is_dbref(ostring):
search_num = search_query[1:]
dbref_match = dbref_search(search_num, limit_types)
dbref_match = self.dbref_search(search_query, limit_types)
if dbref_match is not None:
return [dbref_match]
@ -224,7 +239,7 @@ class ObjectManager(models.Manager):
if search_query[0] == "*":
# Player search- gotta search by name or alias
search_target = search_query[1:]
player_match = player_name_search(search_target)
player_match = self.player_name_search(search_target)
if player_match is not None:
return [player_match]
@ -232,9 +247,11 @@ class ObjectManager(models.Manager):
# Handle our location/contents searches. list_search_object_namestr() does
# name and dbref comparisons against search_query.
if search_contents:
local_matches += list_search_object_namestr(searcher.get_contents(), search_query, limit_types)
local_matches += self.list_search_object_namestr(searcher.get_contents(),
search_query, limit_types)
if search_location:
local_matches += list_search_object_namestr(searcher.get_location().get_contents(), search_query, limit_types=limit_types)
local_matches += self.list_search_object_namestr(searcher.get_location().get_contents(),
search_query, limit_types=limit_types)
return local_matches
def get_user_from_email(self, uemail):
@ -264,7 +281,9 @@ class ObjectManager(models.Manager):
* home: Reference to another object to home to. If not specified, use
location key for home.
"""
next_dbref = get_nextfree_dbnum()
next_dbref = self.get_nextfree_dbnum()
Object = ContentType.objects.get(app_label="objects",
model="object").model_class()
new_object = Object()
new_object.id = next_dbref
@ -301,27 +320,25 @@ class ObjectManager(models.Manager):
return new_object
def create_user(self, cdat, uname, email, password):
def create_user(self, command, uname, email, password):
"""
Handles the creation of new users.
"""
session = cdat['session']
server = cdat['server']
session = command.session
server = command.server
start_room = int(ConfigValue.objects.get_configvalue('player_dbnum_start'))
start_room_obj = get_object_from_dbref(start_room)
start_room_obj = self.get_object_from_dbref(start_room)
# The user's entry in the User table must match up to an object
# on the object table. The id's are the same, we need to figure out
# the next free unique ID to use and make sure the two entries are
# the same number.
uid = get_nextfree_dbnum()
print 'UID', uid
uid = self.get_nextfree_dbnum()
# If this is an object, we know to recycle it since it's garbage. We'll
# pluck the user ID from it.
if not str(uid).isdigit():
uid = uid.id
print 'UID2', uid
user = User.objects.create_user(uname, email, password)
# It stinks to have to do this but it's the only trivial way now.
@ -337,8 +354,12 @@ class ObjectManager(models.Manager):
user = User.objects.get(id=uid)
# Create a player object of the same ID in the Objects table.
odat = {"id": uid, "name": uname, "type": 1, "location": start_room_obj, "owner": None}
user_object = create_object(odat)
odat = {"id": uid,
"name": uname,
"type": 1,
"location": start_room_obj,
"owner": None}
user_object = self.create_object(odat)
# Activate the player's session and set them loose.
session.login(user)

View file

@ -413,7 +413,8 @@ class Object(models.Model):
uobj.is_active = False
uobj.save()
except:
functions_general.log_errmsg('Destroying object %s but no matching player.' % (self,))
functions_general.log_errmsg('Destroying object %s but no matching player.'
% (self,))
# Set the object type to GOING
self.type = 5
@ -490,7 +491,7 @@ class Object(models.Model):
obj.emit_to("You seem to have found a place that does not exist.")
# If home is still None, it goes to a null location.
obj.move_to(home, True)
obj.move_to(home)
obj.save()
def set_attribute(self, attribute, new_value):
@ -538,7 +539,8 @@ class Object(models.Model):
attrs = Attribute.objects.filter(attr_object=self)
# Compile a regular expression that is converted from the user's
# wild-carded search string.
match_exp = re.compile(functions_general.wildcard_to_regexp(searchstr), re.IGNORECASE)
match_exp = re.compile(functions_general.wildcard_to_regexp(searchstr),
re.IGNORECASE)
# If the regular expression search returns a match object, add to results.
if exclude_noset:
return [attr for attr in attrs if match_exp.search(attr.get_name()) and not attr.is_hidden() and not attr.is_noset()]
@ -707,22 +709,34 @@ class Object(models.Model):
except:
return None
def move_to(self, target, quiet=False):
def move_to(self, target, quiet=False, force_look=True):
"""
Moves the object to a new location.
target: (Object) Reference to the object to move to.
quiet: (bool) If true, don't emit left/arrived messages.
force_look: (bool) If true and target is a player, make them 'look'.
"""
if not quiet:
if self.get_location():
self.get_location().emit_to_contents("%s has left." % (self.get_name(),), exclude=self)
location = self.get_location()
if location:
location.emit_to_contents("%s has left." %
(self.get_name(),), exclude=self)
if location.is_player():
location.emit_to("%s has left your inventory." %
(self.get_name()))
self.location = target
self.save()
if not quiet:
self.get_location().emit_to_contents("%s has arrived." % (self.get_name(),), exclude=self)
arrival_message = "%s has arrived." % (self.get_name())
self.get_location().emit_to_contents(arrival_message, exclude=self)
if self.location.is_player():
self.location.emit_to("%s is now in your inventory." % (self.get_name()))
if force_look and self.is_player():
self.get_session().execute_cmd('look')
def dbref_match(self, oname):
"""
@ -750,7 +764,7 @@ class Object(models.Model):
NOTE: A 'name' can be a dbref or the actual name of the object. See
dbref_match for an exclusively name-based match.
"""
if oname[0] == '#':
if util_object.is_dbref(oname):
# First character is a pound sign, looks to be a dbref.
return self.dbref_match(oname)
elif match_type == "exact":

View file

@ -10,6 +10,8 @@ def is_dbref(dbstring):
number = int(dbstring[1:])
except ValueError:
return False
except TypeError:
return False
if not dbstring.startswith("#"):
return False