mirror of
https://github.com/evennia/evennia.git
synced 2026-04-04 06:57:16 +02:00
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:
parent
37d66093cc
commit
d58f4eb517
16 changed files with 818 additions and 698 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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":
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue