diff --git a/apps/objects/managers/object.py b/apps/objects/managers/object.py index 83e7c15bb9..548c4004bf 100644 --- a/apps/objects/managers/object.py +++ b/apps/objects/managers/object.py @@ -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) diff --git a/apps/objects/models.py b/apps/objects/models.py index 28c7c5a7de..b5ca789a89 100755 --- a/apps/objects/models.py +++ b/apps/objects/models.py @@ -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": diff --git a/apps/objects/util/object.py b/apps/objects/util/object.py index c7d6f03e2e..1e8cb9d242 100644 --- a/apps/objects/util/object.py +++ b/apps/objects/util/object.py @@ -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 diff --git a/src/cmdhandler.py b/src/cmdhandler.py index c0a8eccf1c..7e1fd61b83 100755 --- a/src/cmdhandler.py +++ b/src/cmdhandler.py @@ -17,89 +17,104 @@ class UnknownCommand(Exception): """ Throw this when a user enters an an invalid command. """ + pass + +class Command(object): + # Reference to the master server object. + server = None + # The player session that the command originated from. + session = None + # The entire raw, un-parsed command. + raw_input = None + # Just the root command. IE: if input is "look dog", this is just "look". + command_string = None + # A list of switches in the form of strings. + command_switches = [] + # The un-parsed argument provided. IE: if input is "look dog", this is "dog". + command_argument = None + + def parse_command_switches(self): + """ + Splits any switches out of a command_string into the command_switches + list, and yanks the switches out of the original command_string. + """ + splitted_command = self.command_string.split('/') + self.command_switches = splitted_command[1:] + self.command_string = splitted_command[0] + + def parse_command(self): + """ + Breaks the command up into the main command string, a list of switches, + and a string containing the argument provided with the command. More + specific processing is left up to the individual command functions. + """ + try: + """ + Break the command in half into command and argument. If the + command string can't be parsed, it has no argument and is + handled by the except ValueError block below. + """ + (self.command_string, self.command_argument) = self.raw_input.split(' ', 1) + self.command_argument = self.command_argument.strip() + if self.command_argument == '': + self.command_argument = None + except ValueError: + """ + No arguments. IE: look, who. + """ + self.command_string = self.raw_input + finally: + # Parse command_string for switches, regardless of what happens. + self.parse_command_switches() + + def __init__(self, raw_input, server=None, session=None): + self.server = server + self.raw_input = raw_input + self.session = session + self.parse_command() + + def arg_has_target(self): + """ + Returns true if the argument looks to be target-style. IE: + page blah=hi + kick ball=north + """ + return "=" in self.command_argument + + def get_arg_targets(self, delim=','): + """ + Returns a list of targets from the argument. These happen before + the '=' sign and may be separated by a delimiter. + """ + # Make sure we even have a target (= sign). + if not self.arg_has_target(): + return None + + target = self.command_argument.split('=', 1)[0] + return [targ.strip() for targ in target.split(delim)] + + def get_arg_target_value(self): + """ + In a case of something like: page bob=Hello there, the target is "bob", + while the value is "Hello there". This function returns the portion + of the command that takes place after the first equal sign. + """ + # Make sure we even have a target (= sign). + if not self.arg_has_target(): + return None + + return self.command_argument.split('=', 1)[1] def match_exits(pobject, searchstr): """ See if we can find an input match to exits. """ - exits = pobject.get_location().get_contents(filter_type=4) - return Object.objects.list_search_object_namestr(exits, searchstr, match_type="exact") + exits = pobject.get_location().get_contents(filter_type=defines_global.OTYPE_EXIT) + return Object.objects.list_search_object_namestr(exits, + searchstr, + match_type="exact") -def parse_command(command_string): - """ - Tries to handle the most common command strings and returns a dictionary with various data. - Common command types: - - Complex: - @pemit[/option] [/option]= - - Simple: - look - look - - I'm not married to either of these terms, but I couldn't think of anything - better. If you can, lets change it :) - - The only cases that I haven't handled is if someone enters something like: - @pemit /= - - Ends up considering both targets as one with a space between them, - and the switch as a switch. - @pemit / = - - Ends up considering the first target a target, and the second - target as part of the switch. - """ - # Each of the bits of data starts off as None, except for the raw, original - # command - parsed_command = dict( - raw_command=command_string, - data=None, - original_command=None, - original_targets=None, - base_command=None, - command_switches=None, - targets=None, - target_switches=None - ) - try: - # If we make it past this next statement, then this is what we - # consider a complex command - (command_parts, data) = command_string.split('=', 1) - parsed_command['data'] = data - # First we deal with the command part of the command and break it - # down into the base command, along with switches - # If we make it past the next statement, then they must have - # entered a command like: - # p = - # So we should probably just let it get caught by the ValueError - # again and consider it a simple command - (total_command, total_targets) = command_parts.split(' ', 1) - parsed_command['original_command'] = total_command - parsed_command['original_targets'] = total_targets - split_command = total_command.split('/') - parsed_command['base_command'] = split_command[0] - parsed_command['command_switches'] = split_command[1:] - # Now we move onto the target data - try: - # Look for switches- if they give target switches, then we don't - # accept multiple targets - (target, switch_string) = total_targets.split('/', 1) - parsed_command['targets'] = [target] - parsed_command['target_switches'] = switch_string.split('/') - except ValueError: - # Alright, no switches, so lets consider multiple targets - parsed_command['targets'] = total_targets.split() - except ValueError: - # Ok, couldn't find an =, so not a complex command - try: - (command, data) = command_string.split(' ', 1) - parsed_command['base_command'] = command - parsed_command['data'] = data - except ValueError: - # No arguments - # ie: - # - look - parsed_command['base_command'] = command_string - return parsed_command - -def handle(cdat): +def handle(command): """ Use the spliced (list) uinput variable to retrieve the correct command, or return an invalid command error. @@ -108,32 +123,22 @@ def handle(cdat): their input on to 'cmd_' and looking it up in the GenCommands class. """ - session = cdat['session'] - server = cdat['server'] + session = command.session + server = command.server try: # TODO: Protect against non-standard characters. - if cdat['uinput'] == '': + if command.raw_input == '': + # Nothing sent in of value, ignore it. return - parsed_input = {} - parsed_input['parsed_command'] = parse_command(cdat['uinput']) - - # First we split the input up by spaces. - parsed_input['splitted'] = cdat['uinput'].split() - # Now we find the root command chunk (with switches attached). - parsed_input['root_chunk'] = parsed_input['splitted'][0].split('/') - # And now for the actual root command. It's the first entry in root_chunk. - parsed_input['root_cmd'] = parsed_input['root_chunk'][0].lower() - # Keep around the full, raw input in case a command needs it - cdat['raw_input'] = cdat['uinput'] - # Now we'll see if the user is using an alias. We do a dictionary lookup, - # if the key (the player's root command) doesn't exist on the dict, we - # don't replace the existing root_cmd. If the key exists, its value - # replaces the previously splitted root_cmd. For example, sa -> say. - alias_list = server.cmd_alias_list - parsed_input['root_cmd'] = alias_list.get(parsed_input['root_cmd'],parsed_input['root_cmd']) + # if the key (the player's command_string) doesn't exist on the dict, + # just keep the command_string the same. If the key exists, its value + # replaces the command_string. For example, sa -> say. + command.command_string = server.cmd_alias_list.get( + command.command_string, + command.command_string) # This will hold the reference to the command's function. cmd = None @@ -143,7 +148,7 @@ def handle(cdat): session.cmd_last = time.time() # Lets the users get around badly configured NAT timeouts. - if parsed_input['root_cmd'] == 'idle': + if command.command_string == 'idle': return # Increment our user's command counter. @@ -152,55 +157,34 @@ def handle(cdat): session.cmd_last_visible = time.time() # Just in case. Prevents some really funky-case crashes. - if len(parsed_input['root_cmd']) == 0: + if len(command.command_string) == 0: raise UnknownCommand - # Shortened say alias. - if parsed_input['root_cmd'][0] == '"': - parsed_input['splitted'].insert(0, "say") - parsed_input['splitted'][1] = parsed_input['splitted'][1][1:] - parsed_input['root_cmd'] = 'say' - # Shortened pose alias. - elif parsed_input['root_cmd'][0] == ':': - parsed_input['splitted'].insert(0, "pose") - parsed_input['splitted'][1] = parsed_input['splitted'][1][1:] - parsed_input['root_cmd'] = 'pose' - # Pose without space alias. - elif parsed_input['root_cmd'][0] == ';': - parsed_input['splitted'].insert(0, "pose/nospace") - parsed_input['root_chunk'] = ['pose', 'nospace'] - parsed_input['splitted'][1] = parsed_input['splitted'][1][1:] - parsed_input['root_cmd'] = 'pose' - # Channel alias match. - elif comsys.plr_has_channel(session, - parsed_input['root_cmd'], - alias_search=True, - return_muted=True): + if comsys.plr_has_channel(session, command.command_string, + alias_search=True, return_muted=True): - calias = parsed_input['root_cmd'] + calias = command.command_string cname = comsys.plr_cname_from_alias(session, calias) - cmessage = ' '.join(parsed_input['splitted'][1:]) - if cmessage == "who": + if command.command_argument == "who": comsys.msg_cwho(session, cname) return - elif cmessage == "on": + elif command.command_argument == "on": comsys.plr_chan_on(session, calias) return - elif cmessage == "off": + elif command.command_argument == "off": comsys.plr_chan_off(session, calias) return - elif cmessage == "last": + elif command.command_argument == "last": comsys.msg_chan_hist(session, cname) return - second_arg = "%s=%s" % (cname, cmessage) - parsed_input['splitted'] = ["@cemit/sendername", second_arg] - parsed_input['root_chunk'] = ['@cemit', 'sendername', 'quiet'] - parsed_input['root_cmd'] = '@cemit' + second_arg = "%s=%s" % (cname, command.command_argument) + command.command_string = "@cemit" + command.command_switches = ["sendername", "quiet"] # Get the command's function reference (Or False) - cmdtuple = cmdtable.GLOBAL_CMD_TABLE.get_command_tuple(parsed_input['root_cmd']) + cmdtuple = cmdtable.GLOBAL_CMD_TABLE.get_command_tuple(command.command_string) if cmdtuple: # If there is a permissions element to the entry, check perms. if cmdtuple[1]: @@ -212,7 +196,7 @@ def handle(cdat): else: # Not logged in, look through the unlogged-in command table. - cmdtuple = cmdtable.GLOBAL_UNCON_CMD_TABLE.get_command_tuple(parsed_input['root_cmd']) + cmdtuple = cmdtable.GLOBAL_UNCON_CMD_TABLE.get_command_tuple(command.command_string) if cmdtuple: cmd = cmdtuple[0] @@ -221,9 +205,8 @@ def handle(cdat): #session.msg("SPLIT: %s" % (parsed_input['splitted'],)) if callable(cmd): - cdat['uinput'] = parsed_input try: - cmd(cdat) + cmd(command) except: session.msg("Untrapped error, please file a bug report:\n%s" % (format_exc(),)) logger.log_errmsg("Untrapped error, evoker %s: %s" % @@ -233,12 +216,10 @@ def handle(cdat): if session.logged_in: # If we're not logged in, don't check exits. pobject = session.get_pobject() - exit_matches = match_exits(pobject, ' '.join(parsed_input['splitted'])) + exit_matches = match_exits(pobject, command.command_string) if exit_matches: targ_exit = exit_matches[0] - if targ_exit.get_home(): - cdat['uinput'] = parsed_input - + if targ_exit.get_home(): # SCRIPT: See if the player can traverse the exit if not targ_exit.scriptlink.default_lock({ "pobject": pobject diff --git a/src/cmdtable.py b/src/cmdtable.py index b3df75922f..9e02f186ce 100644 --- a/src/cmdtable.py +++ b/src/cmdtable.py @@ -10,6 +10,7 @@ privilege checking in the command function), use None in place of the permissions tuple. """ import commands.general +import commands.paging import commands.privileged import commands.comsys import commands.unloggedin @@ -54,7 +55,7 @@ GLOBAL_CMD_TABLE.add_command("help", commands.general.cmd_help), GLOBAL_CMD_TABLE.add_command("idle", commands.general.cmd_idle), GLOBAL_CMD_TABLE.add_command("inventory", commands.general.cmd_inventory), GLOBAL_CMD_TABLE.add_command("look", commands.general.cmd_look), -GLOBAL_CMD_TABLE.add_command("page", commands.general.cmd_page), +GLOBAL_CMD_TABLE.add_command("page", commands.paging.cmd_page), GLOBAL_CMD_TABLE.add_command("pose", commands.general.cmd_pose), GLOBAL_CMD_TABLE.add_command("quit", commands.general.cmd_quit), GLOBAL_CMD_TABLE.add_command("say", commands.general.cmd_say), @@ -80,7 +81,7 @@ GLOBAL_CMD_TABLE.add_command("@dig", commands.objmanip.cmd_dig, priv_tuple=("genperms.builder")), GLOBAL_CMD_TABLE.add_command("@emit", commands.general.cmd_emit, priv_tuple=("genperms.announce")), -#GLOBAL_CMD_TABLE.add_command("@pemit", commands.general.cmd_pemit, None), +#GLOBAL_CMD_TABLE.add_command("@pemit", commands.general.cmd_pemit), GLOBAL_CMD_TABLE.add_command("@find", commands.objmanip.cmd_find, priv_tuple=("genperms.builder")), GLOBAL_CMD_TABLE.add_command("@link", commands.objmanip.cmd_link, diff --git a/src/commands/comsys.py b/src/commands/comsys.py index 38d1df9809..4c091ccc9a 100644 --- a/src/commands/comsys.py +++ b/src/commands/comsys.py @@ -11,32 +11,26 @@ from src import defines_global from src import ansi from src.util import functions_general -def cmd_addcom(cdat): +def cmd_addcom(command): """ addcom Adds an alias for a channel. addcom foo=Bar """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - server = cdat['server'] - args = cdat['uinput']['splitted'][1:] + server = command.server + eq_args = command.command_argument.split('=', 1) - if len(args) == 0: + if not command.command_argument: session.msg("You need to specify a channel alias and name.") return - - eq_args = args[0].split('=') - - if len(eq_args) < 2: - session.msg("You need to specify a channel name.") - return - + chan_alias = eq_args[0] chan_name = eq_args[1] - - if len(chan_name) == 0: + + if len(eq_args) < 2 or len(chan_name) == 0: session.msg("You need to specify a channel name.") return @@ -59,40 +53,38 @@ def cmd_addcom(cdat): else: session.msg("Could not find channel %s." % (chan_name,)) -def cmd_delcom(cdat): +def cmd_delcom(command): """ delcom Removes the specified alias to a channel. If this is the last alias, the user is effectively removed from the channel. """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - uinput= cdat['uinput']['splitted'] - chan_alias = ' '.join(uinput[1:]) - if len(chan_alias) == 0: + if len(command.command_argument) == 0: session.msg("You must specify a channel alias.") return - if chan_alias not in session.channels_subscribed: + if command.command_argument not in session.channels_subscribed: session.msg("You are not on that channel.") return - chan_name = session.channels_subscribed[chan_alias][0] + chan_name = session.channels_subscribed[command.command_argument][0] session.msg("You have left %s." % (chan_name,)) - src.comsys.plr_del_channel(session, chan_alias) + src.comsys.plr_del_channel(session, command.command_argument) # Announce the user's leaving. leave_msg = "[%s] %s has left the channel." % \ (chan_name, pobject.get_name(show_dbref=False)) src.comsys.send_cmessage(chan_name, leave_msg) -def cmd_comlist(cdat): +def cmd_comlist(command): """ Lists the channels a user is subscribed to. """ - session = cdat['session'] + session = command.session session.msg("Alias Channel Status") for chan in session.channels_subscribed: @@ -105,46 +97,48 @@ def cmd_comlist(cdat): (chan, session.channels_subscribed[chan][0], chan_on)) session.msg("-- End of comlist --") -def cmd_allcom(cdat): +def cmd_allcom(command): """ allcom Allows the user to universally turn off or on all channels they are on, as well as perform a "who" for all channels they are on. """ + # TODO: Implement cmd_allcom pass -def cmd_clearcom(cdat): +def cmd_clearcom(command): """ clearcom Effectively runs delcom on all channels the user is on. It will remove their aliases, remove them from the channel, and clear any titles they have set. """ + # TODO: Implement cmd_clearcom pass -def cmd_clist(cdat): +def cmd_clist(command): """ @clist Lists all available channels on the game. """ - session = cdat['session'] + session = command.session session.msg("** Channel Owner Description") for chan in src.comsys.get_all_channels(): session.msg("%s%s %-13.13s %-15.15s %-45.45s" % - ('-', '-', chan.get_name(), chan.get_owner().get_name(), 'No Description')) + ('-', '-', chan.get_name(), chan.get_owner().get_name(), + 'No Description')) session.msg("-- End of Channel List --") -def cmd_cdestroy(cdat): +def cmd_cdestroy(command): """ @cdestroy Destroys a channel. """ - session = cdat['session'] - uinput= cdat['uinput']['splitted'] - cname = ' '.join(uinput[1:]) + session = command.session + cname = command.command_argument if cname == '': session.msg("You must supply a name!") @@ -158,56 +152,56 @@ def cmd_cdestroy(cdat): session.msg("Channel %s destroyed." % (name_matches[0],)) name_matches.delete() -def cmd_cset(cdat): +def cmd_cset(command): """ @cset Sets various flags on a channel. """ + # TODO: Implement cmd_cset pass -def cmd_ccharge(cdat): +def cmd_ccharge(command): """ @ccharge Sets the cost to transmit over a channel. Default is free. """ + # TODO: Implement cmd_ccharge pass -def cmd_cboot(cdat): +def cmd_cboot(command): """ @cboot Kicks a player or object from the channel. """ + # TODO: Implement cmd_cboot pass -def cmd_cemit(cdat): +def cmd_cemit(command): """ - @cemit - @cemit/noheader - @cemit/sendername + @cemit = + @cemit/noheader = + @cemit/sendername = Allows the user to send a message over a channel as long as they own or control it. It does not show the user's name unless they provide the /sendername switch. """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - server = cdat['server'] - args = cdat['uinput']['splitted'][1:] - switches = cdat['uinput']['root_chunk'][1:] + server = command.server - if len(args) == 0: + if command.command_argument == 0: session.msg("Channel emit what?") return - # Combine the arguments into one string, split it by equal signs into - # channel (entry 0 in the list), and message (entry 1 and above). - eq_args = ' '.join(args).split('=') + eq_args = command.command_argument.split('=', 1) cname = eq_args[0] - cmessage = ' '.join(eq_args[1:]) + cmessage = eq_args[1] + if len(eq_args) != 2: session.msg("You must provide a channel name and a message to emit.") return @@ -219,36 +213,37 @@ def cmd_cemit(cdat): return name_matches = src.comsys.cname_search(cname, exact=True) - - try: - # Safety first, kids! + if name_matches: cname_parsed = name_matches[0].get_name() - except: + else: session.msg("Could not find channel %s." % (cname,)) return - if "noheader" in switches: + if "noheader" in command.command_switches: if not pobject.user_has_perm("objects.emit_commchannel"): session.msg(defines_global.NOPERMS_MSG) return final_cmessage = cmessage else: - if "sendername" in switches: - if not src.comsys.plr_has_channel(session, cname_parsed, return_muted=False): + if "sendername" in command.command_switches: + if not src.comsys.plr_has_channel(session, cname_parsed, + return_muted=False): session.msg("You must be on %s to do that." % (cname_parsed,)) return - final_cmessage = "[%s] %s: %s" % (cname_parsed, pobject.get_name(show_dbref=False), cmessage) + final_cmessage = "[%s] %s: %s" % (cname_parsed, + pobject.get_name(show_dbref=False), + cmessage) else: if not pobject.user_has_perm("objects.emit_commchannel"): session.msg(defines_global.NOPERMS_MSG) return final_cmessage = "[%s] %s" % (cname_parsed, cmessage) - if not "quiet" in switches: + if not "quiet" in command.command_switches: session.msg("Sent - %s" % (name_matches[0],)) src.comsys.send_cmessage(cname_parsed, final_cmessage) -def cmd_cwho(cdat): +def cmd_cwho(command): """ @cwho @@ -256,22 +251,24 @@ def cmd_cwho(cdat): Adding /all after the channel name will list disconnected players as well. """ + # TODO: Implement cmd_cwho pass -def cmd_ccreate(cdat): +def cmd_ccreate(command): """ @ccreate Creates a new channel with the invoker being the default owner. """ - session = cdat['session'] + # TODO: Implement cmd_ccreate + session = command.session pobject = session.get_pobject() - uinput= cdat['uinput']['splitted'] - cname = ' '.join(uinput[1:]) - if cname == '': + if not command.command_argument: session.msg("You must supply a name!") return + + cname = command.command_argument name_matches = src.comsys.cname_search(cname, exact=True) @@ -279,14 +276,14 @@ def cmd_ccreate(cdat): session.msg("A channel with that name already exists.") else: # Create and set the object up. - cdat = {"name": cname, "owner": pobject} - new_chan = src.comsys.create_channel(cdat) + new_chan = src.comsys.create_channel(cname, pobject) session.msg("Channel %s created." % (new_chan.get_name(),)) -def cmd_cchown(cdat): +def cmd_cchown(command): """ @cchown Changes the owner of a channel. """ + # TODO: Implement cmd_cchown. pass diff --git a/src/commands/general.py b/src/commands/general.py index 4abd395aee..2b9413f09e 100644 --- a/src/commands/general.py +++ b/src/commands/general.py @@ -14,18 +14,22 @@ from src import session_mgr from src import ansi from src.util import functions_general -def cmd_password(cdat): +def cmd_password(command): """ Changes your own password. - @newpass = + @password = """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - args = cdat['uinput']['splitted'][1:] - eq_args = ' '.join(args).split('=') - oldpass = ''.join(eq_args[0]) - newpass = ''.join(eq_args[1:]) + eq_args = command.command_argument.split('=', 1) + + if len(eq_args) != 2: + session.msg("Incorrect number of arguments.") + return + + oldpass = eq_args[0] + newpass = eq_args[1] if len(oldpass) == 0: session.msg("You must provide your old password.") @@ -44,47 +48,52 @@ def cmd_password(cdat): uaccount.save() session.msg("Password changed.") -def cmd_emit(cdat): +def cmd_pemit(command): + """ + Emits something to a player. + """ + # TODO: Implement cmd_pemit + +def cmd_emit(command): """ Emits something to your location. """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - uinput= cdat['uinput']['splitted'] - message = ' '.join(uinput[1:]) + message = command.command_argument - if message == '': - session.msg("Emit what?") - else: + if message: pobject.get_location().emit_to_contents(message) + else: + session.msg("Emit what?") -def cmd_wall(cdat): +def cmd_wall(command): """ Announces a message to all connected players. """ - session = cdat['session'] - wallstring = ' '.join(cdat['uinput']['splitted'][1:]) + session = command.session + wallstring = command.command_argument pobject = session.get_pobject() - if wallstring == '': + if not wallstring: session.msg("Announce what?") return message = "%s shouts \"%s\"" % (session.get_pobject().get_name(show_dbref=False), wallstring) session_mgr.announce_all(message) -def cmd_idle(cdat): +def cmd_idle(command): """ Returns nothing, this lets the player set an idle timer without spamming his screen. """ pass -def cmd_inventory(cdat): +def cmd_inventory(command): """ Shows a player's inventory. """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() session.msg("You are carrying:") @@ -99,21 +108,23 @@ def cmd_inventory(cdat): session.msg("You have %d %s." % (money,money_name)) -def cmd_look(cdat): +def cmd_look(command): """ Handle looking at objects. """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - args = cdat['uinput']['splitted'][1:] - - if len(args) == 0: - target_obj = pobject.get_location() - else: - target_obj = Object.objects.standard_plr_objsearch(session, ' '.join(args)) + + # If an argument is provided with the command, search for the object. + # else look at the current room. + if command.command_argument: + target_obj = Object.objects.standard_plr_objsearch(session, + command.command_argument) # Use standard_plr_objsearch to handle duplicate/nonexistant results. if not target_obj: return + else: + target_obj = pobject.get_location() # SCRIPT: Get the item's appearance from the scriptlink. session.msg(target_obj.scriptlink.return_appearance({ @@ -126,20 +137,21 @@ def cmd_look(cdat): "target_obj": pobject }) -def cmd_get(cdat): +def cmd_get(command): """ Get an object and put it in a player's inventory. """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - args = cdat['uinput']['splitted'][1:] plr_is_staff = pobject.is_staff() - if len(args) == 0: + if not command.command_argument: session.msg("Get what?") return else: - target_obj = Object.objects.standard_plr_objsearch(session, ' '.join(args), search_contents=False) + target_obj = Object.objects.standard_plr_objsearch(session, + command.command_argument, + search_contents=False) # Use standard_plr_objsearch to handle duplicate/nonexistant results. if not target_obj: return @@ -158,27 +170,31 @@ def cmd_get(cdat): target_obj.move_to(pobject, quiet=True) session.msg("You pick up %s." % (target_obj.get_name(),)) - pobject.get_location().emit_to_contents("%s picks up %s." % (pobject.get_name(), target_obj.get_name()), exclude=pobject) + pobject.get_location().emit_to_contents("%s picks up %s." % + (pobject.get_name(), + target_obj.get_name()), + exclude=pobject) # SCRIPT: Call the object's script's a_get() method. target_obj.scriptlink.a_get({ "pobject": pobject }) -def cmd_drop(cdat): +def cmd_drop(command): """ Drop an object from a player's inventory into their current location. """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - args = cdat['uinput']['splitted'][1:] plr_is_staff = pobject.is_staff() - if len(args) == 0: + if not command.command_argument: session.msg("Drop what?") return else: - target_obj = Object.objects.standard_plr_objsearch(session, ' '.join(args), search_location=False) + target_obj = Object.objects.standard_plr_objsearch(session, + command.command_argument, + search_location=False) # Use standard_plr_objsearch to handle duplicate/nonexistant results. if not target_obj: return @@ -189,28 +205,30 @@ def cmd_drop(cdat): target_obj.move_to(pobject.get_location(), quiet=True) session.msg("You drop %s." % (target_obj.get_name(),)) - pobject.get_location().emit_to_contents("%s drops %s." % (pobject.get_name(), target_obj.get_name()), exclude=pobject) + pobject.get_location().emit_to_contents("%s drops %s." % + (pobject.get_name(), + target_obj.get_name()), + exclude=pobject) # SCRIPT: Call the object's script's a_drop() method. target_obj.scriptlink.a_drop({ "pobject": pobject }) -def cmd_examine(cdat): +def cmd_examine(command): """ Detailed object examine command """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - args = cdat['uinput']['splitted'][1:] attr_search = False - if len(args) == 0: + if not command.command_argument: # If no arguments are provided, examine the invoker's location. target_obj = pobject.get_location() else: # Look for a slash in the input, indicating an attribute search. - attr_split = args[0].split("/") + attr_split = command.command_argument.split("/", 1) # If the splitting by the "/" character returns a list with more than 1 # entry, it's an attribute match. @@ -218,41 +236,59 @@ def cmd_examine(cdat): attr_search = True # Strip the object search string from the input with the # object/attribute pair. - searchstr = attr_split[0] - # Just in case there's a slash in an attribute name. - attr_searchstr = '/'.join(attr_split[1:]) + obj_searchstr = attr_split[0] + attr_searchstr = attr_split[1].strip() + + # Protect against stuff like: ex me/ + if attr_searchstr == '': + session.msg('No attribute name provided.') + return else: - searchstr = ' '.join(args) + # No slash in argument, just examine an object. + obj_searchstr = command.command_argument - target_obj = Object.objects.standard_plr_objsearch(session, searchstr) + # Resolve the target object. + target_obj = Object.objects.standard_plr_objsearch(session, + obj_searchstr) # Use standard_plr_objsearch to handle duplicate/nonexistant results. if not target_obj: return if attr_search: + """ + Player did something like: examine me/* or examine me/TE*. Return + each matching attribute with its value. + """ attr_matches = target_obj.attribute_namesearch(attr_searchstr) if attr_matches: for attribute in attr_matches: session.msg(attribute.get_attrline()) else: session.msg("No matching attributes found.") - # End attr_search if() else: + """ + Player is examining an object. Return a full readout of attributes, + along with detailed information about said object. + """ + # Format the examine header area with general flag/type info. session.msg("%s\r\n%s" % ( target_obj.get_name(fullname=True), target_obj.get_description(no_parsing=True), )) - session.msg("Type: %s Flags: %s" % (target_obj.get_type(), target_obj.get_flags())) + session.msg("Type: %s Flags: %s" % (target_obj.get_type(), + target_obj.get_flags())) session.msg("Owner: %s " % (target_obj.get_owner(),)) session.msg("Zone: %s" % (target_obj.get_zone(),)) for attribute in target_obj.get_all_attributes(): session.msg(attribute.get_attrline()) + # Contents container lists for sorting by type. con_players = [] con_things = [] con_exits = [] + # Break each object out into their own list. for obj in target_obj.get_contents(): if obj.is_player(): con_players.append(obj) @@ -261,157 +297,47 @@ def cmd_examine(cdat): elif obj.is_thing(): con_things.append(obj) + # Render Contents display. if con_players or con_things: - session.msg("%sContents:%s" % (ansi.ansi["hilite"], ansi.ansi["normal"],)) + session.msg("%sContents:%s" % (ansi.ansi["hilite"], + ansi.ansi["normal"],)) for player in con_players: session.msg('%s' % (player.get_name(fullname=True),)) for thing in con_things: session.msg('%s' % (thing.get_name(fullname=True),)) + # Render Exists display. if con_exits: - session.msg("%sExits:%s" % (ansi.ansi["hilite"], ansi.ansi["normal"],)) + session.msg("%sExits:%s" % (ansi.ansi["hilite"], + ansi.ansi["normal"],)) for exit in con_exits: session.msg('%s' %(exit.get_name(fullname=True),)) - + + # Render the object's home or destination (for exits). if not target_obj.is_room(): if target_obj.is_exit(): + # The Home attribute on an exit is really its destination. session.msg("Destination: %s" % (target_obj.get_home(),)) else: + # For everything else, home is home. session.msg("Home: %s" % (target_obj.get_home(),)) - + # This obviously isn't valid for rooms. session.msg("Location: %s" % (target_obj.get_location(),)) -def cmd_page(cdat): - """ - Send a message to target user (if online). - """ - session = cdat['session'] - pobject = session.get_pobject() - server = cdat['server'] - args = cdat['uinput']['splitted'][1:] - parsed_command = cdat['uinput']['parsed_command'] - # We use a dict to ensure that the list of targets is unique - targets = dict() - # Get the last paged person - last_paged_dbrefs = pobject.get_attribute_value("LASTPAGED") - # If they have paged someone before, go ahead and grab the object of - # that person. - if last_paged_dbrefs is not False: - last_paged_objects = list() - try: - last_paged_dbref_list = [ - x.strip() for x in last_paged_dbrefs.split(',')] - for dbref in last_paged_dbref_list: - if not Object.objects.is_dbref(dbref): - raise ValueError - last_paged_object = Object.objects.dbref_search(dbref) - if last_paged_object is not None: - last_paged_objects.append(last_paged_object) - except ValueError: - # LASTPAGED Attribute is not a list of dbrefs - last_paged_dbrefs = False - # Remove the invalid LASTPAGED attribute - pobject.clear_attribute("LASTPAGED") - - # If they don't give a target, or any data to send to the target - # then tell them who they last paged if they paged someone, if not - # tell them they haven't paged anyone. - if parsed_command['targets'] is None and parsed_command['data'] is None: - if last_paged_dbrefs is not False and not last_paged_objects == list(): - session.msg("You last paged: %s." % ( - ', '.join([x.name for x in last_paged_objects]))) - return - session.msg("You have not paged anyone.") - return - - # Build a list of targets - # If there are no targets, then set the targets to the last person they - # paged. - if parsed_command['targets'] is None: - if not last_paged_objects == list(): - targets = dict([(target, 1) for target in last_paged_objects]) - else: - # First try to match the entire target string against a single player - full_target_match = Object.objects.player_name_search( - parsed_command['original_targets']) - if full_target_match is not None: - targets[full_target_match] = 1 - else: - # For each of the targets listed, grab their objects and append - # it to the targets list - for target in parsed_command['targets']: - # If the target is a dbref, behave appropriately - if Object.objects.is_dbref(target): - session.msg("Is dbref.") - matched_object = Object.objects.dbref_search(target, - limit_types=[defines_global.OTYPE_PLAYER]) - if matched_object is not None: - targets[matched_object] = 1 - else: - # search returned None - session.msg("Player '%s' does not exist." % ( - target)) - else: - # Not a dbref, so must be a username, treat it as such - matched_object = Object.objects.player_name_search( - target) - if matched_object is not None: - targets[matched_object] = 1 - else: - # search returned None - session.msg("Player '%s' does not exist." % ( - target)) - data = parsed_command['data'] - sender_name = pobject.get_name(show_dbref=False) - # Build our messages - target_message = "%s pages: %s" - sender_message = "You paged %s with '%s'." - # Handle paged emotes - if data.startswith(':'): - data = data[1:] - target_message = "From afar, %s %s" - sender_message = "Long distance to %s: %s %s" - # Handle paged emotes without spaces - if data.startswith(';'): - data = data[1:] - target_message = "From afar, %s%s" - sender_message = "Long distance to %s: %s%s" - - # We build a list of target_names for the sender_message later - target_names = [] - for target in targets.keys(): - # Check to make sure they're connected, or a player - if target.is_connected_plr(): - target.emit_to(target_message % (sender_name, data)) - target_names.append(target.get_name(show_dbref=False)) - else: - session.msg("Player %s does not exist or is not online." % ( - target.get_name(show_dbref=False))) - - if len(target_names) > 0: - target_names_string = ', '.join(target_names) - try: - session.msg(sender_message % (target_names_string, sender_name, data)) - except TypeError: - session.msg(sender_message % (target_names_string, data)) - # Now set the LASTPAGED attribute - pobject.set_attribute("LASTPAGED", ','.join( - ["#%d" % (x.id) for x in targets.keys()])) - -def cmd_quit(cdat): +def cmd_quit(command): """ Gracefully disconnect the user as per his own request. """ - session = cdat['session'] + session = command.session session.msg("Quitting!") session.handle_close() -def cmd_who(cdat): +def cmd_who(command): """ Generic WHO command. """ session_list = session_mgr.get_session_list() - session = cdat['session'] + session = command.session pobject = session.get_pobject() show_session_data = pobject.user_has_perm("genperms.see_session_data") @@ -457,18 +383,19 @@ def cmd_who(cdat): session.msg(retval) -def cmd_say(cdat): +def cmd_say(command): """ Room-based speech command. """ - session = cdat['session'] + session = command.session - if not functions_general.cmd_check_num_args(session, cdat['uinput']['splitted'], 1, errortext="Say what?"): + if not command.command_argument: + session.msg("Say what?") return session_list = session_mgr.get_session_list() pobject = session.get_pobject() - speech = ' '.join(cdat['uinput']['splitted'][1:]) + speech = command.command_argument players_present = [player for player in session_list if player.get_pobject().get_location() == session.get_pobject().get_location() and player != session] @@ -478,23 +405,25 @@ def cmd_say(cdat): session.msg(retval) -def cmd_pose(cdat): +def cmd_pose(command): """ Pose/emote command. """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - switches = cdat['uinput']['root_chunk'][1:] - if not functions_general.cmd_check_num_args(session, cdat['uinput']['splitted'], 1, errortext="Do what?"): + if not command.command_argument: + session.msg("Do what?") return session_list = session_mgr.get_session_list() - speech = ' '.join(cdat['uinput']['splitted'][1:]) + speech = command.command_argument - if "nospace" in switches: + if "nospace" in command.command_switches: + # Output without a space between the player name and the emote. sent_msg = "%s%s" % (pobject.get_name(show_dbref=False), speech) else: + # No switches, default. sent_msg = "%s %s" % (pobject.get_name(show_dbref=False), speech) players_present = [player for player in session_list if player.get_pobject().get_location() == session.get_pobject().get_location()] @@ -502,15 +431,15 @@ def cmd_pose(cdat): for player in players_present: player.msg(sent_msg) -def cmd_help(cdat): +def cmd_help(command): """ Help system commands. """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - topicstr = ' '.join(cdat['uinput']['splitted'][1:]) + topicstr = command.command_argument - if len(topicstr) == 0: + if not command.command_argument: topicstr = "Help Index" elif len(topicstr) < 2 and not topicstr.isdigit(): session.msg("Your search query is too short. It must be at least three letters long.") diff --git a/src/commands/info.py b/src/commands/info.py index 5e7389a6b7..fe1084c010 100644 --- a/src/commands/info.py +++ b/src/commands/info.py @@ -16,79 +16,95 @@ import django from apps.objects.models import Object from src import scheduler from src import defines_global +from src import flags -def cmd_version(cdat): +def cmd_version(command): """ Version info command. """ - session = cdat['session'] + session = command.session retval = "-"*50 +"\n\r" retval += " Evennia %s\n\r" % (defines_global.EVENNIA_VERSION,) retval += " Django %s\n\r" % (django.get_version()) retval += "-"*50 session.msg(retval) -def cmd_time(cdat): +def cmd_time(command): """ Server local time. """ - session = cdat['session'] - session.msg('Current server time : %s' % (time.strftime('%a %b %d %H:%M:%S %Y (%Z)', time.localtime(),))) + session = command.session + session.msg('Current server time : %s' % + (time.strftime('%a %b %d %H:%M:%S %Y (%Z)', time.localtime(),))) -def cmd_uptime(cdat): +def cmd_uptime(command): """ Server uptime and stats. """ - session = cdat['session'] - server = cdat['server'] + session = command.session + server = command.server start_delta = time.time() - server.start_time - loadavg = os.getloadavg() - session.msg('Current server time : %s' % (time.strftime('%a %b %d %H:%M %Y (%Z)', time.localtime(),))) - session.msg('Server start time : %s' % (time.strftime('%a %b %d %H:%M %Y', time.localtime(server.start_time),))) - session.msg('Server uptime : %s' % functions_general.time_format(start_delta, style=2)) - session.msg('Server load (1 min) : %.2f' % loadavg[0]) + + session.msg('Current server time : %s' % + (time.strftime('%a %b %d %H:%M %Y (%Z)', time.localtime(),))) + session.msg('Server start time : %s' % + (time.strftime('%a %b %d %H:%M %Y', time.localtime(server.start_time),))) + session.msg('Server uptime : %s' % + functions_general.time_format(start_delta, style=2)) + + # os.getloadavg() is not available on Windows. + if not functions_general.host_os_is('nt'): + loadavg = os.getloadavg() + session.msg('Server load (1 min) : %.2f' % + loadavg[0]) -def cmd_list(cdat): +def cmd_list(command): """ Shows some game related information. """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - args = cdat['uinput']['splitted'][1:] - argstr = ''.join(args) msg_invalid = "Unknown option. Use one of: commands, flags, process" - if len(argstr) == 0: + if not command.command_argument: session.msg(msg_invalid) - elif argstr == "commands": + elif command.command_argument == "commands": session.msg('Commands: '+ ' '.join(session.server.command_list())) - elif argstr == "process": + elif command.command_argument == "process": if not functions_general.host_os_is('nt'): loadvg = os.getloadavg() psize = resource.getpagesize() rusage = resource.getrusage(resource.RUSAGE_SELF) - session.msg("Process ID: %10d %10d bytes per page" % (os.getpid(), psize)) - session.msg("Time used: %10d user %10d sys" % (rusage[0],rusage[1])) - session.msg("Integral mem:%10d shared %10d private%10d stack" % (rusage[3], rusage[4], rusage[5])) - session.msg("Max res mem: %10d pages %10d bytes" % (rusage[2],rusage[2] * psize)) - session.msg("Page faults: %10d hard %10d soft %10d swapouts" % (rusage[7], rusage[6], rusage[8])) - session.msg("Disk I/O: %10d reads %10d writes" % (rusage[9], rusage[10])) - session.msg("Network I/O: %10d in %10d out" % (rusage[12], rusage[11])) - session.msg("Context swi: %10d vol %10d forced %10d sigs" % (rusage[14], rusage[15], rusage[13])) + session.msg("Process ID: %10d %10d bytes per page" % + (os.getpid(), psize)) + session.msg("Time used: %10d user %10d sys" % + (rusage[0],rusage[1])) + session.msg("Integral mem:%10d shared %10d private%10d stack" % + (rusage[3], rusage[4], rusage[5])) + session.msg("Max res mem: %10d pages %10d bytes" % + (rusage[2],rusage[2] * psize)) + session.msg("Page faults: %10d hard %10d soft %10d swapouts" % + (rusage[7], rusage[6], rusage[8])) + session.msg("Disk I/O: %10d reads %10d writes" % + (rusage[9], rusage[10])) + session.msg("Network I/O: %10d in %10d out" % + (rusage[12], rusage[11])) + session.msg("Context swi: %10d vol %10d forced %10d sigs" % + (rusage[14], rusage[15], rusage[13])) else: session.msg("Feature not available on Windows.") return - elif argstr == "flags": - session.msg("Flags: "+" ".join(defines_global.SERVER_FLAGS)) + elif command.command_argument == "flags": + session.msg("Flags: "+" ".join(flags.SERVER_FLAGS)) else: session.msg(msg_invalid) -def cmd_ps(cdat): +def cmd_ps(command): """ Shows the process/event table. """ - session = cdat['session'] + session = command.session session.msg("-- Interval Events --") for event in scheduler.schedule: session.msg(" [%d/%d] %s" % (scheduler.get_event_nextfire(event), @@ -96,14 +112,15 @@ def cmd_ps(cdat): scheduler.get_event_description(event))) session.msg("Totals: %d interval events" % (len(scheduler.schedule),)) -def cmd_stats(cdat): +def cmd_stats(command): """ Shows stats about the database. 4012 objects = 144 rooms, 212 exits, 613 things, 1878 players. (1165 garbage) """ - session = cdat['session'] + session = command.session stats_dict = Object.objects.object_totals() - session.msg("%d objects = %d rooms, %d exits, %d things, %d players. (%d garbage)" % (stats_dict["objects"], + session.msg("%d objects = %d rooms, %d exits, %d things, %d players. (%d garbage)" % + (stats_dict["objects"], stats_dict["rooms"], stats_dict["exits"], stats_dict["things"], diff --git a/src/commands/objmanip.py b/src/commands/objmanip.py index efdc7a4cd6..cf300629e3 100644 --- a/src/commands/objmanip.py +++ b/src/commands/objmanip.py @@ -1,27 +1,31 @@ """ These commands typically are to do with building or modifying Objects. """ -from apps.objects.models import Object +from apps.objects.models import Object, Attribute # We'll import this as the full path to avoid local variable clashes. import src.flags from src import ansi from src import session_mgr -def cmd_teleport(cdat): +def cmd_teleport(command): """ Teleports an object somewhere. """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - server = cdat['server'] - args = cdat['uinput']['splitted'][1:] + server = command.server - if len(args) == 0: + if not command.command_argument: session.msg("Teleport where/what?") return - eq_args = args[0].split('=') - search_str = ''.join(args) + eq_args = command.command_argument.split('=', 1) + + # The quiet switch suppresses leaving and arrival messages. + if "quiet" in command.command_switches: + tel_quietly = True + else: + tel_quietly = False # If we have more than one entry in our '=' delimited argument list, # then we're doing a @tel =. If not, we're doing @@ -46,19 +50,11 @@ def cmd_teleport(cdat): session.msg("You can't teleport an object inside of itself!") return session.msg("Teleported.") - victim.move_to(destination) - - # This is somewhat kludgy right now, we'll have to find a better way - # to do it sometime else. If we can find a session in the server's - # session list matching the object we're teleporting, force it to - # look. This is going to typically be a player. - victim_session = session_mgr.session_from_object(victim) - if victim_session: - victim_session.execute_cmd("look") - + victim.move_to(destination, quiet=tel_quietly) else: # Direct teleport (no equal sign) - target_obj = Object.objects.standard_plr_objsearch(session, search_str) + target_obj = Object.objects.standard_plr_objsearch(session, + command.command_argument) # Use standard_plr_objsearch to handle duplicate/nonexistant results. if not target_obj: return @@ -67,76 +63,82 @@ def cmd_teleport(cdat): session.msg("You can't teleport inside yourself!") return session.msg("Teleported.") - pobject.move_to(target_obj) - session.execute_cmd("look") + + pobject.move_to(target_obj, quiet=tel_quietly) -def cmd_stats(cdat): +def cmd_stats(command): """ Shows stats about the database. 4012 objects = 144 rooms, 212 exits, 613 things, 1878 players. (1165 garbage) """ - session = cdat['session'] + session = command.session stats_dict = Object.objects.object_totals() - session.msg("%d objects = %d rooms, %d exits, %d things, %d players. (%d garbage)" % (stats_dict["objects"], + session.msg("%d objects = %d rooms, %d exits, %d things, %d players. (%d garbage)" % + (stats_dict["objects"], stats_dict["rooms"], stats_dict["exits"], stats_dict["things"], stats_dict["players"], stats_dict["garbage"])) -def cmd_alias(cdat): +def cmd_alias(command): """ Assigns an alias to a player object for ease of paging, etc. """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - args = cdat['uinput']['splitted'][1:] - if len(args) == 0: + if not command.command_argument: session.msg("Alias whom?") return - # Resplit the args on = to check for an almost-required = - eq_args = ' '.join(args).split('=') + eq_args = command.command_argument.split('=', 1) if len(eq_args) < 2: session.msg("Alias missing.") return - target = Object.objects.standard_plr_objsearch(session, eq_args[0]) + target_string = eq_args[0] + new_alias = eq_args[1] + + # An Object instance for the victim. + target = Object.objects.standard_plr_objsearch(session, target_string) # Use standard_plr_objsearch to handle duplicate/nonexistant results. if not target: - session.msg("Alias whom?") + session.msg("I can't find that player.") return - duplicates = Object.objects.player_alias_search(pobject, eq_args[1]) - - if duplicates: - session.msg("Alias '%s' already exists." % (eq_args[1],)) - return - else: + old_alias = target.get_attribute_value('ALIAS') + duplicates = Object.objects.player_alias_search(pobject, new_alias) + if not duplicates or old_alias.lower() == new_alias.lower(): + # Either no duplicates or just changing the case of existing alias. if pobject.controls_other(target): - target.set_attribute('ALIAS', eq_args[1]) - session.msg("Alias '%s' set for %s." % (eq_args[1], target.get_name())) + target.set_attribute('ALIAS', new_alias) + session.msg("Alias '%s' set for %s." % (new_alias, + target.get_name())) else: - session.msg("You do not have access to set an alias for %s." % (target.get_name(),)) + session.msg("You do not have access to set an alias for %s." % + (target.get_name(),)) + else: + # Duplicates were found. + session.msg("Alias '%s' is already in use." % (new_alias,)) + return -def cmd_wipe(cdat): +def cmd_wipe(command): """ Wipes an object's attributes, or optionally only those matching a search string. """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - args = cdat['uinput']['splitted'][1:] attr_search = False - if len(args) == 0: + if not command.command_argument: session.msg("Wipe what?") return # Look for a slash in the input, indicating an attribute wipe. - attr_split = args[0].split("/") + attr_split = command.command_argument.split("/", 1) # If the splitting by the "/" character returns a list with more than 1 # entry, it's an attribute match. @@ -144,13 +146,11 @@ def cmd_wipe(cdat): attr_search = True # Strip the object search string from the input with the # object/attribute pair. - searchstr = attr_split[0] - # Just in case there's a slash in an attribute name. - attr_searchstr = '/'.join(attr_split[1:]) + searchstr = attr_split[1] else: - searchstr = ' '.join(args) + searchstr = command.command_argument - target_obj = Object.objects.standard_plr_objsearch(session, searchstr) + target_obj = Object.objects.standard_plr_objsearch(session, attr_split[0]) # Use standard_plr_objsearch to handle duplicate/nonexistant results. if not target_obj: return @@ -158,11 +158,13 @@ def cmd_wipe(cdat): if attr_search: # User has passed an attribute wild-card string. Search for name matches # and wipe. - attr_matches = target_obj.attribute_namesearch(attr_searchstr, exclude_noset=True) + attr_matches = target_obj.attribute_namesearch(searchstr, + exclude_noset=True) if attr_matches: for attr in attr_matches: target_obj.clear_attribute(attr.get_name()) - session.msg("%s - %d attributes wiped." % (target_obj.get_name(), len(attr_matches))) + session.msg("%s - %d attributes wiped." % (target_obj.get_name(), + len(attr_matches))) else: session.msg("No matching attributes found.") else: @@ -170,27 +172,25 @@ def cmd_wipe(cdat): attr_matches = target_obj.attribute_namesearch("*", exclude_noset=True) for attr in attr_matches: target_obj.clear_attribute(attr.get_name()) - session.msg("%s - %d attributes wiped." % (target_obj.get_name(), len(attr_matches))) + session.msg("%s - %d attributes wiped." % (target_obj.get_name(), + len(attr_matches))) -def cmd_set(cdat): +def cmd_set(command): """ Sets flags or attributes on objects. """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - server = cdat['server'] - args = cdat['uinput']['splitted'][1:] + server = command.server - if len(args) == 0: + if not command.command_argument: session.msg("Set what?") return - - # There's probably a better way to do this. Break the arguments (minus - # the root command) up so we have two items in the list, 0 being the victim, - # 1 being the list of flags or the attribute/value pair. - eq_args = ' '.join(args).split('=') - + + # Break into target and value by the equal sign. + eq_args = command.command_argument.split('=', 1) if len(eq_args) < 2: + # Equal signs are not optional for @set. session.msg("Set what?") return @@ -203,8 +203,7 @@ def cmd_set(cdat): session.msg(defines_global.NOCONTROL_MSG) return - attrib_args = eq_args[1].split(':') - + attrib_args = eq_args[1].split(':', 1) if len(attrib_args) > 1: # We're dealing with an attribute/value pair. attrib_name = attrib_args[0].upper() @@ -212,7 +211,7 @@ def cmd_set(cdat): attrib_value = eq_args[1][splicenum:] # In global_defines.py, see NOSET_ATTRIBS for protected attribute names. - if not src.flags.is_modifiable_attrib(attrib_name) and not pobject.is_superuser(): + if not Attribute.objects.is_modifiable_attrib(attrib_name) and not pobject.is_superuser(): session.msg("You can't modify that attribute.") return @@ -237,30 +236,32 @@ def cmd_set(cdat): if not src.flags.is_modifiable_flag(flag): session.msg("You can't set/unset the flag - %s." % (flag,)) else: - session.msg('%s - %s cleared.' % (victim.get_name(), flag.upper(),)) + session.msg('%s - %s cleared.' % (victim.get_name(), + flag.upper(),)) victim.set_flag(flag, False) else: # We're setting the flag. if not src.flags.is_modifiable_flag(flag): session.msg("You can't set/unset the flag - %s." % (flag,)) else: - session.msg('%s - %s set.' % (victim.get_name(), flag.upper(),)) + session.msg('%s - %s set.' % (victim.get_name(), + flag.upper(),)) victim.set_flag(flag, True) -def cmd_find(cdat): +def cmd_find(command): """ Searches for an object of a particular name. """ - session = cdat['session'] - server = cdat['server'] - searchstring = ' '.join(cdat['uinput']['splitted'][1:]) + session = command.session + server = command.server pobject = session.get_pobject() can_find = pobject.user_has_perm("genperms.builder") - if searchstring == '': + if not command.command_argument: session.msg("No search pattern given.") return + searchstring = command.command_argument results = Object.objects.global_object_name_search(searchstring) if len(results) > 0: @@ -271,35 +272,37 @@ def cmd_find(cdat): else: session.msg("No name matches found for: %s" % (searchstring,)) -def cmd_create(cdat): +def cmd_create(command): """ Creates a new object of type 'THING'. """ - session = cdat['session'] + session = command.session server = session.server pobject = session.get_pobject() - uinput= cdat['uinput']['splitted'] - thingname = ' '.join(uinput[1:]) - if thingname == '': + if not command.command_argument: session.msg("You must supply a name!") else: # Create and set the object up. - odat = {"name": thingname, "type": 3, "location": pobject, "owner": pobject} + # TODO: This dictionary stuff is silly. Feex. + odat = {"name": command.command_argument, + "type": 3, + "location": pobject, + "owner": pobject} new_object = Object.objects.create_object(odat) session.msg("You create a new thing: %s" % (new_object,)) -def cmd_nextfree(cdat): +def cmd_nextfree(command): """ Returns the next free object number. """ - session = cdat['session'] + session = command.session nextfree = Object.objects.get_nextfree_dbnum() session.msg("Next free object number: #%s" % (nextfree,)) -def cmd_open(cdat): +def cmd_open(command): """ Handle the opening of exits. @@ -308,16 +311,15 @@ def cmd_open(cdat): @open = @open =, """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - server = cdat['server'] - args = cdat['uinput']['splitted'][1:] + server = command.server - if len(args) == 0: + if not command.command_argument: session.msg("Open an exit to where?") return - eq_args = ' '.join(args).split('=') + eq_args = command.command_argument.split('=', 1) exit_name = eq_args[0] if len(exit_name) == 0: @@ -329,8 +331,9 @@ def cmd_open(cdat): # an un-linked exit, @open . if len(eq_args) > 1: # Opening an exit to another location via @open =[,]. - comma_split = eq_args[1].split(',') - destination = Object.objects.standard_plr_objsearch(session, comma_split[0]) + comma_split = eq_args[1].split(',', 1) + destination = Object.objects.standard_plr_objsearch(session, + comma_split[0]) # Use standard_plr_objsearch to handle duplicate/nonexistant results. if not destination: return @@ -339,43 +342,56 @@ def cmd_open(cdat): session.msg("You can't open an exit to an exit!") return - odat = {"name": exit_name, "type": 4, "location": pobject.get_location(), "owner": pobject, "home":destination} + odat = {"name": exit_name, + "type": 4, + "location": pobject.get_location(), + "owner": pobject, + "home":destination} new_object = Object.objects.create_object(odat) - session.msg("You open the an exit - %s to %s" % (new_object.get_name(),destination.get_name())) - + session.msg("You open the an exit - %s to %s" % (new_object.get_name(), + destination.get_name())) if len(comma_split) > 1: second_exit_name = ','.join(comma_split[1:]) - odat = {"name": second_exit_name, "type": 4, "location": destination, "owner": pobject, "home": pobject.get_location()} + odat = {"name": second_exit_name, + "type": 4, + "location": destination, + "owner": pobject, + "home": pobject.get_location()} new_object = Object.objects.create_object(odat) - session.msg("You open the an exit - %s to %s" % (new_object.get_name(),pobject.get_location().get_name())) + session.msg("You open the an exit - %s to %s" % ( + new_object.get_name(), + pobject.get_location().get_name())) else: # Create an un-linked exit. - odat = {"name": exit_name, "type": 4, "location": pobject.get_location(), "owner": pobject, "home":None} + odat = {"name": exit_name, + "type": 4, + "location": pobject.get_location(), + "owner": pobject, + "home":None} new_object = Object.objects.create_object(odat) session.msg("You open an unlinked exit - %s" % (new_object,)) -def cmd_link(cdat): +def cmd_link(command): """ Sets an object's home or an exit's destination. Forms: @link = """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - server = cdat['server'] - args = cdat['uinput']['splitted'][1:] + server = command.server - if len(args) == 0: + if not command.command_argument: session.msg("Link what?") return - eq_args = args[0].split('=') + eq_args = command.command_argument.split('=', 1) target_name = eq_args[0] - dest_name = '='.join(eq_args[1:]) + dest_name = eq_args[1] if len(target_name) == 0: session.msg("What do you want to link?") @@ -410,19 +426,21 @@ def cmd_link(cdat): session.msg("You must provide a destination to link to.") return -def cmd_unlink(cdat): +def cmd_unlink(command): """ Unlinks an object. - """ - session = cdat['session'] - pobject = session.get_pobject() - args = cdat['uinput']['splitted'][1:] - if len(args) == 0: + @unlink + """ + session = command.session + pobject = session.get_pobject() + + if not command.command_argument: session.msg("Unlink what?") return else: - target_obj = Object.objects.standard_plr_objsearch(session, ' '.join(args)) + target_obj = Object.objects.standard_plr_objsearch(session, + command.command_argument) # Use standard_plr_objsearch to handle duplicate/nonexistant results. if not target_obj: return @@ -434,67 +452,75 @@ def cmd_unlink(cdat): target_obj.set_home(None) session.msg("You have unlinked %s." % (target_obj.get_name(),)) -def cmd_dig(cdat): +def cmd_dig(command): """ Creates a new object of type 'ROOM'. - """ - session = cdat['session'] - pobject = session.get_pobject() - uinput= cdat['uinput']['splitted'] - roomname = ' '.join(uinput[1:]) - if roomname == '': + @dig + """ + session = command.session + pobject = session.get_pobject() + roomname = command.command_argument + + if not roomname: session.msg("You must supply a name!") else: # Create and set the object up. - odat = {"name": roomname, "type": 2, "location": None, "owner": pobject} + odat = {"name": roomname, + "type": 2, + "location": None, + "owner": pobject} new_object = Object.objects.create_object(odat) session.msg("You create a new room: %s" % (new_object,)) -def cmd_name(cdat): +def cmd_name(command): """ Handle naming an object. - """ - session = cdat['session'] - pobject = session.get_pobject() - args = cdat['uinput']['splitted'][1:] - eq_args = ' '.join(args).split('=') - searchstring = ''.join(eq_args[0]) - if len(args) == 0: + @name = + """ + session = command.session + pobject = session.get_pobject() + + if not command.command_string: session.msg("What do you want to name?") - elif len(eq_args) < 2: + return + + eq_args = command.command_argument.split('=', 1) + # Only strip spaces from right side in case they want to be silly and + # have a left-padded object name. + new_name = eq_args[1].rstrip() + + if len(eq_args) < 2 or eq_args[1] == '': session.msg("What would you like to name that object?") else: - target_obj = Object.objects.standard_plr_objsearch(session, searchstring) + target_obj = Object.objects.standard_plr_objsearch(session, eq_args[0]) # Use standard_plr_objsearch to handle duplicate/nonexistant results. if not target_obj: return - if len(eq_args[1]) == 0: - session.msg("What would you like to name that object?") - else: - newname = '='.join(eq_args[1:]) - session.msg("You have renamed %s to %s." % (target_obj, ansi.parse_ansi(newname, strip_formatting=True))) - target_obj.set_name(newname) + ansi_name = ansi.parse_ansi(new_name, strip_formatting=True) + session.msg("You have renamed %s to %s." % (target_obj, ansi_name)) + target_obj.set_name(new_name) -def cmd_description(cdat): +def cmd_description(command): """ Set an object's description. """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - args = cdat['uinput']['splitted'][1:] - eq_args = ' '.join(args).split('=') - searchstring = ''.join(eq_args[0]) - if len(args) == 0: + if not command.command_argument: session.msg("What do you want to describe?") - elif len(eq_args) < 2: + return + + eq_args = command.command_argument.split('=', 1) + + if len(eq_args) < 2 or eq_args[1] == '': session.msg("How would you like to describe that object?") else: - target_obj = Object.objects.standard_plr_objsearch(session, searchstring) + target_obj = Object.objects.standard_plr_objsearch(session, eq_args[0]) # Use standard_plr_objsearch to handle duplicate/nonexistant results. if not target_obj: return @@ -503,45 +529,45 @@ def cmd_description(cdat): session.msg(defines_global.NOCONTROL_MSG) return - new_desc = '='.join(eq_args[1:]) + new_desc = eq_args[1] session.msg("%s - DESCRIPTION set." % (target_obj,)) target_obj.set_description(new_desc) -def cmd_destroy(cdat): +def cmd_destroy(command): """ Destroy an object. """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - args = cdat['uinput']['splitted'][1:] - switches = cdat['uinput']['root_chunk'][1:] switch_override = False - - if "override" in switches: - switch_override = True - - if len(args) == 0: + + if not command.command_argument: session.msg("Destroy what?") return - else: - target_obj = Object.objects.standard_plr_objsearch(session, ' '.join(args)) - # Use standard_plr_objsearch to handle duplicate/nonexistant results. - if not target_obj: - return + + # Safety feature. Switch required to delete players and SAFE objects. + if "override" in command.command_switches: + switch_override = True - if target_obj.is_player(): - if pobject.id == target_obj.id: - session.msg("You can't destroy yourself.") - return - if not switch_override: - session.msg("You must use @destroy/override on players.") - return - if target_obj.is_superuser(): - session.msg("You can't destroy a superuser.") - return - elif target_obj.is_going() or target_obj.is_garbage(): - session.msg("That object is already destroyed.") + target_obj = Object.objects.standard_plr_objsearch(session, + command.command_argument) + # Use standard_plr_objsearch to handle duplicate/nonexistant results. + if not target_obj: + return + + if target_obj.is_player(): + if pobject.id == target_obj.id: + session.msg("You can't destroy yourself.") return + if not switch_override: + session.msg("You must use @destroy/override on players.") + return + if target_obj.is_superuser(): + session.msg("You can't destroy a superuser.") + return + elif target_obj.is_going() or target_obj.is_garbage(): + session.msg("That object is already destroyed.") + return session.msg("You destroy %s." % (target_obj.get_name(),)) target_obj.destroy() diff --git a/src/commands/paging.py b/src/commands/paging.py new file mode 100644 index 0000000000..1699216bd7 --- /dev/null +++ b/src/commands/paging.py @@ -0,0 +1,119 @@ +""" +Paging command and support functions. +""" +from apps.objects.models import Object +from src import defines_global + +def get_last_paged_objects(pobject): + """ + Returns a list of objects of the user's last paged list, or None if invalid + or non-existant. + """ + last_paged_dbrefs = pobject.get_attribute_value("LASTPAGED") + if last_paged_dbrefs is not False: + last_paged_objects = list() + try: + last_paged_dbref_list = [ + x.strip() for x in last_paged_dbrefs.split(',') + ] + for dbref in last_paged_dbref_list: + if not Object.objects.is_dbref(dbref): + raise ValueError + last_paged_object = Object.objects.dbref_search(dbref) + if last_paged_object is not None: + last_paged_objects.append(last_paged_object) + return last_paged_objects + except ValueError: + # Remove the invalid LASTPAGED attribute + pobject.clear_attribute("LASTPAGED") + return None + +def cmd_page(command): + """ + Send a message to target user (if online). + """ + session = command.session + pobject = session.get_pobject() + server = command.server + args = command.command_argument.split() + targets = [] + + # Get the last paged person(s) + last_paged_objects = get_last_paged_objects(pobject) + + # If they don't give a target, or any data to send to the target + # then tell them who they last paged if they paged someone, if not + # tell them they haven't paged anyone. + if not command.command_argument: + if last_paged_objects: + session.msg("You last paged: %s." % ( + ', '.join([x.name for x in last_paged_objects]))) + return + session.msg("You have not paged anyone.") + return + + # Build a list of targets + # If there are no targets, then set the targets to the last person they + # paged. + cmd_targets = command.get_arg_targets() + if cmd_targets is None: + targets = last_paged_objects + else: + # For each of the targets listed, grab their objects and append + # it to the targets list + for target in cmd_targets: + matched_object = Object.objects.local_and_global_search(pobject, + target, + limit_types=[defines_global.OTYPE_PLAYER]) + if matched_object: + targets.append(matched_object[0]) + print "MATCH:", matched_object[0] + else: + # search returned None + session.msg("Player '%s' can not be found." % ( + target)) + + # Depending on the argument provided, either send the entire thing as + # a message or break off the point after the equal sign. + if command.arg_has_target(): + message = command.get_arg_target_value() + else: + message = command.command_argument + + sender_name = pobject.get_name(show_dbref=False) + # Build our messages + target_message = "%s pages: %s" + sender_message = "You paged %s with '%s'." + # Handle paged emotes + if message.startswith(':'): + message = message[1:] + target_message = "From afar, %s %s" + sender_message = "Long distance to %s: %s %s" + # Handle paged emotes without spaces + if message.startswith(';'): + message = message[1:] + target_message = "From afar, %s%s" + sender_message = "Long distance to %s: %s%s" + + # We build a list of target_names for the sender_message later + target_names = [] + for target in targets: + # Check to make sure they're connected, or a player + if target.is_connected_plr(): + target.emit_to(target_message % (sender_name, message)) + target_names.append(target.get_name(show_dbref=False)) + else: + session.msg("Player %s does not exist or is not online." % ( + target.get_name(show_dbref=False))) + + # Now send a confirmation to the person doing the paging. + if len(target_names) > 0: + target_names_string = ', '.join(target_names) + try: + session.msg(sender_message % (target_names_string, sender_name, message)) + except TypeError: + session.msg(sender_message % (target_names_string, message)) + + # Now set the LASTPAGED attribute + pobject.set_attribute("LASTPAGED", ','.join( + ["#%d" % (x.id) for x in targets])) \ No newline at end of file diff --git a/src/commands/privileged.py b/src/commands/privileged.py index 4cdba5c268..40b61b2785 100644 --- a/src/commands/privileged.py +++ b/src/commands/privileged.py @@ -5,56 +5,54 @@ are generally @-prefixed commands, but there are exceptions. from apps.objects.models import Object from src import defines_global from src import ansi +from src import session_mgr from src.util import functions_general -def cmd_reload(cdat): +def cmd_reload(command): """ Reloads all modules. """ - session = cdat['session'] + session = command.session server = session.server.reload(session) -def cmd_boot(cdat): +def cmd_boot(command): """ Boot a player object from the server. """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - args = cdat['uinput']['splitted'][1:] - eq_args = ' '.join(args).split('=') - searchstring = ''.join(eq_args[0]) - switches = cdat['uinput']['root_chunk'][1:] switch_quiet = False switch_port = False - if not pobject.is_staff(): - session.msg("You do not have permission to do that.") - return - - if "quiet" in switches: + if "quiet" in command.command_switches: + # Don't tell the player they've been disconnected, silently boot them. switch_quiet = True - if "port" in switches: + if "port" in command.command_switches: + # Boot by port number instead of name or dbref. switch_port = True - if len(args) == 0: + if not command.command_argument: session.msg("Who would you like to boot?") return else: boot_list = [] if switch_port: + # Boot a particular port. sessions = session_mgr.get_session_list(True) for sess in sessions: - if sess.getClientAddress()[1] == int(searchstring): + # Find the session with the matching port number. + if sess.getClientAddress()[1] == int(command.command_argument): boot_list.append(sess) - # We're done here + # Match found, kill the loop and continue with booting. break else: # Grab the objects that match - objs = Objects.object.global_object_name_search(searchstring) + objs = Object.objects.local_and_global_search(pobject, + command.command_argument) - if len(objs) < 1: - session.msg("Who would you like to boot?") + if not objs: + session.msg("No name or dbref match found for booting.") return if not objs[0].is_player(): @@ -71,7 +69,15 @@ def cmd_boot(cdat): if objs[0].is_connected_plr(): boot_list.append(session_mgr.session_from_object(objs[0])) + else: + session.msg("That player is not connected.") + return + if not boot_list: + session.msg("No matches found.") + return + + # Carry out the booting of the sessions in the boot list. for boot in boot_list: if not switch_quiet: boot.msg("You have been disconnected by %s." % (pobject.name)) @@ -79,25 +85,24 @@ def cmd_boot(cdat): session_mgr.remove_session(boot) return -def cmd_newpassword(cdat): +def cmd_newpassword(command): """ Set a player's password. """ - session = cdat['session'] + session = command.session pobject = session.get_pobject() - args = cdat['uinput']['splitted'][1:] - eq_args = ' '.join(args).split('=') - searchstring = ''.join(eq_args[0]) - newpass = ''.join(eq_args[1:]) + eq_args = command.command_argument.split('=', 1) + searchstring = eq_args[0] + newpass = eq_args[1] - if len(args) == 0: + if not command.command_argument or len(searchstring) == 0: session.msg("What player's password do you want to change") return if len(newpass) == 0: session.msg("You must supply a new password.") return - target_obj = Objects.object.standard_plr_objsearch(session, searchstring) + target_obj = Object.objects.standard_plr_objsearch(session, searchstring) # Use standard_plr_objsearch to handle duplicate/nonexistant results. if not target_obj: return @@ -114,14 +119,15 @@ def cmd_newpassword(cdat): uaccount.set_password(newpass) uaccount.save() session.msg("%s - PASSWORD set." % (target_obj.get_name(),)) - target_obj.emit_to("%s has changed your password." % (pobject.get_name(show_dbref=False),)) + target_obj.emit_to("%s has changed your password." % + (pobject.get_name(show_dbref=False),)) -def cmd_shutdown(cdat): +def cmd_shutdown(command): """ Shut the server down gracefully. """ - session = cdat['session'] - server = cdat['server'] + session = command.session + server = command.server pobject = session.get_pobject() session.msg('Shutting down...') diff --git a/src/commands/unloggedin.py b/src/commands/unloggedin.py index 1088955fe1..857cbca1d3 100644 --- a/src/commands/unloggedin.py +++ b/src/commands/unloggedin.py @@ -7,51 +7,52 @@ from apps.objects.models import Attribute, Object from src import defines_global from src.util import functions_general -def cmd_connect(cdat): +def cmd_connect(command): """ 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'] + session = command.session # Argument check. - if not functions_general.cmd_check_num_args(session, cdat['uinput']['splitted'], 2): + arg_list = command.command_argument.split() + if not functions_general.cmd_check_num_args(session, arg_list, 2): return - uemail = cdat['uinput']['splitted'][1] - password = cdat['uinput']['splitted'][2] + uemail = arg_list[0] + password = arg_list[1] # Match an email address to an account. email_matches = Object.objects.get_user_from_email(uemail) - autherror = "Specified email does not match any accounts!" # No username match if email_matches.count() == 0: - session.msg(autherror) + session.msg("Specified email does not match any accounts!") return # We have at least one result, so we can check the password. user = email_matches[0] if not user.check_password(password): - session.msg(autherror) + session.msg("Incorrect password.") else: uname = user.username session.login(user) -def cmd_create(cdat): +def cmd_create(command): """ Handle the creation of new accounts. """ - session = cdat['session'] + session = command.session # Argument check. - if not functions_general.cmd_check_num_args(session, cdat['uinput']['splitted'], 2): + arg_list = command.command_argument.split() + if not functions_general.cmd_check_num_args(session, arg_list, 2): return server = session.server - quote_split = ' '.join(cdat['uinput']['splitted']).split("\"") + quote_split = command.command_argument.split("\"") if len(quote_split) < 2: session.msg("You must enclose your username in quotation marks.") @@ -84,14 +85,14 @@ def cmd_create(cdat): elif len(password) < 3: session.msg("Your password must be 3 characters or longer.") else: - Object.objects.create_user(cdat, uname, email, password) + Object.objects.create_user(command, uname, email, password) -def cmd_quit(cdat): +def cmd_quit(command): """ 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 = command.session session.msg("Disconnecting...") session.handle_close() diff --git a/src/comsys.py b/src/comsys.py index b00f6cd428..9a6cfa9d00 100644 --- a/src/comsys.py +++ b/src/comsys.py @@ -239,17 +239,16 @@ def get_cobj_from_name(cname): """ return CommChannel.objects.get(name=cname) -def create_channel(cdat): +def create_channel(name, owner): """ - Create a new channel. cdat is a dictionary that contains the following keys. - REQUIRED KEYS: - * name: The name of the new channel. - * owner: The creator of the channel. + Create a new channel. + name: (string) Name of the new channel + owner: (Object) Objec that owns the channel """ new_chan = CommChannel() - new_chan.name = ansi.parse_ansi(cdat["name"], strip_ansi=True) - new_chan.ansi_name = "[%s]" % (ansi.parse_ansi(cdat["name"]),) - new_chan.set_owner(cdat["owner"]) + new_chan.name = ansi.parse_ansi(name, strip_ansi=True) + new_chan.ansi_name = "[%s]" % (ansi.parse_ansi(name),) + new_chan.set_owner(owner) new_chan.save() return new_chan diff --git a/src/server.py b/src/server.py index 3627ddcea5..fb3de389f2 100755 --- a/src/server.py +++ b/src/server.py @@ -85,7 +85,7 @@ class EvenniaService(service.Service): """ Return a string representing the server's command list. """ - clist = cmdtable.ctable.keys() + clist = cmdtable.GLOBAL_CMD_TABLE.ctable.keys() clist.sort() return clist diff --git a/src/session.py b/src/session.py index 41ff8c0bdc..90b1395fd1 100755 --- a/src/session.py +++ b/src/session.py @@ -74,13 +74,20 @@ class SessionProtocol(StatefulTelnetProtocol): Any line return indicates a command for the purpose of a MUD. So we take the user input and pass it to our command handler. """ + # Clean up the input. line = (''.join(data)) line = line.strip('\r') uinput = line - # Stuff anything we need to pass in this dictionary. - cdat = {"server": self.factory.server, "uinput": uinput, "session": self} - cmdhandler.handle(cdat) + # The Command object has all of the methods for parsing and preparing + # for searching and execution. + command = cmdhandler.Command(uinput, + server=self.factory.server, + session=self) + + # Send the command object to the command handler for parsing + # and eventual execution. + cmdhandler.handle(command) def execute_cmd(self, cmdstr): """ diff --git a/src/util/functions_general.py b/src/util/functions_general.py index 2db614534b..229b4af749 100644 --- a/src/util/functions_general.py +++ b/src/util/functions_general.py @@ -33,7 +33,7 @@ def cmd_check_num_args(session, arg_list, min_args, errortext="Missing arguments Check a player command's splitted argument list to make sure it contains the minimum allowable number of arguments. """ - if len(arg_list) < min_args+1: + if len(arg_list) < min_args: session.msg(errortext) return False return True