diff --git a/src/commands/default/admin.py b/src/commands/default/admin.py index 72630d75cd..0a4e0e5dd6 100644 --- a/src/commands/default/admin.py +++ b/src/commands/default/admin.py @@ -16,13 +16,13 @@ from src.commands.default.muxcommand import MuxCommand PERMISSION_HIERARCHY = [p.lower() for p in settings.PERMISSION_HIERARCHY] # limit members for API inclusion -__all__ = ("CmdBoot", "CmdBan", "CmdUnban", "CmdDelPlayer", "CmdEmit", "CmdNewPassword", +__all__ = ("CmdBoot", "CmdBan", "CmdUnban", "CmdDelPlayer", "CmdEmit", "CmdNewPassword", "CmdPerm", "CmdWall") class CmdBoot(MuxCommand): """ - @boot + @boot Usage @boot[/switches] [: reason] @@ -30,11 +30,11 @@ class CmdBoot(MuxCommand): Switches: quiet - Silently boot without informing player port - boot by port number instead of name or dbref - + Boot a player object from the server. If a reason is - supplied it will be echoed to the user unless /quiet is set. + supplied it will be echoed to the user unless /quiet is set. """ - + key = "@boot" locks = "cmd:perm(boot) or perm(Wizards)" help_category = "Admin" @@ -43,7 +43,7 @@ class CmdBoot(MuxCommand): "Implementing the function" caller = self.caller args = self.args - + if not args: caller.msg("Usage: @boot[/switches] [:reason]") return @@ -67,12 +67,12 @@ class CmdBoot(MuxCommand): # Boot by player object pobj = caller.search("*%s" % args, global_search=True, player=True) if not pobj: - return + return if pobj.character.has_player: if not pobj.access(caller, 'boot'): string = "You don't have the permission to boot %s." pobj.msg(string) - return + return # we have a bootable object with a connected user matches = SESSIONS.sessions_from_player(pobj) for match in matches: @@ -87,7 +87,7 @@ class CmdBoot(MuxCommand): # Carry out the booting of the sessions in the boot list. - feedback = None + feedback = None if not 'quiet' in self.switches: feedback = "You have been disconnected by %s.\n" % caller.name if reason: @@ -108,16 +108,16 @@ def list_bans(banlist): Helper function to display a list of active bans. Input argument is the banlist read into the two commands @ban and @undban below. """ - if not banlist: + if not banlist: return "No active bans were found." table = [["id"], ["name/ip"], ["date"], ["reason"]] table[0].extend([str(i+1) for i in range(len(banlist))]) - for ban in banlist: - if ban[0]: + for ban in banlist: + if ban[0]: table[1].append(ban[0]) - else: - table[1].append(ban[1]) + else: + table[1].append(ban[1]) table[2].extend([ban[3] for ban in banlist]) table[3].extend([ban[4] for ban in banlist]) ftable = utils.format_table(table, 4) @@ -128,8 +128,8 @@ def list_bans(banlist): srow = "{w%s{n" % srow.rstrip() else: srow = "\n" + "{w%s{n" % row[0] + "".join(row[1:]) - string += srow.rstrip() - return string + string += srow.rstrip() + return string class CmdBan(MuxCommand): """ @@ -137,34 +137,34 @@ class CmdBan(MuxCommand): Usage: @ban [ [: reason]] - - Without any arguments, shows numbered list of active bans. - + + Without any arguments, shows numbered list of active bans. + This command bans a user from accessing the game. Supply an optional reason to be able to later remember why the ban was put in place - + It is often to prefer over deleting a player with @delplayer. If banned by name, that player account can no longer be logged into. IP (Internet Protocol) address banning allows to block all access from a specific address or subnet. Use the asterisk (*) as a - wildcard. + wildcard. - Examples: + Examples: @ban thomas - ban account 'thomas' @ban/ip 134.233.2.111 - ban specific ip address - @ban/ip 134.233.2.* - ban all in a subnet - @ban/ip 134.233.*.* - even wider ban - + @ban/ip 134.233.2.* - ban all in a subnet + @ban/ip 134.233.*.* - even wider ban + A single IP filter is easy to circumvent by changing the computer (also, some ISPs assign only temporary IPs to their users in the first placer. Widening the IP block filter with wildcards might be tempting, but remember that blocking too much may accidentally also block innocent users connecting from the same country and region. - + """ key = "@ban" aliases = ["@bans"] @@ -173,25 +173,25 @@ class CmdBan(MuxCommand): def func(self): """ - Bans are stored in a serverconf db object as a list of - dictionaries: + Bans are stored in a serverconf db object as a list of + dictionaries: [ (name, ip, ipregex, date, reason), (name, ip, ipregex, date, reason),... ] where name and ip are set by the user and are shown in lists. ipregex is a converted form of ip where the * is replaced by an appropriate regex pattern for fast matching. date is the time stamp the ban was instigated and - 'reason' is any optional info given to the command. Unset + 'reason' is any optional info given to the command. Unset values in each tuple is set to the empty string. - """ + """ banlist = ServerConfig.objects.conf('server_bans') if not banlist: banlist = [] - - if not self.args or (self.switches - and not any(switch in ('ip', 'name') for switch in self.switches)): + + if not self.args or (self.switches + and not any(switch in ('ip', 'name') for switch in self.switches)): self.caller.msg(list_bans(banlist)) - return + return now = time.ctime() reason = "" @@ -199,13 +199,13 @@ class CmdBan(MuxCommand): ban, reason = self.args.rsplit(':',1) else: ban = self.args - ban = ban.lower() + ban = ban.lower() ipban = IPREGEX.findall(ban) if not ipban: - # store as name + # store as name typ = "Name" - bantup = (ban, "", "", now, reason) - else: + bantup = (ban, "", "", now, reason) + else: # an ip address. typ = "IP" ban = ipban[0] @@ -215,16 +215,16 @@ class CmdBan(MuxCommand): print "regex:",ipregex ipregex = re.compile(r"%s" % ipregex) bantup = ("", ban, ipregex, now, reason) - # save updated banlist + # save updated banlist banlist.append(bantup) - ServerConfig.objects.conf('server_bans', banlist) + ServerConfig.objects.conf('server_bans', banlist) self.caller.msg("%s-Ban {w%s{x was added." % (typ, ban)) -class CmdUnban(MuxCommand): +class CmdUnban(MuxCommand): """ remove a ban - Usage: + Usage: @unban This will clear a player name/ip ban previously set with the @ban @@ -236,26 +236,26 @@ class CmdUnban(MuxCommand): key = "@unban" locks = "cmd:perm(unban) or perm(Immortals)" help_category="Admin" - + def func(self): "Implement unbanning" banlist = ServerConfig.objects.conf('server_bans') - if not self.args: + if not self.args: self.caller.msg(list_bans(banlist)) - return + return - try: + try: num = int(self.args) except Exception: self.caller.msg("You must supply a valid ban id to clear.") - return + return - if not banlist: + if not banlist: self.caller.msg("There are no bans to clear.") elif not (0 < num < len(banlist) + 1): - self.caller.msg("Ban id {w%s{x was not found." % self.args) + self.caller.msg("Ban id {w%s{x was not found." % self.args) else: # all is ok, clear ban ban = banlist[num-1] @@ -263,20 +263,20 @@ class CmdUnban(MuxCommand): ServerConfig.objects.conf('server_bans', banlist) self.caller.msg("Cleared ban %s: %s" % (num, " ".join([s for s in ban[:2]]))) - + class CmdDelPlayer(MuxCommand): """ delplayer - delete player from server Usage: @delplayer[/switch] [: reason] - + Switch: delobj - also delete the player's currently - assigned in-game object. + assigned in-game object. Completely deletes a user from the server database, - making their nick and e-mail again available. + making their nick and e-mail again available. """ key = "@delplayer" @@ -287,10 +287,10 @@ class CmdDelPlayer(MuxCommand): "Implements the command." caller = self.caller - args = self.args + args = self.args if hasattr(caller, 'player'): - caller = caller.player + caller = caller.player if not args: caller.msg("Usage: @delplayer[/delobj] [: reason]") @@ -309,26 +309,26 @@ class CmdDelPlayer(MuxCommand): except ValueError: pass - if not players: + if not players: # try to find a user instead of a Player try: user = User.objects.get(id=args) - except Exception: + except Exception: try: - user = User.objects.get(username__iexact=args) + user = User.objects.get(username__iexact=args) except Exception: string = "No Player nor User found matching '%s'." % args caller.msg(string) - return + return try: player = user.get_profile() except Exception: - player = None - + player = None + if player and not player.access(caller, 'delete'): string = "You don't have the permissions to delete this player." caller.msg(string) - return + return string = "" name = user.username @@ -340,13 +340,13 @@ class CmdDelPlayer(MuxCommand): else: string += "The User %s was deleted. It had no Player associated with it." % name caller.msg(string) - return - + return + elif utils.is_iter(players): string = "There were multiple matches:" for player in players: - string += "\n %s %s" % (player.id, player.key) - return + string += "\n %s %s" % (player.id, player.key) + return else: # one single match @@ -357,10 +357,10 @@ class CmdDelPlayer(MuxCommand): if not player.access(caller, 'delete'): string = "You don't have the permissions to delete that player." caller.msg(string) - return + return uname = user.username - # boot the player then delete + # boot the player then delete if character and character.has_player: caller.msg("Booting and informing player ...") string = "\nYour account '%s' is being *permanently* deleted.\n" % uname @@ -368,30 +368,30 @@ class CmdDelPlayer(MuxCommand): string += " Reason given:\n '%s'" % reason character.msg(string) caller.execute_cmd("@boot %s" % uname) - + player.delete() - user.delete() + user.delete() caller.msg("Player %s was successfully deleted." % uname) -class CmdEmit(MuxCommand): +class CmdEmit(MuxCommand): """ @emit Usage: @emit[/switches] [, , ... =] - @remit [, , ... =] - @pemit [, , ... =] + @remit [, , ... =] + @pemit [, , ... =] Switches: room : limit emits to rooms only (default) - players : limit emits to players only + players : limit emits to players only contents : send to the contents of matched objects too - + Emits a message to the selected objects or to your immediate surroundings. If the object is a room, - send to its contents. @remit and @pemit are just - limited forms of @emit, for sending to rooms and + send to its contents. @remit and @pemit are just + limited forms of @emit, for sending to rooms and to players respectively. """ key = "@emit" @@ -401,7 +401,7 @@ class CmdEmit(MuxCommand): def func(self): "Implement the command" - + caller = self.caller args = self.args @@ -411,12 +411,12 @@ class CmdEmit(MuxCommand): string += "\n@remit [, , ... =] " string += "\n@pemit [, , ... =] " caller.msg(string) - return + return rooms_only = 'rooms' in self.switches players_only = 'players' in self.switches send_to_contents = 'contents' in self.switches - + # we check which command was used to force the switches if self.cmdstring == '@remit': rooms_only = True @@ -429,12 +429,12 @@ class CmdEmit(MuxCommand): else: message = self.rhs objnames = self.lhslist - + # send to all objects for objname in objnames: obj = caller.search(objname, global_search=True) if not obj: - return + return if rooms_only and not obj.location == None: caller.msg("%s is not a room. Ignored." % objname) continue @@ -463,7 +463,7 @@ class CmdNewPassword(MuxCommand): Set a player's password. """ - + key = "@userpassword" locks = "cmd:perm(newpassword) or perm(Wizards)" help_category = "Admin" @@ -475,12 +475,12 @@ class CmdNewPassword(MuxCommand): if not self.rhs: caller.msg("Usage: @userpassword = ") - return - - # the player search also matches 'me' etc. - player = caller.search("*%s" % self.lhs, global_search=True, player=True) + return + + # the player search also matches 'me' etc. + player = caller.search("*%s" % self.lhs, global_search=True, player=True) if not player: - return + return player.user.set_password(self.rhs) player.user.save() caller.msg("%s - new password set to '%s'." % (player.name, self.rhs)) @@ -495,12 +495,12 @@ class CmdPerm(MuxCommand): Usage: @perm[/switch] [= [,,...]] @perm[/switch] * [= [,,...]] - + Switches: del : delete the given permission from or . player : set permission on a player (same as adding * to name) - This command sets/clears individual permission strings on an object + This command sets/clears individual permission strings on an object or player. If no permission is given, list all permissions on . """ key = "@perm" @@ -515,19 +515,19 @@ class CmdPerm(MuxCommand): switches = self.switches lhs, rhs = self.lhs, self.rhs - if not self.args: - string = "Usage: @perm[/switch] object [ = permission, permission, ...]" + if not self.args: + string = "Usage: @perm[/switch] object [ = permission, permission, ...]" caller.msg(string) return - + playermode = 'player' in self.switches or lhs.startswith('*') - - # locate the object + + # locate the object obj = caller.search(lhs, global_search=True, player=playermode) if not obj: - return - - if not rhs: + return + + if not rhs: if not obj.access(caller, 'examine'): caller.msg("You are not allowed to examine this object.") return @@ -539,15 +539,15 @@ class CmdPerm(MuxCommand): string += ", ".join(obj.permissions) if hasattr(obj, 'player') and hasattr(obj.player, 'is_superuser') and obj.player.is_superuser: string += "\n(... but this object is currently controlled by a SUPERUSER! " - string += "All access checks are passed automatically.)" + string += "All access checks are passed automatically.)" caller.msg(string) - return - + return + # we supplied an argument on the form obj = perm if not obj.access(caller, 'control'): caller.msg("You are not allowed to edit this object's permissions.") - return + return cstring = "" tstring = "" @@ -561,24 +561,24 @@ class CmdPerm(MuxCommand): continue permissions = obj.permissions del permissions[index] - obj.permissions = permissions + obj.permissions = permissions cstring += "\nPermission '%s' was removed from %s." % (perm, obj.name) tstring += "\n%s revokes the permission '%s' from you." % (caller.name, perm) else: - # add a new permission + # add a new permission permissions = obj.permissions - caller.permissions - + caller.permissions + for perm in self.rhslist: - + # don't allow to set a permission higher in the hierarchy than the one the # caller has (to prevent self-escalation) if perm.lower() in PERMISSION_HIERARCHY and not obj.locks.check_lockstring(caller, "dummy:perm(%s)" % perm): caller.msg("You cannot assign a permission higher than the one you have yourself.") - return + return if perm in permissions: cstring += "\nPermission '%s' is already defined on %s." % (rhs, obj.name) @@ -586,7 +586,7 @@ class CmdPerm(MuxCommand): permissions.append(perm) obj.permissions = permissions cstring += "\nPermission '%s' given to %s." % (rhs, obj.name) - tstring += "\n%s gives you the permission '%s'." % (caller.name, rhs) + tstring += "\n%s gives you the permission '%s'." % (caller.name, rhs) caller.msg(cstring.strip()) if tstring: obj.msg(tstring.strip()) @@ -597,7 +597,7 @@ class CmdWall(MuxCommand): Usage: @wall - + Announces a message to all connected players. """ key = "@wall" diff --git a/src/commands/default/batchprocess.py b/src/commands/default/batchprocess.py index 5aa6eddfb2..cb49142e5c 100644 --- a/src/commands/default/batchprocess.py +++ b/src/commands/default/batchprocess.py @@ -1,16 +1,16 @@ """ Batch processors -These commands implements the 'batch-command' and 'batch-code' -processors, using the functionality in src.utils.batchprocessors. -They allow for offline world-building. +These commands implements the 'batch-command' and 'batch-code' +processors, using the functionality in src.utils.batchprocessors. +They allow for offline world-building. Batch-command is the simpler system. This reads a file (*.ev) containing a list of in-game commands and executes them in sequence as if they had been entered in the game (including permission checks etc). -Example batch-command file: game/gamesrc/commands/examples/example_batch_cmd.ev +Example batch-command file: game/gamesrc/commands/examples/example_batch_cmd.ev Batch-code is a full-fledged python code interpreter that reads blocks of python code (*.py) and executes them in sequence. This allows for @@ -18,7 +18,7 @@ much more power than Batch-command, but requires knowing Python and the Evennia API. It is also a severe security risk and should therefore always be limited to superusers only. -Example batch-code file: game/gamesrc/commands/examples/example_batch_code.py +Example batch-code file: game/gamesrc/commands/examples/example_batch_code.py """ from traceback import format_exc @@ -42,10 +42,10 @@ UTF8_ERROR = \ fine and fully supported! But for Evennia to know how to decode such characters in a universal way, the batchfile must be saved with the international 'UTF-8' encoding. This file is not. - + Please re-save the batchfile with the UTF-8 encoding (refer to the - documentation of your text editor on how to do this, or switch to a - better featured one) and try again. + documentation of your text editor on how to do this, or switch to a + better featured one) and try again. The (first) error was found with a character on line %s in the file. """ @@ -60,16 +60,16 @@ def format_header(caller, entry): Formats a header """ width = HEADER_WIDTH - 10 - entry = entry.strip() + entry = entry.strip() header = utils.crop(entry, width=width) - ptr = caller.ndb.batch_stackptr + 1 - stacklen = len(caller.ndb.batch_stack) + ptr = caller.ndb.batch_stackptr + 1 + stacklen = len(caller.ndb.batch_stack) header = "{w%02i/%02i{G: %s{n" % (ptr, stacklen, header) # add extra space to the side for padding. header = "%s%s" % (header, " "*(width - len(header))) header = header.replace('\n', '\\n') - - return header + + return header def format_code(entry): """ @@ -89,7 +89,7 @@ def batch_cmd_exec(caller): command = stack[ptr] caller.msg(format_header(caller, command)) try: - caller.execute_cmd(command) + caller.execute_cmd(command) except Exception: caller.msg(format_code(format_exc())) return False @@ -98,24 +98,24 @@ def batch_cmd_exec(caller): def batch_code_exec(caller): """ Helper function for executing a single batch-code entry - """ + """ ptr = caller.ndb.batch_stackptr stack = caller.ndb.batch_stack debug = caller.ndb.batch_debug codedict = stack[ptr] - + caller.msg(format_header(caller, codedict['code'])) - err = BATCHCODE.code_exec(codedict, - extra_environ={"caller":caller}, debug=debug) + err = BATCHCODE.code_exec(codedict, + extra_environ={"caller":caller}, debug=debug) if err: caller.msg(format_code(err)) return False - return True + return True def step_pointer(caller, step=1): """ Step in stack, returning the item located. - + stackptr - current position in stack stack - the stack of units step - how many steps to move from stackptr @@ -139,10 +139,10 @@ def show_curr(caller, showall=False): if stackptr >= len(stack): caller.ndb.batch_stackptr = len(stack) - 1 show_curr(caller, showall) - return + return + + entry = stack[stackptr] - entry = stack[stackptr] - if type(entry) == dict: # this is a batch-code entry string = format_header(caller, entry['code']) @@ -160,7 +160,7 @@ def show_curr(caller, showall=False): def purge_processor(caller): """ This purges all effects running - on the caller. + on the caller. """ try: del caller.ndb.batch_stack @@ -169,17 +169,17 @@ def purge_processor(caller): del caller.ndb.batch_batchmode except: pass - # clear everything but the default cmdset. - caller.cmdset.delete(BatchSafeCmdSet) - caller.cmdset.clear() + # clear everything but the default cmdset. + caller.cmdset.delete(BatchSafeCmdSet) + caller.cmdset.clear() caller.scripts.validate() # this will purge interactive mode #------------------------------------------------------------ -# main access commands +# main access commands #------------------------------------------------------------ class CmdBatchCommands(MuxCommand): - """ + """ Build from batch-command file Usage: @@ -188,9 +188,9 @@ class CmdBatchCommands(MuxCommand): Switch: interactive - this mode will offer more control when executing the batch file, like stepping, - skipping, reloading etc. + skipping, reloading etc. - Runs batches of commands from a batch-cmd text file (*.ev). + Runs batches of commands from a batch-cmd text file (*.ev). """ key = "@batchcommands" @@ -200,23 +200,23 @@ class CmdBatchCommands(MuxCommand): def func(self): "Starts the processor." - + caller = self.caller args = self.args if not args: caller.msg("Usage: @batchcommands[/interactive] ") - return + return python_path = self.args - #parse indata file + #parse indata file try: commands = BATCHCMD.parse_file(python_path) except UnicodeDecodeError, err: lnum = err.linenum caller.msg(UTF8_ERROR % (python_path, lnum)) - return + return if not commands: string = "'%s' not found.\nYou have to supply the python path " @@ -225,37 +225,37 @@ class CmdBatchCommands(MuxCommand): return switches = self.switches - # Store work data in cache + # Store work data in cache caller.ndb.batch_stack = commands caller.ndb.batch_stackptr = 0 caller.ndb.batch_pythonpath = python_path caller.ndb.batch_batchmode = "batch_commands" - caller.cmdset.add(BatchSafeCmdSet) + caller.cmdset.add(BatchSafeCmdSet) if 'inter' in switches or 'interactive' in switches: # Allow more control over how batch file is executed - # Set interactive state directly + # Set interactive state directly caller.cmdset.add(BatchInteractiveCmdSet) caller.msg("\nBatch-command processor - Interactive mode for %s ..." % python_path) show_curr(caller) else: caller.msg("Running Batch-command processor - Automatic mode for %s ..." % python_path) - + # add the 'safety' cmdset in case the batch processing adds cmdsets to us for inum in range(len(commands)): - # loop through the batch file + # loop through the batch file if not batch_cmd_exec(caller): - return + return step_pointer(caller, 1) - # clean out the safety cmdset and clean out all other temporary attrs. - string = " Batchfile '%s' applied." % python_path + # clean out the safety cmdset and clean out all other temporary attrs. + string = " Batchfile '%s' applied." % python_path caller.msg("{G%s" % string) purge_processor(caller) class CmdBatchCode(MuxCommand): - """ + """ Build from batch-code file Usage: @@ -264,29 +264,29 @@ class CmdBatchCode(MuxCommand): Switch: interactive - this mode will offer more control when executing the batch file, like stepping, - skipping, reloading etc. + skipping, reloading etc. debug - auto-delete all objects that has been marked as deletable in the script file (see example files for syntax). This is useful so as to to not leave multiple object copies behind when testing out the script. - Runs batches of commands from a batch-code text file (*.py). + Runs batches of commands from a batch-code text file (*.py). """ key = "@batchcode" aliases = ["@batchcodes"] - locks = "cmd:superuser()" + locks = "cmd:superuser()" help_category = "Building" def func(self): "Starts the processor." - + caller = self.caller args = self.args if not args: caller.msg("Usage: @batchcode[/interactive/debug] ") - return + return python_path = self.args #parse indata file @@ -295,7 +295,7 @@ class CmdBatchCode(MuxCommand): except UnicodeDecodeError, err: lnum = err.linenum caller.msg(UTF8_ERROR % (python_path, lnum)) - return + return if not codes: string = "'%s' not found.\nYou have to supply the python path " @@ -314,12 +314,12 @@ class CmdBatchCode(MuxCommand): caller.ndb.batch_pythonpath = python_path caller.ndb.batch_batchmode = "batch_code" caller.ndb.batch_debug = debug - caller.cmdset.add(BatchSafeCmdSet) + caller.cmdset.add(BatchSafeCmdSet) if 'inter' in switches or 'interactive'in switches: # Allow more control over how batch file is executed - # Set interactive state directly + # Set interactive state directly caller.cmdset.add(BatchInteractiveCmdSet) caller.msg("\nBatch-code processor - Interactive mode for %s ..." % python_path) @@ -328,11 +328,11 @@ class CmdBatchCode(MuxCommand): caller.msg("Running Batch-code processor - Automatic mode for %s ..." % python_path) # add the 'safety' cmdset in case the batch processing adds cmdsets to us for inum in range(len(codes)): - # loop through the batch file + # loop through the batch file if not batch_code_exec(caller): - return + return step_pointer(caller, 1) - string = " Batchfile '%s' applied." % python_path + string = " Batchfile '%s' applied." % python_path caller.msg("{G%s" % string) purge_processor(caller) @@ -346,41 +346,41 @@ class CmdStateAbort(MuxCommand): @abort This is a safety feature. It force-ejects us out of the processor and to - the default cmdset, regardless of what current cmdset the processor might + the default cmdset, regardless of what current cmdset the processor might have put us in (e.g. when testing buggy scripts etc). """ key = "@abort" help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" + locks = "cmd:perm(batchcommands)" def func(self): "Exit back to default." purge_processor(self.caller) self.caller.msg("Exited processor and reset out active cmdset back to the default one.") - + class CmdStateLL(MuxCommand): """ ll - + Look at the full source for the current - command definition. + command definition. """ key = "ll" help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" + locks = "cmd:perm(batchcommands)" - def func(self): + def func(self): show_curr(self.caller, showall=True) class CmdStatePP(MuxCommand): """ pp - + Process the currently shown command definition. """ key = "pp" help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" + locks = "cmd:perm(batchcommands)" def func(self): """ @@ -392,17 +392,17 @@ class CmdStatePP(MuxCommand): else: batch_cmd_exec(caller) - + class CmdStateRR(MuxCommand): """ rr Reload the batch file, keeping the current - position in it. + position in it. """ key = "rr" help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" + locks = "cmd:perm(batchcommands)" def func(self): caller = self.caller @@ -410,7 +410,7 @@ class CmdStateRR(MuxCommand): new_data = BATCHCODE.parse_file(caller.ndb.batch_pythonpath) else: new_data = BATCHCMD.parse_file(caller.ndb.batch_pythonpath) - caller.ndb.batch_stack = new_data + caller.ndb.batch_stack = new_data caller.msg(format_code("File reloaded. Staying on same command.")) show_curr(caller) @@ -423,7 +423,7 @@ class CmdStateRRR(MuxCommand): """ key = "rrr" help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" + locks = "cmd:perm(batchcommands)" def func(self): caller = self.caller @@ -443,7 +443,7 @@ class CmdStateNN(MuxCommand): """ key = "nn" help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" + locks = "cmd:perm(batchcommands)" def func(self): caller = self.caller @@ -464,7 +464,7 @@ class CmdStateNL(MuxCommand): """ key = "nl" help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" + locks = "cmd:perm(batchcommands)" def func(self): caller = self.caller @@ -485,7 +485,7 @@ class CmdStateBB(MuxCommand): """ key = "bb" help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" + locks = "cmd:perm(batchcommands)" def func(self): caller = self.caller @@ -493,7 +493,7 @@ class CmdStateBB(MuxCommand): if arg and arg.isdigit(): step = -int(self.args) else: - step = -1 + step = -1 step_pointer(caller, step) show_curr(caller) @@ -506,7 +506,7 @@ class CmdStateBL(MuxCommand): """ key = "bl" help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" + locks = "cmd:perm(batchcommands)" def func(self): caller = self.caller @@ -514,9 +514,9 @@ class CmdStateBL(MuxCommand): if arg and arg.isdigit(): step = -int(self.args) else: - step = -1 + step = -1 step_pointer(caller, step) - show_curr(caller, showall=True) + show_curr(caller, showall=True) class CmdStateSS(MuxCommand): """ @@ -528,7 +528,7 @@ class CmdStateSS(MuxCommand): """ key = "ss" help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" + locks = "cmd:perm(batchcommands)" def func(self): caller = self.caller @@ -536,14 +536,14 @@ class CmdStateSS(MuxCommand): if arg and arg.isdigit(): step = int(self.args) else: - step = 1 + step = 1 for istep in range(step): if caller.ndb.batch_batchmode == "batch_code": batch_code_exec(caller) else: batch_cmd_exec(caller) - step_pointer(caller, 1) + step_pointer(caller, 1) show_curr(caller) class CmdStateSL(MuxCommand): @@ -552,11 +552,11 @@ class CmdStateSL(MuxCommand): Process current command, then step to the next one, viewing its full source. If steps is given, - process this many commands. + process this many commands. """ key = "sl" help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" + locks = "cmd:perm(batchcommands)" def func(self): caller = self.caller @@ -564,7 +564,7 @@ class CmdStateSL(MuxCommand): if arg and arg.isdigit(): step = int(self.args) else: - step = 1 + step = 1 for istep in range(step): if caller.ndb.batch_batchmode == "batch_code": @@ -583,7 +583,7 @@ class CmdStateCC(MuxCommand): """ key = "cc" help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" + locks = "cmd:perm(batchcommands)" def func(self): caller = self.caller @@ -604,7 +604,7 @@ class CmdStateCC(MuxCommand): del caller.ndb.batch_pythonpath del caller.ndb.batch_batchmode caller.msg(format_code("Finished processing batch file.")) - + class CmdStateJJ(MuxCommand): """ j @@ -613,7 +613,7 @@ class CmdStateJJ(MuxCommand): """ key = "j" help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" + locks = "cmd:perm(batchcommands)" def func(self): caller = self.caller @@ -622,9 +622,9 @@ class CmdStateJJ(MuxCommand): number = int(self.args)-1 else: caller.msg(format_code("You must give a number index.")) - return + return ptr = caller.ndb.batch_stackptr - step = number - ptr + step = number - ptr step_pointer(caller, step) show_curr(caller) @@ -636,7 +636,7 @@ class CmdStateJL(MuxCommand): """ key = "jl" help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" + locks = "cmd:perm(batchcommands)" def func(self): caller = self.caller @@ -645,43 +645,43 @@ class CmdStateJL(MuxCommand): number = int(self.args)-1 else: caller.msg(format_code("You must give a number index.")) - return + return ptr = caller.ndb.batch_stackptr - step = number - ptr + step = number - ptr step_pointer(caller, step) show_curr(caller, showall=True) class CmdStateQQ(MuxCommand): """ - qq + qq Quit the batchprocessor. """ key = "qq" help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" + locks = "cmd:perm(batchcommands)" def func(self): purge_processor(self.caller) self.caller.msg("Aborted interactive batch mode.") - + class CmdStateHH(MuxCommand): "Help command" key = "hh" help_category = "BatchProcess" - locks = "cmd:perm(batchcommands)" + locks = "cmd:perm(batchcommands)" def func(self): string = """ Interactive batch processing commands: nn [steps] - next command (no processing) - nl [steps] - next & look + nl [steps] - next & look bb [steps] - back to previous command (no processing) - bl [steps] - back & look + bl [steps] - back & look jj - jump to command nr N (no processing) - jl - jump & look + jl - jump & look pp - process currently shown command (no step) ss [steps] - process & step sl [steps] - process & step & look @@ -693,9 +693,9 @@ class CmdStateHH(MuxCommand): cc - continue processing to end, then quit. qq - quit (abort all remaining commands) - @abort - this is a safety command that always is available + @abort - this is a safety command that always is available regardless of what cmdsets gets added to us during - batch-command processing. It immediately shuts down + batch-command processing. It immediately shuts down the processor and returns us to the default cmdset. """ self.caller.msg(string) diff --git a/src/commands/default/building.py b/src/commands/default/building.py index dc251cf00a..f1876c6024 100644 --- a/src/commands/default/building.py +++ b/src/commands/default/building.py @@ -399,9 +399,8 @@ class CmdCreate(ObjManipCommand): # object typeclass will automatically be used) lockstring = "control:id(%s);examine:perm(Builders);delete:id(%s) or perm(Wizards);get:all()" % (caller.id, caller.id) obj = create.create_object(typeclass, name, caller, - home=caller, aliases=aliases, locks=lockstring) + home=caller, aliases=aliases, locks=lockstring, report_to=caller) if not obj: - string = "Error when creating object." continue if aliases: string = "You create a new %s: %s (aliases: %s)." @@ -416,8 +415,8 @@ class CmdCreate(ObjManipCommand): if caller.location: obj.home = caller.location obj.move_to(caller.location, quiet=True) - if string: - caller.msg(string) + if string: + caller.msg(string) class CmdDebug(MuxCommand): @@ -630,7 +629,7 @@ class CmdDig(ObjManipCommand): lockstring = lockstring % (caller.dbref, caller.dbref, caller.dbref) new_room = create.create_object(typeclass, room["name"], - aliases=room["aliases"]) + aliases=room["aliases"], report_to=caller) new_room.locks.add(lockstring) alias_string = "" if new_room.aliases: @@ -659,7 +658,7 @@ class CmdDig(ObjManipCommand): new_to_exit = create.create_object(typeclass, to_exit["name"], location, aliases=to_exit["aliases"], - locks=lockstring, destination=new_room) + locks=lockstring, destination=new_room, report_to=caller) alias_string = "" if new_to_exit.aliases: alias_string = " (%s)" % ", ".join(new_to_exit.aliases) @@ -684,7 +683,7 @@ class CmdDig(ObjManipCommand): typeclass = settings.BASE_EXIT_TYPECLASS new_back_exit = create.create_object(typeclass, back_exit["name"], new_room, aliases=back_exit["aliases"], - locks=lockstring, destination=location) + locks=lockstring, destination=location, report_to=caller) alias_string = "" if new_back_exit.aliases: alias_string = " (%s)" % ", ".join(new_back_exit.aliases) @@ -1083,7 +1082,7 @@ class CmdOpen(ObjManipCommand): typeclass = settings.BASE_EXIT_TYPECLASS exit_obj = create.create_object(typeclass, key=exit_name, location=location, - aliases=exit_aliases) + aliases=exit_aliases, report_to=caller) if exit_obj: # storing a destination is what makes it an exit! exit_obj.destination = destination @@ -1283,9 +1282,9 @@ class CmdTypeclass(MuxCommand): @typeclass - set object typeclass Usage: - @typclass[/switch] [= ] - @type '' - @parent '' + @typclass[/switch] [= ] + @type '' + @parent '' Switch: reset - clean out *all* the attributes on the object - @@ -1295,12 +1294,18 @@ class CmdTypeclass(MuxCommand): Example: @type button = examples.red_button.RedButton - Sets an object's typeclass. The typeclass must be identified - by its location using python dot-notation pointing to the correct - module and class. If no typeclass is given (or a wrong typeclass - is given), the object will be set to the default typeclass. - The location of the typeclass module is searched from - the default typeclass directory, as defined in the server settings. + View or set an object's typeclass. If setting, the creation hooks + of the new typeclass will be run on the object. If you have + clashing properties on the old class, use /reset. By default you + are protected from changing to a typeclass of the same name as the + one you already have, use /force to override this protection. + + The given typeclass must be identified by its location using + python dot-notation pointing to the correct module and class. If + no typeclass is given (or a wrong typeclass is given). Errors in + the path or new typeclass will lead to the old typeclass being + kept. The location of the typeclass module is searched from the + default typeclass directory, as defined in the server settings. """ @@ -1327,7 +1332,7 @@ class CmdTypeclass(MuxCommand): # we did not supply a new typeclass, view the # current one instead. if hasattr(obj, "typeclass"): - string = "%s's current typeclass is '%s'." % (obj.name, obj.typeclass.typename) + string = "%s's current typeclass is '%s' (%s)." % (obj.name, obj.typeclass.typename, obj.typeclass.path) else: string = "%s is not a typed object." % obj.name caller.msg(string) @@ -1344,25 +1349,31 @@ class CmdTypeclass(MuxCommand): caller.msg("This object cannot have a type at all!") return - if obj.is_typeclass(typeclass) and not 'force' in self.switches: - string = "%s already has the typeclass '%s'." % (obj.name, typeclass) + is_same = obj.is_typeclass(typeclass) + if is_same and not 'force' in self.switches: + string = "%s already has the typeclass '%s'. Use /force to override." % (obj.name, typeclass) else: reset = "reset" in self.switches - old_typeclass_name = obj.typeclass.typename + old_typeclass_path = obj.typeclass.path ok = obj.swap_typeclass(typeclass, clean_attributes=reset) if ok: - string = "%s's type is now %s (instead of %s).\n" % (obj.name, - obj.typeclass.typename, - old_typeclass_name) - if reset: - string += "All attributes where reset." + if is_same: + string = "%s updated its existing typeclass (%s).\n" % (obj.name, obj.typeclass.path) else: - string += "Note that the new class type could have overwritten " - string += "same-named attributes on the existing object." + string = "%s's changed typeclass from %s to %s.\n" % (obj.name, + old_typeclass_path, + obj.typeclass.path) + string += "Creation hooks were run." + if reset: + string += " All old attributes where deleted before the swap." + else: + string += " Note that the typeclassed object could have ended up with a mixture of old" + string += "\nand new attributes. Use /reset to remove old attributes if you don't want this." else: - string = "Could not swap '%s' (%s) to typeclass '%s'." % (obj.name, - old_typeclass_name, - typeclass) + string = obj.typeclass_last_errmsg + string += "\nCould not swap '%s' (%s) to typeclass '%s'." % (obj.name, + old_typeclass_path, + typeclass) caller.msg(string) diff --git a/src/commands/default/comms.py b/src/commands/default/comms.py index adc20a406a..8551c06500 100644 --- a/src/commands/default/comms.py +++ b/src/commands/default/comms.py @@ -2,9 +2,9 @@ Comsystem command module. Comm commands are OOC commands and intended to be made available to -the Player at all times (they go into the PlayerCmdSet). So we +the Player at all times (they go into the PlayerCmdSet). So we make sure to homogenize self.caller to always be the player object -for easy handling. +for easy handling. """ from django.conf import settings @@ -12,7 +12,7 @@ from src.comms.models import Channel, Msg, PlayerChannelConnection, ExternalChan from src.comms import irc, imc2, rss from src.comms.channelhandler import CHANNELHANDLER from src.utils import create, utils -from src.commands.default.muxcommand import MuxCommand +from src.commands.default.muxcommand import MuxCommand # limit symbol import for API __all__ = ("CommCommand", "CmdAddCom", "CmdDelCom", "CmdAllCom", @@ -45,10 +45,10 @@ def find_channel(caller, channelname, silent=False, noaliases=False): class CommCommand(MuxCommand): """ This is a parent for comm-commands. Since - These commands are to be available to the - Player, we make sure to homogenize the caller - here, so it's always seen as a player to the - command body. + These commands are to be available to the + Player, we make sure to homogenize the caller + here, so it's always seen as a player to the + command body. """ def parse(self): @@ -60,14 +60,14 @@ class CommCommand(MuxCommand): if utils.inherits_from(self.caller, "src.objects.objects.Object"): # an object. Convert it to its player. self.caller = self.caller.player - + class CmdAddCom(MuxCommand): """ addcom - subscribe to a channel with optional alias Usage: addcom [alias=] - + Joins a given channel. If alias is given, this will allow you to refer to the channel by this alias rather than the full channel name. Subsequent calls of this command can be used to add multiple @@ -81,7 +81,7 @@ class CmdAddCom(MuxCommand): def func(self): "Implement the command" - + caller = self.caller args = self.args player = caller @@ -92,7 +92,7 @@ class CmdAddCom(MuxCommand): if self.rhs: # rhs holds the channelname - channelname = self.rhs + channelname = self.rhs alias = self.lhs else: channelname = self.args @@ -101,12 +101,12 @@ class CmdAddCom(MuxCommand): channel = find_channel(caller, channelname) if not channel: # we use the custom search method to handle errors. - return + return # check permissions if not channel.access(player, 'listen'): caller.msg("%s: You are not allowed to listen to this channel." % channel.key) - return + return string = "" if not channel.has_connection(player): @@ -114,16 +114,16 @@ class CmdAddCom(MuxCommand): if not channel.connect_to(player): # if this would have returned True, the player is connected caller.msg("%s: You are not allowed to join this channel." % channel.key) - return + return else: string += "You now listen to the channel %s. " % channel.key else: string += "You are already connected to channel %s." % channel.key - + if alias: # create a nick and add it to the caller. caller.nicks.add(alias, channel.key, nick_type="channel") - string += " You can now refer to the channel %s with the alias '%s'." + string += " You can now refer to the channel %s with the alias '%s'." caller.msg(string % (channel.key, alias)) else: string += " No alias added." @@ -155,26 +155,26 @@ class CmdDelCom(MuxCommand): if not self.args: caller.msg("Usage: delcom ") - return + return ostring = self.args.lower() - + channel = find_channel(caller, ostring, silent=True, noaliases=True) if channel: # we have given a channel name - unsubscribe if not channel.has_connection(player): caller.msg("You are not listening to that channel.") - return + return chkey = channel.key.lower() # find all nicks linked to this channel and delete them - for nick in [nick for nick in caller.nicks.get(nick_type="channel") - if nick.db_real.lower() == chkey]: + for nick in [nick for nick in caller.nicks.get(nick_type="channel") + if nick.db_real.lower() == chkey]: nick.delete() channel.disconnect_from(player) caller.msg("You stop listening to channel '%s'. Eventual aliases were removed." % channel.key) - return + return else: # we are removing a channel nick - channame = caller.nicks.get(ostring, nick_type="channel") + channame = caller.nicks.get(ostring, nick_type="channel") channel = find_channel(caller, channame, silent=True) if not channel: caller.msg("No channel with alias '%s' was found." % ostring) @@ -184,13 +184,13 @@ class CmdDelCom(MuxCommand): caller.msg("Your alias '%s' for channel %s was cleared." % (ostring, channel.key)) else: caller.msg("You had no such alias defined for this channel.") - + class CmdAllCom(MuxCommand): """ allcom - operate on all channels - Usage: - allcom [on | off | who | destroy] + Usage: + allcom [on | off | who | destroy] 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. Destroy deletes @@ -198,11 +198,11 @@ class CmdAllCom(MuxCommand): Without argument, works like comlist. """ - + key = "allcom" locks = "cmd: not pperm(channel_banned)" help_category = "Comms" - + def func(self): "Runs the function" @@ -224,12 +224,12 @@ class CmdAllCom(MuxCommand): for channel in channels: caller.execute_cmd("delcom %s" % channel.key) elif args == "destroy": - # destroy all channels you control + # destroy all channels you control channels = [chan for chan in Channel.objects.get_all_channels() if chan.access(caller, 'control')] for channel in channels: caller.execute_cmd("@cdestroy %s" % channel.key) elif args == "who": - # run a who, listing the subscribers on visible channels. + # run a who, listing the subscribers on visible channels. string = "\n{CChannel subscriptions{n" channels = [chan for chan in Channel.objects.get_all_channels() if chan.access(caller, 'listen')] if not channels: @@ -243,7 +243,7 @@ class CmdAllCom(MuxCommand): string += " " caller.msg(string.strip()) else: - # wrong input + # wrong input caller.msg("Usage: allcom on | off | who | clear") class CmdChannels(MuxCommand): @@ -255,7 +255,7 @@ class CmdChannels(MuxCommand): @clist comlist - Lists all channels available to you, wether you listen to them or not. + Lists all channels available to you, wether you listen to them or not. Use 'comlist" to only view your current channel subscriptions. """ key = "@channels" @@ -265,11 +265,11 @@ class CmdChannels(MuxCommand): def func(self): "Implement function" - + caller = self.caller - + # all channels we have available to listen to - channels = [chan for chan in Channel.objects.get_all_channels() if chan.access(caller, 'listen')] + channels = [chan for chan in Channel.objects.get_all_channels() if chan.access(caller, 'listen')] if not channels: caller.msg("No channels available.") return @@ -278,7 +278,7 @@ class CmdChannels(MuxCommand): if self.cmdstring != "comlist": - string = "\nChannels available:" + string = "\nChannels available:" cols = [[" "], ["Channel"], ["Aliases"], ["Perms"], ["Description"]] for chan in channels: if chan in subs: @@ -289,10 +289,10 @@ class CmdChannels(MuxCommand): cols[2].append(",".join(chan.aliases)) cols[3].append(str(chan.locks)) cols[4].append(chan.desc) - # put into table + # put into table for ir, row in enumerate(utils.format_table(cols)): if ir == 0: - string += "\n{w" + "".join(row) + "{n" + string += "\n{w" + "".join(row) + "{n" else: string += "\n" + "".join(row) self.caller.msg(string) @@ -306,13 +306,13 @@ class CmdChannels(MuxCommand): for chan in subs: cols[0].append(" ") cols[1].append(chan.key) - cols[2].append(",".join([nick.db_nick for nick in nicks + cols[2].append(",".join([nick.db_nick for nick in nicks if nick.db_real.lower() == chan.key.lower()] + chan.aliases)) cols[3].append(chan.desc) # put into table for ir, row in enumerate(utils.format_table(cols)): if ir == 0: - string += "\n{w" + "".join(row) + "{n" + string += "\n{w" + "".join(row) + "{n" else: string += "\n" + "".join(row) caller.msg(string) @@ -341,10 +341,10 @@ class CmdCdestroy(MuxCommand): channel = find_channel(caller, self.args) if not channel: caller.msg("Could not find channel %s." % self.args) - return + return if not channel.access(caller, 'control'): caller.msg("You are not allowed to do that.") - return + return message = "%s is being destroyed. Make sure to change your aliases." % channel msgobj = create.create_message(caller, message, channel) @@ -352,7 +352,7 @@ class CmdCdestroy(MuxCommand): channel.delete() CHANNELHANDLER.update() caller.msg("%s was destroyed." % channel) - + class CmdCBoot(MuxCommand): """ @cboot @@ -370,24 +370,24 @@ class CmdCBoot(MuxCommand): key = "@cboot" locks = "cmd: not pperm(channel_banned)" help_category = "Comms" - + def func(self): "implement the function" - + if not self.args or not self.rhs: string = "Usage: @cboot[/quiet] = [:reason]" self.caller.msg(string) - return - + return + channel = find_channel(self.caller, self.lhs) if not channel: return reason = "" if ":" in self.rhs: - playername, reason = self.rhs.rsplit(":", 1) + playername, reason = self.rhs.rsplit(":", 1) searchstring = playername.lstrip('*') else: - searchstring = self.rhs.lstrip('*') + searchstring = self.rhs.lstrip('*') player = self.caller.search(searchstring, player=True) if not player: return @@ -396,7 +396,7 @@ class CmdCBoot(MuxCommand): if not channel.access(self.caller, "control"): string = "You don't control this channel." self.caller.msg(string) - return + return if not PlayerChannelConnection.objects.has_connection(player, channel): string = "Player %s is not connected to channel %s." % (player.key, channel.key) self.caller.msg(string) @@ -405,10 +405,10 @@ class CmdCBoot(MuxCommand): string = "%s boots %s from channel.%s" % (self.caller, player.key, reason) channel.msg(string) # find all player's nicks linked to this channel and delete them - for nick in [nick for nick in player.character.nicks.get(nick_type="channel") - if nick.db_real.lower() == channel.key]: + for nick in [nick for nick in player.character.nicks.get(nick_type="channel") + if nick.db_real.lower() == channel.key]: nick.delete() - # disconnect player + # disconnect player channel.disconnect_from(player) class CmdCemit(MuxCommand): @@ -426,9 +426,9 @@ class CmdCemit(MuxCommand): Allows the user to broadcast a message over a channel as long as they control it. It does not show the user's name unless they provide the /sendername switch. - + """ - + key = "@cemit" aliases = ["@cmsg"] locks = "cmd: not pperm(channel_banned)" @@ -440,18 +440,18 @@ class CmdCemit(MuxCommand): if not self.args or not self.rhs: string = "Usage: @cemit[/switches] = " self.caller.msg(string) - return + return channel = find_channel(self.caller, self.lhs) if not channel: return if not channel.access(self.caller, "control"): string = "You don't control this channel." self.caller.msg(string) - return + return message = self.rhs if "sendername" in self.switches: message = "%s: %s" % (self.caller.key, message) - if not "noheader" in self.switches: + if not "noheader" in self.switches: message = "[%s] %s" % (channel.key, message) channel.msg(message) if not "quiet" in self.switches: @@ -461,8 +461,8 @@ class CmdCemit(MuxCommand): class CmdCWho(MuxCommand): """ @cwho - - Usage: + + Usage: @cwho List who is connected to a given channel you have access to. @@ -473,18 +473,18 @@ class CmdCWho(MuxCommand): def func(self): "implement function" - + if not self.args: string = "Usage: @cwho " self.caller.msg(string) - return + return channel = find_channel(self.caller, self.lhs) if not channel: - return + return if not channel.access(self.caller, "listen"): string = "You can't access this channel." - self.caller.msg(string) + self.caller.msg(string) string = "\n{CChannel subscriptions{n" string += "\n{w%s:{n\n" % channel.key conns = PlayerChannelConnection.objects.get_all_connections(channel) @@ -497,13 +497,13 @@ class CmdCWho(MuxCommand): class CmdChannelCreate(MuxCommand): """ @ccreate - channelcreate + channelcreate Usage: @ccreate [;alias;alias...] = description Creates a new channel owned by you. """ - + key = "@ccreate" aliases = "channelcreate" locks = "cmd:not pperm(channel_banned)" @@ -517,7 +517,7 @@ class CmdChannelCreate(MuxCommand): if not self.args: caller.msg("Usage @ccreate [;alias;alias..] = description") return - + description = "" if self.rhs: @@ -526,25 +526,25 @@ class CmdChannelCreate(MuxCommand): channame = lhs aliases = None if ';' in lhs: - channame, aliases = [part.strip().lower() + channame, aliases = [part.strip().lower() for part in lhs.split(';', 1) if part.strip()] - aliases = [alias.strip().lower() - for alias in aliases.split(';') if alias.strip()] - channel = Channel.objects.channel_search(channame) + aliases = [alias.strip().lower() + for alias in aliases.split(';') if alias.strip()] + channel = Channel.objects.channel_search(channame) if channel: caller.msg("A channel with that name already exists.") - return + return # Create and set the channel up lockstring = "send:all();listen:all();control:id(%s)" % caller.id new_chan = create.create_channel(channame, aliases, description, locks=lockstring) new_chan.connect_to(caller) caller.msg("Created channel %s and connected to it." % new_chan.key) - + class CmdCset(MuxCommand): """ @cset - changes channel access restrictions - + Usage: @cset [= ] @@ -559,26 +559,26 @@ class CmdCset(MuxCommand): def func(self): "run the function" - + if not self.args: string = "Usage: @cset channel [= lockstring]" self.caller.msg(string) - return + return channel = find_channel(self.caller, self.lhs) if not channel: - return + return if not self.rhs: # no =, so just view the current locks string = "Current locks on %s:" % channel.key string = "%s\n %s" % (string, channel.locks) self.caller.msg(string) - return - # we want to add/change a lock. + return + # we want to add/change a lock. if not channel.access(self.caller, "control"): string = "You don't control this channel." self.caller.msg(string) - return + return # Try to add the lock channel.locks.add(self.rhs) string = "Lock(s) applied. " @@ -595,7 +595,7 @@ class CmdCdesc(MuxCommand): @cdesc = Changes the description of the channel as shown in - channel lists. + channel lists. """ key = "@cdesc" @@ -604,12 +604,12 @@ class CmdCdesc(MuxCommand): def func(self): "Implement command" - + caller = self.caller if not self.rhs: caller.msg("Usage: @cdesc = ") - return + return channel = find_channel(caller, self.lhs) if not channel: caller.msg("Channel '%s' not found." % self.lhs) @@ -635,7 +635,7 @@ class CmdPage(MuxCommand): Switch: last - shows who you last messaged list - show your last of tells/pages (default) - + Send a message to target user (if online). If no argument is given, you will get a list of your latest messages. """ @@ -644,24 +644,24 @@ class CmdPage(MuxCommand): aliases = ['tell'] locks = "cmd:not pperm(page_banned)" help_category = "Comms" - + def func(self): - + "Implement function using the Msg methods" caller = self.caller player = caller # get the messages we've sent - messages_we_sent = list(Msg.objects.get_messages_by_sender(player)) - pages_we_sent = [msg for msg in messages_we_sent + messages_we_sent = list(Msg.objects.get_messages_by_sender(player)) + pages_we_sent = [msg for msg in messages_we_sent if msg.receivers] # get last messages we've got - pages_we_got = list(Msg.objects.get_messages_by_receiver(player)) - + pages_we_got = list(Msg.objects.get_messages_by_receiver(player)) + if 'last' in self.switches: if pages_we_sent: - string = "You last paged {c%s{n." % (", ".join([obj.name + string = "You last paged {c%s{n." % (", ".join([obj.name for obj in pages_we_sent[-1].receivers])) caller.msg(string) return @@ -680,15 +680,15 @@ class CmdPage(MuxCommand): number = int(self.args) except ValueError: caller.msg("Usage: tell [ = msg]") - return + return if len(pages) > number: lastpages = pages[-number:] else: - lastpages = pages - - lastpages = "\n ".join(["{w%s{n {c%s{n to {c%s{n: %s" % (utils.datetime_format(page.date_sent), - page.sender.name, + lastpages = pages + + lastpages = "\n ".join(["{w%s{n {c%s{n to {c%s{n: %s" % (utils.datetime_format(page.date_sent), + page.sender.name, "{n,{c ".join([obj.name for obj in page.receivers]), page.message) for page in lastpages]) @@ -704,16 +704,16 @@ class CmdPage(MuxCommand): # We are sending. Build a list of targets if not self.lhs: - # If there are no targets, then set the targets + # If there are no targets, then set the targets # to the last person they paged. if pages_we_sent: receivers = pages_we_sent[-1].receivers else: caller.msg("Who do you want to page?") - return + return else: - receivers = self.lhslist - + receivers = self.lhslist + recobjs = [] for receiver in set(receivers): if isinstance(receiver, basestring): @@ -724,22 +724,22 @@ class CmdPage(MuxCommand): pobj = receiver.character else: caller.msg("Who do you want to page?") - return + return recobjs.append(pobj) if not recobjs: caller.msg("No players matching your target were found.") - return - + return + header = "{wPlayer{n {c%s{n {wpages:{n" % caller.key message = self.rhs # if message begins with a :, we assume it is a 'page-pose' - if message.startswith(":"): + if message.startswith(":"): message = "%s %s" % (caller.key, message.strip(':').strip()) # create the persistent message object - msg = create.create_message(player, message, - receivers=recobjs) + msg = create.create_message(player, message, + receivers=recobjs) # tell the players they got a message. received = [] @@ -747,8 +747,8 @@ class CmdPage(MuxCommand): for pobj in recobjs: if not pobj.access(caller, 'msg'): rstrings.append("You are not allowed to page %s." % pobj) - continue - pobj.msg("%s %s" % (header, message)) + continue + pobj.msg("%s %s" % (header, message)) if hasattr(pobj, 'has_player') and not pobj.has_player: received.append("{C%s{n" % pobj.name) rstrings.append("%s is offline. They will see your message if they list their pages later." % received[-1]) @@ -768,19 +768,19 @@ class CmdIRC2Chan(MuxCommand): Switches: /disconnect - this will delete the bot and remove the irc connection to the channel. - /remove - " + /remove - " /list - show all irc<->evennia mappings Example: @irc2chan myircchan = irc.dalnet.net 6667 myevennia-channel evennia-bot - This creates an IRC bot that connects to a given IRC network and channel. It will - relay everything said in the evennia channel to the IRC channel and vice versa. The - bot will automatically connect at server start, so this comman need only be given once. - The /disconnect switch will permanently delete the bot. To only temporarily deactivate it, - use the @services command instead. + This creates an IRC bot that connects to a given IRC network and channel. It will + relay everything said in the evennia channel to the IRC channel and vice versa. The + bot will automatically connect at server start, so this comman need only be given once. + The /disconnect switch will permanently delete the bot. To only temporarily deactivate it, + use the @services command instead. """ - + key = "@irc2chan" locks = "cmd:serversetting(IRC_ENABLED) and pperm(Immortals)" help_category = "Comms" @@ -811,21 +811,21 @@ class CmdIRC2Chan(MuxCommand): self.caller.msg(string) else: self.caller.msg("No connections found.") - return + return if not self.args or not self.rhs: string = "Usage: @irc2chan[/switches] = <#irchannel> " self.caller.msg(string) - return + return channel = self.lhs self.rhs = self.rhs.replace('#', ' ') # to avoid Python comment issues try: irc_network, irc_port, irc_channel, irc_botname = [part.strip() for part in self.rhs.split(None, 3)] irc_channel = "#%s" % irc_channel - except Exception: + except Exception: string = "IRC bot definition '%s' is not valid." % self.rhs self.caller.msg(string) - return + return if 'disconnect' in self.switches or 'remove' in self.switches or 'delete' in self.switches: chanmatch = find_channel(self.caller, channel, silent=True) @@ -837,7 +837,7 @@ class CmdIRC2Chan(MuxCommand): self.caller.msg("IRC connection/bot could not be removed, does it exist?") else: self.caller.msg("IRC connection destroyed.") - return + return channel = find_channel(self.caller, channel) if not channel: @@ -845,7 +845,7 @@ class CmdIRC2Chan(MuxCommand): ok = irc.create_connection(channel, irc_network, irc_port, irc_channel, irc_botname) if not ok: self.caller.msg("This IRC connection already exists.") - return + return self.caller.msg("Connection created. Starting IRC bot.") class CmdIMC2Chan(MuxCommand): @@ -857,12 +857,12 @@ class CmdIMC2Chan(MuxCommand): Switches: /disconnect - this clear the imc2 connection to the channel. - /remove - " + /remove - " /list - show all imc2<->evennia mappings Example: @imc2chan myimcchan = ievennia - + Connect an existing evennia channel to a channel on an IMC2 network. The network contact information is defined in settings and should already be accessed at this point. Use @imcchanlist to see @@ -901,27 +901,27 @@ class CmdIMC2Chan(MuxCommand): self.caller.msg(string) else: self.caller.msg("No connections found.") - return + return if not self.args or not self.rhs: string = "Usage: @imc2chan[/switches] = " self.caller.msg(string) - return + return channel = self.lhs imc2_channel = self.rhs - + if 'disconnect' in self.switches or 'remove' in self.switches or 'delete' in self.switches: # we don't search for channels before this since we want to clear the link - # also if the channel no longer exists. + # also if the channel no longer exists. ok = imc2.delete_connection(channel, imc2_channel) if not ok: self.caller.msg("IMC2 connection could not be removed, does it exist?") else: self.caller.msg("IMC2 connection destroyed.") - return + return - # actually get the channel object + # actually get the channel object channel = find_channel(self.caller, channel) if not channel: return @@ -929,7 +929,7 @@ class CmdIMC2Chan(MuxCommand): ok = imc2.create_connection(channel, imc2_channel) if not ok: self.caller.msg("The connection %s <-> %s already exists." % (channel.key, imc2_channel)) - return + return self.caller.msg("Created connection channel %s <-> IMC channel %s." % (channel.key, imc2_channel)) @@ -940,18 +940,18 @@ class CmdIMCInfo(MuxCommand): Usage: @imcinfo[/switches] @imcchanlist - list imc2 channels - @imclist - list connected muds + @imclist - list connected muds @imcwhois - whois info about a remote player Switches for @imcinfo: channels - as @imcchanlist (default) - games or muds - as @imclist + games or muds - as @imclist whois - as @imcwhois (requires an additional argument) update - force an update of all lists - + Shows lists of games or channels on the IMC2 network. """ - + key = "@imcinfo" aliases = ["@imcchanlist", "@imclist", "@imcwhois"] locks = "cmd: serversetting(IMC2_ENABLED) and pperm(Wizards)" @@ -966,18 +966,18 @@ class CmdIMCInfo(MuxCommand): return if "update" in self.switches: - # update the lists + # update the lists import time from src.comms.imc2lib import imc2_packets as pck from src.comms.imc2 import IMC2_MUDLIST, IMC2_CHANLIST, IMC2_CLIENT - # update connected muds + # update connected muds IMC2_CLIENT.send_packet(pck.IMC2PacketKeepAliveRequest()) - # prune inactive muds + # prune inactive muds for name, mudinfo in IMC2_MUDLIST.mud_list.items(): if time.time() - mudinfo.last_updated > 3599: del IMC2_MUDLIST.mud_list[name] - # update channel list - IMC2_CLIENT.send_packet(pck.IMC2PacketIceRefresh()) + # update channel list + IMC2_CLIENT.send_packet(pck.IMC2PacketIceRefresh()) self.caller.msg("IMC2 lists were re-synced.") elif "games" in self.switches or "muds" in self.switches or self.cmdstring == "@imclist": @@ -999,24 +999,24 @@ class CmdIMCInfo(MuxCommand): cols[3].append(mud.port) ftable = utils.format_table(cols) for ir, row in enumerate(ftable): - if ir == 0: + if ir == 0: string += "\n{w" + "".join(row) + "{n" else: string += "\n" + "".join(row) string += "\n %i Muds found." % nmuds - self.caller.msg(string) + self.caller.msg(string) elif "whois" in self.switches or self.cmdstring == "@imcwhois": # find out about a player - if not self.args: + if not self.args: self.caller.msg("Usage: @imcwhois ") return from src.comms.imc2 import IMC2_CLIENT - self.caller.msg("Sending IMC whois request. If you receive no response, no matches were found.") + self.caller.msg("Sending IMC whois request. If you receive no response, no matches were found.") IMC2_CLIENT.msg_imc2(None, from_obj=self.caller, packet_type="imcwhois", data={"target":self.args}) elif not self.switches or "channels" in self.switches or self.cmdstring == "@imcchanlist": - # show channels + # show channels from src.comms.imc2 import IMC2_CHANLIST, IMC2_CLIENT channels = IMC2_CHANLIST.get_channel_list() @@ -1028,12 +1028,12 @@ class CmdIMCInfo(MuxCommand): nchans += 1 cols[0].append(channel.name) cols[1].append(channel.localname) - cols[2].append(channel.owner) + cols[2].append(channel.owner) cols[3].append(channel.level) cols[4].append(channel.policy) ftable = utils.format_table(cols) for ir, row in enumerate(ftable): - if ir == 0: + if ir == 0: string += "\n{w" + "".join(row) + "{n" else: string += "\n" + "".join(row) @@ -1045,19 +1045,19 @@ class CmdIMCInfo(MuxCommand): string = "Usage: imcinfo|imcchanlist|imclist" self.caller.msg(string) -# unclear if this is working ... +# unclear if this is working ... class CmdIMCTell(MuxCommand): """ imctell - send a page to a remote IMC player - Usage: - imctell User@MUD = - imcpage " + Usage: + imctell User@MUD = + imcpage " Sends a page to a user on a remote MUD, connected - over IMC2. + over IMC2. """ - + key = "imctell" aliases = ["imcpage", "imc2tell", "imc2page"] locks = "cmd: serversetting(IMC2_ENABLED)" @@ -1072,11 +1072,11 @@ class CmdIMCTell(MuxCommand): return from src.comms.imc2 import IMC2_CLIENT - + if not self.args or not '@' in self.lhs or not self.rhs: string = "Usage: imctell User@Mud = " self.caller.msg(string) - return + return target, destination = self.lhs.split("@", 1) message = self.rhs.strip() data = {"target":target, "destination":destination} @@ -1087,7 +1087,7 @@ class CmdIMCTell(MuxCommand): self.caller.msg("You paged {c%s@%s{n (over IMC): '%s'." % (target, destination, message)) -# RSS connection +# RSS connection class CmdRSS2Chan(MuxCommand): """ @rss2chan - link evennia channel to an RSS feed @@ -1097,20 +1097,20 @@ class CmdRSS2Chan(MuxCommand): Switches: /disconnect - this will stop the feed and remove the connection to the channel. - /remove - " + /remove - " /list - show all rss->evennia mappings Example: @rss2chan rsschan = http://code.google.com/feeds/p/evennia/updates/basic - This creates an RSS reader that connects to a given RSS feed url. Updates will be + This creates an RSS reader that connects to a given RSS feed url. Updates will be echoed as a title and news link to the given channel. The rate of updating is set - with the RSS_UPDATE_INTERVAL variable in settings (default is every 10 minutes). - + with the RSS_UPDATE_INTERVAL variable in settings (default is every 10 minutes). + When disconnecting you need to supply both the channel and url again so as to identify - the connection uniquely. + the connection uniquely. """ - + key = "@rss2chan" locks = "cmd:serversetting(RSS_ENABLED) and pperm(Immortals)" help_category = "Comms" @@ -1125,7 +1125,7 @@ class CmdRSS2Chan(MuxCommand): if 'list' in self.switches: # show all connections - connections = ExternalChannelConnection.objects.filter(db_external_key__startswith='rss_') + connections = ExternalChannelConnection.objects.filter(db_external_key__startswith='rss_') if connections: cols = [["Evennia-channel"], ["RSS-url"]] for conn in connections: @@ -1141,12 +1141,12 @@ class CmdRSS2Chan(MuxCommand): self.caller.msg(string) else: self.caller.msg("No connections found.") - return + return if not self.args or not self.rhs: string = "Usage: @rss2chan[/switches] = " self.caller.msg(string) - return + return channel = self.lhs url = self.rhs @@ -1160,8 +1160,8 @@ class CmdRSS2Chan(MuxCommand): self.caller.msg("RSS connection/reader could not be removed, does it exist?") else: self.caller.msg("RSS connection destroyed.") - return - + return + channel = find_channel(self.caller, channel) if not channel: return @@ -1171,5 +1171,5 @@ class CmdRSS2Chan(MuxCommand): ok = rss.create_connection(channel, url, interval) if not ok: self.caller.msg("This RSS connection already exists.") - return + return self.caller.msg("Connection created. Starting RSS reader.") diff --git a/src/commands/default/general.py b/src/commands/default/general.py index 01d9877b1e..8ff336d287 100644 --- a/src/commands/default/general.py +++ b/src/commands/default/general.py @@ -23,17 +23,17 @@ class CmdHome(MuxCommand): home Usage: - home + home Teleports the player to their home. """ - + key = "home" - locks = "cmd:perm(home) or perm(Builders)" + locks = "cmd:perm(home) or perm(Builders)" def func(self): "Implement the command" - caller = self.caller + caller = self.caller home = caller.home if not home: caller.msg("You have no home set.") @@ -47,7 +47,7 @@ class CmdLook(MuxCommand): Usage: look - look + look look * Observes your location or objects in your vicinity. @@ -59,27 +59,27 @@ class CmdLook(MuxCommand): def func(self): """ - Handle the looking. + Handle the looking. """ caller = self.caller - args = self.args + args = self.args if args: # Use search to handle duplicate/nonexistant results. looking_at_obj = caller.search(args, use_nicks=True) if not looking_at_obj: - return + return else: looking_at_obj = caller.location if not looking_at_obj: caller.msg("You have no location to look at!") return - + if not hasattr(looking_at_obj, 'return_appearance'): # this is likely due to us having a player instead - looking_at_obj = looking_at_obj.character + looking_at_obj = looking_at_obj.character if not looking_at_obj.access(caller, "view"): caller.msg("Could not find '%s'." % args) - return + return # get object's appearance caller.msg(looking_at_obj.return_appearance(caller)) # the object's at_desc() method. @@ -93,16 +93,16 @@ class CmdPassword(MuxCommand): @password = Changes your password. Make sure to pick a safe one. - """ - key = "@password" + """ + key = "@password" locks = "cmd:all()" def func(self): "hook function." - caller = self.caller + caller = self.caller if hasattr(caller, "player"): - caller = caller.player + caller = caller.player if not self.rhs: caller.msg("Usage: @password = ") @@ -131,16 +131,16 @@ class CmdNick(MuxCommand): nick[/switches] = [] alias '' - Switches: + Switches: object - alias an object - player - alias a player + player - alias a player clearall - clear all your aliases - list - show all defined aliases - + list - show all defined aliases + If no switch is given, a command alias is created, used to replace strings before sending the command. Give an empty right-hand side to clear the nick - + Creates a personal nick for some in-game object or string. When you enter that string, it will be replaced with the alternate string. The switches dictate in what @@ -148,15 +148,15 @@ class CmdNick(MuxCommand): is None, the alias (if it exists) will be cleared. Obs - no objects are actually changed with this command, if you want to change the inherent aliases of an object, - use the @alias command instead. + use the @alias command instead. """ key = "nick" aliases = ["nickname", "nicks", "@nick", "alias"] - locks = "cmd:all()" + locks = "cmd:all()" def func(self): "Create the nickname" - + caller = self.caller switches = self.switches @@ -178,20 +178,20 @@ class CmdNick(MuxCommand): if 'clearall' in switches: nicks.delete() caller.msg("Cleared all aliases.") - return + return if not self.args or not self.lhs: caller.msg("Usage: nick[/switches] nickname = [realname]") - return + return nick = self.lhs - real = self.rhs + real = self.rhs if real == nick: caller.msg("No point in setting nick same as the string to replace...") - return - + return + # check so we have a suitable nick type if not any(True for switch in switches if switch in ("object", "player", "inputline")): - switches = ["inputline"] + switches = ["inputline"] string = "" for switch in switches: oldnick = Nick.objects.filter(db_obj=caller.dbobj, db_nick__iexact=nick, db_type__iexact=switch) @@ -204,14 +204,14 @@ class CmdNick(MuxCommand): else: string += "\nNo nick '%s' found, so it could not be removed." % nick else: - # creating new nick + # creating new nick if oldnick: string += "\nNick %s changed from '%s' to '%s'." % (nick, oldnick[0].db_real, real) else: string += "\nNick set: '%s' = '%s'." % (nick, real) - caller.nicks.add(nick, real, nick_type=switch) + caller.nicks.add(nick, real, nick_type=switch) caller.msg(string) - + class CmdInventory(MuxCommand): """ inventory @@ -219,9 +219,9 @@ class CmdInventory(MuxCommand): Usage: inventory inv - + Shows a player's inventory. - """ + """ key = "inventory" aliases = ["inv", "i"] locks = "cmd:all()" @@ -235,7 +235,7 @@ class CmdInventory(MuxCommand): # format item list into nice collumns cols = [[],[]] for item in items: - cols[0].append(item.name) + cols[0].append(item.name) desc = item.db.desc if not desc: desc = "" @@ -247,19 +247,19 @@ class CmdInventory(MuxCommand): string += "\n " + "{C%s{n - %s" % (row[0], row[1]) self.caller.msg(string) -class CmdGet(MuxCommand): +class CmdGet(MuxCommand): """ get Usage: get - + Picks up an object from your location and puts it in your inventory. """ key = "get" aliases = "grab" - locks = "cmd:all()" + locks = "cmd:all()" def func(self): "implements the command." @@ -287,13 +287,13 @@ class CmdGet(MuxCommand): obj.move_to(caller, quiet=True) caller.msg("You pick up %s." % obj.name) - caller.location.msg_contents("%s picks up %s." % - (caller.name, - obj.name), + caller.location.msg_contents("%s picks up %s." % + (caller.name, + obj.name), exclude=caller) # calling hook method obj.at_get(caller) - + class CmdDrop(MuxCommand): """ @@ -301,14 +301,14 @@ class CmdDrop(MuxCommand): Usage: drop - - Lets you drop an object from your inventory into the + + Lets you drop an object from your inventory into the location you are currently in. """ - + key = "drop" locks = "cmd:all()" - + def func(self): "Implement command" @@ -318,17 +318,17 @@ class CmdDrop(MuxCommand): return results = caller.search(self.args, ignore_errors=True) - # we process the results ourselves since we want to sift out only - # those in our inventory. + # we process the results ourselves since we want to sift out only + # those in our inventory. results = [obj for obj in results if obj in caller.contents] # now we send it into the handler. obj = AT_SEARCH_RESULT(caller, self.args, results, False) if not obj: - return - + return + obj.move_to(caller.location, quiet=True) caller.msg("You drop %s." % (obj.name,)) - caller.location.msg_contents("%s drops %s." % + caller.location.msg_contents("%s drops %s." % (caller.name, obj.name), exclude=caller) # Call the object script's at_drop() method. @@ -340,33 +340,33 @@ class CmdQuit(MuxCommand): quit Usage: - @quit + @quit Gracefully disconnect from the game. """ key = "@quit" - locks = "cmd:all()" + locks = "cmd:all()" def func(self): - "hook function" + "hook function" for session in self.caller.sessions: session.msg("{RQuitting{n. Hope to see you soon again.") session.session_disconnect() - + class CmdWho(MuxCommand): """ who Usage: - who - doing + who + doing Shows who is currently online. Doing is an alias that limits info also for those with all permissions. """ key = "who" - aliases = "doing" + aliases = "doing" locks = "cmd:all()" def func(self): @@ -386,7 +386,7 @@ class CmdWho(MuxCommand): table = [["Player Name"], ["On for"], ["Idle"], ["Room"], ["Cmds"], ["Host"]] else: table = [["Player Name"], ["On for"], ["Idle"]] - + for session in session_list: if not session.logged_in: continue @@ -396,12 +396,12 @@ class CmdWho(MuxCommand): plr_pobject = session.get_character() if not plr_pobject: plr_pobject = session.get_player() - show_session_data = False + show_session_data = False table = [["Player Name"], ["On for"], ["Idle"]] if show_session_data: table[0].append(plr_pobject.name[:25]) table[1].append(utils.time_format(delta_conn, 0)) - table[2].append(utils.time_format(delta_cmd, 1)) + table[2].append(utils.time_format(delta_cmd, 1)) table[3].append(plr_pobject.location.id) table[4].append(session.cmd_total) table[5].append(session.address[0]) @@ -421,7 +421,7 @@ class CmdWho(MuxCommand): else: string += "\n" + "".join(row) nplayers = (SESSIONS.player_count()) - if nplayers == 1: + if nplayers == 1: string += '\nOne player logged in.' else: string += '\n%d players logged in.' % nplayers @@ -434,14 +434,14 @@ class CmdSay(MuxCommand): Usage: say - - Talk to those in your current location. + + Talk to those in your current location. """ - + key = "say" aliases = ['"', "'"] locks = "cmd:all()" - + def func(self): "Run the say command" @@ -458,13 +458,13 @@ class CmdSay(MuxCommand): # Feedback for the object doing the talking. caller.msg('You say, "%s{n"' % speech) - + # Build the string to emit to neighbors. - emit_string = '{c%s{n says, "%s{n"' % (caller.name, + emit_string = '{c%s{n says, "%s{n"' % (caller.name, speech) - caller.location.msg_contents(emit_string, + caller.location.msg_contents(emit_string, exclude=caller) - + class CmdPose(MuxCommand): """ @@ -477,13 +477,13 @@ class CmdPose(MuxCommand): Example: pose is standing by the wall, smiling. -> others will see: - Tom is standing by the wall, smiling. + Tom is standing by the wall, smiling. Describe an script being taken. The pose text will - automatically begin with your name. + automatically begin with your name. """ key = "pose" - aliases = [":", "emote"] + aliases = [":", "emote"] locks = "cmd:all()" def parse(self): @@ -491,7 +491,7 @@ class CmdPose(MuxCommand): Custom parse the cases where the emote starts with some special letter, such as 's, at which we don't want to separate - the caller's name and the emote with a + the caller's name and the emote with a space. """ args = self.args @@ -500,33 +500,33 @@ class CmdPose(MuxCommand): self.args = args def func(self): - "Hook function" + "Hook function" if not self.args: msg = "Do what?" self.caller.msg(msg) else: msg = "%s%s" % (self.caller.name, self.args) self.caller.location.msg_contents(msg) - + class CmdEncoding(MuxCommand): """ encoding - set a custom text encoding - Usage: + Usage: @encoding/switches [] Switches: clear - clear your custom encoding - - This sets the text encoding for communicating with Evennia. This is mostly an issue only if + + This sets the text encoding for communicating with Evennia. This is mostly an issue only if you want to use non-ASCII characters (i.e. letters/symbols not found in English). If you see that your characters look strange (or you get encoding errors), you should use this command - to set the server encoding to be the same used in your client program. - + to set the server encoding to be the same used in your client program. + Common encodings are utf-8 (default), latin-1, ISO-8859-1 etc. - - If you don't submit an encoding, the current encoding will be displayed instead. + + If you don't submit an encoding, the current encoding will be displayed instead. """ key = "@encoding" @@ -539,7 +539,7 @@ class CmdEncoding(MuxCommand): """ caller = self.caller if hasattr(caller, 'player'): - caller = caller.player + caller = caller.player if 'clear' in self.switches: # remove customization @@ -551,22 +551,22 @@ class CmdEncoding(MuxCommand): del caller.db.encoding elif not self.args: # just list the encodings supported - pencoding = caller.db.encoding + pencoding = caller.db.encoding string = "" - if pencoding: - string += "Default encoding: {g%s{n (change with {w@encoding {n)" % pencoding + if pencoding: + string += "Default encoding: {g%s{n (change with {w@encoding {n)" % pencoding encodings = settings.ENCODINGS if encodings: - string += "\nServer's alternative encodings (tested in this order):\n {g%s{n" % ", ".join(encodings) + string += "\nServer's alternative encodings (tested in this order):\n {g%s{n" % ", ".join(encodings) if not string: string = "No encodings found." - else: - # change encoding + else: + # change encoding old_encoding = caller.db.encoding encoding = self.args caller.db.encoding = encoding string = "Your custom text encoding was changed from '%s' to '%s'." % (old_encoding, encoding) - caller.msg(string.strip()) + caller.msg(string.strip()) class CmdAccess(MuxCommand): """ @@ -575,7 +575,7 @@ class CmdAccess(MuxCommand): Usage: access - This command shows you the permission hierarchy and + This command shows you the permission hierarchy and which permission groups you are a member of. """ key = "access" @@ -587,8 +587,8 @@ class CmdAccess(MuxCommand): caller = self.caller hierarchy_full = settings.PERMISSION_HIERARCHY - string = "\n{wPermission Hierarchy{n (climbing):\n %s" % ", ".join(hierarchy_full) - hierarchy = [p.lower() for p in hierarchy_full] + string = "\n{wPermission Hierarchy{n (climbing):\n %s" % ", ".join(hierarchy_full) + #hierarchy = [p.lower() for p in hierarchy_full] if self.caller.player.is_superuser: cperms = "" @@ -603,7 +603,7 @@ class CmdAccess(MuxCommand): string += "\nPlayer {c%s{n: %s" % (caller.player.key, pperms) caller.msg(string) -# OOC commands +# OOC commands class CmdOOCLook(CmdLook): """ @@ -614,8 +614,8 @@ class CmdOOCLook(CmdLook): This is an OOC version of the look command. Since a Player doesn't have an in-game existence, there is no - concept of location or "self". If we are controlling - a character, pass control over to normal look. + concept of location or "self". If we are controlling + a character, pass control over to normal look. """ @@ -631,7 +631,7 @@ class CmdOOCLook(CmdLook): if utils.inherits_from(self.caller, "src.objects.objects.Object"): # An object of some type is calling. Convert to player. #print self.caller, self.caller.__class__ - self.character = self.caller + self.character = self.caller if hasattr(self.caller, "player"): self.caller = self.caller.player @@ -642,20 +642,20 @@ class CmdOOCLook(CmdLook): else: self.caller = self.character # we have to put this back for normal look to work. super(CmdOOCLook, self).func() - + class CmdIC(MuxCommand): """ Switch control to an object - + Usage: @ic - - Go in-character (IC) as a given Character. + + Go in-character (IC) as a given Character. This will attempt to "become" a different object assuming you have the right to do so. You cannot become an object that is already controlled by another player. In principle can be - any in-game object as long as you have access right to puppet it. + any in-game object as long as you have access right to puppet it. """ key = "@ic" @@ -671,7 +671,7 @@ class CmdIC(MuxCommand): if utils.inherits_from(caller, "src.objects.objects.Object"): caller = caller.player - new_character = None + new_character = None if not self.args: new_character = caller.db.last_puppet if not new_character: @@ -682,19 +682,19 @@ class CmdIC(MuxCommand): new_character = caller.search(self.args, global_search=True) if not new_character: # the search method handles error messages etc. - return + return if new_character.player: if new_character.player == caller: caller.msg("{RYou already are {c%s{n." % new_character.name) else: - caller.msg("{c%s{r is already acted by another player.{n" % new_character.name) - return + caller.msg("{c%s{r is already acted by another player.{n" % new_character.name) + return if not new_character.access(caller, "puppet"): caller.msg("{rYou may not become %s.{n" % new_character.name) return - old_char = None + old_char = None if caller.character: - # save the old character. We only assign this to last_puppet if swap is successful. + # save the old character. We only assign this to last_puppet if swap is successful. old_char = caller.character if caller.swap_character(new_character): new_character.msg("\n{gYou become {c%s{n.\n" % new_character.name) @@ -704,7 +704,7 @@ class CmdIC(MuxCommand): loc = new_character.db.prelogout_location if not loc: # still no location; use home loc = new_character.home - new_character.location = loc + new_character.location = loc if new_character.location: new_character.location.msg_contents("%s has entered the game." % new_character.key, exclude=[new_character]) new_character.location.at_object_receive(new_character, new_character.location) @@ -715,10 +715,10 @@ class CmdIC(MuxCommand): class CmdOOC(MuxCommand): """ @ooc - go ooc - + Usage: @ooc - + Go out-of-character (OOC). This will leave your current character and put you in a incorporeal OOC state. @@ -730,8 +730,8 @@ class CmdOOC(MuxCommand): help_category = "General" def func(self): - "Implement function" - + "Implement function" + caller = self.caller if utils.inherits_from(caller, "src.objects.objects.Object"): @@ -740,18 +740,18 @@ class CmdOOC(MuxCommand): if not caller.character: string = "You are already OOC." caller.msg(string) - return + return caller.db.last_puppet = caller.character # save location as if we were disconnecting from the game entirely. if caller.character.location: caller.character.location.msg_contents("%s has left the game." % caller.character.key, exclude=[caller.character]) caller.character.db.prelogout_location = caller.character.location - caller.character.location = None - - # disconnect + caller.character.location = None + + # disconnect caller.character.player = None - caller.character = None + caller.character = None caller.msg("\n{GYou go OOC.{n\n") caller.execute_cmd("look") diff --git a/src/commands/default/help.py b/src/commands/default/help.py index 6fabddae7e..4d5f60a5de 100644 --- a/src/commands/default/help.py +++ b/src/commands/default/help.py @@ -5,11 +5,11 @@ command-help is all auto-loaded and searched from the current command set. The normal, database-tied help system is used for collaborative creation of other help topics such as RP help or game-world aides. """ - + from src.utils.utils import fill, dedent from src.commands.command import Command from src.help.models import HelpEntry -from src.utils import create +from src.utils import create from src.commands.default.muxcommand import MuxCommand # limit symbol import for API @@ -18,43 +18,43 @@ __all__ = ("CmdHelp", "CmdSetHelp") LIST_ARGS = ("list", "all") SEP = "{C" + "-"*78 + "{n" - + def format_help_entry(title, help_text, aliases=None, suggested=None): """ This visually formats the help entry. - """ + """ string = SEP + "\n" - if title: - string += "{CHelp topic for {w%s{n" % (title.capitalize()) + if title: + string += "{CHelp topic for {w%s{n" % (title.capitalize()) if aliases: string += " {C(aliases: {w%s{n{C){n" % (", ".join(aliases)) if help_text: string += "\n%s" % dedent(help_text.rstrip()) if suggested: string += "\n\n{CSuggested:{n " - string += "{w%s{n" % fill(", ".join(suggested)) + string += "{w%s{n" % fill(", ".join(suggested)) string.strip() - string += "\n" + SEP - return string + string += "\n" + SEP + return string def format_help_list(hdict_cmds, hdict_db): """ - Output a category-ordered list. The input are the - pre-loaded help files for commands and database-helpfiles + Output a category-ordered list. The input are the + pre-loaded help files for commands and database-helpfiles resectively. - """ + """ string = "" if hdict_cmds and hdict_cmds.values(): string += "\n" + SEP + "\n {CCommand help entries{n\n" + SEP for category in sorted(hdict_cmds.keys()): - string += "\n {w%s{n:\n" % (str(category).capitalize()) + string += "\n {w%s{n:\n" % (str(category).capitalize()) string += "{G" + fill(", ".join(sorted(hdict_cmds[category]))) + "{n" if hdict_db and hdict_db.values(): - string += "\n\n" + SEP + "\n\r {COther help entries{n\n" + SEP + string += "\n\n" + SEP + "\n\r {COther help entries{n\n" + SEP for category in sorted(hdict_db.keys()): - string += "\n\r {w%s{n:\n" % (str(category).capitalize()) - string += "{G" + fill(", ".join(sorted([str(topic) for topic in hdict_db[category]]))) + "{n" - return string + string += "\n\r {w%s{n:\n" % (str(category).capitalize()) + string += "{G" + fill(", ".join(sorted([str(topic) for topic in hdict_db[category]]))) + "{n" + return string class CmdHelp(Command): """ @@ -66,15 +66,15 @@ class CmdHelp(Command): help all This will search for help on commands and other - topics related to the game. + topics related to the game. """ key = "help" locks = "cmd:all()" # this is a special cmdhandler flag that makes the cmdhandler also pack - # the current cmdset with the call to self.func(). - return_cmdset = True - + # the current cmdset with the call to self.func(). + return_cmdset = True + def parse(self): """ input is a string containing the command or topic to match. @@ -85,7 +85,7 @@ class CmdHelp(Command): def func(self): """ Run the dynamic help entry creator. - """ + """ query, cmdset = self.args, self.cmdset caller = self.caller @@ -95,37 +95,37 @@ class CmdHelp(Command): # removing doublets in cmdset, caused by cmdhandler # having to allow doublet commands to manage exits etc. cmdset.make_unique(caller) - + # Listing all help entries - + if query in LIST_ARGS: # we want to list all available help entries, grouped by category. hdict_cmd = {} - for cmd in (cmd for cmd in cmdset if cmd.auto_help and not cmd.is_exit + for cmd in (cmd for cmd in cmdset if cmd.auto_help and not cmd.is_exit and not cmd.key.startswith('__') and cmd.access(caller)): try: hdict_cmd[cmd.help_category].append(cmd.key) except KeyError: - hdict_cmd[cmd.help_category] = [cmd.key] + hdict_cmd[cmd.help_category] = [cmd.key] hdict_db = {} for topic in (topic for topic in HelpEntry.objects.get_all_topics() if topic.access(caller, 'view', default=True)): try: - hdict_db[topic.help_category].append(topic.key) + hdict_db[topic.help_category].append(topic.key) except KeyError: hdict_db[topic.help_category] = [topic.key] help_entry = format_help_list(hdict_cmd, hdict_db) caller.msg(help_entry) - return - + return + # Look for a particular help entry - - # Cmd auto-help dynamic entries + + # Cmd auto-help dynamic entries cmdmatches = [cmd for cmd in cmdset if query in cmd and cmd.auto_help and cmd.access(caller)] if len(cmdmatches) > 1: # multiple matches. Try to limit it down to exact match cmdmatches = [cmd for cmd in cmdmatches if cmd == query] or cmdmatches - + # Help-database static entries dbmatches = [topic for topic in HelpEntry.objects.find_topicmatch(query, exact=False) @@ -135,7 +135,7 @@ class CmdHelp(Command): dbmatches = [topic for topic in HelpEntry.objects.find_topicmatch(query, exact=True) if topic.access(caller, 'view', default=True)] or dbmatches - # Handle result + # Handle result if (not cmdmatches) and (not dbmatches): # no normal match. Check if this is a category match instead categ_cmdmatches = [cmd.key for cmd in cmdset if query == cmd.help_category and cmd.access(caller)] @@ -143,13 +143,13 @@ class CmdHelp(Command): if topic.access(caller, 'view', default=True)] cmddict = None dbdict = None - + if categ_cmdmatches: cmddict = {query:categ_cmdmatches} - if categ_dbmatches: - dbdict = {query:categ_dbmatches} + if categ_dbmatches: + dbdict = {query:categ_dbmatches} if cmddict or dbdict: - help_entry = format_help_list(cmddict, dbdict) + help_entry = format_help_list(cmddict, dbdict) else: help_entry = "No help entry found for '%s'" % self.original_args @@ -187,33 +187,33 @@ class CmdSetHelp(MuxCommand): add - add or replace a new topic with text. append - add text to the end of topic with a newline between. merge - As append, but don't add a newline between the old - text and the appended text. + text and the appended text. delete - remove help topic. force - (used with add) create help topic also if the topic - already exists. + already exists. Examples: @sethelp/add throw = This throws something at ... @sethelp/append pickpocketing,Thievery,is_thief, is_staff) = This steals ... @sethelp/append pickpocketing, ,is_thief, is_staff) = This steals ... - + """ key = "@help" aliases = "@sethelp" locks = "cmd:perm(PlayerHelpers)" help_category = "Building" - + def func(self): "Implement the function" - - caller = self.caller + + caller = self.caller switches = self.switches lhslist = self.lhslist rhs = self.rhs if not self.args: caller.msg("Usage: @sethelp/[add|del|append|merge] [,category[,locks,..] = ]") - return + return topicstr = "" category = "" @@ -226,12 +226,12 @@ class CmdSetHelp(MuxCommand): pass if not topicstr: caller.msg("You have to define a topic!") - return + return string = "" #print topicstr, category, lockstring if switches and switches[0] in ('append', 'app','merge'): - # add text to the end of a help topic + # add text to the end of a help topic # find the topic to append to old_entry = HelpEntry.objects.filter(db_key__iexact=topicstr) if not old_entry: @@ -242,14 +242,14 @@ class CmdSetHelp(MuxCommand): if switches[0] == 'merge': old_entry.entrytext = "%s %s" % (entrytext, self.rhs) string = "Added the new text right after the old one (merge)." - else: + else: old_entry.entrytext = "%s\n\n%s" % (entrytext, self.rhs) string = "Added the new text as a new paragraph after the old one (append)" old_entry.save() elif switches and switches[0] in ('delete','del'): #delete a help entry - old_entry = HelpEntry.objects.filter(db_key__iexact=topicstr) + old_entry = HelpEntry.objects.filter(db_key__iexact=topicstr) if not old_entry: string = "Could not find topic '%s'." % topicstr else: @@ -257,14 +257,14 @@ class CmdSetHelp(MuxCommand): string = "Deleted the help entry '%s'." % topicstr else: - # add a new help entry. + # add a new help entry. force_create = ('for' in switches) or ('force' in switches) - old_entry = None + old_entry = None try: old_entry = HelpEntry.objects.get(key=topicstr) except Exception: pass - if old_entry: + if old_entry: if force_create: old_entry.key = topicstr old_entry.entrytext = self.rhs @@ -277,13 +277,13 @@ class CmdSetHelp(MuxCommand): string = "Topic '%s' already exists. Use /force to overwrite it." % topicstr else: # no old entry. Create a new one. - new_entry = create.create_help_entry(topicstr, + new_entry = create.create_help_entry(topicstr, rhs, category, lockstring) if new_entry: string = "Topic '%s' was successfully created." % topicstr else: - string = "Error when creating topic '%s'! Maybe it already exists?" % topicstr + string = "Error when creating topic '%s'! Maybe it already exists?" % topicstr # give feedback caller.msg(string) diff --git a/src/commands/default/syscommands.py b/src/commands/default/syscommands.py index f5671cd6ff..ccd46f9e9d 100644 --- a/src/commands/default/syscommands.py +++ b/src/commands/default/syscommands.py @@ -4,18 +4,18 @@ System commands These are the default commands called by the system commandhandler when various exceptions occur. If one of these commands are not implemented and part of the current cmdset, the engine falls back -to a default solution instead. +to a default solution instead. Some system commands are shown in this module -as a REFERENCE only (they are not all added to Evennia's -default cmdset since they don't currently do anything differently from the +as a REFERENCE only (they are not all added to Evennia's +default cmdset since they don't currently do anything differently from the default backup systems hard-wired in the engine). Overloading these commands in a cmdset can be used to create interesting effects. An example is using the NoMatch system command to implement a line-editor where you don't have to start each line with a command (if there is no match to a known command, -the line is just added to the editor buffer). +the line is just added to the editor buffer). """ from src.comms.models import Channel @@ -27,7 +27,7 @@ from src.commands.cmdhandler import CMD_NOINPUT from src.commands.cmdhandler import CMD_NOMATCH from src.commands.cmdhandler import CMD_MULTIMATCH from src.commands.cmdhandler import CMD_CHANNEL - + from src.commands.default.muxcommand import MuxCommand # Command called when there is no input at line @@ -59,7 +59,7 @@ class SystemNoMatch(MuxCommand): def func(self): """ This is given the failed raw string as input. - """ + """ self.caller.msg("Huh?") # @@ -69,13 +69,13 @@ class SystemMultimatch(MuxCommand): """ Multiple command matches. - The cmdhandler adds a special attribute 'matches' to this - system command. + The cmdhandler adds a special attribute 'matches' to this + system command. matches = [(candidate, cmd) , (candidate, cmd), ...], - + where candidate is an instance of src.commands.cmdparser.CommandCandidate - and cmd is an an instantiated Command object matching the candidate. + and cmd is an an instantiated Command object matching the candidate. """ key = CMD_MULTIMATCH locks = "cmd:all()" @@ -84,21 +84,21 @@ class SystemMultimatch(MuxCommand): """ Format multiple command matches to a useful error. - This is copied directly from the default method in - src.commands.cmdhandler. + This is copied directly from the default method in + src.commands.cmdhandler. """ string = "There where multiple matches:" - for num, match in enumerate(matches): + for num, match in enumerate(matches): # each match is a tuple (candidate, cmd) - candidate, cmd = match + candidate, cmd = match is_channel = hasattr(cmd, "is_channel") and cmd.is_channel if is_channel: is_channel = " (channel)" else: is_channel = "" - is_exit = hasattr(cmd, "is_exit") and cmd.is_exit + is_exit = hasattr(cmd, "is_exit") and cmd.is_exit if is_exit and cmd.destination: is_exit = " (exit to %s)" % cmd.destination else: @@ -115,7 +115,7 @@ class SystemMultimatch(MuxCommand): id2 = "" string += "\n %s%s%s%s%s" % (id1, candidate.cmdname, id2, is_channel, is_exit) return string - + def func(self): """ argument to cmd is a comma-separated string of @@ -126,37 +126,37 @@ class SystemMultimatch(MuxCommand): # Command called when the command given at the command line # was identified as a channel name, like there existing a -# channel named 'ooc' and the user wrote -# > ooc Hello! +# channel named 'ooc' and the user wrote +# > ooc Hello! class SystemSendToChannel(MuxCommand): """ This is a special command that the cmdhandler calls when it detects that the command given matches - an existing Channel object key (or alias). + an existing Channel object key (or alias). """ key = CMD_CHANNEL locks = "cmd:all()" def parse(self): - channelname, msg = self.args.split(':', 1) + channelname, msg = self.args.split(':', 1) self.args = channelname.strip(), msg.strip() def func(self): """ Create a new message and send it to channel, using the already formatted input. - """ - caller = self.caller + """ + caller = self.caller channelkey, msg = self.args if not msg: caller.msg("Say what?") - return + return channel = Channel.objects.get_channel(channelkey) if not channel: caller.msg("Channel '%s' not found." % channelkey) - return + return if not channel.has_connection(caller): string = "You are not connected to channel '%s'." caller.msg(string % channelkey) @@ -165,6 +165,6 @@ class SystemSendToChannel(MuxCommand): string = "You are not permitted to send to channel '%s'." caller.msg(string % channelkey) return - msg = "[%s] %s: %s" % (channel.key, caller.name, msg) + msg = "[%s] %s: %s" % (channel.key, caller.name, msg) msgobj = create.create_message(caller, msg, channels=[channel]) channel.msg(msgobj) diff --git a/src/commands/default/system.py b/src/commands/default/system.py index 6d5ad2ed6b..47bc58cc21 100644 --- a/src/commands/default/system.py +++ b/src/commands/default/system.py @@ -8,14 +8,12 @@ import traceback import os, datetime, time import django, twisted -from django.contrib.auth.models import User from django.conf import settings from src.server.sessionhandler import SESSIONS from src.scripts.models import ScriptDB from src.objects.models import ObjectDB from src.players.models import PlayerDB -from src.server.models import ServerConfig -from src.utils import create, logger, utils, gametime +from src.utils import logger, utils, gametime from src.commands.default.muxcommand import MuxCommand # limit symbol import for API @@ -40,7 +38,7 @@ class CmdReload(MuxCommand): def func(self): """ - Reload the system. + Reload the system. """ SESSIONS.announce_all(" Server restarting ...") SESSIONS.server.shutdown(mode='reload') @@ -64,7 +62,7 @@ class CmdReset(MuxCommand): def func(self): """ - Reload the system. + Reload the system. """ SESSIONS.announce_all(" Server restarting ...") SESSIONS.server.shutdown(mode='reset') @@ -101,7 +99,7 @@ class CmdShutdown(MuxCommand): class CmdPy(MuxCommand): """ - Execute a snippet of python code + Execute a snippet of python code Usage: @py @@ -110,10 +108,10 @@ class CmdPy(MuxCommand): available for convenience in order to offer access to the system (you can import more at execution time). - Available variables in @py environment: + Available variables in @py environment: self, me : caller here : caller.location - ev : the evennia API + ev : the evennia API inherits_from(obj, parent) : check object inheritance {rNote: In the wrong hands this command is a severe security risk. @@ -160,7 +158,7 @@ class CmdPy(MuxCommand): caller.msg(ret) # helper function. Kept outside so it can be imported and run -# by other commands. +# by other commands. def format_script_list(scripts): "Takes a list of scripts and formats the output." @@ -216,7 +214,7 @@ class CmdScripts(MuxCommand): Usage: @scripts[/switches] [] - + Switches: stop - stops an existing script kill - kills a script - without running its cleanup hooks @@ -232,7 +230,7 @@ class CmdScripts(MuxCommand): aliases = "@listscripts" locks = "cmd:perm(listscripts) or perm(Wizards)" help_category = "System" - + def func(self): "implement method" @@ -247,7 +245,7 @@ class CmdScripts(MuxCommand): if not scripts: # try to find an object instead. objects = ObjectDB.objects.object_search(args, caller=caller, global_search=True) - if objects: + if objects: scripts = [] for obj in objects: # get all scripts on the object(s) @@ -267,7 +265,7 @@ class CmdScripts(MuxCommand): string = "No scripts/objects matching '%s'. " % args string += "Be more specific." elif len(scripts) == 1: - # we have a unique match! + # we have a unique match! if 'kill' in self.switches: string = "Killing script '%s'" % scripts[0].key scripts[0].stop(kill=True) @@ -300,8 +298,8 @@ class CmdObjects(MuxCommand): Usage: @objects [] - Gives statictics on objects in database as well as - a list of latest objects in database. If not + Gives statictics on objects in database as well as + a list of latest objects in database. If not given, defaults to 10. """ key = "@objects" @@ -379,7 +377,7 @@ class CmdService(MuxCommand): list - shows all available services (default) start - activates a service stop - stops a service - + Service management system. Allows for the listing, starting, and stopping of services. If no switches are given, services will be listed. @@ -487,8 +485,8 @@ class CmdTime(MuxCommand): @time Usage: - @time - + @time + Server local time. """ key = "@time" @@ -498,12 +496,12 @@ class CmdTime(MuxCommand): def func(self): "Show times." - + table = [["Current server uptime:", "Total server running time:", "Total in-game time (realtime x %g):" % (gametime.TIMEFACTOR), "Server time stamp:" - ], + ], [utils.time_format(time.time() - SESSIONS.server.start_time, 3), utils.time_format(gametime.runtime(format=False), 2), utils.time_format(gametime.gametime(format=False), 2), @@ -523,13 +521,13 @@ class CmdTime(MuxCommand): self.caller.msg(string) class CmdServerLoad(MuxCommand): - """ + """ server load statistics Usage: @serverload - Show server load statistics in a table. + Show server load statistics in a table. """ key = "@serverload" locks = "cmd:perm(list) or perm(Immortals)" @@ -607,9 +605,9 @@ class CmdServerLoad(MuxCommand): # class CmdPs(MuxCommand): # """ # list processes - + # Usage -# @ps +# @ps # Shows the process/event table. # """ diff --git a/src/commands/default/unloggedin.py b/src/commands/default/unloggedin.py index 8642d2ac40..82c60e0c7f 100644 --- a/src/commands/default/unloggedin.py +++ b/src/commands/default/unloggedin.py @@ -182,13 +182,14 @@ its and @/./+/-/_ only.") # this echoes the restrictions made by django's auth m typeclass = settings.BASE_CHARACTER_TYPECLASS permissions = settings.PERMISSION_PLAYER_DEFAULT - new_character = create.create_player(playername, email, password, - permissions=permissions, - character_typeclass=typeclass, - character_location=default_home, - character_home=default_home) - if not new_character: - session.msg("There was an error creating the default Character/Player. This error was logged. Contact an admin.") + try: + new_character = create.create_player(playername, email, password, + permissions=permissions, + character_typeclass=typeclass, + character_location=default_home, + character_home=default_home) + except Exception, e: + session.msg("There was an error creating the default Character/Player:\n%s\n If this problem persists, contact an admin.") return new_player = new_character.player diff --git a/src/objects/objects.py b/src/objects/objects.py index 1e5880bea4..9da82c02f7 100644 --- a/src/objects/objects.py +++ b/src/objects/objects.py @@ -323,7 +323,7 @@ class Object(TypeClass): """ - self.dbobj.swap_typeclass(new_typeclass, clean_attributes=clean_attributes, no_default=no_default) + return self.dbobj.swap_typeclass(new_typeclass, clean_attributes=clean_attributes, no_default=no_default) def access(self, accessing_obj, access_type='read', default=False): """ diff --git a/src/server/initial_setup.py b/src/server/initial_setup.py index 4e12d44ea5..837a0927b2 100644 --- a/src/server/initial_setup.py +++ b/src/server/initial_setup.py @@ -58,9 +58,6 @@ def create_objects(): create_character=True, character_typeclass=character_typeclass) - if not god_character: - raise Exception(_("#1 could not be created. Check the Player/Character typeclass for bugs.")) - god_character.id = 1 god_character.db.desc = _('This is User #1.') god_character.locks.add("examine:perm(Immortals);edit:false();delete:false();boot:false();msg:all();puppet:false()") @@ -164,7 +161,11 @@ def create_admin_media_links(): on system. """ import django, os - dpath = os.path.join(django.__path__[0], 'contrib', 'admin', 'media') + + if django.get_version() < 1.4: + dpath = os.path.join(django.__path__[0], 'contrib', 'admin', 'media') + else: + dpath = os.path.join(django.__path__[0], 'contrib', 'admin', 'static', 'admin') apath = os.path.join(settings.ADMIN_MEDIA_ROOT) if os.path.isdir(apath): print _(" ADMIN_MEDIA_ROOT already exists. Ignored.") @@ -177,8 +178,8 @@ def create_admin_media_links(): try: os.symlink(dpath, apath) print _(" Admin-media symlinked to ADMIN_MEDIA_ROOT.") - except OSError: - print _(" There was an error symlinking Admin-media to ADMIN_MEDIA_ROOT. If you see issues, link manually.") + except OSError, e: + print _(" There was an error symlinking Admin-media to ADMIN_MEDIA_ROOT:\n %s\n -> \n %s\n (%s)\n If you see issues, link manually." % (dpath, apath, e)) else: print _(" Admin-media files should be copied manually to ADMIN_MEDIA_ROOT.") @@ -194,7 +195,7 @@ def at_initial_setup(): return try: mod = __import__(modname, fromlist=[None]) - except ImportError, ValueError: + except (ImportError, ValueError): return print _(" Running at_initial_setup() hook.") if mod.__dict__.get("at_initial_setup", None): diff --git a/src/server/msdp.py b/src/server/msdp.py index aac6ca4fb0..a5c2cb9461 100644 --- a/src/server/msdp.py +++ b/src/server/msdp.py @@ -12,6 +12,7 @@ etc. """ import re from src.utils.utils import make_iter +from src.utils import logger # variables MSDP = chr(69) @@ -24,7 +25,7 @@ MSDP_ARRAY_CLOSE = chr(6) regex_array = re.compile(r"%s(.*?)%s%s(.*?)%s" % (MSDP_VAR, MSDP_VAL, MSDP_ARRAY_OPEN, MSDP_ARRAY_CLOSE)) # return 2-tuple regex_table = re.compile(r"%s(.*?)%s%s(.*?)%s" % (MSDP_VAR, MSDP_VAL, MSDP_TABLE_OPEN, MSDP_TABLE_CLOSE)) # return 2-tuple (may be nested) -regex_varval = re.compile(r"%s(.*?)%s(.*?)[%s]" % (MSDP_VAR, MSDP_VAL, ENDING)) # return 2-tuple +regex_varval = re.compile(r"%s(.*?)%s(.*?)" % (MSDP_VAR, MSDP_VAL)) # return 2-tuple class Msdp(object): """ @@ -111,8 +112,8 @@ class Msdp(object): tables[table[0]] = dict(regex_varval(table[1])) for array in regex_array.findall(data): arrays[array[0]] = dict(regex_varval(array[1])) - variables = dict(regex._varval(regex_array.sub("", regex_table.sub("", data)))) - + variables = dict(regex_varval(regex_array.sub("", regex_table.sub("", data)))) + print variables # MSDP Commands @@ -125,7 +126,7 @@ class Msdp(object): The List command allows for retrieving various info about the server/client """ if arg == 'COMMANDS': - return self.func_to_msdp(arg, MSDP_COMMANDS.keys()) + return self.func_to_msdp(arg, self.MSDP_COMMANDS.keys()) elif arg == 'LISTS': return self.func_to_msdp(arg, ("COMMANDS", "LISTS", "CONFIGURABLE_VARIABLES", @@ -133,11 +134,11 @@ class Msdp(object): elif arg == 'CONFIGURABLE_VARIABLES': return self.func_to_msdp(arg, ("CLIENT_NAME", "CLIENT_VERSION", "PLUGIN_ID")) elif arg == 'REPORTABLE_VARIABLES': - return self.func_to_msdp(arg, MSDP_REPORTABLE.keys()) + return self.func_to_msdp(arg, self.MSDP_REPORTABLE.keys()) elif arg == 'REPORTED_VARIABLES': - return self.func_to_msdp(arg, MSDP_REPORTED.keys()) + return self.func_to_msdp(arg, self.MSDP_REPORTED.keys()) elif arg == 'SENDABLE_VARIABLES': - return self.func_to_msdp(arg, MSDP_SEND.keys()) + return self.func_to_msdp(arg, self.MSDP_SEND.keys()) else: return self.func_to_msdp("LIST", arg) @@ -147,7 +148,7 @@ class Msdp(object): reportable variable to the client. """ try: - MSDP_REPORTABLE[arg](report=True) + self.MSDP_REPORTABLE[arg](report=True) except Exception: logger.log_trace() @@ -156,16 +157,16 @@ class Msdp(object): Unreport a previously reported variable """ try: - MSDP_REPORTABLE[arg](eport=False) + self.MSDP_REPORTABLE[arg](eport=False) except Exception: - logger.log_trace() + self.logger.log_trace() def msdp_cmd_reset(self, arg): """ The reset command resets a variable to its initial state. """ try: - MSDP_REPORTABLE[arg](reset=True) + self.MSDP_REPORTABLE[arg](reset=True) except Exception: logger.log_trace() @@ -177,21 +178,22 @@ class Msdp(object): arg - this is a list of variables the client wants. """ ret = [] - for var in makeiter(arg): + for var in make_iter(arg): try: - ret.append(MSDP_REPORTABLE[arg](send=True)) + ret.append(self.MSDP_REPORTABLE[arg](send=True)) except Exception: logger.log_trace() return ret MSDP_COMMANDS = { - "LIST": self.msdp_list, + "LIST": "msdp_list", "REPORT":"mspd_report", "RESET":"mspd_reset", "SEND":"mspd_send", "UNREPORT":"mspd_unreport" } + # MSDP_MAP is a standard suggestions for making it easy to create generic guis. # this maps MSDP command names to Evennia commands found in OOB_FUNC_MODULE. It # is up to these commands to return data on proper form. diff --git a/src/server/serversession.py b/src/server/serversession.py index 702484deae..c9b09d74cd 100644 --- a/src/server/serversession.py +++ b/src/server/serversession.py @@ -244,6 +244,7 @@ class ServerSession(Session): else: logger.log_errmsg("oob_data_in error: funcname '%s' not found in OOB_FUNC_MODULE." % funcname) if outdata: + # we have a result, send it back self.oob_data_out(outdata) diff --git a/src/typeclasses/models.py b/src/typeclasses/models.py index 545d408e95..3d0e497bac 100644 --- a/src/typeclasses/models.py +++ b/src/typeclasses/models.py @@ -951,6 +951,7 @@ class TypedObject(SharedMemoryModel): # If we reach this point we couldn't import any typeclasses. Return default. It's up to the calling # method to use e.g. self.is_typeclass() to detect that the result is not the one asked for. _GA(self, "_display_errmsg")(errstring) + _SA(self, "typeclass_lasterrmsg", errstring) return _GA(self, "_get_default_typeclass")(cache=False, silent=False, save=False) #@typeclass.deleter @@ -961,6 +962,11 @@ class TypedObject(SharedMemoryModel): # typeclass property typeclass = property(__typeclass_get, fdel=__typeclass_del) + # the last error string will be stored here for accessing methods to access. + # It is set by _display_errmsg, which will print to log if error happens + # during server startup. + typeclass_last_errmsg = "" + def _path_import(self, path): """ Import a class from a python path of the @@ -973,17 +979,19 @@ class TypedObject(SharedMemoryModel): return None try: modpath, class_name = path.rsplit('.', 1) - module = __import__(modpath, fromlist=[class_name]) + module = __import__(modpath, fromlist=["none"]) return module.__dict__[class_name] except ImportError: trc = sys.exc_traceback if not trc.tb_next: # we separate between not finding the module, and finding a buggy one. - errstring += "(Tried path '%s')." % path + errstring = "Typeclass not found trying path '%s'." % path else: # a bug in the module is reported normally. trc = traceback.format_exc() - errstring += "\n%sError importing '%s'." % (trc, path) + errstring = "\n%sError importing '%s'." % (trc, path) + except (ValueError, TypeError): + errstring = "Malformed typeclass path '%s'." % path except KeyError: errstring = "No class '%s' was found in module '%s'." errstring = errstring % (class_name, modpath) @@ -997,26 +1005,32 @@ class TypedObject(SharedMemoryModel): """ Helper function to display error. """ - infochan = None - cmessage = message - try: - from src.comms.models import Channel - infochan = settings.CHANNEL_MUDINFO - infochan = Channel.objects.get_channel(infochan[0]) - if infochan: - cname = infochan.key - cmessage = "\n".join(["[%s]: %s" % (cname, line) for line in message.split('\n') if line]) - cmessage = cmessage.strip() - infochan.msg(cmessage) - else: - # no mudinfo channel is found. Log instead. - cmessage = "\n".join(["[NO MUDINFO CHANNEL]: %s" % line for line in message.split('\n')]) - logger.log_errmsg(cmessage) - except Exception: - if ServerConfig.objects.conf("server_starting_mode"): - print cmessage - else: - logger.log_trace(cmessage) + if ServerConfig.objects.conf("server_starting_mode"): + print message.strip() + else: + _SA(self, "typeclass_last_errmsg", message.strip()) + return + + #infochan = None + #cmessage = message + #try: + # from src.comms.models import Channel + # infochan = settings.CHANNEL_MUDINFO + # infochan = Channel.objects.get_channel(infochan[0]) + # if infochan: + # cname = infochan.key + # cmessage = "\n".join(["[%s]: %s" % (cname, line) for line in message.split('\n') if line]) + # cmessage = cmessage.strip() + # infochan.msg(cmessage) + # else: + # # no mudinfo channel is found. Log instead. + # cmessage = "\n".join(["[NO MUDINFO CHANNEL]: %s" % line for line in message.split('\n')]) + # logger.log_errmsg(cmessage) + #except Exception: + # if ServerConfig.objects.conf("server_starting_mode"): + # print cmessage + # else: + # logger.log_trace(cmessage) def _get_default_typeclass(self, cache=False, silent=False, save=False): """ @@ -1064,7 +1078,9 @@ class TypedObject(SharedMemoryModel): """ Returns true if this object has this type OR has a typeclass which is an subclass of - the given typeclass. + the given typeclass. This operates on the actually + loaded typeclass (this is important since a failing + typeclass may instead have its default currently loaded) typeclass - can be a class object or the python path to such an object to match against. @@ -1079,7 +1095,7 @@ class TypedObject(SharedMemoryModel): pass typeclasses = [typeclass] + ["%s.%s" % (path, typeclass) for path in _GA(self, "_typeclass_paths")] if exact: - current_path = _GA(self, "_cached_db_typeclass_path") + current_path = _GA(self.typeclass, "path") #"_GA(self, "_cached_db_typeclass_path") return typeclass and any((current_path == typec for typec in typeclasses)) else: # check parent chain @@ -1158,10 +1174,9 @@ class TypedObject(SharedMemoryModel): self.nattr(nattr, delete=True) else: #print "deleting attrs ..." - self.get_all_attributes() for attr in self.get_all_attributes(): attr.delete() - for nattr in self.ndb.all(): + for nattr in self.ndb.all: del nattr # run hooks for this new typeclass @@ -1328,8 +1343,9 @@ class TypedObject(SharedMemoryModel): _GA(self, 'obj').set_attribute(attrname, value) def __delattr__(self, attrname): _GA(self, 'obj').del_attribute(attrname) - def all(self): + def get_all(self): return _GA(self, 'obj').get_all_attributes() + all = property(get_all) self._db_holder = DbHolder(self) return self._db_holder #@db.setter @@ -1386,9 +1402,10 @@ class TypedObject(SharedMemoryModel): except AttributeError: class NdbHolder(object): "Holder for storing non-persistent attributes." - def all(self): + def get_all(self): return [val for val in self.__dict__.keys() - if not val.startswith['_']] + if not val.startswith('_')] + all = property(get_all) def __getattribute__(self, key): # return None if no matching attribute was found. try: diff --git a/src/utils/create.py b/src/utils/create.py index da2b959a01..0000881565 100644 --- a/src/utils/create.py +++ b/src/utils/create.py @@ -13,12 +13,12 @@ shorter "create.object()". The respective object managers hold more methods for manipulating and searching objects already existing in the database. -Models covered: +Models covered: Objects Scripts Help Message - Channel + Channel Players """ @@ -26,8 +26,7 @@ from django.conf import settings from django.contrib.auth.models import User from django.db import IntegrityError from src.utils.idmapper.models import SharedMemoryModel -from src.utils import logger, utils, idmapper -from src.utils.utils import is_iter, has_parent, inherits_from +from src.utils import utils, logger # limit symbol import from API __all__ = ("create_object", "create_script", "create_help_entry", "create_message", "create_channel", "create_player") @@ -35,23 +34,28 @@ __all__ = ("create_object", "create_script", "create_help_entry", "create_messag GA = object.__getattribute__ # -# Game Object creation +# Game Object creation # def create_object(typeclass, key=None, location=None, - home=None, player=None, permissions=None, locks=None, - aliases=None, destination=None): + home=None, player=None, permissions=None, locks=None, + aliases=None, destination=None, report_to=None): """ Create a new in-game object. Any game object is a combination of a database object that stores data persistently to the database, and a typeclass, which on-the-fly 'decorates' the database object into whataver different type of object - it is supposed to be in the game. + it is supposed to be in the game. See src.objects.managers for methods to manipulate existing objects in the database. src.objects.objects holds the base typeclasses - and src.objects.models hold the database model. + and src.objects.models hold the database model. + + report_to is an optional object for reporting errors to in string form. + If report_to is not set, errors will be raised as en Exception + containing the error message. If set, this method will return + None upon errors. """ # deferred import to avoid loops from src.objects.objects import Object @@ -64,32 +68,36 @@ def create_object(typeclass, key=None, location=None, typeclass = typeclass.typeclass.path elif isinstance(typeclass, Object) or utils.inherits_from(typeclass, Object): # this is already an object typeclass, extract its path - typeclass = typeclass.path + typeclass = typeclass.path - # create new database object + # create new database object new_db_object = ObjectDB() - - # assign the typeclass + + # assign the typeclass typeclass = utils.to_unicode(typeclass) new_db_object.typeclass_path = typeclass # the name/key is often set later in the typeclass. This - # is set here as a failsafe. + # is set here as a failsafe. if key: - new_db_object.key = key + new_db_object.key = key else: new_db_object.key = "#%i" % new_db_object.id # this will either load the typeclass or the default one new_object = new_db_object.typeclass - - if not GA(new_db_object, "is_typeclass")(typeclass, exact=True): + if not GA(new_object, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input and it still gave us a default SharedMemoryModel.delete(new_db_object) - return None + if report_to: + GA(report_to, "msg")("Error creating %s (%s):\n%s" % (new_db_object.key, typeclass, + GA(new_db_object, "typeclass_last_errmsg"))) + return None + else: + raise Exception(GA(new_db_object, "typeclass_last_errmsg")) - # from now on we can use the typeclass object + # from now on we can use the typeclass object # as if it was the database object. if player: @@ -97,14 +105,14 @@ def create_object(typeclass, key=None, location=None, new_object.player = player player.obj = new_object - new_object.destination = destination + new_object.destination = destination # call the hook method. This is where all at_creation # customization happens as the typeclass stores custom - # things on its database object. + # things on its database object. new_object.basetype_setup() # setup the basics of Exits, Characters etc. new_object.at_object_creation() - + # custom-given perms/locks overwrite hooks if permissions: new_object.permissions = permissions @@ -119,15 +127,15 @@ def create_object(typeclass, key=None, location=None, else: new_object.home = settings.CHARACTER_DEFAULT_HOME - + if location: new_object.move_to(location, quiet=True) else: # rooms would have location=None. - new_object.location = None + new_object.location = None # post-hook setup (mainly used by Exits) - new_object.basetype_posthook_setup() + new_object.basetype_posthook_setup() new_object.save() return new_object @@ -136,12 +144,12 @@ def create_object(typeclass, key=None, location=None, object = create_object # -# Script creation +# Script creation # -def create_script(typeclass, key=None, obj=None, locks=None, - interval=None, start_delay=None, repeats=None, - persistent=None, autostart=True): +def create_script(typeclass, key=None, obj=None, locks=None, + interval=None, start_delay=None, repeats=None, + persistent=None, autostart=True, report_to=None): """ Create a new script. All scripts are a combination of a database object that communicates with the @@ -149,42 +157,47 @@ def create_script(typeclass, key=None, obj=None, locks=None, database object into being different types of scripts. It's behaviour is similar to the game objects except scripts has a time component and are more limited in - scope. + scope. Argument 'typeclass' can be either an actual typeclass object or a python path to such an object. Only set key here if you want a unique name for this particular script (set it in config to give same key to all scripts of the same type). Set obj - to tie this script to a particular object. + to tie this script to a particular object. See src.scripts.manager for methods to manipulate existing scripts in the database. + + report_to is an obtional object to receive error messages. + If report_to is not set, an Exception with the + error will be raised. If set, this method will + return None upon errors. """ # deferred import to avoid loops. from src.scripts.scripts import Script - #print "in create_script", typeclass - from src.scripts.models import ScriptDB + #print "in create_script", typeclass + from src.scripts.models import ScriptDB if not typeclass: typeclass = settings.BASE_SCRIPT_TYPECLASS elif isinstance(typeclass, ScriptDB): # this is already an scriptdb instance, extract its typeclass - typeclass = new_db_object.typeclass.path + typeclass = typeclass.typeclass.path elif isinstance(typeclass, Script) or utils.inherits_from(typeclass, Script): # this is already an object typeclass, extract its path - typeclass = typeclass.path + typeclass = typeclass.path # create new database script - new_db_script = ScriptDB() + new_db_script = ScriptDB() - # assign the typeclass + # assign the typeclass typeclass = utils.to_unicode(typeclass) new_db_script.typeclass_path = typeclass - + # the name/key is often set later in the typeclass. This - # is set here as a failsafe. + # is set here as a failsafe. if key: new_db_script.key = key else: @@ -195,15 +208,19 @@ def create_script(typeclass, key=None, obj=None, locks=None, if not GA(new_db_script, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input and it still gave us a default - print "failure:", new_db_script, typeclass SharedMemoryModel.delete(new_db_script) - return None + if report_to: + GA(report_to, "msg")("Error creating %s (%s): %s" % (new_db_script.key, typeclass, + GA(new_db_script, "typeclass_last_errmsg"))) + return None + else: + raise Exception(GA(new_db_script, "typeclass_last_errmsg")) if obj: try: new_script.obj = obj except ValueError: - new_script.obj = obj.dbobj + new_script.obj = obj.dbobj # call the hook method. This is where all at_creation # customization happens as the typeclass stores custom @@ -212,10 +229,10 @@ def create_script(typeclass, key=None, obj=None, locks=None, # custom-given variables override the hook if key: - new_script.key = key + new_script.key = key if locks: new_script.locks.add(locks) - if interval != None: + if interval != None: new_script.interval = interval if start_delay != None: new_script.start_delay = start_delay @@ -223,13 +240,13 @@ def create_script(typeclass, key=None, obj=None, locks=None, new_script.repeats = repeats if persistent != None: new_script.persistent = persistent - + # a new created script should usually be started. if autostart: new_script.start() - + new_db_script.save() - return new_script + return new_script #alias script = create_script @@ -243,7 +260,7 @@ def create_help_entry(key, entrytext, category="General", locks=None): help entries are dynamic and directly taken from the __doc__ entries of the command. The database-stored help entries are intended for more general help on the game, more extensive info, in-game setting information - and so on. + and so on. """ from src.help.models import HelpEntry @@ -255,19 +272,19 @@ def create_help_entry(key, entrytext, category="General", locks=None): if locks: new_help.locks.add(locks) new_help.save() - return new_help + return new_help except IntegrityError: string = "Could not add help entry: key '%s' already exists." % key logger.log_errmsg(string) return None except Exception: logger.log_trace() - return None + return None # alias help_entry = create_help_entry # -# Comm system methods +# Comm system methods # def create_message(senderobj, message, channels=None, @@ -279,7 +296,7 @@ def create_message(senderobj, message, channels=None, senderobj - the player sending the message. This must be the actual object. message - text with the message. Eventual headers, titles etc should all be included in this text string. Formatting - will be retained. + will be retained. channels - a channel or a list of channels to send to. The channels may be actual channel objects or their unique key strings. receivers - a player to send to, or a list of them. May be Player objects @@ -289,7 +306,7 @@ def create_message(senderobj, message, channels=None, The Comm system is created very open-ended, so it's fully possible to let a message both go to several channels and to several receivers at the same time, it's up to the command definitions to limit this as - desired. + desired. """ from src.comms.models import Msg from src.players.models import PlayerDB @@ -304,10 +321,10 @@ def create_message(senderobj, message, channels=None, elif hasattr(obj, 'db_player'): return obj.db_player else: - return None + return None if not message: - # we don't allow empty messages. + # we don't allow empty messages. return new_message = Msg() @@ -315,19 +332,19 @@ def create_message(senderobj, message, channels=None, new_message.message = message new_message.save() if channels: - if not is_iter(channels): + if not utils.is_iter(channels): channels = [channels] new_message.channels = [channel for channel in [to_object(channel, objtype='channel') - for channel in channels] if channel] + for channel in channels] if channel] if receivers: #print "Found receiver:", receivers - if not is_iter(receivers): + if not utils.is_iter(receivers): receivers = [receivers] #print "to_player: %s" % to_player(receivers[0]) new_message.receivers = [to_player(receiver) for receiver in [to_object(receiver) for receiver in receivers] - if receiver] + if receiver] if locks: new_message.locks.add(locks) new_message.save() @@ -343,20 +360,20 @@ def create_channel(key, aliases=None, desc=None, specifying the receivers explicitly. Instead players may 'connect' to the channel and follow the flow of messages. By default the channel allows access to all old messages, but - this can be turned off with the keep_log switch. + this can be turned off with the keep_log switch. - key - this must be unique. + key - this must be unique. aliases - list of alternative (likely shorter) keynames. locks - lock string definitions """ - from src.comms.models import Channel - from src.comms import channelhandler + from src.comms.models import Channel + from src.comms import channelhandler try: new_channel = Channel() - new_channel.key = key + new_channel.key = key if aliases: - if not is_iter(aliases): + if not utils.is_iter(aliases): aliases = [aliases] new_channel.aliases = ",".join([alias for alias in aliases]) new_channel.desc = desc @@ -369,33 +386,33 @@ def create_channel(key, aliases=None, desc=None, new_channel.locks.add(locks) new_channel.save() channelhandler.CHANNELHANDLER.add_channel(new_channel) - return new_channel + return new_channel + +channel = create_channel -channel = create_channel - # -# Player creation methods +# Player creation methods # def create_player(name, email, password, user=None, typeclass=None, - is_superuser=False, + is_superuser=False, locks=None, permissions=None, create_character=True, character_typeclass=None, character_location=None, character_home=None, - player_dbobj=None): + player_dbobj=None, report_to=None): + - """ This creates a new player, handling the creation of the User - object and its associated Player object. + object and its associated Player object. - If player_dbobj is given, this player object is used instead of + If player_dbobj is given, this player object is used instead of creating a new one. This is called by the admin interface since it needs to create the player object in order to relate it automatically - to the user. - + to the user. + If create_character is True, a game player object with the same name as the User/Player will also be created. Its typeclass and base properties can also be given. @@ -403,15 +420,15 @@ def create_player(name, email, password, Returns the new game character, or the Player obj if no character is created. For more info about the typeclass argument, see create_objects() above. - - Note: if user is supplied, it will NOT be modified (args name, email, - passw and is_superuser will be ignored). Change those properties - directly on the User instead. + + Note: if user is supplied, it will NOT be modified (args name, email, + passw and is_superuser will be ignored). Change those properties + directly on the User instead. If no permissions are given (None), the default permission group - as defined in settings.PERMISSION_PLAYER_DEFAULT will be + as defined in settings.PERMISSION_PLAYER_DEFAULT will be assigned. If permissions are given, no automatic assignment will - occur. + occur. Concerning is_superuser: A superuser should have access to everything @@ -420,18 +437,18 @@ def create_player(name, email, password, django's own creation, not this one). Usually only the server admin should need to be superuser, all other access levels can be handled with more fine-grained - permissions or groups. + permissions or groups. Since superuser overrules all permissions, we don't set any in this case. - + """ # The system should already have checked so the name/email # isn't already registered, and that the password is ok before - # getting here. + # getting here. from src.players.models import PlayerDB from src.players.player import Player - + if not email: email = "dummy@dummy.com" if user: @@ -441,7 +458,7 @@ def create_player(name, email, password, if is_superuser: new_user = User.objects.create_superuser(name, email, password) else: - new_user = User.objects.create_user(name, email, password) + new_user = User.objects.create_user(name, email, password) try: if not typeclass: typeclass = settings.BASE_PLAYER_TYPECLASS @@ -450,7 +467,7 @@ def create_player(name, email, password, typeclass = typeclass.typeclass.path elif isinstance(typeclass, Player) or utils.inherits_from(typeclass, Player): # this is already an object typeclass, extract its path - typeclass = typeclass.path + typeclass = typeclass.path if player_dbobj: new_db_player = player_dbobj @@ -458,7 +475,7 @@ def create_player(name, email, password, new_db_player = PlayerDB(db_key=name, user=new_user) new_db_player.save() - # assign the typeclass + # assign the typeclass typeclass = utils.to_unicode(typeclass) new_db_player.typeclass_path = typeclass @@ -468,13 +485,18 @@ def create_player(name, email, password, if not GA(new_db_player, "is_typeclass")(typeclass, exact=True): # this will fail if we gave a typeclass as input and it still gave us a default SharedMemoryModel.delete(new_db_player) - return None + if report_to: + GA(report_to, "msg")("Error creating %s (%s):\n%s" % (new_db_player.key, typeclass, + GA(new_db_player, "typeclass_last_errmsg"))) + return None + else: + raise Exception(GA(new_db_player, "typeclass_last_errmsg")) new_player.basetype_setup() # setup the basic locks and cmdset # call hook method (may override default permissions) new_player.at_player_creation() - # custom given arguments potentially overrides the hook + # custom given arguments potentially overrides the hook if permissions: new_player.permissions = permissions elif not new_player.permissions: @@ -483,19 +505,19 @@ def create_player(name, email, password, if locks: new_player.locks.add(locks) - # create *in-game* 'player' object + # create *in-game* 'player' object if create_character: if not character_typeclass: character_typeclass = settings.BASE_CHARACTER_TYPECLASS # creating the object automatically links the player # and object together by player.obj <-> obj.player new_character = create_object(character_typeclass, key=name, - location=None, home=character_location, + location=None, home=character_location, permissions=permissions, - player=new_player) + player=new_player, report_to=report_to) return new_character return new_player - except Exception,e: + except Exception: # a failure in creating the character if not user: # in there was a failure we clean up everything we can @@ -507,12 +529,12 @@ def create_player(name, email, password, try: new_player.delete() except Exception: - pass + pass try: del new_character except Exception: - pass - raise + pass + raise # alias player = create_player