mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
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:
parent
334c0b1d08
commit
95d672763b
17 changed files with 207 additions and 165 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:"
|
||||
|
|
|
|||
|
|
@ -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!
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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 = []
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue