PEP8 cleanup of the entire codebase. Unchanged are many cases of too-long lines, partly because of the rewrite they would require but also because splitting many lines up would make the code harder to read. Also the third-party libraries (idmapper, prettytable etc) were not cleaned.

This commit is contained in:
Griatch 2013-11-14 19:31:17 +01:00
parent 30b7d2a405
commit 1ae17bcbe4
154 changed files with 5613 additions and 4054 deletions

View file

@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View file

@ -72,20 +72,25 @@ CMD_LOGINSTART = "__unloggedin_look_command"
# custom Exceptions
class NoCmdSets(Exception):
"No cmdsets found. Critical error."
pass
class ExecSystemCommand(Exception):
"Run a system command"
def __init__(self, syscmd, sysarg):
self.args = (syscmd, sysarg) # needed by exception error handling
self.args = (syscmd, sysarg) # needed by exception error handling
self.syscmd = syscmd
self.sysarg = sysarg
# Helper function
@inlineCallbacks
def get_and_merge_cmdsets(caller, session, player, obj, callertype, sessid=None):
def get_and_merge_cmdsets(caller, session, player, obj,
callertype, sessid=None):
"""
Gather all relevant cmdsets and merge them.
@ -124,20 +129,25 @@ def get_and_merge_cmdsets(caller, session, player, obj, callertype, sessid=None)
if location and not obj_cmdset.no_objs:
# Gather all cmdsets stored on objects in the room and
# also in the caller's inventory and the location itself
local_objlist = yield location.contents_get(exclude=obj.dbobj) + obj.contents + [location]
local_objlist = yield (location.contents_get(exclude=obj.dbobj) +
obj.contents +
[location])
for lobj in local_objlist:
try:
# call hook in case we need to do dynamic changing to cmdset
_GA(lobj, "at_cmdset_get")()
except Exception:
logger.log_trace()
# the call-type lock is checked here, it makes sure a player is not seeing e.g. the commands
# on a fellow player (which is why the no_superuser_bypass must be True)
local_obj_cmdsets = yield [lobj.cmdset.current for lobj in local_objlist
if (lobj.cmdset.current and lobj.locks.check(caller, 'call', no_superuser_bypass=True))]
# the call-type lock is checked here, it makes sure a player
# is not seeing e.g. the commands on a fellow player (which is why
# the no_superuser_bypass must be True)
local_obj_cmdsets = \
yield [lobj.cmdset.current for lobj in local_objlist
if (lobj.cmdset.current and
lobj.locks.check(caller, 'call', no_superuser_bypass=True))]
for cset in local_obj_cmdsets:
#This is necessary for object sets, or we won't be able to separate
#the command sets from each other in a busy room.
#This is necessary for object sets, or we won't be able to
# separate the command sets from each other in a busy room.
cset.old_duplicates = cset.duplicates
cset.duplicates = True
returnValue(local_obj_cmdsets)
@ -159,8 +169,8 @@ def get_and_merge_cmdsets(caller, session, player, obj, callertype, sessid=None)
report_to = session
session_cmdset = yield _get_cmdset(session)
cmdsets = [session_cmdset]
if player: # this automatically implies logged-in
player_cmdset = yield _get_cmdset(player)
if player: # this automatically implies logged-in
player_cmdset = yield _get_cmdset(player)
channel_cmdset = yield _get_channel_cmdsets(player, player_cmdset)
cmdsets.extend([player_cmdset, channel_cmdset])
if obj:
@ -185,21 +195,26 @@ def get_and_merge_cmdsets(caller, session, player, obj, callertype, sessid=None)
cmdsets = [obj_cmdset] + local_obj_cmdsets
else:
raise Exception("get_and_merge_cmdsets: callertype %s is not valid." % callertype)
#cmdsets = yield [caller_cmdset] + [player_cmdset] + [channel_cmdset] + local_obj_cmdsets
#cmdsets = yield [caller_cmdset] + [player_cmdset] +
# [channel_cmdset] + local_obj_cmdsets
# weed out all non-found sets
cmdsets = yield [cmdset for cmdset in cmdsets if cmdset and cmdset.key!="Empty"]
cmdsets = yield [cmdset for cmdset in cmdsets
if cmdset and cmdset.key != "Empty"]
# report cmdset errors to user (these should already have been logged)
yield [report_to.msg(cmdset.errmessage) for cmdset in cmdsets if cmdset.key == "_CMDSET_ERROR"]
yield [report_to.msg(cmdset.errmessage) for cmdset in cmdsets
if cmdset.key == "_CMDSET_ERROR"]
if cmdsets:
mergehash = tuple([id(cmdset) for cmdset in cmdsets]) # faster to do tuple on list than to build tuple directly
# faster to do tuple on list than to build tuple directly
mergehash = tuple([id(cmdset) for cmdset in cmdsets])
if mergehash in _CMDSET_MERGE_CACHE:
# cached merge exist; use that
cmdset = _CMDSET_MERGE_CACHE[mergehash]
else:
# we group and merge all same-prio cmdsets separately (this avoids order-dependent
# clashes in certain cases, such as when duplicates=True)
# we group and merge all same-prio cmdsets separately (this avoids
# order-dependent clashes in certain cases, such as
# when duplicates=True)
tempmergers = {}
for cmdset in cmdsets:
prio = cmdset.priority
@ -241,13 +256,13 @@ def cmdhandler(called_by, raw_string, testing=False, callertype="session", sessi
if True, the command instance will be returned instead.
callertype - this is one of "session", "player" or "object", in decending
order. So when the Session is the caller, it will merge its
own cmdset into cmdsets from both Player and eventual puppeted Object (and
cmdsets in its room etc). A Player will only include its
own cmdset and the Objects and so on. Merge order is the
same order, so that Object cmdsets are merged in last, giving
them precendence for same-name and same-prio commands.
sessid - Relevant if callertype is "player" - the session id will help retrieve the
correct cmdsets from puppeted objects.
own cmdset into cmdsets from both Player and eventual puppeted
Object (and cmdsets in its room etc). A Player will only
include its own cmdset and the Objects and so on. Merge order
is the same order, so that Object cmdsets are merged in last,
giving them precendence for same-name and same-prio commands.
sessid - Relevant if callertype is "player" - the session id will help
retrieve the correct cmdsets from puppeted objects.
Note that this function returns a deferred!
"""
@ -270,10 +285,11 @@ def cmdhandler(called_by, raw_string, testing=False, callertype="session", sessi
# we assign the caller with preference 'bottom up'
caller = obj or player or session
try: # catch bugs in cmdhandler itself
try: # catch special-type commands
try: # catch bugs in cmdhandler itself
try: # catch special-type commands
cmdset = yield get_and_merge_cmdsets(caller, session, player, obj, callertype, sessid)
cmdset = yield get_and_merge_cmdsets(caller, session, player, obj,
callertype, sessid)
if not cmdset:
# this is bad and shouldn't happen.
raise NoCmdSets
@ -323,14 +339,15 @@ def cmdhandler(called_by, raw_string, testing=False, callertype="session", sessi
else:
# fallback to default error text
sysarg = _("Command '%s' is not available.") % raw_string
suggestions = string_suggestions(raw_string, cmdset.get_all_cmd_keys_and_aliases(caller), cutoff=0.7, maxnum=3)
suggestions = string_suggestions(raw_string,
cmdset.get_all_cmd_keys_and_aliases(caller),
cutoff=0.7, maxnum=3)
if suggestions:
sysarg += _(" Maybe you meant %s?") % utils.list_to_string(suggestions, _('or'), addquote=True)
else:
sysarg += _(" Type \"help\" for help.")
raise ExecSystemCommand(syscmd, sysarg)
# Check if this is a Channel-cmd match.
if hasattr(cmd, 'is_channel') and cmd.is_channel:
# even if a user-defined syscmd is not defined, the
@ -380,7 +397,8 @@ def cmdhandler(called_by, raw_string, testing=False, callertype="session", sessi
for func_part in make_iter(cmd.func_parts):
err = yield func_part()
# returning anything but a deferred/None will kill the chain
if err: break
if err:
break
# post-command hook
yield cmd.at_post_cmd()

View file

@ -51,10 +51,10 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
for cmd in cmdset:
try:
matches.extend([create_match(cmdname, raw_string, cmd)
for cmdname in [cmd.key] + cmd.aliases
if cmdname and l_raw_string.startswith(cmdname.lower())
and (not cmd.arg_regex or
cmd.arg_regex.match(l_raw_string[len(cmdname):]))])
for cmdname in [cmd.key] + cmd.aliases
if cmdname and l_raw_string.startswith(cmdname.lower())
and (not cmd.arg_regex or
cmd.arg_regex.match(l_raw_string[len(cmdname):]))])
except Exception:
log_trace("cmdhandler error. raw_input:%s" % raw_string)
@ -67,7 +67,8 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
if mindex.isdigit():
mindex = int(mindex) - 1
# feed result back to parser iteratively
return cmdparser(new_raw_string, cmdset, caller, match_index=mindex)
return cmdparser(new_raw_string, cmdset,
caller, match_index=mindex)
# only select command matches we are actually allowed to call.
matches = [match for match in matches if match[2].access(caller, 'cmd')]
@ -75,7 +76,8 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
if len(matches) > 1:
# See if it helps to analyze the match with preserved case but only if
# it leaves at least one match.
trimmed = [match for match in matches if raw_string.startswith(match[0])]
trimmed = [match for match in matches
if raw_string.startswith(match[0])]
if trimmed:
matches = trimmed
@ -94,15 +96,13 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
matches = matches[-quality.count(quality[-1]):]
if len(matches) > 1 and match_index != None and 0 <= match_index < len(matches):
# We couldn't separate match by quality, but we have an index argument to
# tell us which match to use.
# We couldn't separate match by quality, but we have an
# index argument to tell us which match to use.
matches = [matches[match_index]]
# no matter what we have at this point, we have to return it.
return matches
#------------------------------------------------------------
# Search parsers and support methods
#------------------------------------------------------------
@ -118,7 +118,6 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
# The the replacing modules must have the same inputs and outputs as
# those in this module.
#
def at_search_result(msg_obj, ostring, results, global_search=False,
nofound_string=None, multimatch_string=None):
"""
@ -176,7 +175,7 @@ def at_search_result(msg_obj, ostring, results, global_search=False,
invtext = _(" (carried)")
if show_dbref:
dbreftext = "(#%i)" % result.dbid
string += "\n %i-%s%s%s" % (num+1, result.name,
string += "\n %i-%s%s%s" % (num + 1, result.name,
dbreftext, invtext)
results = None
else:
@ -187,6 +186,7 @@ def at_search_result(msg_obj, ostring, results, global_search=False,
msg_obj.msg(string.strip())
return results
def at_multimatch_input(ostring):
"""
Parse number-identifiers.
@ -231,9 +231,9 @@ def at_multimatch_input(ostring):
if not '-' in ostring:
return (None, ostring)
try:
index = ostring.find('-')
number = int(ostring[:index])-1
return (number, ostring[index+1:])
index = ostring.find('-')
number = int(ostring[:index]) - 1
return (number, ostring[index + 1:])
except ValueError:
#not a number; this is not an identifier.
return (None, ostring)
@ -256,13 +256,15 @@ def at_multimatch_cmd(caller, matches):
else:
is_channel = ""
if cmd.is_exit and cmd.destination:
is_exit = _(" (exit to %s)") % cmd.destination
is_exit = (" (exit to %s)") % cmd.destination
else:
is_exit = ""
id1 = ""
id2 = ""
if not (is_channel or is_exit) and (hasattr(cmd, 'obj') and cmd.obj != caller) and hasattr(cmd.obj, "key"):
if (not (is_channel or is_exit) and
(hasattr(cmd, 'obj') and cmd.obj != caller) and
hasattr(cmd.obj, "key")):
# the command is defined on some other object
id1 = "%s-%s" % (num + 1, cmdname)
id2 = " (%s)" % (cmd.obj.key)

View file

@ -18,6 +18,7 @@ from django.utils.translation import ugettext as _
from src.utils.utils import inherits_from, is_iter
__all__ = ("CmdSet",)
class _CmdSetMeta(type):
"""
This metaclass makes some minor on-the-fly convenience fixes to
@ -38,15 +39,18 @@ class _CmdSetMeta(type):
super(_CmdSetMeta, mcs).__init__(*args, **kwargs)
class CmdSet(object):
"""
This class describes a unique cmdset that understands priorities. CmdSets
can be merged and made to perform various set operations on each other.
CmdSets have priorities that affect which of their ingoing commands gets used.
CmdSets have priorities that affect which of their ingoing commands
gets used.
In the examples, cmdset A always have higher priority than cmdset B.
key - the name of the cmdset. This can be used on its own for game operations
key - the name of the cmdset. This can be used on its own for game
operations
mergetype (partly from Set theory):
@ -80,8 +84,9 @@ class CmdSet(object):
priority- All cmdsets are always merged in pairs of two so that
the higher set's mergetype is applied to the
lower-priority cmdset. Default commands have priority 0,
high-priority ones like Exits and Channels have 10 and 9. Priorities
can be negative as well to give default commands preference.
high-priority ones like Exits and Channels have 10 and 9.
Priorities can be negative as well to give default
commands preference.
duplicates - determines what happens when two sets of equal
priority merge. Default has the first of them in the
@ -130,16 +135,17 @@ class CmdSet(object):
permanent = False
errmessage = ""
# pre-store properties to duplicate straight off
to_duplicate = ("key", "cmdsetobj", "no_exits", "no_objs", "no_channels", "permanent",
"mergetype", "priority", "duplicates", "errmessage")
to_duplicate = ("key", "cmdsetobj", "no_exits", "no_objs",
"no_channels", "permanent", "mergetype",
"priority", "duplicates", "errmessage")
def __init__(self, cmdsetobj=None, key=None):
"""
Creates a new CmdSet instance.
cmdsetobj - this is the database object to which this particular
instance of cmdset is related. It is often a player but may also be a
regular object.
instance of cmdset is related. It is often a character but
may also be a regular object.
"""
if key:
self.key = key
@ -161,7 +167,8 @@ class CmdSet(object):
if cmdset_a.duplicates and cmdset_a.priority == cmdset_b.priority:
cmdset_c.commands.extend(cmdset_b.commands)
else:
cmdset_c.commands.extend([cmd for cmd in cmdset_b if not cmd in cmdset_a])
cmdset_c.commands.extend([cmd for cmd in cmdset_b
if not cmd in cmdset_a])
return cmdset_c
def _intersect(self, cmdset_a, cmdset_b):
@ -206,7 +213,8 @@ class CmdSet(object):
cmdset = CmdSet()
for key, val in ((key, getattr(self, key)) for key in self.to_duplicate):
if val != getattr(cmdset, key):
# only copy if different from default; avoid turning class-vars into instance vars
# only copy if different from default; avoid turning
# class-vars into instance vars
setattr(cmdset, key, val)
cmdset.key_mergetypes = self.key_mergetypes.copy()
return cmdset
@ -230,10 +238,11 @@ class CmdSet(object):
def __contains__(self, othercmd):
"""
Returns True if this cmdset contains the given command (as defined
by command name and aliases). This allows for things like 'if cmd in cmdset'
by command name and aliases). This allows for things
like 'if cmd in cmdset'
"""
ret = self._contains_cache.get(othercmd)
if ret == None:
if ret is None:
ret = othercmd in self.commands
self._contains_cache[othercmd] = ret
return ret
@ -264,7 +273,8 @@ class CmdSet(object):
# A higher or equal priority than B
# preserve system __commands
sys_commands = sys_commands_a + [cmd for cmd in sys_commands_b if cmd not in sys_commands_a]
sys_commands = sys_commands_a + [cmd for cmd in sys_commands_b
if cmd not in sys_commands_a]
mergetype = self.key_mergetypes.get(cmdset_b.key, self.mergetype)
if mergetype == "Intersect":
@ -286,7 +296,8 @@ class CmdSet(object):
# B higher priority than A
# preserver system __commands
sys_commands = sys_commands_b + [cmd for cmd in sys_commands_a if cmd not in sys_commands_b]
sys_commands = sys_commands_b + [cmd for cmd in sys_commands_a
if cmd not in sys_commands_b]
mergetype = cmdset_b.key_mergetypes.get(self.key, cmdset_b.mergetype)
if mergetype == "Intersect":
@ -295,7 +306,7 @@ class CmdSet(object):
cmdset_c = self._replace(cmdset_b, self)
elif mergetype == "Remove":
cmdset_c = self._remove(self, cmdset_b)
else: # Union
else: # Union
cmdset_c = self._union(cmdset_b, self)
cmdset_c.no_channels = cmdset_b.no_channels
cmdset_c.no_exits = cmdset_b.no_exits
@ -311,10 +322,8 @@ class CmdSet(object):
# return the system commands to the cmdset
cmdset_c.add(sys_commands)
return cmdset_c
def add(self, cmd):
"""
Add a command, a list of commands or a cmdset to this cmdset.
@ -338,9 +347,12 @@ class CmdSet(object):
try:
cmd = self._instantiate(cmd)
except RuntimeError:
string = "Adding cmdset %(cmd)s to %(class)s lead to an infinite loop. When adding a cmdset to another, "
string += "make sure they are not themself cyclically added to the new cmdset somewhere in the chain."
raise RuntimeError(_(string) % {"cmd":cmd, "class":self.__class__})
string = "Adding cmdset %(cmd)s to %(class)s lead to an "
string += "infinite loop. When adding a cmdset to another, "
string += "make sure they are not themself cyclically added to "
string += "the new cmdset somewhere in the chain."
raise RuntimeError(_(string) % {"cmd": cmd,
"class": self.__class__})
cmds = cmd.commands
elif is_iter(cmd):
cmds = [self._instantiate(c) for c in cmd]
@ -354,7 +366,7 @@ class CmdSet(object):
cmd.obj = self.cmdsetobj
try:
ic = commands.index(cmd)
commands[ic] = cmd # replace
commands[ic] = cmd # replace
except ValueError:
commands.append(cmd)
# extra run to make sure to avoid doublets
@ -365,11 +377,10 @@ class CmdSet(object):
if cmd.key.startswith("__"):
try:
ic = system_commands.index(cmd)
system_commands[ic] = cmd # replace
system_commands[ic] = cmd # replace
except ValueError:
system_commands.append(cmd)
def remove(self, cmd):
"""
Remove a command instance from the cmdset.
@ -431,7 +442,8 @@ class CmdSet(object):
"""
names = []
if caller:
[names.extend(cmd._keyaliases) for cmd in self.commands if cmd.access(caller)]
[names.extend(cmd._keyaliases) for cmd in self.commands
if cmd.access(caller)]
else:
[names.extend(cmd._keyaliases) for cmd in self.commands]
return names

View file

@ -63,7 +63,6 @@ can then implement separate sets for different situations. For
example, you can have a 'On a boat' set, onto which you then tack on
the 'Fishing' set. Fishing from a boat? No problem!
"""
import traceback
from src.utils import logger, utils
from src.commands.cmdset import CmdSet
from src.server.models import ServerConfig
@ -73,23 +72,27 @@ __all__ = ("import_cmdset", "CmdSetHandler")
_CACHED_CMDSETS = {}
class _ErrorCmdSet(CmdSet):
"This is a special cmdset used to report errors"
key = "_CMDSET_ERROR"
errmessage = "Error when loading cmdset."
def import_cmdset(python_path, cmdsetobj, emit_to_obj=None, no_logging=False):
"""
This helper function is used by the cmdsethandler to load a cmdset
instance from a python module, given a python_path. It's usually accessed
through the cmdsethandler's add() and add_default() methods.
python_path - This is the full path to the cmdset object.
cmdsetobj - the database object/typeclass on which this cmdset is to be assigned
(this can be also channels and exits, as well as players but there will
always be such an object)
emit_to_obj - if given, error is emitted to this object (in addition to logging)
no_logging - don't log/send error messages. This can be useful if import_cmdset is just
used to check if this is a valid python path or not.
cmdsetobj - the database object/typeclass on which this cmdset is to be
assigned (this can be also channels and exits, as well as players
but there will always be such an object)
emit_to_obj - if given, error is emitted to this object (in addition
to logging)
no_logging - don't log/send error messages. This can be useful
if import_cmdset is just used to check if this is a
valid python path or not.
function returns None if an error was encountered or path not found.
"""
@ -117,7 +120,8 @@ def import_cmdset(python_path, cmdsetobj, emit_to_obj=None, no_logging=False):
raise
except KeyError:
errstring = _("Error in loading cmdset: No cmdset class '%(classname)s' in %(modulepath)s.")
errstring = errstring % {"classname":classname, "modulepath":modulepath}
errstring = errstring % {"classname": classname,
"modulepath": modulepath}
raise
except Exception:
errstring = _("Compile/Run error when loading cmdset '%s'. Error was logged.")
@ -135,15 +139,17 @@ def import_cmdset(python_path, cmdsetobj, emit_to_obj=None, no_logging=False):
# classes
class CmdSetHandler(object):
"""
The CmdSetHandler is always stored on an object, this object is supplied as an argument.
The CmdSetHandler is always stored on an object, this object is supplied
as an argument.
The 'current' cmdset is the merged set currently active for this object.
This is the set the game engine will retrieve when determining which
commands are available to the object. The cmdset_stack holds a history of all CmdSets
to allow the handler to remove/add cmdsets at will. Doing so will re-calculate
the 'current' cmdset.
commands are available to the object. The cmdset_stack holds a history of
all CmdSets to allow the handler to remove/add cmdsets at will. Doing so
will re-calculate the 'current' cmdset.
"""
def __init__(self, obj):
@ -176,10 +182,8 @@ class CmdSetHandler(object):
mergelist = []
if len(self.cmdset_stack) > 1:
# We have more than one cmdset in stack; list them all
num = 0
#print self.cmdset_stack, self.mergetype_stack
for snum, cmdset in enumerate(self.cmdset_stack):
num = snum
mergetype = self.mergetype_stack[snum]
permstring = "non-perm"
if cmdset.permanent:
@ -196,17 +200,21 @@ class CmdSetHandler(object):
mergetype = self.mergetype_stack[-1]
if mergetype != self.current.mergetype:
merged_on = self.cmdset_stack[-2].key
mergetype = _("custom %(mergetype)s on cmdset '%(merged_on)s'") % {"mergetype":mergetype, "merged_on":merged_on}
mergetype = _("custom %(mergetype)s on cmdset '%(merged_on)s'") % \
{"mergetype": mergetype, "merged_on":merged_on}
if mergelist:
string += _(" <Merged %(mergelist)s (%(mergetype)s, prio %(prio)i)>: %(current)s") % \
{"mergelist": "+".join(mergelist), "mergetype":mergetype, "prio":self.current.priority, "current":self.current}
{"mergelist": "+".join(mergelist),
"mergetype": mergetype, "prio": self.current.priority,
"current":self.current}
else:
permstring = "non-perm"
if self.current.permanent:
permstring = "perm"
string += _(" <%(key)s (%(mergetype)s, prio %(prio)i, %(permstring)s)>: %(keylist)s") % \
{"key":self.current.key, "mergetype":mergetype, "prio":self.current.priority, "permstring":permstring,
"keylist":", ".join(cmd.key for cmd in sorted(self.current, key=lambda o:o.key))}
{"key": self.current.key, "mergetype": mergetype,
"prio": self.current.priority, "permstring": permstring,
"keylist": ", ".join(cmd.key for cmd in sorted(self.current, key=lambda o: o.key))}
return string.strip()
def _import_cmdset(self, cmdset_path, emit_to_obj=None):
@ -362,10 +370,12 @@ class CmdSetHandler(object):
else:
# try it as a callable
if callable(cmdset) and hasattr(cmdset, 'path'):
delcmdsets = [cset for cset in self.cmdset_stack[1:] if cset.path == cmdset.path]
delcmdsets = [cset for cset in self.cmdset_stack[1:]
if cset.path == cmdset.path]
else:
# try it as a path or key
delcmdsets = [cset for cset in self.cmdset_stack[1:] if cset.path == cmdset or cset.key == cmdset]
delcmdsets = [cset for cset in self.cmdset_stack[1:]
if cset.path == cmdset or cset.key == cmdset]
storage = []
if any(cset.permanent for cset in delcmdsets):
@ -387,7 +397,10 @@ class CmdSetHandler(object):
self.update()
def delete_default(self):
"This explicitly deletes the default cmdset. It's the only command that can."
"""
This explicitly deletes the default cmdset. It's the
only command that can.
"""
if self.cmdset_stack:
cmdset = self.cmdset_stack[0]
if cmdset.permanent:
@ -404,7 +417,8 @@ class CmdSetHandler(object):
def all(self):
"""
Returns the list of cmdsets. Mostly useful to check if stack if empty or not.
Returns the list of cmdsets. Mostly useful to check
if stack if empty or not.
"""
return self.cmdset_stack
@ -431,13 +445,6 @@ class CmdSetHandler(object):
else:
return any([cmdset.key == cmdset_key for cmdset in self.cmdset_stack])
def all(self):
"""
Returns all cmdsets.
"""
return self.cmdset_stack
def reset(self):
"""
Force reload of all cmdsets in handler. This should be called

View file

@ -9,6 +9,7 @@ import re
from src.locks.lockhandler import LockHandler
from src.utils.utils import is_iter, fill
def _init_command(mcs, **kwargs):
"""
Helper command.
@ -17,20 +18,23 @@ def _init_command(mcs, **kwargs):
Sets up locks to be more forgiving. This is used both by the metaclass
and (optionally) at instantiation time.
If kwargs are given, these are set as instance-specific properties on the command.
If kwargs are given, these are set as instance-specific properties
on the command.
"""
for i in range(len(kwargs)):
# used for dynamic creation of commands
key, value = kwargs.popitem()
setattr(mcs, key, value)
# used for dynamic creation of commands
key, value = kwargs.popitem()
setattr(mcs, key, value)
mcs.key = mcs.key.lower()
if mcs.aliases and not is_iter(mcs.aliases):
try:
mcs.aliases = [str(alias).strip().lower() for alias in mcs.aliases.split(',')]
mcs.aliases = [str(alias).strip().lower()
for alias in mcs.aliases.split(',')]
except Exception:
mcs.aliases = []
mcs.aliases = list(set(alias for alias in mcs.aliases if alias and alias != mcs.key))
mcs.aliases = list(set(alias for alias in mcs.aliases
if alias and alias != mcs.key))
# optimization - a set is much faster to match against than a list
mcs._matchset = set([mcs.key] + mcs.aliases)
@ -84,6 +88,7 @@ class CommandMeta(type):
# structure can parse the input string the same way, minimizing
# parsing errors.
class Command(object):
"""
Base command
@ -112,13 +117,16 @@ class Command(object):
key - identifier for command (e.g. "look")
aliases - (optional) list of aliases (e.g. ["l", "loo"])
locks - lock string (default is "cmd:all()")
help_category - how to organize this help entry in help system (default is "General")
help_category - how to organize this help entry in help system
(default is "General")
auto_help - defaults to True. Allows for turning off auto-help generation
arg_regex - (optional) raw string regex defining how the argument part of the command should look
in order to match for this command (e.g. must it be a space between cmdname and arg?)
arg_regex - (optional) raw string regex defining how the argument part of
the command should look in order to match for this command
(e.g. must it be a space between cmdname and arg?)
(Note that if auto_help is on, this initial string is also used by the system
to create the help entry for the command, so it's a good idea to format it similar to this one)
(Note that if auto_help is on, this initial string is also used by the
system to create the help entry for the command, so it's a good idea to
format it similar to this one)
"""
# Tie our metaclass, for some convenience cleanup
__metaclass__ = CommandMeta
@ -127,7 +135,8 @@ class Command(object):
key = "command"
# alternative ways to call the command (e.g. 'l', 'glance', 'examine')
aliases = []
# a list of lock definitions on the form cmd:[NOT] func(args) [ AND|OR][ NOT] func2(args)
# a list of lock definitions on the form
# cmd:[NOT] func(args) [ AND|OR][ NOT] func2(args)
locks = ""
# used by the help system to group commands in lists.
help_category = "general"
@ -136,7 +145,8 @@ class Command(object):
auto_help = True
# auto-set (by Evennia on command instantiation) are:
# obj - which object this command is defined on
# sessid - which session-id (if any) is responsible for triggering this command
# sessid - which session-id (if any) is responsible for
# triggering this command
#
def __init__(self, **kwargs):
@ -206,20 +216,22 @@ class Command(object):
"""
return self.lockhandler.check(srcobj, access_type, default=default)
def msg(self, msg="", to_obj=None, from_obj=None, sessid=None, all_sessions=False, **kwargs):
def msg(self, msg="", to_obj=None, from_obj=None,
sessid=None, all_sessions=False, **kwargs):
"""
This is a shortcut instad of calling msg() directly on an object - it will
detect if caller is an Object or a Player and also appends self.sessid
automatically.
This is a shortcut instad of calling msg() directly on an object - it
will detect if caller is an Object or a Player and also appends
self.sessid automatically.
msg - text string of message to send
to_obj - target object of message. Defaults to self.caller
from_obj - source of message. Defaults to to_obj
data - optional dictionary of data
sessid - supply data only to a unique sessid (normally not used - this is only potentially useful if
to_obj is a Player object different from self.caller or self.caller.player)
all_sessions (bool) - default is to send only to the session connected to
the target object
sessid - supply data only to a unique sessid (normally not used -
this is only potentially useful if to_obj is a Player object
different from self.caller or self.caller.player)
all_sessions (bool) - default is to send only to the session
connected to the target object
"""
from_obj = from_obj or self.caller
to_obj = to_obj or from_obj

View file

@ -4,7 +4,8 @@ Admin commands
"""
import time, re
import time
import re
from django.conf import settings
from django.contrib.auth.models import User
from src.server.sessionhandler import SESSIONS
@ -15,8 +16,8 @@ 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",
"CmdPerm", "CmdWall")
__all__ = ("CmdBoot", "CmdBan", "CmdUnban", "CmdDelPlayer",
"CmdEmit", "CmdNewPassword", "CmdPerm", "CmdWall")
class CmdBoot(MuxCommand):
@ -98,6 +99,7 @@ class CmdBoot(MuxCommand):
# regex matching IP addresses with wildcards, eg. 233.122.4.*
IPREGEX = re.compile(r"[0-9*]{1,3}\.[0-9*]{1,3}\.[0-9*]{1,3}\.[0-9*]{1,3}")
def list_bans(banlist):
"""
Helper function to display a list of active bans. Input argument
@ -108,12 +110,13 @@ def list_bans(banlist):
table = prettytable.PrettyTable(["{wid", "{wname/ip", "{wdate", "{wreason"])
for inum, ban in enumerate(banlist):
table.add_row([str(inum+1),
table.add_row([str(inum + 1),
ban[0] and ban[0] or ban[1],
ban[3], ban[4]])
string = "{wActive bans:{n\n%s" % table
return string
class CmdBan(MuxCommand):
"""
ban a player from the server
@ -152,7 +155,7 @@ class CmdBan(MuxCommand):
key = "@ban"
aliases = ["@bans"]
locks = "cmd:perm(ban) or perm(Immortals)"
help_category="Admin"
help_category = "Admin"
def func(self):
"""
@ -172,14 +175,15 @@ class CmdBan(MuxCommand):
banlist = []
if not self.args or (self.switches
and not any(switch in ('ip', 'name') for switch in self.switches)):
and not any(switch in ('ip', 'name')
for switch in self.switches)):
self.caller.msg(list_bans(banlist))
return
now = time.ctime()
reason = ""
if ':' in self.args:
ban, reason = self.args.rsplit(':',1)
ban, reason = self.args.rsplit(':', 1)
else:
ban = self.args
ban = ban.lower()
@ -193,7 +197,7 @@ class CmdBan(MuxCommand):
typ = "IP"
ban = ipban[0]
# replace * with regex form and compile it
ipregex = ban.replace('.','\.')
ipregex = ban.replace('.', '\.')
ipregex = ipregex.replace('*', '[0-9]{1,3}')
#print "regex:",ipregex
ipregex = re.compile(r"%s" % ipregex)
@ -203,6 +207,7 @@ class CmdBan(MuxCommand):
ServerConfig.objects.conf('server_bans', banlist)
self.caller.msg("%s-Ban {w%s{x was added." % (typ, ban))
class CmdUnban(MuxCommand):
"""
remove a ban
@ -218,7 +223,7 @@ class CmdUnban(MuxCommand):
"""
key = "@unban"
locks = "cmd:perm(unban) or perm(Immortals)"
help_category="Admin"
help_category = "Admin"
def func(self):
"Implement unbanning"
@ -241,10 +246,11 @@ class CmdUnban(MuxCommand):
self.caller.msg("Ban id {w%s{x was not found." % self.args)
else:
# all is ok, clear ban
ban = banlist[num-1]
del banlist[num-1]
ban = banlist[num - 1]
del banlist[num - 1]
ServerConfig.objects.conf('server_bans', banlist)
self.caller.msg("Cleared ban %s: %s" % (num, " ".join([s for s in ban[:2]])))
self.caller.msg("Cleared ban %s: %s" %
(num, " ".join([s for s in ban[:2]])))
class CmdDelPlayer(MuxCommand):
@ -408,7 +414,7 @@ class CmdEmit(MuxCommand):
obj = caller.search(objname, global_search=True)
if not obj:
return
if rooms_only and not obj.location == None:
if rooms_only and not obj.location is None:
caller.msg("%s is not a room. Ignored." % objname)
continue
if players_only and not obj.has_player:
@ -425,7 +431,6 @@ class CmdEmit(MuxCommand):
caller.msg("You are not allowed to emit to %s." % objname)
class CmdNewPassword(MuxCommand):
"""
@userpassword
@ -457,7 +462,8 @@ class CmdNewPassword(MuxCommand):
player.user.save()
self.msg("%s - new password set to '%s'." % (player.name, self.rhs))
if player.character != caller:
player.msg("%s has changed your password to '%s'." % (caller.name, self.rhs))
player.msg("%s has changed your password to '%s'." % (caller.name,
self.rhs))
class CmdPerm(MuxCommand):
@ -497,7 +503,7 @@ class CmdPerm(MuxCommand):
if playermode:
obj = caller.search_player(lhs)
else:
obj = caller.search(lhs, global_search=True)
obj = caller.search(lhs, global_search=True)
if not obj:
return
@ -511,7 +517,9 @@ class CmdPerm(MuxCommand):
string += "<None>"
else:
string += ", ".join(obj.permissions.all())
if hasattr(obj, 'player') and hasattr(obj.player, 'is_superuser') and obj.player.is_superuser:
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.)"
caller.msg(string)
@ -539,9 +547,10 @@ class CmdPerm(MuxCommand):
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):
# 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

View file

@ -95,11 +95,12 @@ def format_header(caller, entry):
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 = "%s%s" % (header, " " * (width - len(header)))
header = header.replace('\n', '\\n')
return header
def format_code(entry):
"""
Formats the viewing of code and errors
@ -109,6 +110,7 @@ def format_code(entry):
code += "\n{G>>>{n %s" % line
return code.strip()
def batch_cmd_exec(caller):
"""
Helper function for executing a single batch-command entry
@ -124,6 +126,7 @@ def batch_cmd_exec(caller):
return False
return True
def batch_code_exec(caller):
"""
Helper function for executing a single batch-code entry
@ -135,12 +138,13 @@ def batch_code_exec(caller):
caller.msg(format_header(caller, codedict['code']))
err = BATCHCODE.code_exec(codedict,
extra_environ={"caller":caller}, debug=debug)
extra_environ={"caller": caller}, debug=debug)
if err:
caller.msg(format_code(err))
return False
return True
def step_pointer(caller, step=1):
"""
Step in stack, returning the item located.
@ -156,7 +160,8 @@ def step_pointer(caller, step=1):
caller.msg("{RBeginning of batch file.")
if ptr + step >= nstack:
caller.msg("{REnd of batch file.")
caller.ndb.batch_stackptr = max(0, min(nstack-1, ptr + step))
caller.ndb.batch_stackptr = max(0, min(nstack - 1, ptr + step))
def show_curr(caller, showall=False):
"""
@ -186,6 +191,7 @@ def show_curr(caller, showall=False):
string += "\n{G|{n %s" % line
caller.msg(string)
def purge_processor(caller):
"""
This purges all effects running
@ -201,12 +207,13 @@ def purge_processor(caller):
# clear everything but the default cmdset.
caller.cmdset.delete(BatchSafeCmdSet)
caller.cmdset.clear()
caller.scripts.validate() # this will purge interactive mode
caller.scripts.validate() # this will purge interactive mode
#------------------------------------------------------------
# main access commands
#------------------------------------------------------------
class CmdBatchCommands(MuxCommand):
"""
Build from batch-command file
@ -275,19 +282,25 @@ class CmdBatchCommands(MuxCommand):
procpool = False
if "PythonProcPool" in utils.server_services():
if utils.uses_database("sqlite3"):
caller.msg("Batchprocessor disabled ProcPool under SQLite3.")
caller.msg("Batchprocessor disabled ProcPool under SQLite3.")
else:
procpool=True
procpool = True
if procpool:
# run in parallel process
def callback(r):
caller.msg(" {GBatchfile '%s' applied." % python_path)
purge_processor(caller)
def errback(e):
caller.msg(" {RError from processor: '%s'" % e)
purge_processor(caller)
utils.run_async(_PROCPOOL_BATCHCMD_SOURCE, commands=commands, caller=caller, at_return=callback, at_err=errback)
utils.run_async(_PROCPOOL_BATCHCMD_SOURCE,
commands=commands,
caller=caller,
at_return=callback,
at_err=errback)
else:
# run in-process (might block)
for inum in range(len(commands)):
@ -295,11 +308,13 @@ class CmdBatchCommands(MuxCommand):
if not batch_cmd_exec(caller):
return
step_pointer(caller, 1)
# clean out the safety cmdset and clean out all other temporary attrs.
# 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
@ -352,7 +367,7 @@ class CmdBatchCode(MuxCommand):
debug = False
if 'debug' in switches:
debug = True
debug = True
# Store work data in cache
caller.ndb.batch_stack = codes
@ -376,18 +391,23 @@ class CmdBatchCode(MuxCommand):
procpool = False
if "PythonProcPool" in utils.server_services():
if utils.uses_database("sqlite3"):
caller.msg("Batchprocessor disabled ProcPool under SQLite3.")
caller.msg("Batchprocessor disabled ProcPool under SQLite3.")
else:
procpool=True
procpool = True
if procpool:
# run in parallel process
def callback(r):
caller.msg(" {GBatchfile '%s' applied." % python_path)
purge_processor(caller)
def errback(e):
caller.msg(" {RError from processor: '%s'" % e)
purge_processor(caller)
utils.run_async(_PROCPOOL_BATCHCODE_SOURCE, codes=codes, caller=caller, at_return=callback, at_err=errback)
utils.run_async(_PROCPOOL_BATCHCODE_SOURCE,
codes=codes,
caller=caller,
at_return=callback,
at_err=errback)
else:
# un in-process (will block)
for inum in range(len(codes)):
@ -395,7 +415,8 @@ class CmdBatchCode(MuxCommand):
if not batch_code_exec(caller):
return
step_pointer(caller, 1)
# clean out the safety cmdset and clean out all other temporary attrs.
# 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)
@ -423,6 +444,7 @@ class CmdStateAbort(MuxCommand):
purge_processor(self.caller)
self.caller.msg("Exited processor and reset out active cmdset back to the default one.")
class CmdStateLL(MuxCommand):
"""
ll
@ -479,6 +501,7 @@ class CmdStateRR(MuxCommand):
caller.msg(format_code("File reloaded. Staying on same command."))
show_curr(caller)
class CmdStateRRR(MuxCommand):
"""
rrr
@ -500,6 +523,7 @@ class CmdStateRRR(MuxCommand):
caller.msg(format_code("File reloaded. Restarting from top."))
show_curr(caller)
class CmdStateNN(MuxCommand):
"""
nn
@ -520,6 +544,7 @@ class CmdStateNN(MuxCommand):
step_pointer(caller, step)
show_curr(caller)
class CmdStateNL(MuxCommand):
"""
nl
@ -541,6 +566,7 @@ class CmdStateNL(MuxCommand):
step_pointer(caller, step)
show_curr(caller, showall=True)
class CmdStateBB(MuxCommand):
"""
bb
@ -562,6 +588,7 @@ class CmdStateBB(MuxCommand):
step_pointer(caller, step)
show_curr(caller)
class CmdStateBL(MuxCommand):
"""
bl
@ -583,6 +610,7 @@ class CmdStateBL(MuxCommand):
step_pointer(caller, step)
show_curr(caller, showall=True)
class CmdStateSS(MuxCommand):
"""
ss [steps]
@ -611,6 +639,7 @@ class CmdStateSS(MuxCommand):
step_pointer(caller, 1)
show_curr(caller)
class CmdStateSL(MuxCommand):
"""
sl [steps]
@ -639,6 +668,7 @@ class CmdStateSL(MuxCommand):
step_pointer(caller, 1)
show_curr(caller)
class CmdStateCC(MuxCommand):
"""
cc
@ -670,6 +700,7 @@ class CmdStateCC(MuxCommand):
del caller.ndb.batch_batchmode
caller.msg(format_code("Finished processing batch file."))
class CmdStateJJ(MuxCommand):
"""
j <command number>
@ -684,7 +715,7 @@ class CmdStateJJ(MuxCommand):
caller = self.caller
arg = self.args
if arg and arg.isdigit():
number = int(self.args)-1
number = int(self.args) - 1
else:
caller.msg(format_code("You must give a number index."))
return
@ -693,6 +724,7 @@ class CmdStateJJ(MuxCommand):
step_pointer(caller, step)
show_curr(caller)
class CmdStateJL(MuxCommand):
"""
jl <command number>
@ -707,7 +739,7 @@ class CmdStateJL(MuxCommand):
caller = self.caller
arg = self.args
if arg and arg.isdigit():
number = int(self.args)-1
number = int(self.args) - 1
else:
caller.msg(format_code("You must give a number index."))
return
@ -716,6 +748,7 @@ class CmdStateJL(MuxCommand):
step_pointer(caller, step)
show_curr(caller, showall=True)
class CmdStateQQ(MuxCommand):
"""
qq
@ -730,6 +763,7 @@ class CmdStateQQ(MuxCommand):
purge_processor(self.caller)
self.caller.msg("Aborted interactive batch mode.")
class CmdStateHH(MuxCommand):
"Help command"
@ -766,7 +800,6 @@ class CmdStateHH(MuxCommand):
self.caller.msg(string)
#------------------------------------------------------------
#
# Defining the cmdsets for the interactive batchprocessor
@ -781,12 +814,13 @@ class BatchSafeCmdSet(CmdSet):
always be available to get out of everything.
"""
key = "Batch_default"
priority = 104 # override other cmdsets.
priority = 104 # override other cmdsets.
def at_cmdset_creation(self):
"Init the cmdset"
self.add(CmdStateAbort())
class BatchInteractiveCmdSet(CmdSet):
"""
The cmdset for the interactive batch processor mode.

View file

@ -29,6 +29,7 @@ except ImportError:
# used by @find
CHAR_TYPECLASS = settings.BASE_CHARACTER_TYPECLASS
class ObjManipCommand(MuxCommand):
"""
This is a parent class for some of the defining objmanip commands
@ -60,7 +61,7 @@ class ObjManipCommand(MuxCommand):
# get all the normal parsing done (switches etc)
super(ObjManipCommand, self).parse()
obj_defs = ([],[]) # stores left- and right-hand side of '='
obj_defs = ([], []) # stores left- and right-hand side of '='
obj_attrs = ([], []) # "
for iside, arglist in enumerate((self.lhslist, self.rhslist)):
@ -101,7 +102,7 @@ class CmdSetObjAlias(MuxCommand):
by everyone.
"""
key = "@alias"
key = "@alias"
aliases = "@setobjalias"
locks = "cmd:perm(setobjalias) or perm(Builders)"
help_category = "Building"
@ -121,7 +122,7 @@ class CmdSetObjAlias(MuxCommand):
obj = caller.search(objname)
if not obj:
return
if self.rhs == None:
if self.rhs is None:
# no =, so we just list aliases on object.
aliases = obj.aliases.all()
if aliases:
@ -146,15 +147,18 @@ class CmdSetObjAlias(MuxCommand):
# merge the old and new aliases (if any)
old_aliases = obj.aliases.all()
new_aliases = [alias.strip().lower() for alias in self.rhs.split(',') if alias.strip()]
new_aliases = [alias.strip().lower() for alias in self.rhs.split(',')
if alias.strip()]
# make the aliases only appear once
old_aliases.extend(new_aliases)
aliases = list(set(old_aliases))
# save back to object.
obj.aliases.add(aliases)
# we treat this as a re-caching (relevant for exits to re-build their exit commands with the correct aliases)
# we treat this as a re-caching (relevant for exits to re-build their
# exit commands with the correct aliases)
caller.msg("Alias(es) for '%s' set to %s." % (obj.key, str(obj.aliases)))
class CmdCopy(ObjManipCommand):
"""
@copy - copy objects
@ -167,8 +171,8 @@ class CmdCopy(ObjManipCommand):
removing any changes that might have been made to the original
since it was first created.
Create one or more copies of an object. If you don't supply any targets, one exact copy
of the original object will be created with the name *_copy.
Create one or more copies of an object. If you don't supply any targets,
one exact copt of the original object will be created with the name *_copy.
"""
key = "@copy"
@ -210,12 +214,15 @@ class CmdCopy(ObjManipCommand):
to_obj_aliases = objdef['aliases']
to_obj_location = objdef['option']
if to_obj_location:
to_obj_location = caller.search(to_obj_location, global_search=True)
to_obj_location = caller.search(to_obj_location,
global_search=True)
if not to_obj_location:
return
copiedobj = ObjectDB.objects.copy_object(from_obj, new_key=to_obj_name,
new_location=to_obj_location, new_aliases=to_obj_aliases)
copiedobj = ObjectDB.objects.copy_object(from_obj,
new_key=to_obj_name,
new_location=to_obj_location,
new_aliases=to_obj_aliases)
if copiedobj:
string = "Copied %s to '%s' (aliases: %s)." % (from_obj_name, to_obj_name,
to_obj_aliases)
@ -225,6 +232,7 @@ class CmdCopy(ObjManipCommand):
# we are done, echo to user
caller.msg(string)
class CmdCpAttr(ObjManipCommand):
"""
@cpattr - copy attributes
@ -244,8 +252,8 @@ class CmdCpAttr(ObjManipCommand):
copies the coolness attribute (defined on yourself), to attributes
on Anna and Tom.
Copy the attribute one object to one or more attributes on another object. If
you don't supply a source object, yourself is used.
Copy the attribute one object to one or more attributes on another object.
If you don't supply a source object, yourself is used.
"""
key = "@cpattr"
locks = "cmd:perm(cpattr) or perm(Builders)"
@ -272,7 +280,8 @@ class CmdCpAttr(ObjManipCommand):
from_obj_attrs = lhs_objattr[0]['attrs']
if not from_obj_attrs:
# this means the from_obj_name is actually an attribute name on self.
# this means the from_obj_name is actually an attribute
# name on self.
from_obj_attrs = [from_obj_name]
from_obj = self.caller
from_obj_name = self.caller.name
@ -282,7 +291,8 @@ class CmdCpAttr(ObjManipCommand):
caller.msg("You have to supply both source object and target(s).")
return
if not from_obj.attributes.has(from_obj_attrs[0]):
caller.msg("%s doesn't have an attribute %s." % (from_obj_name, from_obj_attrs[0]))
caller.msg("%s doesn't have an attribute %s." % (from_obj_name,
from_obj_attrs[0]))
return
srcvalue = from_obj.attributes.get(from_obj_attrs[0])
@ -291,7 +301,8 @@ class CmdCpAttr(ObjManipCommand):
string = "Moving "
else:
string = "Copying "
string += "%s/%s (with value %s) ..." % (from_obj_name, from_obj_attrs[0], srcvalue)
string += "%s/%s (with value %s) ..." % (from_obj_name,
from_obj_attrs[0], srcvalue)
for to_obj in to_objs:
to_obj_name = to_obj['name']
@ -308,15 +319,20 @@ class CmdCpAttr(ObjManipCommand):
# on the to_obj, we copy the original name instead.
to_attr = from_attr
to_obj.attributes.add(to_attr, srcvalue)
if "move" in self.switches and not (from_obj == to_obj and from_attr == to_attr):
if ("move" in self.switches and not (from_obj == to_obj and
from_attr == to_attr)):
from_obj.del_attribute(from_attr)
string += "\nMoved %s.%s -> %s.%s." % (from_obj.name, from_attr,
string += "\nMoved %s.%s -> %s.%s." % (from_obj.name,
from_attr,
to_obj_name, to_attr)
else:
string += "\nCopied %s.%s -> %s.%s." % (from_obj.name, from_attr,
to_obj_name, to_attr)
string += "\nCopied %s.%s -> %s.%s." % (from_obj.name,
from_attr,
to_obj_name,
to_attr)
caller.msg(string)
class CmdMvAttr(ObjManipCommand):
"""
@mvattr - move attributes
@ -330,8 +346,8 @@ class CmdMvAttr(ObjManipCommand):
Switches:
copy - Don't delete the original after moving.
Move an attribute from one object to one or more attributes on another object. If
you don't supply a source object, yourself is used.
Move an attribute from one object to one or more attributes on another
object. If you don't supply a source object, yourself is used.
"""
key = "@mvattr"
locks = "cmd:perm(mvattr) or perm(Builders)"
@ -356,6 +372,7 @@ class CmdMvAttr(ObjManipCommand):
else:
self.caller.execute_cmd("@cpattr/move %s" % self.args)
class CmdCreate(ObjManipCommand):
"""
@create - create new objects
@ -364,8 +381,9 @@ class CmdCreate(ObjManipCommand):
@create[/drop] objname[;alias;alias...][:typeclass], objname...
switch:
drop - automatically drop the new object into your current location (this is not echoed)
this also sets the new object's home to the current location rather than to you.
drop - automatically drop the new object into your current
location (this is not echoed). This also sets the new
object's home to the current location rather than to you.
Creates one or more new objects. If typeclass is given, the object
is created as a child of this typeclass. The typeclass script is
@ -406,7 +424,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, report_to=caller)
home=caller, aliases=aliases,
locks=lockstring, report_to=caller)
if not obj:
continue
if aliases:
@ -423,7 +442,8 @@ class CmdCreate(ObjManipCommand):
obj.home = caller.location
obj.move_to(caller.location, quiet=True)
if string:
caller.msg(string)
caller.msg(string)
class CmdDesc(MuxCommand):
"""
@ -471,8 +491,8 @@ class CmdDestroy(MuxCommand):
@destroy[/switches] [obj, obj2, obj3, [dbref-dbref], ...]
switches:
override - The @destroy command will usually avoid accidentally destroying
player objects. This switch overrides this safety.
override - The @destroy command will usually avoid accidentally
destroying player objects. This switch overrides this safety.
examples:
@destroy house, roof, door, 44-78
@destroy 5-10, flower, 45
@ -502,7 +522,8 @@ class CmdDestroy(MuxCommand):
if not obj:
self.caller.msg(" (Objects to destroy must either be local or specified with a unique #dbref.)")
return ""
if not "override" in self.switches and obj.dbid == int(settings.CHARACTER_DEFAULT_HOME.lstrip("#")):
if (not "override" in self.switches and
obj.dbid == int(settings.CHARACTER_DEFAULT_HOME.lstrip("#"))):
return "\nYou are trying to delete CHARACTER_DEFAULT_HOME. If you want to do this, use the /override switch."
objname = obj.name
if not obj.access(caller, 'delete'):
@ -529,9 +550,10 @@ class CmdDestroy(MuxCommand):
for objname in self.lhslist:
if '-' in objname:
# might be a range of dbrefs
dmin, dmax = [utils.dbref(part, reqhash=False) for part in objname.split('-', 1)]
dmin, dmax = [utils.dbref(part, reqhash=False)
for part in objname.split('-', 1)]
if dmin and dmax:
for dbref in range(int(dmin),int(dmax+1)):
for dbref in range(int(dmin), int(dmax + 1)):
string += delobj("#" + str(dbref), True)
else:
string += delobj(objname)
@ -558,9 +580,11 @@ class CmdDig(ObjManipCommand):
@dig house:myrooms.MyHouseTypeclass
@dig sheer cliff;cliff;sheer = climb up, climb down
This command is a convenient way to build rooms quickly; it creates the new room and you can optionally
set up exits back and forth between your current room and the new one. You can add as many aliases as you
like to the name of the room and the exits in question; an example would be 'north;no;n'.
This command is a convenient way to build rooms quickly; it creates the
new room and you can optionally set up exits back and forth between your
current room and the new one. You can add as many aliases as you
like to the name of the room and the exits in question; an example
would be 'north;no;n'.
"""
key = "@dig"
locks = "cmd:perm(dig) or perm(Builders)"
@ -595,13 +619,14 @@ class CmdDig(ObjManipCommand):
lockstring = lockstring % (caller.dbref, caller.dbref, caller.dbref)
new_room = create.create_object(typeclass, room["name"],
aliases=room["aliases"], report_to=caller)
aliases=room["aliases"],
report_to=caller)
new_room.locks.add(lockstring)
alias_string = ""
if new_room.aliases.all():
alias_string = " (%s)" % ", ".join(new_room.aliases.all())
room_string = "Created room %s(%s)%s of type %s." % (new_room, new_room.dbref, alias_string, typeclass)
room_string = "Created room %s(%s)%s of type %s." % (new_room,
new_room.dbref, alias_string, typeclass)
# create exit to room
@ -622,15 +647,21 @@ class CmdDig(ObjManipCommand):
if not typeclass:
typeclass = settings.BASE_EXIT_TYPECLASS
new_to_exit = create.create_object(typeclass, to_exit["name"], location,
new_to_exit = create.create_object(typeclass, to_exit["name"],
location,
aliases=to_exit["aliases"],
locks=lockstring, destination=new_room, report_to=caller)
locks=lockstring,
destination=new_room,
report_to=caller)
alias_string = ""
if new_to_exit.aliases.all():
alias_string = " (%s)" % ", ".join(new_to_exit.aliases.all())
exit_to_string = "\nCreated Exit from %s to %s: %s(%s)%s."
exit_to_string = exit_to_string % (location.name, new_room.name, new_to_exit,
new_to_exit.dbref, alias_string)
exit_to_string = exit_to_string % (location.name,
new_room.name,
new_to_exit,
new_to_exit.dbref,
alias_string)
# Create exit back from new room
@ -647,15 +678,22 @@ class CmdDig(ObjManipCommand):
typeclass = back_exit["option"]
if not typeclass:
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, report_to=caller)
new_back_exit = create.create_object(typeclass,
back_exit["name"],
new_room,
aliases=back_exit["aliases"],
locks=lockstring,
destination=location,
report_to=caller)
alias_string = ""
if new_back_exit.aliases.all():
alias_string = " (%s)" % ", ".join(new_back_exit.aliases.all())
exit_back_string = "\nCreated Exit back from %s to %s: %s(%s)%s."
exit_back_string = exit_back_string % (new_room.name, location.name,
new_back_exit, new_back_exit.dbref, alias_string)
exit_back_string = exit_back_string % (new_room.name,
location.name,
new_back_exit,
new_back_exit.dbref,
alias_string)
caller.msg("%s%s%s" % (room_string, exit_to_string, exit_back_string))
if new_room and ('teleport' in self.switches or "tel" in self.switches):
caller.move_to(new_room)
@ -693,18 +731,18 @@ class CmdTunnel(MuxCommand):
help_category = "Building"
# store the direction, full name and its opposite
directions = {"n" : ("north", "s"),
directions = {"n": ("north", "s"),
"ne": ("northeast", "sw"),
"e" : ("east", "w"),
"e": ("east", "w"),
"se": ("southeast", "nw"),
"s" : ("south", "n"),
"s": ("south", "n"),
"sw": ("southwest", "ne"),
"w" : ("west", "e"),
"w": ("west", "e"),
"nw": ("northwest", "se"),
"u" : ("up", "d"),
"d" : ("down", "u"),
"i" : ("in", "o"),
"o" : ("out", "i")}
"u": ("up", "d"),
"d": ("down", "u"),
"i": ("in", "o"),
"o": ("out", "i")}
def func(self):
"Implements the tunnel command"
@ -725,7 +763,7 @@ class CmdTunnel(MuxCommand):
roomname = "Some place"
if self.rhs:
roomname = self.rhs # this may include aliases; that's fine.
roomname = self.rhs # this may include aliases; that's fine.
telswitch = ""
if "tel" in self.switches:
@ -735,9 +773,11 @@ class CmdTunnel(MuxCommand):
backstring = ", %s;%s" % (backname, backshort)
# build the string we will use to call @dig
digstring = "@dig%s %s = %s;%s%s" % (telswitch, roomname, exitname, exitshort, backstring)
digstring = "@dig%s %s = %s;%s%s" % (telswitch, roomname,
exitname, exitshort, backstring)
self.caller.execute_cmd(digstring)
class CmdLink(MuxCommand):
"""
@link - connect objects
@ -754,8 +794,9 @@ class CmdLink(MuxCommand):
If <object> is an exit, set its destination to <target>. Two-way operation
instead sets the destination to the *locations* of the respective given
arguments.
The second form (a lone =) sets the destination to None (same as the @unlink command)
and the third form (without =) just shows the currently set destination.
The second form (a lone =) sets the destination to None (same as
the @unlink command) and the third form (without =) just shows the
currently set destination.
"""
key = "@link"
@ -802,7 +843,7 @@ class CmdLink(MuxCommand):
obj.destination = target
string += "\nLink created %s -> %s (one way)." % (obj.name, target)
elif self.rhs == None:
elif self.rhs is None:
# this means that no = was given (otherwise rhs
# would have been an empty string). So we inspect
# the home/destination on object
@ -823,6 +864,7 @@ class CmdLink(MuxCommand):
# give feedback
caller.msg(string.strip())
class CmdUnLink(CmdLink):
"""
@unlink - unconnect objects
@ -857,6 +899,7 @@ class CmdUnLink(CmdLink):
# call the @link functionality
super(CmdUnLink, self).func()
class CmdSetHome(CmdLink):
"""
@home - control an object's home location
@ -893,7 +936,8 @@ class CmdSetHome(CmdLink):
if not home:
string = "This object has no home location set!"
else:
string = "%s's current home is %s(%s)." % (obj, home, home.dbref)
string = "%s's current home is %s(%s)." % (obj, home,
home.dbref)
else:
# set a home location
new_home = self.caller.search(self.rhs, global_search=True)
@ -907,6 +951,7 @@ class CmdSetHome(CmdLink):
string = "%s' home location was set to %s(%s)." % (obj, new_home, new_home.dbref)
self.caller.msg(string)
class CmdListCmdSets(MuxCommand):
"""
list command sets on an object
@ -935,6 +980,7 @@ class CmdListCmdSets(MuxCommand):
string = "%s" % obj.cmdset
caller.msg(string)
class CmdName(ObjManipCommand):
"""
cname - change the name and/or aliases of an object
@ -1006,7 +1052,8 @@ class CmdOpen(ObjManipCommand):
help_category = "Building"
# a custom member method to chug out exits and do checks
def create_exit(self, exit_name, location, destination, exit_aliases=None, typeclass=None):
def create_exit(self, exit_name, location, destination,
exit_aliases=None, typeclass=None):
"""
Helper function to avoid code duplication.
At this point we know destination is a valid location
@ -1047,9 +1094,11 @@ class CmdOpen(ObjManipCommand):
# exit does not exist before. Create a new one.
if not typeclass:
typeclass = settings.BASE_EXIT_TYPECLASS
exit_obj = create.create_object(typeclass, key=exit_name,
exit_obj = create.create_object(typeclass,
key=exit_name,
location=location,
aliases=exit_aliases, report_to=caller)
aliases=exit_aliases,
report_to=caller)
if exit_obj:
# storing a destination is what makes it an exit!
exit_obj.destination = destination
@ -1095,7 +1144,11 @@ class CmdOpen(ObjManipCommand):
return
# Create exit
ok = self.create_exit(exit_name, location, destination, exit_aliases, exit_typeclass)
ok = self.create_exit(exit_name,
location,
destination,
exit_aliases,
exit_typeclass)
if not ok:
# an error; the exit was not created, so we quit.
return
@ -1104,7 +1157,11 @@ class CmdOpen(ObjManipCommand):
back_exit_name = self.lhs_objs[1]['name']
back_exit_aliases = self.lhs_objs[1]['aliases']
back_exit_typeclass = self.lhs_objs[1]['option']
ok = self.create_exit(back_exit_name, destination, location, back_exit_aliases, back_exit_typeclass)
ok = self.create_exit(back_exit_name,
destination,
location,
back_exit_aliases,
back_exit_typeclass)
class CmdSetAttribute(ObjManipCommand):
@ -1126,7 +1183,8 @@ class CmdSetAttribute(ObjManipCommand):
numbers. You can however also set Python primities such as lists,
dictionaries and tuples on objects (this might be important for
the functionality of certain custom objects). This is indicated
by you starting your value with one of {c'{n, {c"{n, {c({n, {c[{n or {c{ {n.
by you starting your value with one of {c'{n, {c"{n, {c({n, {c[{n
or {c{ {n.
Note that you should leave a space after starting a dictionary ('{ ')
so as to not confuse the dictionary start with a colour code like \{g.
Remember that if you use Python primitives like this, you must
@ -1169,10 +1227,14 @@ class CmdSetAttribute(ObjManipCommand):
used for Python <=2.5. After that literal_eval is available.
"""
# simple types
try: return int(obj)
except ValueError: pass
try: return float(obj)
except ValueError: pass
try:
return int(obj)
except ValueError:
pass
try:
return float(obj)
except ValueError:
pass
# iterables
if obj.startswith('[') and obj.endswith(']'):
"A list. Traverse recursively."
@ -1182,7 +1244,8 @@ class CmdSetAttribute(ObjManipCommand):
return tuple([rec_convert(val) for val in obj[1:-1].split(',')])
if obj.startswith('{') and obj.endswith('}') and ':' in obj:
"A dict. Traverse recursively."
return dict([(rec_convert(pair.split(":",1)[0]), rec_convert(pair.split(":",1)[1]))
return dict([(rec_convert(pair.split(":", 1)[0]),
rec_convert(pair.split(":", 1)[1]))
for pair in obj[1:-1].split(',') if ":" in pair])
# if nothing matches, return as-is
return obj
@ -1198,7 +1261,8 @@ class CmdSetAttribute(ObjManipCommand):
self.caller.msg(string)
return utils.to_str(strobj)
else:
# fall back to old recursive solution (does not support nested lists/dicts)
# fall back to old recursive solution (does not support
# nested lists/dicts)
return rec_convert(strobj.strip())
def func(self):
@ -1223,17 +1287,18 @@ class CmdSetAttribute(ObjManipCommand):
string = ""
if not value:
if self.rhs == None:
if self.rhs is None:
# no = means we inspect the attribute(s)
if not attrs:
attrs = [attr.key for attr in obj.get_all_attributes()]
for attr in attrs:
if obj.attributes.has(attr):
string += "\nAttribute %s/%s = %s" % (obj.name, attr, obj.attributes.get(attr))
string += "\nAttribute %s/%s = %s" % (obj.name, attr,
obj.attributes.get(attr))
else:
string += "\n%s has no attribute '%s'." % (obj.name, attr)
# we view it without parsing markup.
self.caller.msg(string.strip(), data={"raw":True})
self.caller.msg(string.strip(), data={"raw": True})
return
else:
# deleting the attribute(s)
@ -1252,9 +1317,11 @@ class CmdSetAttribute(ObjManipCommand):
string += "\nCreated attribute %s/%s = %s" % (obj.name, attr, value)
except SyntaxError:
# this means literal_eval tried to parse a faulty string
string = "{RCritical Python syntax error in your value. Only primitive Python structures"
string += "\nare allowed. You also need to use correct Python syntax. Remember especially"
string += "\nto put quotes around all strings inside lists and dicts.{n"
string = "{RCritical Python syntax error in your value. "
string += "Only primitive Python structures are allowed. "
string += "\nYou also need to use correct Python syntax. "
string += "Remember especially to put quotes around all "
string += "strings inside lists and dicts.{n"
# send feedback
caller.msg(string.strip('\n'))
@ -1314,7 +1381,8 @@ 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' (%s)." % (obj.name, obj.typeclass.typename, obj.typeclass.path)
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)
@ -1343,8 +1411,8 @@ class CmdTypeclass(MuxCommand):
string = "%s updated its existing typeclass (%s).\n" % (obj.name, obj.typeclass.path)
else:
string = "%s changed typeclass from %s to %s.\n" % (obj.name,
old_typeclass_path,
obj.typeclass_path)
old_typeclass_path,
obj.typeclass_path)
string += "Creation hooks were run."
if reset:
string += " All old attributes where deleted before the swap."
@ -1354,8 +1422,8 @@ class CmdTypeclass(MuxCommand):
else:
string = obj.typeclass_last_errmsg
string += "\nCould not swap '%s' (%s) to typeclass '%s'." % (obj.name,
old_typeclass_path,
typeclass)
old_typeclass_path,
typeclass)
caller.msg(string)
@ -1410,6 +1478,7 @@ class CmdWipe(ObjManipCommand):
string = string % (",".join(attrs), obj.name)
caller.msg(string)
class CmdLock(ObjManipCommand):
"""
lock - assign a lock definition to an object
@ -1493,6 +1562,7 @@ class CmdLock(ObjManipCommand):
return
caller.msg(obj.locks)
class CmdExamine(ObjManipCommand):
"""
examine - detailed info on objects
@ -1545,7 +1615,9 @@ class CmdExamine(ObjManipCommand):
else:
db_attr = [(attr.key, attr.value) for attr in obj.db_attributes.all()]
try:
ndb_attr = [(aname, avalue) for aname, avalue in obj.ndb.__dict__.items() if not aname.startswith("_")]
ndb_attr = [(aname, avalue)
for aname, avalue in obj.ndb.__dict__.items()
if not aname.startswith("_")]
except Exception:
ndb_attr = None
string = ""
@ -1572,7 +1644,8 @@ class CmdExamine(ObjManipCommand):
if hasattr(obj, "sessid") and obj.sessid:
string += "\n{wsession{n: %s" % obj.sessid
elif hasattr(obj, "sessions") and obj.sessions:
string += "\n{wsession(s){n: %s" % (", ".join(str(sess.sessid) for sess in obj.sessions))
string += "\n{wsession(s){n: %s" % (", ".join(str(sess.sessid)
for sess in obj.sessions))
if hasattr(obj, "has_player") and obj.has_player:
string += "\n{wPlayer{n: {c%s{n" % obj.player.name
perms = obj.player.permissions.all()
@ -1581,7 +1654,8 @@ class CmdExamine(ObjManipCommand):
elif not perms:
perms = ["<None>"]
string += "\n{wPlayer Perms{n: %s" % (", ".join(perms))
string += "\n{wTypeclass{n: %s (%s)" % (obj.typeclass.typename, obj.typeclass_path)
string += "\n{wTypeclass{n: %s (%s)" % (obj.typeclass.typename,
obj.typeclass_path)
if hasattr(obj, "location"):
string += "\n{wLocation{n: %s" % obj.location
if obj.location:
@ -1610,14 +1684,20 @@ class CmdExamine(ObjManipCommand):
if not (len(obj.cmdset.all()) == 1 and obj.cmdset.current.key == "Empty"):
# list the current cmdsets
all_cmdsets = obj.cmdset.all() + (hasattr(obj, "player") and obj.player and obj.player.cmdset.all() or [])
all_cmdsets += hasattr(obj, "sessid") and hasattr(obj, "player") and obj.player.get_session(obj.sessid).cmdset.all()
all_cmdsets.sort(key=lambda x:x.priority, reverse=True)
string += "\n{wStored Cmdset(s){n:\n %s" % ("\n ".join("%s [%s] (prio %s)" %
(cmdset.path, cmdset.key, cmdset.priority) for cmdset in all_cmdsets))
all_cmdsets = (obj.cmdset.all() +
(hasattr(obj, "player") and
obj.player and obj.player.cmdset.all() or []))
all_cmdsets += (hasattr(obj, "sessid") and
hasattr(obj, "player") and
obj.player.get_session(obj.sessid).cmdset.all())
all_cmdsets.sort(key=lambda x: x.priority, reverse=True)
string += "\n{wStored Cmdset(s){n:\n %s" % ("\n ".join("%s [%s] (prio %s)" % \
(cmdset.path, cmdset.key, cmdset.priority)
for cmdset in all_cmdsets))
# list the commands available to this object
avail_cmdset = sorted([cmd.key for cmd in avail_cmdset if cmd.access(obj, "cmd")])
avail_cmdset = sorted([cmd.key for cmd in avail_cmdset
if cmd.access(obj, "cmd")])
cmdsetstr = utils.fill(", ".join(avail_cmdset), indent=2)
string += "\n{wCommands available to %s (all cmdsets + exits and external cmds){n:\n %s" % (obj.key, cmdsetstr)
@ -1644,10 +1724,10 @@ class CmdExamine(ObjManipCommand):
string += "\n{wCharacters{n: %s" % ", ".join(["{c%s{n" % pobj.name for pobj in pobjs])
if things:
string += "\n{wContents{n: %s" % ", ".join([cont.name for cont in obj.contents
if cont not in exits and cont not in pobjs])
separator = "-"*78
if cont not in exits and cont not in pobjs])
separator = "-" * 78
#output info
return '%s\n%s\n%s' % ( separator, string.strip(), separator )
return '%s\n%s\n%s' % (separator, string.strip(), separator)
def func(self):
"Process command"
@ -1686,7 +1766,7 @@ class CmdExamine(ObjManipCommand):
obj_attrs = objdef['attrs']
self.player_mode = utils.inherits_from(caller, "src.players.player.Player") or \
"player" in self.switches or obj_name.startswith('*')
"player" in self.switches or obj_name.startswith('*')
if self.player_mode:
try:
obj = caller.search_player(obj_name.lstrip('*'))
@ -1699,7 +1779,8 @@ class CmdExamine(ObjManipCommand):
continue
if not obj.access(caller, 'examine'):
#If we don't have special info access, just look at the object instead.
#If we don't have special info access, just look
# at the object instead.
caller.execute_cmd('look %s' % obj_name)
continue
@ -1727,7 +1808,8 @@ class CmdFind(MuxCommand):
Searches the database for an object of a particular name or dbref.
Use *playername to search for a player. The switches allows for
limiting object matches to certain game entities. Dbrefmin and dbrefmax
limits matches to within the given dbrefs, or above/below if only one is given.
limits matches to within the given dbrefs, or above/below if only
one is given.
"""
key = "@find"
@ -1772,11 +1854,13 @@ class CmdFind(MuxCommand):
if not low <= int(result.id) <= high:
string += "\n {RNo match found for '%s' within the given dbref limits.{n" % searchstring
else:
string += "\n{g %s(%s) - %s{n" % (result.key, result.dbref, result.typeclass.path)
string += "\n{g %s(%s) - %s{n" % (result.key, result.dbref,
result.typeclass.path)
else:
# Not a player/dbref search but a wider search; build a queryset.
results = ObjectDB.objects.filter(db_key__istartswith=searchstring, id__gte=low, id__lte=high)
results = ObjectDB.objects.filter(db_key__istartswith=searchstring,
id__gte=low, id__lte=high)
if "room" in switches:
results = results.filter(db_location__isnull=True)
if "exit" in switches:
@ -1909,12 +1993,14 @@ class CmdTeleport(MuxCommand):
use_destination = False
# try the teleport
if obj_to_teleport.move_to(destination, quiet=tel_quietly, emit_to_obj=caller,
if obj_to_teleport.move_to(destination, quiet=tel_quietly,
emit_to_obj=caller,
use_destination=use_destination):
if obj_to_teleport == caller:
caller.msg("Teleported to %s." % destination)
else:
caller.msg("Teleported %s -> %s." % (obj_to_teleport, destination))
caller.msg("Teleported %s -> %s." % (obj_to_teleport,
destination))
class CmdScript(MuxCommand):
@ -1931,9 +2017,10 @@ class CmdScript(MuxCommand):
If no script path/key is given, lists all scripts active on the given
object.
Script path can be given from the base location for scripts as given in
settings. If adding a new script, it will be started automatically (no /start
switch is needed). Using the /start or /stop switches on an object without
specifying a script key/path will start/stop ALL scripts on the object.
settings. If adding a new script, it will be started automatically
(no /start switch is needed). Using the /start or /stop switches on an
object without specifying a script key/path will start/stop ALL scripts on
the object.
"""
key = "@script"
@ -1970,7 +2057,8 @@ class CmdScript(MuxCommand):
string += "%s scripts started on %s." % (num, obj.key)
elif "stop" in self.switches:
for script in scripts:
string += "Stopping script %s on %s." % (script.key, obj.key)
string += "Stopping script %s on %s." % (script.key,
obj.key)
script.stop()
string = string.strip()
obj.scripts.validate()

View file

@ -1,14 +1,15 @@
"""
This module ties together all the commands default Character objects have
available (i.e. IC commands). Note that some commands, such as communication-commands are
instead put on the player level, in the Player cmdset. Player commands remain
available also to Characters.
available (i.e. IC commands). Note that some commands, such as
communication-commands are instead put on the player level, in the
Player cmdset. Player commands remain available also to Characters.
"""
from src.commands.cmdset import CmdSet
from src.commands.default import general, help, admin, system
from src.commands.default import building
from src.commands.default import batchprocess
class CharacterCmdSet(CmdSet):
"""
Implements the default command set.

View file

@ -13,6 +13,7 @@ from src.commands.cmdset import CmdSet
from src.commands.default import help, comms, admin, system
from src.commands.default import building, player
class PlayerCmdSet(CmdSet):
"""
Implements the player command set.

View file

@ -6,6 +6,7 @@ of the state instance in this module.
from src.commands.cmdset import CmdSet
from src.commands.default import unloggedin
class UnloggedinCmdSet(CmdSet):
"""
Sets up the unlogged cmdset.

View file

@ -22,6 +22,7 @@ __all__ = ("CmdAddCom", "CmdDelCom", "CmdAllCom",
"CmdPage", "CmdIRC2Chan", "CmdIMC2Chan", "CmdIMCInfo",
"CmdIMCTell", "CmdRSS2Chan")
def find_channel(caller, channelname, silent=False, noaliases=False):
"""
Helper function for searching for a single channel with
@ -30,7 +31,8 @@ def find_channel(caller, channelname, silent=False, noaliases=False):
channels = ChannelDB.objects.channel_search(channelname)
if not channels:
if not noaliases:
channels = [chan for chan in ChannelDB.objects.get_all_channels() if channelname in chan.aliases.all()]
channels = [chan for chan in ChannelDB.objects.get_all_channels()
if channelname in chan.aliases.all()]
if channels:
return channels[0]
if not silent:
@ -43,6 +45,7 @@ def find_channel(caller, channelname, silent=False, noaliases=False):
return None
return channels[0]
class CmdAddCom(MuxPlayerCommand):
"""
addcom - subscribe to a channel with optional alias
@ -57,7 +60,7 @@ class CmdAddCom(MuxPlayerCommand):
"""
key = "addcom"
aliases = ["aliaschan","chanalias"]
aliases = ["aliaschan", "chanalias"]
help_category = "Comms"
locks = "cmd:not pperm(channel_banned)"
@ -168,6 +171,7 @@ class CmdDelCom(MuxPlayerCommand):
else:
self.msg("You had no such alias defined for this channel.")
class CmdAllCom(MuxPlayerCommand):
"""
allcom - operate on all channels
@ -197,8 +201,10 @@ class CmdAllCom(MuxPlayerCommand):
return
if args == "on":
# get names of all channels available to listen to and activate them all
channels = [chan for chan in ChannelDB.objects.get_all_channels() if chan.access(caller, 'listen')]
# get names of all channels available to listen to
# and activate them all
channels = [chan for chan in ChannelDB.objects.get_all_channels()
if chan.access(caller, 'listen')]
for channel in channels:
caller.execute_cmd("addcom %s" % channel.key)
elif args == "off":
@ -208,13 +214,15 @@ class CmdAllCom(MuxPlayerCommand):
caller.execute_cmd("delcom %s" % channel.key)
elif args == "destroy":
# destroy all channels you control
channels = [chan for chan in ChannelDB.objects.get_all_channels() if chan.access(caller, 'control')]
channels = [chan for chan in ChannelDB.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.
string = "\n{CChannel subscriptions{n"
channels = [chan for chan in ChannelDB.objects.get_all_channels() if chan.access(caller, 'listen')]
channels = [chan for chan in ChannelDB.objects.get_all_channels()
if chan.access(caller, 'listen')]
if not channels:
string += "No channels."
for channel in channels:
@ -229,6 +237,7 @@ class CmdAllCom(MuxPlayerCommand):
# wrong input
self.msg("Usage: allcom on | off | who | clear")
class CmdChannels(MuxPlayerCommand):
"""
@clist
@ -253,7 +262,8 @@ class CmdChannels(MuxPlayerCommand):
caller = self.caller
# all channels we have available to listen to
channels = [chan for chan in ChannelDB.objects.get_all_channels() if chan.access(caller, 'listen')]
channels = [chan for chan in ChannelDB.objects.get_all_channels()
if chan.access(caller, 'listen')]
#print channels
if not channels:
self.msg("No channels available.")
@ -264,28 +274,39 @@ class CmdChannels(MuxPlayerCommand):
if self.cmdstring == "comlist":
# just display the subscribed channels with no extra info
comtable = prettytable.PrettyTable(["{wchannel","{wmy aliases", "{wdescription"])
comtable = prettytable.PrettyTable(["{wchannel",
"{wmy aliases",
"{wdescription"])
for chan in subs:
clower = chan.key.lower()
nicks = caller.nicks.get(category="channel")
comtable.add_row(["%s%s" % (chan.key, chan.aliases.all() and "(%s)" % ",".join(chan.aliases.all()) or ""),
"%s".join(nick for nick in make_iter(nicks) if nick and nick.lower()==clower),
comtable.add_row(["%s%s" % (chan.key, chan.aliases.all() and
"(%s)" % ",".join(chan.aliases.all()) or ""),
"%s".join(nick for nick in make_iter(nicks)
if nick and nick.lower() == clower),
chan.db.desc])
caller.msg("\n{wChannel subscriptions{n (use {w@channels{n to list all, {waddcom{n/{wdelcom{n to sub/unsub):{n\n%s" % comtable)
else:
# full listing (of channels caller is able to listen to)
comtable = prettytable.PrettyTable(["{wsub","{wchannel","{wmy aliases","{wlocks","{wdescription"])
comtable = prettytable.PrettyTable(["{wsub",
"{wchannel",
"{wmy aliases",
"{wlocks",
"{wdescription"])
for chan in channels:
clower = chan.key.lower()
nicks = caller.nicks.get(category="channel")
nicks = nicks or []
comtable.add_row([chan in subs and "{gYes{n" or "{rNo{n",
"%s%s" % (chan.key, chan.aliases.all() and "(%s)" % ",".join(chan.aliases.all()) or ""),
"%s".join(nick for nick in make_iter(nicks) if nick.lower()==clower),
"%s%s" % (chan.key, chan.aliases.all() and
"(%s)" % ",".join(chan.aliases.all()) or ""),
"%s".join(nick for nick in make_iter(nicks)
if nick.lower() == clower),
str(chan.locks),
chan.db.desc])
caller.msg("\n{wAvailable channels{n (use {wcomlist{n,{waddcom{n and {wdelcom{n to manage subscriptions):\n%s" % comtable)
class CmdCdestroy(MuxPlayerCommand):
"""
@cdestroy
@ -322,6 +343,7 @@ class CmdCdestroy(MuxPlayerCommand):
CHANNELHANDLER.update()
self.msg("Channel '%s' was destroyed." % channel)
class CmdCBoot(MuxPlayerCommand):
"""
@cboot
@ -382,6 +404,7 @@ class CmdCBoot(MuxPlayerCommand):
channel.disconnect_from(player)
CHANNELHANDLER.update()
class CmdCemit(MuxPlayerCommand):
"""
@cemit - send a message to channel
@ -429,6 +452,7 @@ class CmdCemit(MuxPlayerCommand):
string = "Sent to channel %s: %s" % (channel.key, message)
self.msg(string)
class CmdCWho(MuxPlayerCommand):
"""
@cwho
@ -466,6 +490,7 @@ class CmdCWho(MuxPlayerCommand):
string += " <None>"
self.msg(string.strip())
class CmdChannelCreate(MuxPlayerCommand):
"""
@ccreate
@ -508,7 +533,10 @@ class CmdChannelCreate(MuxPlayerCommand):
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 = create.create_channel(channame,
aliases,
description,
locks=lockstring)
new_chan.connect_to(caller)
self.msg("Created channel %s and connected to it." % new_chan.key)
@ -593,7 +621,9 @@ class CmdCdesc(MuxPlayerCommand):
# set the description
channel.db.desc = self.rhs
channel.save()
self.msg("Description of channel '%s' set to '%s'." % (channel.key, self.rhs))
self.msg("Description of channel '%s' set to '%s'." % (channel.key,
self.rhs))
class CmdPage(MuxPlayerCommand):
"""
@ -624,15 +654,16 @@ class CmdPage(MuxPlayerCommand):
caller = self.caller
# get the messages we've sent (not to channels)
pages_we_sent = Msg.objects.get_messages_by_sender(caller, exclude_channel_messages=True)
pages_we_sent = Msg.objects.get_messages_by_sender(caller,
exclude_channel_messages=True)
# get last messages we've got
pages_we_got = Msg.objects.get_messages_by_receiver(caller)
if 'last' in self.switches:
if pages_we_sent:
recv = ",".join(obj.key for obj in pages_we_sent[-1].receivers)
self.msg("You last paged {c%s{n:%s" % (recv, pages_we_sent[-1].message))
self.msg("You last paged {c%s{n:%s" % (recv,
pages_we_sent[-1].message))
return
else:
self.msg("You haven't paged anyone yet.")
@ -654,12 +685,12 @@ class CmdPage(MuxPlayerCommand):
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),
",".join(obj.key for obj in page.senders),
"{n,{c ".join([obj.name for obj in page.receivers]),
page.message)
for page in lastpages)
template = "{w%s{n {c%s{n to {c%s{n: %s"
lastpages = "\n ".join(template %
(utils.datetime_format(page.date_sent),
",".join(obj.key for obj in page.senders),
"{n,{c ".join([obj.name for obj in page.receivers]),
page.message) for page in lastpages)
if lastpages:
string = "Your latest pages:\n %s" % lastpages
@ -668,7 +699,6 @@ class CmdPage(MuxPlayerCommand):
self.msg(string)
return
# We are sending. Build a list of targets
if not self.lhs:
@ -722,7 +752,7 @@ class CmdPage(MuxPlayerCommand):
else:
received.append("{c%s{n" % pobj.name)
if rstrings:
self.msg(rstrings = "\n".join(rstrings))
self.msg(rstrings="\n".join(rstrings))
self.msg("You paged %s with: '%s'." % (", ".join(received), message))
@ -734,18 +764,20 @@ class CmdIRC2Chan(MuxCommand):
@irc2chan[/switches] <evennia_channel> = <ircnetwork> <port> <#irchannel> <botname>
Switches:
/disconnect - this will delete the bot and remove the irc connection to the channel.
/disconnect - this will delete the bot and remove the irc connection
to the channel.
/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 {w@services{n
command instead.
"""
key = "@irc2chan"
@ -780,19 +812,25 @@ class CmdIRC2Chan(MuxCommand):
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_network, irc_port, irc_channel, irc_botname = \
[part.strip() for part in self.rhs.split(None, 3)]
irc_channel = "#%s" % irc_channel
except Exception:
string = "IRC bot definition '%s' is not valid." % self.rhs
self.msg(string)
return
if 'disconnect' in self.switches or 'remove' in self.switches or 'delete' in self.switches:
if('disconnect' in self.switches or 'remove' in self.switches or
'delete' in self.switches):
chanmatch = find_channel(self.caller, channel, silent=True)
if chanmatch:
channel = chanmatch.key
ok = irc.delete_connection(channel, irc_network, irc_port, irc_channel, irc_botname)
ok = irc.delete_connection(channel,
irc_network,
irc_port,
irc_channel,
irc_botname)
if not ok:
self.msg("IRC connection/bot could not be removed, does it exist?")
else:
@ -802,12 +840,17 @@ class CmdIRC2Chan(MuxCommand):
channel = find_channel(self.caller, channel)
if not channel:
return
ok = irc.create_connection(channel, irc_network, irc_port, irc_channel, irc_botname)
ok = irc.create_connection(channel,
irc_network,
irc_port,
irc_channel,
irc_botname)
if not ok:
self.msg("This IRC connection already exists.")
return
self.msg("Connection created. Starting IRC bot.")
class CmdIMC2Chan(MuxCommand):
"""
imc2chan - link an evennia channel to imc2
@ -863,9 +906,10 @@ class CmdIMC2Chan(MuxCommand):
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.
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.
ok = imc2.delete_connection(channel, imc2_channel)
if not ok:
self.msg("IMC2 connection could not be removed, does it exist?")
@ -932,7 +976,8 @@ class CmdIMCInfo(MuxCommand):
IMC2_CLIENT.send_packet(pck.IMC2PacketIceRefresh())
self.msg("IMC2 lists were re-synced.")
elif "games" in self.switches or "muds" in self.switches or self.cmdstring == "@imclist":
elif("games" in self.switches or "muds" in self.switches
or self.cmdstring == "@imclist"):
# list muds
from src.comms.imc2 import IMC2_MUDLIST
@ -956,9 +1001,13 @@ class CmdIMCInfo(MuxCommand):
return
from src.comms.imc2 import IMC2_CLIENT
self.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", target=self.args)
IMC2_CLIENT.msg_imc2(None,
from_obj=self.caller,
packet_type="imcwhois",
target=self.args)
elif not self.switches or "channels" in self.switches or self.cmdstring == "@imcchanlist":
elif(not self.switches or "channels" in self.switches or
self.cmdstring == "@imcchanlist"):
# show channels
from src.comms.imc2 import IMC2_CHANLIST, IMC2_CLIENT
@ -968,7 +1017,8 @@ class CmdIMCInfo(MuxCommand):
table = prettytable.PrettyTable(["Full name", "Name", "Owner", "Perm", "Policy"])
for chan in channels:
nchans += 1
table.add_row([chan.name, chan.localname, chan.owner, chan.level, chan.policy])
table.add_row([chan.name, chan.localname, chan.owner,
chan.level, chan.policy])
string += "\n{wChannels on %s:{n\n%s" % (IMC2_CLIENT.factory.network, table)
string += "\n%i Channels found." % nchans
self.msg(string)
@ -977,6 +1027,7 @@ class CmdIMCInfo(MuxCommand):
string = "Usage: imcinfo|imcchanlist|imclist"
self.msg(string)
# unclear if this is working ...
class CmdIMCTell(MuxCommand):
"""
@ -1028,19 +1079,21 @@ class CmdRSS2Chan(MuxCommand):
@rss2chan[/switches] <evennia_channel> = <rss_url>
Switches:
/disconnect - this will stop the feed and remove the connection to the channel.
/disconnect - this will stop the feed and remove the connection to the
channel.
/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
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).
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).
When disconnecting you need to supply both the channel and url again so as to identify
the connection uniquely.
When disconnecting you need to supply both the channel and url again so as
to identify the connection uniquely.
"""
key = "@rss2chan"
@ -1075,7 +1128,8 @@ class CmdRSS2Chan(MuxCommand):
channel = self.lhs
url = self.rhs
if 'disconnect' in self.switches or 'remove' in self.switches or 'delete' in self.switches:
if('disconnect' in self.switches or 'remove' in self.switches or
'delete' in self.switches):
chanmatch = find_channel(self.caller, channel, silent=True)
if chanmatch:
channel = chanmatch.key

View file

@ -13,6 +13,7 @@ __all__ = ("CmdHome", "CmdLook", "CmdNick",
AT_SEARCH_RESULT = utils.variable_from_module(*settings.SEARCH_AT_RESULT.rsplit('.', 1))
class CmdHome(MuxCommand):
"""
home
@ -38,6 +39,7 @@ class CmdHome(MuxCommand):
caller.move_to(home)
caller.msg("There's no place like home ...")
class CmdLook(MuxCommand):
"""
look
@ -126,7 +128,9 @@ class CmdNick(MuxCommand):
nicks = caller.nicks.get(category="channel")
if 'list' in switches:
table = prettytable.PrettyTable(["{wNickType", "{wNickname", "{wTranslates-to"])
table = prettytable.PrettyTable(["{wNickType",
"{wNickname",
"{wTranslates-to"])
for nick in nicks:
table.add_row([nick.db_category, nick.db_key, nick.db_data])
string = "{wDefined Nicks:{n\n%s" % table
@ -170,6 +174,7 @@ class CmdNick(MuxCommand):
caller.nicks.add(nick, real, category=switch)
caller.msg(string)
class CmdInventory(MuxCommand):
"""
inventory
@ -198,6 +203,7 @@ class CmdInventory(MuxCommand):
string = "{wYou are carrying:\n%s" % table
self.caller.msg(string)
class CmdGet(MuxCommand):
"""
get
@ -327,7 +333,6 @@ class CmdGive(MuxCommand):
target.msg("%s gives you %s." % (caller.key, to_give.key))
class CmdSay(MuxCommand):
"""
say
@ -365,6 +370,7 @@ class CmdSay(MuxCommand):
caller.location.msg_contents(emit_string,
exclude=caller)
class CmdPose(MuxCommand):
"""
pose - strike a pose
@ -407,6 +413,7 @@ class CmdPose(MuxCommand):
msg = "%s%s" % (self.caller.name, self.args)
self.caller.location.msg_contents(msg)
class CmdAccess(MuxCommand):
"""
access - show access groups
@ -440,5 +447,4 @@ class CmdAccess(MuxCommand):
string += "\nCharacter {c%s{n: %s" % (caller.key, cperms)
if hasattr(caller, 'player'):
string += "\nPlayer {c%s{n: %s" % (caller.player.key, pperms)
caller.msg(string)
caller.msg(string)

View file

@ -18,7 +18,8 @@ from src.commands.default.muxcommand import MuxCommand
__all__ = ("CmdHelp", "CmdSetHelp")
SEP = "{C" + "-"*78 + "{n"
SEP = "{C" + "-" * 78 + "{n"
def format_help_entry(title, help_text, aliases=None, suggested=None):
"""
@ -38,6 +39,7 @@ def format_help_entry(title, help_text, aliases=None, suggested=None):
string += "\n" + SEP
return string
def format_help_list(hdict_cmds, hdict_db):
"""
Output a category-ordered list. The input are the
@ -57,6 +59,7 @@ def format_help_list(hdict_cmds, hdict_db):
string += "{G" + fill(", ".join(sorted([str(topic) for topic in hdict_db[category]]))) + "{n"
return string
class CmdHelp(Command):
"""
The main help command
@ -129,13 +132,18 @@ class CmdHelp(Command):
# try an exact command auto-help match
match = [cmd for cmd in all_cmds if cmd == query]
if len(match) == 1:
self.msg(format_help_entry(match[0].key, match[0].__doc__, aliases=match[0].aliases, suggested=suggestions))
self.msg(format_help_entry(match[0].key,
match[0].__doc__,
aliases=match[0].aliases,
suggested=suggestions))
return
# try an exact database help entry match
match = list(HelpEntry.objects.find_topicmatch(query, exact=True))
if len(match) == 1:
self.msg(format_help_entry(match[0].key, match[0].entrytext, suggested=suggestions))
self.msg(format_help_entry(match[0].key,
match[0].entrytext,
suggested=suggestions))
return
# try to see if a category name was entered
@ -147,6 +155,7 @@ class CmdHelp(Command):
# no exact matches found. Just give suggestions.
self.msg(format_help_entry("", "No help entry found for '%s'" % query, None, suggested=suggestions))
class CmdSetHelp(MuxCommand):
"""
@help - edit the help database
@ -169,9 +178,9 @@ class CmdSetHelp(MuxCommand):
@sethelp/append pickpocketing, ,attr(is_thief) = This steals ...
This command manipulates the help database. A help entry can be created,
appended/merged to and deleted. If you don't assign a category, the "General"
category will be used. If no lockstring is specified, default is to let everyone read
the help file.
appended/merged to and deleted. If you don't assign a category, the
"General" category will be used. If no lockstring is specified, default
is to let everyone read the help file.
"""
key = "@help"

View file

@ -74,8 +74,8 @@ class MuxCommand(Command):
The 'name[ with several words]' part is already dealt with by the
cmdhandler at this point, and stored in self.cmdname (we don't use
it here). The rest of the command is stored in self.args, which can start
with the switch indicator /.
it here). The rest of the command is stored in self.args, which can
start with the switch indicator /.
This parser breaks self.args into its constituents and stores them in the
following variables:

View file

@ -24,8 +24,9 @@ from src.utils import utils, create, search, prettytable
from settings import MAX_NR_CHARACTERS, MULTISESSION_MODE
# limit symbol import for API
__all__ = ("CmdOOCLook", "CmdIC", "CmdOOC", "CmdPassword", "CmdQuit", "CmdCharCreate",
"CmdEncoding", "CmdSessions", "CmdWho", "CmdColorTest", "CmdQuell")
__all__ = ("CmdOOCLook", "CmdIC", "CmdOOC", "CmdPassword", "CmdQuit",
"CmdCharCreate", "CmdEncoding", "CmdSessions", "CmdWho",
"CmdColorTest", "CmdQuell")
# force max nr chars to 1 if mode is 0 or 1
MAX_NR_CHARACTERS = MULTISESSION_MODE < 2 and 1 or MAX_NR_CHARACTERS
@ -58,7 +59,8 @@ class CmdOOCLook(MuxPlayerCommand):
"Hook method for when an argument is given."
player = self.caller
key = self.args.lower()
chars = dict((utils.to_str(char.key.lower()), char) for char in player.db._playable_characters)
chars = dict((utils.to_str(char.key.lower()), char)
for char in player.db._playable_characters)
looktarget = chars.get(key)
if looktarget:
self.msg(looktarget.return_appearance(player))
@ -101,7 +103,7 @@ class CmdOOCLook(MuxPlayerCommand):
string += "\n\nAvailable character%s (%i/unlimited):" % (string_s_ending, len(characters))
else:
string += "\n\nAvailable character%s%s:" % (string_s_ending,
MAX_NR_CHARACTERS > 1 and " (%i/%i)" % (len(characters), MAX_NR_CHARACTERS) or "")
MAX_NR_CHARACTERS > 1 and " (%i/%i)" % (len(characters), MAX_NR_CHARACTERS) or "")
for char in characters:
csessid = char.sessid
@ -171,8 +173,10 @@ class CmdCharCreate(MuxPlayerCommand):
typeclass = settings.BASE_CHARACTER_TYPECLASS
permissions = settings.PERMISSION_PLAYER_DEFAULT
new_character = create.create_object(typeclass, key=key, location=default_home,
home=default_home, permissions=permissions)
new_character = create.create_object(typeclass, key=key,
location=default_home,
home=default_home,
permissions=permissions)
# only allow creator (and immortals) to puppet this char
new_character.locks.add("puppet:id(%i) or pid(%i) or perm(Immortals) or pperm(Immortals)" %
(new_character.id, player.id))
@ -203,7 +207,8 @@ class CmdIC(MuxPlayerCommand):
"""
key = "@ic"
locks = "cmd:all()" # must be all() or different puppeted objects won't be able to access it.
# lockmust be all() for different puppeted objects to access it.
locks = "cmd:all()"
aliases = "@puppet"
help_category = "General"
@ -235,7 +240,8 @@ class CmdIC(MuxPlayerCommand):
if new_character.player:
# may not puppet an already puppeted character
if new_character.sessid and new_character.player == player:
# as a safeguard we allow "taking over chars from your own sessions.
# as a safeguard we allow "taking over chars from
# your own sessions.
player.msg("{c%s{n{R is now acted from another of your sessions.{n" % (new_character.name), sessid=new_character.sessid)
player.unpuppet_object(new_character.sessid)
self.msg("Taking over {c%s{n from another of your sessions." % new_character.name)
@ -251,6 +257,7 @@ class CmdIC(MuxPlayerCommand):
else:
self.msg("{rYou cannot become {C%s{n." % new_character.name)
class CmdOOC(MuxPlayerCommand):
"""
go ooc
@ -264,7 +271,8 @@ class CmdOOC(MuxPlayerCommand):
"""
key = "@ooc"
locks = "cmd:all()" # this must be all(), or different puppeted objects won't be able to access it.
# lock must be all(), for different puppeted objects to access it.
locks = "cmd:all()"
aliases = "@unpuppet"
help_category = "General"
@ -311,17 +319,22 @@ class CmdSessions(MuxPlayerCommand):
player = self.caller
sessions = player.get_all_sessions()
table = prettytable.PrettyTable(["{wsessid", "{wprotocol", "{whost", "{wpuppet/character", "{wlocation"])
for sess in sorted(sessions, key=lambda x:x.sessid):
table = prettytable.PrettyTable(["{wsessid",
"{wprotocol",
"{whost",
"{wpuppet/character",
"{wlocation"])
for sess in sorted(sessions, key=lambda x: x.sessid):
sessid = sess.sessid
char = player.get_puppet(sessid)
table.add_row([str(sessid), str(sess.protocol_key),
type(sess.address)==tuple and sess.address[0] or sess.address,
type(sess.address) == tuple and sess.address[0] or sess.address,
char and str(char) or "None",
char and str(char.location) or "N/A"])
string = "{wYour current session(s):{n\n%s" % table
self.msg(string)
class CmdWho(MuxPlayerCommand):
"""
who
@ -355,7 +368,13 @@ class CmdWho(MuxPlayerCommand):
nplayers = (SESSIONS.player_count())
if show_session_data:
table = prettytable.PrettyTable(["{wPlayer Name","{wOn for", "{wIdle", "{wRoom", "{wCmds", "{wProtocol", "{wHost"])
table = prettytable.PrettyTable(["{wPlayer Name",
"{wOn for",
"{wIdle",
"{wRoom",
"{wCmds",
"{wProtocol",
"{wHost"])
for session in session_list:
if not session.logged_in: continue
delta_cmd = time.time() - session.cmd_last_visible
@ -372,7 +391,8 @@ class CmdWho(MuxPlayerCommand):
else:
table = prettytable.PrettyTable(["{wPlayer name", "{wOn for", "{wIdle"])
for session in session_list:
if not session.logged_in: continue
if not session.logged_in:
continue
delta_cmd = time.time() - session.cmd_last_visible
delta_conn = time.time() - session.conn_time
plr_pobject = session.get_puppet()
@ -397,14 +417,16 @@ class CmdEncoding(MuxPlayerCommand):
clear - clear your custom encoding
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.
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.
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"
@ -444,6 +466,7 @@ class CmdEncoding(MuxPlayerCommand):
string = "Your custom text encoding was changed from '%s' to '%s'." % (old_encoding, encoding)
self.msg(string.strip())
class CmdPassword(MuxPlayerCommand):
"""
@password - set your password
@ -463,8 +486,8 @@ class CmdPassword(MuxPlayerCommand):
if not self.rhs:
self.msg("Usage: @password <oldpass> = <newpass>")
return
oldpass = self.lhslist[0] # this is already stripped by parse()
newpass = self.rhslist[0] # ''
oldpass = self.lhslist[0] # this is already stripped by parse()
newpass = self.rhslist[0] # ''
if not player.check_password(oldpass):
self.msg("The specified old password isn't correct.")
elif len(newpass) < 3:
@ -474,6 +497,7 @@ class CmdPassword(MuxPlayerCommand):
player.save()
self.msg("Password changed.")
class CmdQuit(MuxPlayerCommand):
"""
quit
@ -518,10 +542,10 @@ class CmdColorTest(MuxPlayerCommand):
Usage:
@color ansi|xterm256
Print a color map along with in-mud color codes, while testing what is supported in your client.
Choices are 16-color ansi (supported in most muds) or the 256-color xterm256 standard.
No checking is done to determine your client supports color - if not you will
see rubbish appear.
Print a color map along with in-mud color codes, while testing what is
supported in your client. Choices are 16-color ansi (supported in most
muds) or the 256-color xterm256 standard. No checking is done to determine
your client supports color - if not you will see rubbish appear.
"""
key = "@color"
locks = "cmd:all()"
@ -552,10 +576,10 @@ class CmdColorTest(MuxPlayerCommand):
ap = ansi.ANSI_PARSER
# ansi colors
# show all ansi color-related codes
col1 = ["%s%s{n" % (code, code.replace("{","{{")) for code, _ in ap.ext_ansi_map[:-1]]
col1 = ["%s%s{n" % (code, code.replace("{", "{{")) for code, _ in ap.ext_ansi_map[:-1]]
hi = "%ch"
col2 = ["%s%s{n" % (code, code.replace("%", "%%")) for code, _ in ap.mux_ansi_map[3:-2]]
col3 = ["%s%s{n" % (hi+code, (hi+code).replace("%", "%%")) for code, _ in ap.mux_ansi_map[3:-2]]
col3 = ["%s%s{n" % (hi + code, (hi + code).replace("%", "%%")) for code, _ in ap.mux_ansi_map[3:-2]]
table = utils.format_table([col1, col2, col3], extra_space=1)
string = "ANSI colors:"
for row in table:
@ -566,16 +590,16 @@ class CmdColorTest(MuxPlayerCommand):
elif self.args.startswith("x"):
# show xterm256 table
table = [[],[],[],[],[],[],[],[],[],[],[],[]]
table = [[], [], [], [], [], [], [], [], [], [], [], []]
for ir in range(6):
for ig in range(6):
for ib in range(6):
# foreground table
table[ir].append("%%c%i%i%i%s{n" % (ir,ig,ib, "{{%i%i%i" % (ir,ig,ib)))
table[ir].append("%%c%i%i%i%s{n" % (ir, ig, ib, "{{%i%i%i" % (ir, ig, ib)))
# background table
table[6+ir].append("%%cb%i%i%i%%c%i%i%i%s{n" % (ir,ig,ib,
5-ir,5-ig,5-ib,
"{{b%i%i%i" % (ir,ig,ib)))
table[6+ir].append("%%cb%i%i%i%%c%i%i%i%s{n" % (ir, ig, ib,
5 - ir, 5 - ig, 5 - ib,
"{{b%i%i%i" % (ir, ig, ib)))
table = self.table_format(table)
string = "Xterm256 colors (if not all hues show, your client might not report that it can handle xterm256):"
for row in table:
@ -586,6 +610,7 @@ class CmdColorTest(MuxPlayerCommand):
# malformed input
self.msg("Usage: @color ansi|xterm256")
class CmdQuell(MuxPlayerCommand):
"""
Quelling permissions
@ -604,7 +629,7 @@ class CmdQuell(MuxPlayerCommand):
"""
key = "@quell"
aliases =["@unquell"]
aliases = ["@unquell"]
locks = "cmd:all()"
help_category = "General"
@ -613,8 +638,9 @@ class CmdQuell(MuxPlayerCommand):
if self.sessid:
char = player.get_puppet(self.sessid)
if char:
# we are already puppeting an object. We need to reset the lock caches
# (otherwise the superuser status change won't be visible until repuppet)
# we are already puppeting an object. We need to reset
# the lock caches (otherwise the superuser status change
# won't be visible until repuppet)
char.locks.reset()
player.locks.reset()

View file

@ -33,6 +33,7 @@ from src.commands.default.muxcommand import MuxCommand
# Command called when there is no input at line
# (i.e. an lone return key)
class SystemNoInput(MuxCommand):
"""
This is called when there is no input given
@ -44,11 +45,11 @@ class SystemNoInput(MuxCommand):
"Do nothing."
pass
#
# Command called when there was no match to the
# command name
#
class SystemNoMatch(MuxCommand):
"""
No command was found matching the given input.
@ -62,6 +63,7 @@ class SystemNoMatch(MuxCommand):
"""
self.caller.msg("Huh?")
#
# Command called when there were mulitple matches to the command.
#
@ -100,7 +102,7 @@ class SystemMultimatch(MuxCommand):
is_channel = ""
is_exit = hasattr(cmd, "is_exit") and cmd.is_exit
if is_exit and cmd.destination:
is_exit = " (exit to %s)" % cmd.destination
is_exit = " (exit to %s)" % cmd.destination
else:
is_exit = ""
@ -124,6 +126,7 @@ class SystemMultimatch(MuxCommand):
string = self.format_multimatches(self.caller, self.matches)
self.caller.msg(string)
# 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
@ -167,4 +170,4 @@ class SystemSendToChannel(MuxCommand):
return
msg = "[%s] %s: %s" % (channel.key, caller.name, msg)
msgobj = create.create_message(caller, msg, channels=[channel])
channel.msg(msgobj)
channel.msg(msgobj)

View file

@ -5,10 +5,13 @@ System commands
"""
import traceback
import os, datetime, time
from time import time as timemeasure
import os
import datetime
import time
import sys
import django, twisted
import django
import twisted
from time import time as timemeasure
from django.conf import settings
from src.server.caches import get_cache_sizes
@ -30,6 +33,7 @@ __all__ = ("CmdReload", "CmdReset", "CmdShutdown", "CmdPy",
"CmdScripts", "CmdObjects", "CmdService", "CmdAbout",
"CmdTime", "CmdServerLoad")
class CmdReload(MuxCommand):
"""
Reload the system
@ -55,6 +59,7 @@ class CmdReload(MuxCommand):
SESSIONS.announce_all(" Server restarting %s..." % reason)
SESSIONS.server.shutdown(mode='reload')
class CmdReset(MuxCommand):
"""
Reset and reboot the system
@ -110,6 +115,7 @@ class CmdShutdown(MuxCommand):
SESSIONS.portal_shutdown()
SESSIONS.server.shutdown(mode='shutdown')
class CmdPy(MuxCommand):
"""
Execute a snippet of python code
@ -157,18 +163,17 @@ class CmdPy(MuxCommand):
# import useful variables
import ev
available_vars = {'self':caller,
'me':caller,
'here':hasattr(caller, "location") and caller.location or None,
'ev':ev,
'inherits_from':utils.inherits_from}
available_vars = {'self': caller,
'me': caller,
'here': hasattr(caller, "location") and caller.location or None,
'ev': ev,
'inherits_from': utils.inherits_from}
try:
self.msg(">>> %s" % pycode, raw=True, sessid=self.sessid)
except TypeError:
self.msg(">>> %s" % pycode, raw=True)
mode = "eval"
try:
try:
@ -195,7 +200,7 @@ class CmdPy(MuxCommand):
errlist = errlist[4:]
ret = "\n".join("{n<<< %s" % line for line in errlist if line)
if ret != None:
if ret is not None:
try:
self.msg(ret, sessid=self.sessid)
except TypeError:
@ -210,7 +215,16 @@ def format_script_list(scripts):
if not scripts:
return "<No scripts>"
table = prettytable.PrettyTable(["{wid","{wobj","{wkey","{wintval","{wnext","{wrept","{wdb"," {wtypeclass","{wdesc"],align='r')
table = prettytable.PrettyTable(["{wid",
"{wobj",
"{wkey",
"{wintval",
"{wnext",
"{wrept",
"{wdb",
"{wtypeclass",
"{wdesc"],
align='r')
table.align = 'r'
for script in scripts:
nextrep = script.time_until_next_repeat()
@ -322,7 +336,6 @@ class CmdScripts(MuxCommand):
caller.msg(string)
class CmdObjects(MuxCommand):
"""
@objects - Give a summary of object types in database
@ -357,32 +370,37 @@ class CmdObjects(MuxCommand):
nother = nobjs - nchars - nrooms - nexits
# total object sum table
totaltable = prettytable.PrettyTable(["{wtype","{wcomment","{wcount", "{w%%"])
totaltable = prettytable.PrettyTable(["{wtype", "{wcomment", "{wcount", "{w%%"])
totaltable.align = 'l'
totaltable.add_row(["Characters", "(BASE_CHARACTER_TYPECLASS)", nchars, "%.2f" % ((float(nchars)/nobjs)*100)])
totaltable.add_row(["Rooms", "(location=None)", nrooms, "%.2f" % ((float(nrooms)/nobjs)*100)])
totaltable.add_row(["Exits", "(destination!=None)", nexits, "%.2f" % ((float(nexits)/nobjs)*100)])
totaltable.add_row(["Other", "", nother, "%.2f" % ((float(nother)/nobjs)*100)])
totaltable.add_row(["Characters", "(BASE_CHARACTER_TYPECLASS)", nchars, "%.2f" % ((float(nchars) / nobjs) * 100)])
totaltable.add_row(["Rooms", "(location=None)", nrooms, "%.2f" % ((float(nrooms) / nobjs) * 100)])
totaltable.add_row(["Exits", "(destination!=None)", nexits, "%.2f" % ((float(nexits) / nobjs) * 100)])
totaltable.add_row(["Other", "", nother, "%.2f" % ((float(nother) / nobjs) * 100)])
# typeclass table
typetable = prettytable.PrettyTable(["{wtypeclass","{wcount", "{w%%"])
typetable = prettytable.PrettyTable(["{wtypeclass", "{wcount", "{w%%"])
typetable.align = 'l'
dbtotals = ObjectDB.objects.object_totals()
for path, count in dbtotals.items():
typetable.add_row([path, count, "%.2f" % ((float(count)/nobjs)*100)])
typetable.add_row([path, count, "%.2f" % ((float(count) / nobjs) * 100)])
# last N table
objs = ObjectDB.objects.all().order_by("db_date_created")[max(0, nobjs - nlim):]
latesttable = prettytable.PrettyTable(["{wcreated","{wdbref","{wname","{wtypeclass"])
latesttable = prettytable.PrettyTable(["{wcreated",
"{wdbref",
"{wname",
"{wtypeclass"])
latesttable.align = 'l'
for obj in objs:
latesttable.add_row([utils.datetime_format(obj.date_created), obj.dbref, obj.key, obj.typeclass.path])
latesttable.add_row([utils.datetime_format(obj.date_created),
obj.dbref, obj.key, obj.typeclass.path])
string = "\n{wObject subtype totals (out of %i Objects):{n\n%s" % (nobjs, totaltable)
string += "\n{wObject typeclass distribution:{n\n%s" % typetable
string += "\n{wLast %s Objects created:{n\n%s" % (min(nobjs, nlim), latesttable)
caller.msg(string)
class CmdPlayers(MuxCommand):
"""
@players - give a summary of all registed Players
@ -397,6 +415,7 @@ class CmdPlayers(MuxCommand):
key = "@players"
aliases = ["@listplayers"]
locks = "cmd:perm(listplayers) or perm(Wizards)"
def func(self):
"List the players"
@ -413,10 +432,10 @@ class CmdPlayers(MuxCommand):
typetable = prettytable.PrettyTable(["{wtypeclass", "{wcount", "{w%%"])
typetable.align = 'l'
for path, count in dbtotals.items():
typetable.add_row([path, count, "%.2f" % ((float(count)/nplayers)*100)])
typetable.add_row([path, count, "%.2f" % ((float(count) / nplayers) * 100)])
# last N table
plyrs = PlayerDB.objects.all().order_by("db_date_created")[max(0, nplayers - nlim):]
latesttable = prettytable.PrettyTable(["{wcreated", "{wdbref","{wname","{wtypeclass"])
latesttable = prettytable.PrettyTable(["{wcreated", "{wdbref", "{wname", "{wtypeclass"])
latesttable.align = 'l'
for ply in plyrs:
latesttable.add_row([utils.datetime_format(ply.date_created), ply.dbref, ply.key, ply.typeclass.path])
@ -425,6 +444,7 @@ class CmdPlayers(MuxCommand):
string += "\n{wLast %s Players created:{n\n%s" % (min(nplayers, nlim), latesttable)
caller.msg(string)
class CmdService(MuxCommand):
"""
@service - manage services
@ -441,7 +461,8 @@ class CmdService(MuxCommand):
Service management system. Allows for the listing,
starting, and stopping of services. If no switches
are given, services will be listed. Note that to operate on the
service you have to supply the full (green or red) name as given in the list.
service you have to supply the full (green or red) name as given
in the list.
"""
key = "@service"
@ -520,6 +541,7 @@ class CmdService(MuxCommand):
caller.msg("Starting service '%s'." % self.args)
service.startService()
class CmdAbout(MuxCommand):
"""
@about - game engine info
@ -567,6 +589,7 @@ class CmdAbout(MuxCommand):
sversion)
self.caller.msg(string)
class CmdTime(MuxCommand):
"""
@time
@ -591,6 +614,7 @@ class CmdTime(MuxCommand):
table.add_row(["Server time stamp", datetime.datetime.now()])
self.caller.msg(str(table))
class CmdServerLoad(MuxCommand):
"""
server load and memory statistics
@ -648,20 +672,20 @@ class CmdServerLoad(MuxCommand):
pid = os.getpid()
rmem = float(os.popen('ps -p %d -o %s | tail -1' % (pid, "rss")).read()) / 1024.0 # resident memory
vmem = float(os.popen('ps -p %d -o %s | tail -1' % (pid, "vsz")).read()) / 1024.0 # virtual memory
pmem = float(os.popen('ps -p %d -o %s | tail -1' % (pid, "%mem")).read()) # percent of resident memory to total
pmem = float(os.popen('ps -p %d -o %s | tail -1' % (pid, "%mem")).read()) # percent of resident memory to total
rusage = resource.getrusage(resource.RUSAGE_SELF)
# load table
loadtable = prettytable.PrettyTable(["property", "statistic"])
loadtable.align = 'l'
loadtable.add_row(["Server load (1 min)","%g" % loadavg[0]])
loadtable.add_row(["Process ID","%g" % pid]),
loadtable.add_row(["Bytes per page","%g " % psize])
loadtable.add_row(["Server load (1 min)", "%g" % loadavg[0]])
loadtable.add_row(["Process ID", "%g" % pid]),
loadtable.add_row(["Bytes per page", "%g " % psize])
loadtable.add_row(["CPU time used (total)", "%s (%gs)" % (utils.time_format(rusage.ru_utime), rusage.ru_utime)])
loadtable.add_row(["CPU time used (user)", "%s (%gs)" % (utils.time_format(rusage.ru_stime), rusage.ru_stime)])
loadtable.add_row(["Memory usage","%g MB (%g%%)" % (rmem, pmem)])
loadtable.add_row(["Virtual address space\n {x(resident+swap+caching){n", "%g MB" % vmem])
loadtable.add_row(["Page faults","%g hard, %g soft, %g swapouts" % (rusage.ru_majflt, rusage.ru_minflt, rusage.ru_nswap)])
loadtable.add_row(["Page faults", "%g hard, %g soft, %g swapouts" % (rusage.ru_majflt, rusage.ru_minflt, rusage.ru_nswap)])
loadtable.add_row(["Disk I/O", "%g reads, %g writes" % (rusage.ru_inblock, rusage.ru_oublock)])
loadtable.add_row(["Network I/O", "%g in, %g out" % (rusage.ru_msgrcv, rusage.ru_msgsnd)])
loadtable.add_row(["Context switching", "%g vol, %g forced, %g signals" % (rusage.ru_nvcsw, rusage.ru_nivcsw, rusage.ru_nsignals)])
@ -669,17 +693,24 @@ class CmdServerLoad(MuxCommand):
string = "{wServer CPU and Memory load:{n\n%s" % loadtable
if not is_pypy:
# Cache size measurements are not available on PyPy because it lacks sys.getsizeof
# Cache size measurements are not available on PyPy
# because it lacks sys.getsizeof
# object cache size
cachedict = _idmapper.cache_size()
totcache = cachedict["_total"]
sorted_cache = sorted([(key, tup[0], tup[1]) for key, tup in cachedict.items() if key !="_total" and tup[0] > 0],
key=lambda tup: tup[2], reverse=True)
memtable = prettytable.PrettyTable(["entity name", "number", "cache (MB)", "idmapper %%"])
memtable = prettytable.PrettyTable(["entity name",
"number",
"cache (MB)",
"idmapper %%"])
memtable.align = 'l'
for tup in sorted_cache:
memtable.add_row([tup[0], "%i" % tup [1], "%5.2f" % tup[2], "%.2f" % (float(tup[2]/totcache[1])*100)])
memtable.add_row([tup[0],
"%i" % tup[1],
"%5.2f" % tup[2],
"%.2f" % (float(tup[2] / totcache[1]) * 100)])
# get sizes of other caches
attr_cache_info, field_cache_info, prop_cache_info = get_cache_sizes()

View file

@ -18,7 +18,7 @@ from django.utils.unittest import TestCase
from src.server.serversession import ServerSession
from src.objects.objects import Object, Character
from src.players.player import Player
from src.utils import create, utils, ansi
from src.utils import create, ansi
from src.server.sessionhandler import SESSIONS
from django.db.models.signals import pre_save
@ -33,16 +33,20 @@ _RE = re.compile(r"^\+|-+\+|\+-+|--*|\|", re.MULTILINE)
# Command testing
# ------------------------------------------------------------
def dummy(self, *args, **kwargs):
pass
SESSIONS.data_out = dummy
SESSIONS.disconnect = dummy
class TestObjectClass(Object):
def msg(self, text="", **kwargs):
"test message"
pass
class TestCharacterClass(Character):
def msg(self, text="", **kwargs):
"test message"
@ -52,17 +56,21 @@ class TestCharacterClass(Character):
if not self.ndb.stored_msg:
self.ndb.stored_msg = []
self.ndb.stored_msg.append(text)
class TestPlayerClass(Player):
def msg(self, text="", **kwargs):
"test message"
if not self.ndb.stored_msg:
self.ndb.stored_msg = []
self.ndb.stored_msg.append(text)
def _get_superuser(self):
"test with superuser flag"
return self.ndb.is_superuser
is_superuser = property(_get_superuser)
class CommandTest(TestCase):
"""
Tests a command
@ -93,6 +101,7 @@ class CommandTest(TestCase):
SESSIONS.portal_connect(session.get_sync_data())
SESSIONS.login(SESSIONS.session_from_sessid(self.CID), self.player, testmode=True)
def call(self, cmdobj, args, msg=None, cmdset=None, noansi=True, caller=None):
"""
Test a command by assigning all the needed
@ -141,6 +150,7 @@ class CommandTest(TestCase):
from src.commands.default import general
class TestGeneral(CommandTest):
CID = 1
def test_cmds(self):
self.call(general.CmdLook(), "here", "Room1\n room_desc")
self.call(general.CmdHome(), "", "You are already home")
@ -158,6 +168,7 @@ class TestGeneral(CommandTest):
self.call(general.CmdSay(), "Testing", "You say, \"Testing\"")
self.call(general.CmdAccess(), "", "Permission Hierarchy (climbing):")
from src.commands.default import help
from src.commands.default.cmdset_character import CharacterCmdSet
class TestHelp(CommandTest):
@ -167,6 +178,7 @@ class TestHelp(CommandTest):
self.call(help.CmdSetHelp(), "testhelp, General = This is a test", "Topic 'testhelp' was successfully created.")
self.call(help.CmdHelp(), "testhelp", "Help topic for testhelp", cmdset=CharacterCmdSet())
from src.commands.default import system
class TestSystem(CommandTest):
CID = 3
@ -179,6 +191,7 @@ class TestSystem(CommandTest):
self.call(system.CmdAbout(), "", None)
self.call(system.CmdServerLoad(), "", "Server CPU and Memory load:")
from src.commands.default import admin
class TestAdmin(CommandTest):
CID = 4
@ -190,6 +203,7 @@ class TestAdmin(CommandTest):
self.call(admin.CmdPerm(), "Char4b = Builders","Permission 'Builders' given to Char4b.")
self.call(admin.CmdBan(), "Char4", "NameBan char4 was added.")
from src.commands.default import player
class TestPlayer(CommandTest):
CID = 5
@ -209,6 +223,7 @@ class TestPlayer(CommandTest):
self.call(player.CmdCharCreate(), "Test1=Test char","Created new character Test1. Use @ic Test1 to enter the game", caller=self.player)
self.call(player.CmdQuell(), "", "Quelling Player permissions (immortals). Use @unquell to get them back.", caller=self.player)
from src.commands.default import building
class TestBuilding(CommandTest):
CID = 6
@ -239,6 +254,7 @@ class TestBuilding(CommandTest):
self.call(building.CmdScript(), "Obj6 = src.scripts.scripts.Script", "Script src.scripts.scripts.Script successfully added")
self.call(building.CmdTeleport(), "TestRoom1", "TestRoom1\nExits: back|Teleported to TestRoom1.")
from src.commands.default import comms
class TestComms(CommandTest):
CID = 7
@ -257,6 +273,7 @@ class TestComms(CommandTest):
self.call(comms.CmdCBoot(), "", "Usage: @cboot[/quiet] <channel> = <player> [:reason]") # noone else connected to boot
self.call(comms.CmdCdestroy(), "testchan" ,"Channel 'testchan' was destroyed.")
from src.commands.default import batchprocess
class TestBatchProcess(CommandTest):
CID = 8

View file

@ -14,7 +14,8 @@ from src.commands.default.muxcommand import MuxCommand
from src.commands.cmdhandler import CMD_LOGINSTART
# limit symbol import for API
__all__ = ("CmdUnconnectedConnect", "CmdUnconnectedCreate", "CmdUnconnectedQuit", "CmdUnconnectedLook", "CmdUnconnectedHelp")
__all__ = ("CmdUnconnectedConnect", "CmdUnconnectedCreate",
"CmdUnconnectedQuit", "CmdUnconnectedLook", "CmdUnconnectedHelp")
MULTISESSION_MODE = settings.MULTISESSION_MODE
CONNECTION_SCREEN_MODULE = settings.CONNECTION_SCREEN_MODULE
@ -26,6 +27,7 @@ except Exception:
if not CONNECTION_SCREEN:
CONNECTION_SCREEN = "\nEvennia: Error in CONNECTION_SCREEN MODULE (randomly picked connection screen variable is not a string). \nEnter 'help' for aid."
class CmdUnconnectedConnect(MuxCommand):
"""
Connect to the game.
@ -40,7 +42,7 @@ class CmdUnconnectedConnect(MuxCommand):
"""
key = "connect"
aliases = ["conn", "con", "co"]
locks = "cmd:all()" # not really needed
locks = "cmd:all()" # not really needed
def func(self):
"""
@ -92,12 +94,13 @@ class CmdUnconnectedConnect(MuxCommand):
# actually do the login. This will call all other hooks:
# session.at_login()
# player.at_init() # always called when object is loaded from disk
# player.at_init() # always called when object is loaded from disk
# player.at_pre_login()
# player.at_first_login() # only once
# player.at_post_login(sessid=sessid)
session.sessionhandler.login(session, player)
class CmdUnconnectedCreate(MuxCommand):
"""
Create a new account.
@ -134,8 +137,9 @@ class CmdUnconnectedCreate(MuxCommand):
# sanity checks
if not re.findall('^[\w. @+-]+$', playername) or not (0 < len(playername) <= 30):
# this echoes the restrictions made by django's auth module (except not
# allowing spaces, for convenience of logging in).
# this echoes the restrictions made by django's auth
# module (except not allowing spaces, for convenience of
# logging in).
string = "\n\r Playername can max be 30 characters or fewer. Letters, spaces, digits and @/./+/-/_ only."
session.msg(string)
return
@ -163,14 +167,14 @@ class CmdUnconnectedCreate(MuxCommand):
new_player = create.create_player(playername, None, password,
permissions=permissions)
except Exception, e:
session.msg("There was an error creating the default Player/Character:\n%s\n If this problem persists, contact an admin." % e)
logger.log_trace()
return
# This needs to be called so the engine knows this player is logging in for the first time.
# (so it knows to call the right hooks during login later)
# This needs to be called so the engine knows this player is
# logging in for the first time. (so it knows to call the right
# hooks during login later)
utils.init_new_player(new_player)
# join the new player to the public channel
@ -181,7 +185,6 @@ class CmdUnconnectedCreate(MuxCommand):
string = "New player '%s' could not connect to public channel!" % new_player.key
logger.log_errmsg(string)
if MULTISESSION_MODE < 2:
# if we only allow one character, create one with the same name as Player
# (in mode 2, the character must be created manually once logging in)
@ -210,12 +213,14 @@ class CmdUnconnectedCreate(MuxCommand):
session.msg(string % (playername, playername))
except Exception:
# We are in the middle between logged in and -not, so we have to handle tracebacks
# ourselves at this point. If we don't, we won't see any errors at all.
# We are in the middle between logged in and -not, so we have
# to handle tracebacks ourselves at this point. If we don't,
# we won't see any errors at all.
string = "%s\nThis is a bug. Please e-mail an admin if the problem persists."
session.msg(string % (traceback.format_exc()))
logger.log_errmsg(traceback.format_exc())
class CmdUnconnectedQuit(MuxCommand):
"""
We maintain a different version of the quit command
@ -230,7 +235,8 @@ class CmdUnconnectedQuit(MuxCommand):
"Simply close the connection."
session = self.caller
#session.msg("Good bye! Disconnecting ...")
session.sessionhandler.disconnect(session, "Good bye! Disconnecting ...")
session.sessionhandler.disconnect(session, "Good bye! Disconnecting.")
class CmdUnconnectedLook(MuxCommand):
"""
@ -247,6 +253,7 @@ class CmdUnconnectedLook(MuxCommand):
"Show the connect screen."
self.caller.msg(CONNECTION_SCREEN)
class CmdUnconnectedHelp(MuxCommand):
"""
This is an unconnected version of the help command,