From 703fddcb7fe567cb5ff1c4d5ea530267b75e4950 Mon Sep 17 00:00:00 2001 From: Greg Taylor Date: Sun, 3 Dec 2006 00:25:10 +0000 Subject: [PATCH] Big big update. Lots of reorganization and shuffling. --- evennia/trunk/apps/objects/models.py | 73 +++++++++--- evennia/trunk/cmdhandler.py | 163 +-------------------------- evennia/trunk/commands_general.py | 72 ++++++++++++ evennia/trunk/commands_staff.py | 95 ++++++++++++++++ evennia/trunk/commands_unloggedin.py | 54 +++++++++ evennia/trunk/commonfuncs.py | 4 +- evennia/trunk/functions_db.py | 47 ++++++++ evennia/trunk/server.py | 13 +++ evennia/trunk/sessions.py | 2 +- 9 files changed, 345 insertions(+), 178 deletions(-) create mode 100644 evennia/trunk/commands_general.py create mode 100644 evennia/trunk/commands_staff.py create mode 100644 evennia/trunk/commands_unloggedin.py create mode 100644 evennia/trunk/functions_db.py diff --git a/evennia/trunk/apps/objects/models.py b/evennia/trunk/apps/objects/models.py index 158850ce2c..b8312bae23 100755 --- a/evennia/trunk/apps/objects/models.py +++ b/evennia/trunk/apps/objects/models.py @@ -1,6 +1,7 @@ from django.db import models from django.contrib.auth.models import User + class ObjectClass(models.Model): """ Each object class can have different behaviors to apply to it. @@ -66,21 +67,63 @@ class Object(models.Model): # attribute's names. attrib_list = {} - def __str__(self): - return "%s(%d)" % (self.name, self.id,) - - def is_type(self, typename): - """ - Do a string comparison of user's input and the object's type class object's - name. - """ - return self.type.name == typename - - def set_type(self, typename): - """ - Sets a object's type. - """ - pass + class Meta: + permissions = ( + ("can_examine", "Can examine objects"), + ) class Admin: list_display = ('name',) + + """ + BEGIN COMMON METHODS + """ + def move_to(self, target): + """ + Moves the object to a new location. + """ + self.location.contents_list.remove(self) + self.location = target + target.contents_list.append(self) + self.save() + + def dbref_match(self, oname): + import functions_db + """ + Check if the input (oname) can be used to identify this particular object + by means of a dbref match. + """ + if not functions_db.is_dbref(oname): + return False + + try: + is_match = int(oname[1:]) == self.id + except ValueError: + return false + + return is_match + + def name_match(self, oname): + import functions_db + """ + See if the input (oname) can be used to identify this particular object. + Check the # sign for dbref (exact) reference, and anything else is a + name comparison. + + 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] == '#': + return self.dbref_match(oname) + else: + return oname.lower() in self.name.lower() + + def filter_contents_from_str(self, oname): + """ + Search an object's contents for name and dbref matches. Don't put any + logic in here, we'll do that from the end of the command or function. + """ + return [prospect for prospect in self.contents_list if prospect.name_match(oname)] + + def __str__(self): + return "%s(%d)" % (self.name, self.id,) diff --git a/evennia/trunk/cmdhandler.py b/evennia/trunk/cmdhandler.py index af4dac3ed1..6b89df0e2b 100755 --- a/evennia/trunk/cmdhandler.py +++ b/evennia/trunk/cmdhandler.py @@ -1,168 +1,11 @@ -from django.contrib.auth.models import User -from apps.objects.models import Object -import settings -import string -from ansi import * +from commands_staff import StaffCommands +from commands_general import GenCommands +from commands_unloggedin import UnLoggedInCommands """ This is the command processing module. It is instanced once in the main server module and the handle() function is hit every time a player sends something. """ - -class GenCommands: - """ - Generic command class. Pretty much every command should go here for - now. - """ - def do_look(self, cdat): - """ - Handle looking at objects. - """ - session = cdat['session'] - server = cdat['server'] - player_loc = session.player_loc - player_loc_obj = server.object_list[player_loc] - - retval = "%s%s%s%s\n\r%s" % ( - ansi["normal"], - ansi["hilite"], - player_loc_obj.name, - ansi["normal"], - player_loc_obj.description, - ) - session.msg(retval) - - def do_quit(self, cdat): - """ - Gracefully disconnect the user as per his own request. - """ - session = cdat['session'] - session.msg("Quitting!") - session.handle_close() - - def do_who(self, cdat): - """ - Generic WHO command. - """ - session_list = cdat['server'].session_list - session = cdat['session'] - - retval = "Player Name\n\r" - for player in session_list: - retval += '%s\n\r' % (player,) - retval += '%d Players logged in.' % (len(session_list),) - - session.msg(retval) - - def do_say(self, cdat): - """ - Room-based speech command. - """ - session_list = cdat['server'].session_list - session = cdat['session'] - speech = cdat['uinput']['splitted'][1:] - players_present = [player for player in session_list if player.player_loc == session.player_loc and player != session] - - retval = "You say, '%s'" % (''.join(speech),) - for player in players_present: - player.msg("%s says, '%s'" % (session.name, speech,)) - - session.msg(retval) - - def do_version(self, cdat): - """ - Version info command. - """ - session = cdat['session'] - retval = "-"*50 +"\n\r" - retval += "Evennia %s\n\r" % (settings.EVENNIA_VERSION,) - retval += "-"*50 - session.msg(retval) - -class StaffCommands: - """ - Restricted staff commands. - """ - def do_dig(self, cdat): - """ - Digs a new room out. - """ - session = cdat['session'] - uinput= cdat['uinput'] - roomname = ''.join(uinput[1:]) - - if roomname == '': - session.msg("You must supply a room name!") - else: - newroom = Object() - newroom.name = roomname - newroom.type = "Room" - - def do_nextfree(self, cdat): - """ - Returns the next free object number. - """ - session = cdat['session'] - server = cdat['server'] - - nextfree = server.get_nextfree_dbnum() - retval = "Next free object number: %s" % (nextfree,) - - session.msg(retval) - -class UnLoggedInCommands: - """ - Commands that are available from the connect screen. - """ - def do_connect(self, cdat): - """ - This is the connect command at the connection screen. Fairly simple, - uses the Django database API and User model to make it extremely simple. - """ - session = cdat['session'] - uname = cdat['uinput']['splitted'][1] - password = cdat['uinput']['splitted'][2] - - account = User.objects.filter(username=uname) - user = account[0] - - autherror = "Invalid username or password!" - if account.count() == 0: - session.msg(autherror) - if not user.check_password(password): - session.msg(autherror) - else: - uname = user.username - session.login(user) - - def do_create(self, cdat): - """ - Handle the creation of new accounts. - """ - session = cdat['session'] - server = cdat['server'] - uname = cdat['uinput']['splitted'][1] - email = cdat['uinput']['splitted'][2] - password = cdat['uinput']['splitted'][3] - account = User.objects.filter(username=uname) - - if not account.count() == 0: - session.msg("There is already a player with that name!") - elif len(password) < 3: - session.msg("Your password must be 3 characters or longer.") - else: - server.create_user(session, uname, email, password) - - def do_quit(self, cdat): - """ - We're going to maintain a different version of the quit command - here for unconnected users for the sake of simplicity. The logged in - version will be a bit more complicated. - """ - session = cdat['session'] - session.msg("Disconnecting...") - session.handle_close() - # We'll use this for our getattr() in the Handler class. gencommands = GenCommands() staffcommands = StaffCommands() diff --git a/evennia/trunk/commands_general.py b/evennia/trunk/commands_general.py new file mode 100644 index 0000000000..b8bdff1619 --- /dev/null +++ b/evennia/trunk/commands_general.py @@ -0,0 +1,72 @@ +import settings +from ansi import * + +class GenCommands: + """ + Generic command class. Pretty much every command should go here for + now. + """ + def do_look(self, cdat): + """ + Handle looking at objects. + """ + session = cdat['session'] + server = cdat['server'] + player_loc = session.player_loc + player_loc_obj = server.object_list[player_loc] + + retval = "%s%s%s%s\n\r%s" % ( + ansi["normal"], + ansi["hilite"], + player_loc_obj.name, + ansi["normal"], + player_loc_obj.description, + ) + session.msg(retval) + + def do_quit(self, cdat): + """ + Gracefully disconnect the user as per his own request. + """ + session = cdat['session'] + session.msg("Quitting!") + session.handle_close() + + def do_who(self, cdat): + """ + Generic WHO command. + """ + session_list = cdat['server'].session_list + session = cdat['session'] + + retval = "Player Name\n\r" + for player in session_list: + retval += '%s\n\r' % (player,) + retval += '%d Players logged in.' % (len(session_list),) + + session.msg(retval) + + def do_say(self, cdat): + """ + Room-based speech command. + """ + session_list = cdat['server'].session_list + session = cdat['session'] + speech = cdat['uinput']['splitted'][1:] + players_present = [player for player in session_list if player.player_loc == session.player_loc and player != session] + + retval = "You say, '%s'" % (''.join(speech),) + for player in players_present: + player.msg("%s says, '%s'" % (session.name, speech,)) + + session.msg(retval) + + def do_version(self, cdat): + """ + Version info command. + """ + session = cdat['session'] + retval = "-"*50 +"\n\r" + retval += "Evennia %s\n\r" % (settings.EVENNIA_VERSION,) + retval += "-"*50 + session.msg(retval) diff --git a/evennia/trunk/commands_staff.py b/evennia/trunk/commands_staff.py new file mode 100644 index 0000000000..c39594810c --- /dev/null +++ b/evennia/trunk/commands_staff.py @@ -0,0 +1,95 @@ +from apps.objects.models import Object +import functions_db + +class StaffCommands: + """ + Restricted staff commands. + """ + def do_dig(self, cdat): + """ + Digs a new room out. + """ + session = cdat['session'] + uinput= cdat['uinput'] + roomname = ''.join(uinput[1:]) + + if roomname == '': + session.msg("You must supply a room name!") + else: + newroom = Object() + newroom.name = roomname + newroom.type = "Room" + + def do_nextfree(self, cdat): + """ + Returns the next free object number. + """ + session = cdat['session'] + server = cdat['server'] + + nextfree = server.get_nextfree_dbnum() + retval = "Next free object number: %s" % (nextfree,) + + session.msg(retval) + + def do_teleport(self, cdat): + """ + Teleports an object somewhere. + """ + session = cdat['session'] + pobject = session.pobject + server = cdat['server'] + args = cdat['uinput']['splitted'][1:] + + if len(args) == 0: + session.msg("Teleport where/what?") + return + + eq_args = args[0].split('=') + + # If we have more than one entry in our '=' delimited argument list, + # then we're doing a @tel =. If not, we're doing + # a direct teleport, @tel . + if len(eq_args) > 1: + session.msg("Equal sign present.") + else: + session.msg("No equal sign, direct tport.") + results = functions_db.local_and_global_search(pobject, ''.join(args)) + + if len(results) > 1: + session.msg("More than one match found (please narrow target):") + for result in results: + session.msg(" %s(#%s)" % (result.name, result.id,)) + elif len(results) == 0: + session.msg("I don't see that here.") + else: + session.msg("Teleported.") + pobject.move_to(results[0]) + #GenCommands.do_look(cdat) + + #session.msg("Args: %s\n\rEqargs: %s" % (args, eq_args,)) + + def do_find(self, cdat): + """ + Searches for an object of a particular name. + """ + session = cdat['session'] + server = cdat['server'] + searchstring = ''.join(cdat['uinput']['splitted'][1:]) + + if searchstring == '': + session.msg("No search pattern given.") + return + + memory_based = True + + if memory_based: + results = functions_db.list_search_object_namestr(server.object_list.values(), searchstring) + + if len(results) > 0: + session.msg("Name matches for: %s" % (searchstring,)) + for result in results: + session.msg(" %s(#%s)" % (result.name, result.id,)) + session.msg("%d matches returned." % (len(results),)) + else: + session.msg("No name matches found for: %s" % (searchstring,)) diff --git a/evennia/trunk/commands_unloggedin.py b/evennia/trunk/commands_unloggedin.py new file mode 100644 index 0000000000..404aa276bf --- /dev/null +++ b/evennia/trunk/commands_unloggedin.py @@ -0,0 +1,54 @@ +from django.contrib.auth.models import User + +class UnLoggedInCommands: + """ + Commands that are available from the connect screen. + """ + def do_connect(self, cdat): + """ + This is the connect command at the connection screen. Fairly simple, + uses the Django database API and User model to make it extremely simple. + """ + session = cdat['session'] + uname = cdat['uinput']['splitted'][1] + password = cdat['uinput']['splitted'][2] + + account = User.objects.filter(username=uname) + user = account[0] + + autherror = "Invalid username or password!" + if account.count() == 0: + session.msg(autherror) + if not user.check_password(password): + session.msg(autherror) + else: + uname = user.username + session.login(user) + + def do_create(self, cdat): + """ + Handle the creation of new accounts. + """ + session = cdat['session'] + server = cdat['server'] + uname = cdat['uinput']['splitted'][1] + email = cdat['uinput']['splitted'][2] + password = cdat['uinput']['splitted'][3] + account = User.objects.filter(username=uname) + + if not account.count() == 0: + session.msg("There is already a player with that name!") + elif len(password) < 3: + session.msg("Your password must be 3 characters or longer.") + else: + server.create_user(session, uname, email, password) + + def do_quit(self, cdat): + """ + We're going to maintain a different version of the quit command + here for unconnected users for the sake of simplicity. The logged in + version will be a bit more complicated. + """ + session = cdat['session'] + session.msg("Disconnecting...") + session.handle_close() diff --git a/evennia/trunk/commonfuncs.py b/evennia/trunk/commonfuncs.py index d2c628de4d..8addcb88c5 100755 --- a/evennia/trunk/commonfuncs.py +++ b/evennia/trunk/commonfuncs.py @@ -1,4 +1,4 @@ from apps.objects.models import Object, Attribute -def object_find_neighbor(searcher, target_string): - pass +def list_search_object_str(searchlist, ostring): + [prospect for prospect in searchlist if prospect.name_match(ostring)] diff --git a/evennia/trunk/functions_db.py b/evennia/trunk/functions_db.py new file mode 100644 index 0000000000..7430708efe --- /dev/null +++ b/evennia/trunk/functions_db.py @@ -0,0 +1,47 @@ +from apps.objects.models import Object + +def list_search_object_namestr(searchlist, ostring, dbref_only=False): + """ + Iterates through a list of objects and returns a list of + name matches. + """ + if dbref_only: + return [prospect for prospect in searchlist if prospect.dbref_match(ostring)] + else: + return [prospect for prospect in searchlist if prospect.name_match(ostring)] + +def local_and_global_search(object, ostring): + """ + Searches an object's location then globally for a dbref or name match. + """ + search_query = ''.join(ostring) + + local_matches = list_search_object_namestr(object.location.contents_list, search_query) + + # If the object the invoker is in matches, add it as well. + if object.location.dbref_match(ostring) or ostring == 'here': + local_matches.append(object.location) + + global_matches = [] + if is_dbref(ostring): + global_matches = list(Object.objects.filter(id=search_query)) + + return local_matches + global_matches + +def is_dbref(dbstring): + """ + Is the input a well-formed dbref number? + """ + try: + number = int(dbstring[1:]) + except ValueError: + return False + + if dbstring[0] != '#': + return False + elif number < 1: + return False + else: + return True + + diff --git a/evennia/trunk/server.py b/evennia/trunk/server.py index 81d335e77b..974702b902 100755 --- a/evennia/trunk/server.py +++ b/evennia/trunk/server.py @@ -51,6 +51,7 @@ class Server(dispatcher): # Load stuff up into memory for easy/quick access. self.load_configvalues() self.load_objects() + self.load_objects_contents() self.load_attributes() self.load_cmd_aliases() @@ -87,7 +88,19 @@ class Server(dispatcher): dbnum = object.id self.object_list[dbnum] = object print ' Objects Loaded: %d' % (len(self.object_list),) + + def load_objects_contents(self): + """ + Populate the 'contents_list' list for each object. + TODO: Make this a lot more efficient or merge into + load_objects. + """ + for key, object in self.object_list.iteritems(): + if object.location: + object.location.contents_list.append(object) + print ' * Object Inventories Populated' + def load_attributes(self): """ Load all of our attributes into memory. diff --git a/evennia/trunk/sessions.py b/evennia/trunk/sessions.py index cacbcd519a..bf1e08745f 100755 --- a/evennia/trunk/sessions.py +++ b/evennia/trunk/sessions.py @@ -81,7 +81,7 @@ class PlayerSession(async_chat): """ After the user has authenticated, handle logging him in. """ - self.pobject = user + self.pobject = Object.objects.filter(id=user.id)[0] self.name = user.username self.logged_in = True self.conn_time = time.time()