Multiple fixes and cleanups - command parser excludes inaccessible commands already at parse level now. Fixed the functionality of a few of the lock functions to be more intuitive. Added functionality to the examine command to better show the commands available to an object.

This commit is contained in:
Griatch 2011-06-26 14:35:02 +00:00
parent 334c0b1d08
commit 95d672763b
17 changed files with 207 additions and 165 deletions

View file

@ -121,7 +121,8 @@ class Character(BaseCharacter):
else:
self.db.prelogout_location = self.location
self.location.msg_contents("%s has entered the game." % self.name)
self.location.at_object_receive(self, self.location)
class Room(BaseRoom):
"""
Rooms are like any object, except their location is None

View file

@ -31,16 +31,14 @@ command line. The process is as follows:
by the parser. The result is a list of command matches tied to their respective match object.
9) If we found no matches, branch to system command CMD_NOMATCH --> Finished
10) If we were unable to weed out multiple matches, branch CMD_MULTIMATCH --> Finished
11) If we have a single match, we now check user permissions.
not permissions: branch to system command CMD_NOPERM --> Finished
12) We analyze the matched command to determine if it is a channel-type command, that is
11) We analyze the matched command to determine if it is a channel-type command, that is
a command auto-created to represent a valid comm channel. If so, we see if CMD_CHANNEL is
custom-defined in the merged cmdset, or we launch the auto-created command
direclty --> Finished
13 We next check if this is an exit-type command, that is, a command auto-created to represent
12 We next check if this is an exit-type command, that is, a command auto-created to represent
an exit from this room. If so we check for custom CMD_EXIT in cmdset or launch
the auto-generated command directly --> Finished
14) At this point we have found a normal command. We assign useful variables to it, that
13) At this point we have found a normal command. We assign useful variables to it, that
will be available to the command coder at run-time.
When launching the command (normal, or system command both), two hook functions are called
@ -68,7 +66,6 @@ COMMAND_PARSER = utils.mod_import(*settings.COMMAND_PARSER.rsplit('.', 1))
CMD_NOINPUT = "__noinput_command"
CMD_NOMATCH = "__nomatch_command"
CMD_MULTIMATCH = "__multimatch_command"
CMD_NOPERM = "__noperm_command"
CMD_CHANNEL = "__send_to_channel"
class NoCmdSets(Exception):
@ -176,21 +173,9 @@ def cmdhandler(caller, raw_string, unloggedin=False, testing=False):
raise ExecSystemCommand(syscmd, sysarg)
# Parse the input string and match to available cmdset.
matches = COMMAND_PARSER(raw_string, cmdset)
#string ="Command candidates"
#for cand in cmd_candidates:
# string += "\n %s || %s" % (cand.cmdname, cand.args)
#caller.msg(string)
# Try to produce a unique match between the merged
# cmdset and the candidates.
# if unloggedin:
# matches = match_command(cmd_candidates, cmdset)
# else:
# matches = match_command(cmd_candidates, cmdset, caller)
#print "matches: ", matches
# This also checks for permissions, so all commands in match
# are commands the caller is allowed to call.
matches = COMMAND_PARSER(raw_string, cmdset, caller)
# Deal with matches
if not matches:
@ -216,15 +201,6 @@ def cmdhandler(caller, raw_string, unloggedin=False, testing=False):
match = matches[0]
cmdname, args, cmd = match[0], match[1], match[2]
# Check so we have permission to use this command.
if not cmd.access(caller):
cmd = cmdset.get(CMD_NOPERM)
if cmd:
sysarg = raw_string
else:
sysarg = "Huh? (type 'help' for help)"
raise ExecSystemCommand(cmd, sysarg)
# Check if this is a Channel match.
if hasattr(cmd, 'is_channel') and cmd.is_channel:
# even if a user-defined syscmd is not defined, the

View file

@ -5,7 +5,7 @@ replacing cmdparser function. The replacement parser must
return a CommandCandidates object.
"""
def cmdparser(raw_string, cmdset, match_index=None):
def cmdparser(raw_string, cmdset, caller, match_index=None):
"""
This function is called by the cmdhandler once it has
gathered all valid cmdsets for the calling player. raw_string
@ -61,6 +61,9 @@ def cmdparser(raw_string, cmdset, match_index=None):
# feed result back to parser iteratively
return cmdparser(new_raw_string, cmdset, 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')]
if len(matches) > 1:
# see if it helps to analyze the match with preserved case.
matches = [match for match in matches if raw_string.startswith(match[0])]
@ -82,7 +85,7 @@ def cmdparser(raw_string, cmdset, match_index=None):
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.
matches = [matches[match_index]]
matches = [matches[match_index]]
# no matter what we have at this point, we have to return it.
return matches

View file

@ -180,7 +180,8 @@ class CmdSet(object):
no_exits = False
no_objs = False
no_channels = False
permanent = False
def __init__(self, cmdsetobj=None, key=None):
"""
Creates a new CmdSet instance.
@ -272,6 +273,10 @@ class CmdSet(object):
if thiscmd == cmd:
return thiscmd
def count(self):
"Return number of commands in set"
return len(self.commands)
def get_system_cmds(self):
"""
Return system commands in the cmdset, defined as
@ -323,7 +328,7 @@ class CmdSet(object):
"""
Show all commands in cmdset when printing it.
"""
return ", ".join([str(cmd) for cmd in self.commands])
return ", ".join([str(cmd) for cmd in sorted(self.commands, key=lambda o:o.key)])
def __iter__(self):
"""

View file

@ -64,7 +64,7 @@ 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
from src.utils import logger, utils
from src.commands.cmdset import CmdSet
from src.server.models import ServerConfig
@ -163,7 +163,7 @@ class CmdSetHandler(object):
"Display current commands"
string = ""
merged = False
mergelist = []
if len(self.cmdset_stack) > 1:
# We have more than one cmdset in stack; list them all
num = 0
@ -176,19 +176,19 @@ class CmdSetHandler(object):
string += "\n %i: <%s (%s, prio %i)>: %s" % \
(snum, cmdset.key, mergetype,
cmdset.priority, cmdset)
mergelist.append(str(snum))
string += "\n"
merged = True
# Display the currently active cmdset, limited by self.obj's permissions
mergetype = self.mergetype_stack[-1]
if mergetype != self.current.mergetype:
merged_on = self.cmdset_stack[-2].key
mergetype = "custom %s on %s" % (mergetype, merged_on)
if merged:
string += " <Merged (%s, prio %i)>: %s" % (mergetype, self.current.priority, self.current)
if mergelist:
string += " <Merged %s (%s, prio %i)>: %s" % ("+".join(mergelist), mergetype, self.current.priority, self.current)
else:
string += " <%s (%s, prio %i)>: %s" % (self.current.key, mergetype, self.current.priority,
", ".join(cmd.key for cmd in self.current if cmd.access(self.obj, "cmd")))
", ".join(cmd.key for cmd in sorted(self.current, key=lambda o:o.key)))
return string.strip()
def update(self, init_mode=False):
@ -259,6 +259,8 @@ class CmdSetHandler(object):
that has to be documented.
"""
if callable(cmdset):
if not utils.inherits_from(cmdset, CmdSet):
raise Exception("Only CmdSets can be added to the cmdsethandler!")
cmdset = cmdset(self.obj)
elif isinstance(cmdset, basestring):
# this is (maybe) a python path. Try to import from cache.
@ -286,6 +288,8 @@ class CmdSetHandler(object):
See also the notes for self.add(), which applies here too.
"""
if callable(cmdset):
if not utils.inherits_from(cmdset, CmdSet):
raise Exception("Only CmdSets can be added to the cmdsethandler!")
cmdset = cmdset(self.obj)
elif isinstance(cmdset, basestring):
# this is (maybe) a python path. Try to import from cache.

View file

@ -31,6 +31,9 @@ class CommandMeta(type):
temp = []
if hasattr(mcs, 'permissions'):
mcs.locks = mcs.permissions
if not hasattr(mcs, 'locks'):
# default if one forgets to define completely
mcs.locks = "cmd:all()"
for lockstring in mcs.locks.split(';'):
if lockstring and not ':' in lockstring:
lockstring = "cmd:%s" % lockstring

View file

@ -218,8 +218,8 @@ class CmdBatchCommands(MuxCommand):
if not commands:
string = "'%s' not found.\nYou have to supply the python path "
string += "of the file relative to \nyour batch-file directory (%s)."
caller.msg(string % (python_path, settings.BASE_BATCHPROCESS_PATH))
string += "of the file relative to \none of your batch-file directories (%s)."
caller.msg(string % (python_path, ", ".join(settings.BASE_BATCHPROCESS_PATHS)))
return
switches = self.switches
@ -404,9 +404,10 @@ class CmdStateRR(MuxCommand):
def func(self):
caller = self.caller
if caller.ndb.batch_batchmode == "batch_code":
BATCHCODE.parse_file(caller.ndb.batch_pythonpath)
new_data = BATCHCODE.parse_file(caller.ndb.batch_pythonpath)
else:
BATCHCMD.parse_file(caller.ndb.batch_pythonpath)
new_data = BATCHCMD.parse_file(caller.ndb.batch_pythonpath)
caller.ndb.batch_stack = new_data
caller.msg(format_code("File reloaded. Staying on same command."))
show_curr(caller)

View file

@ -350,6 +350,7 @@ class CmdCreate(ObjManipCommand):
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.
Creates one or more new objects. If typeclass is given, the object
is created as a child of this typeclass. The typeclass script is
@ -405,6 +406,7 @@ class CmdCreate(ObjManipCommand):
obj.db.desc = "You see nothing special."
if 'drop' in self.switches:
if caller.location:
obj.home = caller.location
obj.move_to(caller.location, quiet=True)
caller.msg(string)
@ -482,7 +484,7 @@ class CmdDesc(MuxCommand):
return
desc = self.rhs
else:
obj = caller
obj = caller.location
desc = self.args
# storing the description
obj.db.desc = desc
@ -494,14 +496,17 @@ class CmdDestroy(MuxCommand):
@destroy - remove objects from the game
Usage:
@destroy[/<switches>] obj [,obj2, obj3, ...]
@delete ''
@destroy[/switches] [obj, obj2, obj3, [dbref-dbref], ...]
switches:
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
Destroys one or many objects.
Destroys one or many objects. If dbrefs are used, a range to delete can be
given, e.g. 4-10. Also the end points will be deleted.
"""
key = "@destroy"
@ -515,22 +520,22 @@ class CmdDestroy(MuxCommand):
caller = self.caller
if not self.args or not self.lhslist:
caller.msg("Usage: @destroy[/switches] obj [,obj2, obj3, ...]")
return
caller.msg("Usage: @destroy[/switches] [obj, obj2, obj3, [dbref-dbref],...]")
return ""
string = ""
for objname in self.lhslist:
def delobj(objname):
# helper function for deleting a single object
string = ""
obj = caller.search(objname)
if not obj:
self.caller.msg(" (Objects to destroy must either be local or specified with a unique dbref.)")
return
return ""
objname = obj.name
if not obj.access(caller, 'delete'):
string += "\nYou don't have permission to delete %s." % objname
continue
return "\nYou don't have permission to delete %s." % objname
if obj.player and not 'override' in self.switches:
string += "\nObject %s is controlled by an active player. Use /override to delete anyway." % objname
continue
return "\nObject %s is controlled by an active player. Use /override to delete anyway." % objname
had_exits = hasattr(obj, "exits") and obj.exits
had_objs = hasattr(obj, "contents") and any(obj for obj in obj.contents
if not (hasattr(obj, "exits") and obj not in obj.exits))
@ -544,9 +549,21 @@ class CmdDestroy(MuxCommand):
string += " Exits to and from %s were destroyed as well." % objname
if had_objs:
string += " Objects inside %s were moved to their homes." % objname
return string
string = ""
for objname in self.lhslist:
if '-' in objname:
# might be a range of dbrefs
dmin, dmax = [utils.dbref(part) for part in objname.split('-', 1)]
if dmin and dmax:
for dbref in range(int(dmin),int(dmax+1)):
string += delobj(str(dbref))
else:
string += delobj(objname)
if string:
caller.msg(string.strip())
class CmdDig(ObjManipCommand):
"""
@ -619,7 +636,7 @@ class CmdDig(ObjManipCommand):
to_exit = self.rhs_objs[0]
if not to_exit["name"]:
exit_to_string = \
"\nYou didn't give a name for the exit to the new room."
"\nNo exit created to new room."
elif not location:
exit_to_string = \
"\nYou cannot create an exit from a None-location."
@ -646,7 +663,7 @@ class CmdDig(ObjManipCommand):
back_exit = self.rhs_objs[1]
if not back_exit["name"]:
exit_back_string = \
"\nYou didn't give a name for the exit back here."
"\nNo back exit created."
elif not location:
exit_back_string = \
"\nYou cannot create an exit back to a None-location."
@ -1506,7 +1523,8 @@ class CmdExamine(ObjManipCommand):
"destination":"\n{wDestination{n: %s",
"perms":"\n{wPermissions{n: %s",
"locks":"\n{wLocks{n:",
"cmdset":"\n{wCurrent Cmdset (including permission checks){n:\n %s",
"cmdset":"\n{wCurrent Cmdset(s){n:\n %s",
"cmdset_avail":"\n{wActual commands available to %s (incl. lock-checks, external cmds etc){n:\n %s",
"scripts":"\n{wScripts{n:\n %s",
"exits":"\n{wExits{n: ",
"characters":"\n{wCharacters{n: ",
@ -1520,7 +1538,8 @@ class CmdExamine(ObjManipCommand):
"destination":"\nDestination: %s",
"perms":"\nPermissions: %s",
"locks":"\nLocks:",
"cmdset":"\nCurrent Cmdset (including permission checks):\n %s",
"cmdset":"\nCurrent Cmdset(s):\n %s",
"cmdset_avail":"\nActual commands available to %s (incl. lock-checks, external cmds, etc):\n %s",
"scripts":"\nScripts:\n %s",
"exits":"\nExits: ",
"characters":"\nCharacters: ",
@ -1556,8 +1575,18 @@ class CmdExamine(ObjManipCommand):
string += headers["locks"] + utils.fill("; ".join([lock for lock in locks.split(';')]), indent=6)
if not (len(obj.cmdset.all()) == 1 and obj.cmdset.current.key == "Empty"):
cmdsetstr = "\n".join([utils.fill(cmdset, indent=2) for cmdset in str(obj.cmdset).split("\n")])
# list the current cmdsets
cmdsetstr = "\n".join([utils.fill(cmdset, indent=2) for cmdset in str(obj.cmdset).split("\n")])
string += headers["cmdset"] % cmdsetstr
# list the actually available commands
from src.commands.cmdhandler import get_and_merge_cmdsets
avail_cmdset = get_and_merge_cmdsets(obj)
avail_cmdset = sorted([cmd.key for cmd in avail_cmdset if cmd.access(obj, "cmd")])
cmdsetstr = utils.fill(", ".join(avail_cmdset), indent=2)
string += headers["cmdset_avail"] % (obj.key, cmdsetstr)
if hasattr(obj, "scripts") and hasattr(obj.scripts, "all") and obj.scripts.all():
string += headers["scripts"] % obj.scripts
# add the attributes

View file

@ -229,11 +229,11 @@ class CmdInventory(MuxCommand):
# format item list into nice collumns
cols = [[],[]]
for item in items:
cols[0].append(item.name)
desc = utils.crop(item.db.desc)
cols[0].append(item.name)
desc = item.db.desc
if not desc:
desc = ""
cols[1].append(desc)
cols[1].append(utils.crop(str(desc)))
# auto-format the columns to make them evenly wide
ftable = utils.format_table(cols)
string = "You are carrying:"

View file

@ -26,7 +26,6 @@ from src.utils import create
from src.commands.cmdhandler import CMD_NOINPUT
from src.commands.cmdhandler import CMD_NOMATCH
from src.commands.cmdhandler import CMD_MULTIMATCH
from src.commands.cmdhandler import CMD_NOPERM
from src.commands.cmdhandler import CMD_CHANNEL
from src.commands.default.muxcommand import MuxCommand
@ -124,26 +123,8 @@ class SystemMultimatch(MuxCommand):
"""
string = self.format_multimatches(self.caller, self.matches)
self.caller.msg(string)
class SystemNoPerm(MuxCommand):
"""
This is called when the user does not have the
correct permissions to use a particular command.
"""
key = CMD_NOPERM
locks = "cmd:all()"
def func(self):
"""
This receives the original raw
input string (the one whose command failed to validate)
as argument.
"""
self.caller.msg("You are not allowed to do that.")
# Command called when the comman given at the command line
# Command called when the command given at the command line
# was identified as a channel name, like there existing a
# channel named 'ooc' and the user wrote
# > ooc Hello!

View file

@ -124,6 +124,7 @@ class CmdScripts(MuxCommand):
Switches:
stop - stops an existing script
kill - kills a script - without running its cleanup hooks
validate - run a validation on the script(s)
If no switches are given, this command just views all active
@ -212,15 +213,19 @@ class CmdScripts(MuxCommand):
caller.msg(string)
return
if self.switches and self.switches[0] in ('stop', 'del', 'delete'):
if self.switches and self.switches[0] in ('stop', 'del', 'delete', 'kill'):
# we want to delete something
if not scripts:
string = "No scripts/objects matching '%s'. " % args
string += "Be more specific."
elif len(scripts) == 1:
# we have a unique match!
string = "Stopping script '%s'." % scripts[0].key
scripts[0].stop()
if 'kill' in self.switches:
string = "Killing script '%s'" % scripts[0].key
scripts[0].stop(kill=True)
else:
string = "Stopping script '%s'." % scripts[0].key
scripts[0].stop()
ScriptDB.objects.validate() #just to be sure all is synced
else:
# multiple matches.

View file

@ -217,10 +217,11 @@ def attr(accessing_obj, accessed_obj, *args, **kwargs):
the one given).
Searches attributes *and* properties stored on the checking
object. The first form works like a flag - if the attribute/property
exists on the object, it returns True. The second form also requires
that the value of the attribute/property matches. Note that all
retrieved values will be converted to strings before doing the comparison.
object. The first form works like a flag - if the
attribute/property exists on the object, the value is checked for
True/False. The second form also requires that the value of the
attribute/property matches. Note that all retrieved values will be
converted to strings before doing the comparison.
"""
# deal with arguments
if not args:
@ -258,15 +259,15 @@ def attr(accessing_obj, accessed_obj, *args, **kwargs):
# first, look for normal properties on the object trying to gain access
if hasattr(accessing_obj, attrname):
if value:
return valcompare(str(getattr(accessing_obj, attrname)), value, compare)
return True
return valcompare(str(getattr(accessing_obj, attrname)), value, compare)
return getattr(accessing_obj, attrname) # will return Fail on False value etc
# check attributes, if they exist
if (hasattr(accessing_obj, 'has_attribute')
and accessing_obj.has_attribute(attrname)):
if value:
return (hasattr(accessing_obj, 'get_attribute')
and valcompare(accessing_obj.get_attribute(attrname), value, compare))
return True
return accessing_obj.get_attribute(attrname) # fails on False/None values
return False
def objattr(accessing_obj, accessed_obj, *args, **kwargs):
@ -292,8 +293,7 @@ def locattr(accessing_obj, accessed_obj, *args, **kwargs):
locattr(attrname, value, compare=type)
Works like attr, except it looks for an attribute on
accessing_obj.location, if such an entity exists. Suitable
for commands.
accessing_obj.location, if such an entity exists.
"""
if hasattr(accessing_obj, "location"):
@ -348,44 +348,51 @@ def attr_ne(accessing_obj, accessed_obj, *args, **kwargs):
"""
return attr(accessing_obj, accessed_obj, *args, **{'compare':'ne'})
def holds(accessing_obj, accessed_obj, objid, *args, **kwargs):
def holds(accessing_obj, accessed_obj, *args, **kwargs):
"""
Usage:
holds(object_id)
This is passed if accessing_obj 'contains' an object with the given
key name or dbref.
"""
dbref = utils.dbref(objid)
contains = accessing_obj.contains
if dbref and any((True for obj in contains if obj.id == dbref)):
return True
objid = objid.lower()
return any((True for obj in contains
if obj.name.lower() == objid or objid in [al.lower() for al in obj.aliases]))
def carried(accessing_obj, accessed_obj):
"""
Usage:
carried()
holds() # checks if accessed_obj or accessed_obj.obj is held by accessing_obj
holds(key/dbref) # checks if accessing_obj holds an object with given key/dbref
This is passed if accessed_obj is carried by accessing_obj (that is,
accessed_obj.location == accessing_obj)
accessed_obj.location == accessing_obj), or if accessing_obj itself holds an
object matching the given key.
"""
return hasattr(accessed_obj, "location") and accessed_obj.location == accessing_obj
print "holds ..."
try:
# commands and scripts don't have contents, so we are usually looking
# for the contents of their .obj property instead (i.e. the object the
# command/script is attached to).
contents = accessing_obj.contents
except AttributeError:
try:
contents = accessing_obj.obj.contents
except AttributeError:
return False
print "holds", contents, accessing_obj, accessed_obj
def objcarried(accessing_obj, accessed_obj):
"""
Usage:
objcarried()
Like carried, except this lock looks for a property "obj" on the accessed_obj
and tries to determine if *this* is carried by accessing_obj. This works well
for accessing commands and scripts.
"""
return hasattr(accessed_obj, "obj") and accessed_obj.obj and \
hasattr(accessed_obj.obj, "location") and accessed_obj.obj.location == accessing_obj
def check_holds(objid):
# helper function. Compares both dbrefs and keys/aliases.
objid = str(objid)
dbref = utils.dbref(objid)
if dbref and any((True for obj in contents if obj.id == dbref)):
return True
objid = objid.lower()
return any((True for obj in contents
if obj.key.lower() == objid or objid in [al.lower() for al in obj.aliases]))
if args and args[0]:
return check_holds(args[0])
else:
try:
if check_holds(accessed_obj.id):
print "holds: accessed_obj.id - True"
return True
except Exception:
pass
print "holds: accessed_obj.obj.id -", hasattr(accessed_obj, "obj") and check_holds(accessed_obj.obj.id)
return hasattr(accessed_obj, "obj") and check_holds(accessed_obj.obj.id)
def superuser(*args, **kwargs):
"""
Only accepts an accesing_obj that is superuser (e.g. user #1)
@ -406,7 +413,7 @@ def serversetting(accessing_obj, accessed_obj, *args, **kwargs):
A given True/False or integers will be converted properly.
"""
if not args:
if not args or not args[0]:
return False
if len(args) < 2:
setting = args[0]

View file

@ -14,6 +14,7 @@ the database object. Like everything else, they can be accessed
transparently through the decorating TypeClass.
"""
import traceback
from django.db import models
from django.conf import settings
from django.contrib.contenttypes.models import ContentType
@ -448,6 +449,13 @@ class ObjectDB(TypedObject):
"""
return any(self.sessions)
has_player = property(has_player_get)
is_player = property(has_player_get)
#@property
def is_superuser_get(self):
"Check if user has a player, and if so, if it is a superuser."
return any(self.sessions) and self.player.is_superuser
is_superuser = property(is_superuser_get)
#@property
def contents_get(self, exclude=None):
@ -612,6 +620,12 @@ class ObjectDB(TypedObject):
quiet: (bool) If true, don't emit left/arrived messages.
emit_to_obj: (Object) object to receive error messages
"""
def logerr(string=""):
trc = traceback.format_exc()
errstring = "%s%s" % (trc, string)
logger.log_trace()
self.msg(errstring)
errtxt = "Couldn't perform move ('%s'). Contact an admin."
if not emit_to_obj:
emit_to_obj = self
@ -628,8 +642,9 @@ class ObjectDB(TypedObject):
if not self.at_before_move(destination):
return
except Exception:
emit_to_obj.msg(errtxt % "at_before_move()")
logger.log_trace()
logerr(errtxt % "at_before_move()")
#emit_to_obj.msg(errtxt % "at_before_move()")
#logger.log_trace()
return False
# Save the old location
@ -648,8 +663,9 @@ class ObjectDB(TypedObject):
try:
source_location.at_object_leave(self, destination)
except Exception:
emit_to_obj.msg(errtxt % "at_object_leave()")
logger.log_trace()
logerr(errtxt % "at_object_leave()")
#emit_to_obj.msg(errtxt % "at_object_leave()")
#logger.log_trace()
return False
if not quiet:
@ -657,8 +673,9 @@ class ObjectDB(TypedObject):
try:
self.announce_move_from(destination)
except Exception:
emit_to_obj.msg(errtxt % "at_announce_move()" )
logger.log_trace()
logerr(errtxt % "at_announce_move()")
#emit_to_obj.msg(errtxt % "at_announce_move()" )
#logger.log_trace()
return False
# Perform move
@ -674,27 +691,31 @@ class ObjectDB(TypedObject):
try:
self.announce_move_to(source_location)
except Exception:
emit_to_obj.msg(errtxt % "announce_move_to()")
logger.log_trace()
logerr(errtxt % "announce_move_to()")
#emit_to_obj.msg(errtxt % "announce_move_to()")
#logger.log_trace()
return False
# Perform eventual extra commands on the receiving location
# (the object has already arrived at this point)
try:
destination.at_object_receive(self, source_location)
except Exception:
logerr(errtxt % "at_object_receive()")
#emit_to_obj.msg(errtxt % "at_object_receive()")
#logger.log_trace()
return False
# Execute eventual extra commands on this object after moving it
# (usually calling 'look')
try:
self.at_after_move(source_location)
except Exception:
emit_to_obj.msg(errtxt % "at_after_move()")
logger.log_trace()
logerr(errtxt % "at_after_move")
#emit_to_obj.msg(errtxt % "at_after_move()")
#logger.log_trace()
return False
# Perform eventual extra commands on the receiving location
try:
destination.at_object_receive(self, source_location)
except Exception:
emit_to_obj.msg(errtxt % "at_obj_receive()")
logger.log_trace()
return False
#
# Object Swap, Delete and Cleanup methods

View file

@ -235,7 +235,7 @@ class Object(TypeClass):
exits = []
users = []
things = []
for content in self.contents:
for content in [con for con in self.contents if con.access(pobject, 'view')]:
if content == pobject:
continue
name = content.name

View file

@ -47,11 +47,13 @@ class ScriptHandler(object):
def add(self, scriptclass, key=None, autostart=True):
"""
Add an script to this object. The scriptclass
argument can be either a class object
inheriting from Script, an instantiated script object
or a python path to such a class object.
Add an script to this object.
scriptclass - either a class object
inheriting from Script, an instantiated script object
or a python path to such a class object.
key - optional identifier for the script (often set in script definition)
autostart - start the script upon adding it
"""
script = create.create_script(scriptclass, key=key, obj=self.obj, autostart=autostart)
if not script:

View file

@ -123,16 +123,19 @@ class ScriptClass(TypeClass):
#print "... Start cancelled (invalid start or already running)."
return 0 # this is used by validate() for counting started scripts
def stop(self):
def stop(self, kill=False):
"""
Called to stop the script from running.
This also deletes the script.
kill - don't call finishing hooks.
"""
#print "stopping script %s" % self.key
try:
self.at_stop()
except Exception:
logger.log_trace()
if not kill:
try:
self.at_stop()
except Exception:
logger.log_trace()
if self.interval:
try:
self._stop_task()

View file

@ -163,13 +163,14 @@ def read_batchfile(pythonpath, file_ending='.py'):
"""
# open the file
if pythonpath and not (pythonpath.startswith('src.') or pythonpath.startswith('game.')):
if pythonpath and not (pythonpath.startswith('src.') or pythonpath.startswith('game.')
or pythonpath.startswith('contrib.')):
abspaths = []
for basepath in settings.BASE_BATCHPROCESS_PATHS:
abspaths.append(utils.pypath_to_realpath("%s.%s" % (basepath, pythonpath), file_ending))
else:
abspaths = [pythonpath]
fobj = None
abspaths = [utils.pypath_to_realpath(pythonpath, file_ending)]
fobj, lines, err = None, [], None
for file_encoding in ENCODINGS:
# try different encodings, in order
load_errors = []