Cleaning some unnecessary whitespace, overall cleanup of various source codes.
This commit is contained in:
parent
d4c97d7df8
commit
c0322c9eae
27 changed files with 1342 additions and 1318 deletions
|
|
@ -2,35 +2,35 @@
|
|||
Command handler
|
||||
|
||||
This module contains the infrastructure for accepting commands on the
|
||||
command line. The process is as follows:
|
||||
command line. The process is as follows:
|
||||
|
||||
1) The calling object (caller) inputs a string and triggers the command parsing system.
|
||||
2) The system checks the state of the caller - loggedin or not
|
||||
3) If no command string was supplied, we search the merged cmdset for system command CMD_NOINPUT
|
||||
3) If no command string was supplied, we search the merged cmdset for system command CMD_NOINPUT
|
||||
and branches to execute that. --> Finished
|
||||
4) Cmdsets are gathered from different sources (in order of dropping priority):
|
||||
channels - all available channel names are auto-created into a cmdset, to allow
|
||||
4) Cmdsets are gathered from different sources (in order of dropping priority):
|
||||
channels - all available channel names are auto-created into a cmdset, to allow
|
||||
for giving the channel name and have the following immediately
|
||||
sent to the channel. The sending is performed by the CMD_CHANNEL
|
||||
system command.
|
||||
object cmdsets - all objects at caller's location are scanned for non-empty
|
||||
cmdsets. This includes cmdsets on exits.
|
||||
cmdsets. This includes cmdsets on exits.
|
||||
caller - the caller is searched for its own currently active cmdset.
|
||||
player - lastly the cmdsets defined on caller.player are added.
|
||||
5) All the gathered cmdsets (if more than one) are merged into one using the cmdset priority rules.
|
||||
player - lastly the cmdsets defined on caller.player are added.
|
||||
5) All the gathered cmdsets (if more than one) are merged into one using the cmdset priority rules.
|
||||
6) If merged cmdset is empty, raise NoCmdSet exception (this should not happen, at least the
|
||||
player should have a default cmdset available at all times). --> Finished
|
||||
7) The raw input string is parsed using the parser defined by settings.COMMAND_PARSER. It
|
||||
player should have a default cmdset available at all times). --> Finished
|
||||
7) The raw input string is parsed using the parser defined by settings.COMMAND_PARSER. It
|
||||
uses the available commands from the merged cmdset to know which commands to look for and
|
||||
returns one or many matches.
|
||||
returns one or many matches.
|
||||
8) If match list is empty, branch to system command CMD_NOMATCH --> Finished
|
||||
9) If match list has more than one element, branch to system command CMD_MULTIMATCH --> Finished
|
||||
10) A single match was found. If this is a channel-command (i.e. the command name is that of a channel),
|
||||
branch to CMD_CHANNEL --> Finished
|
||||
branch to CMD_CHANNEL --> Finished
|
||||
11) 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.
|
||||
12) We have a unique cmdobject, primed for use. Call all hooks:
|
||||
at_pre_cmd(), cmdobj.parse(), cmdobj.func() and finally at_post_cmd().
|
||||
will be available to the command coder at run-time.
|
||||
12) We have a unique cmdobject, primed for use. Call all hooks:
|
||||
at_pre_cmd(), cmdobj.parse(), cmdobj.func() and finally at_post_cmd().
|
||||
|
||||
|
||||
"""
|
||||
|
|
@ -41,19 +41,19 @@ from twisted.internet.defer import inlineCallbacks, returnValue
|
|||
from django.conf import settings
|
||||
from src.comms.channelhandler import CHANNELHANDLER
|
||||
from src.commands.cmdsethandler import import_cmdset
|
||||
from src.utils import logger, utils
|
||||
from src.utils import logger, utils
|
||||
from src.commands.cmdparser import at_multimatch_cmd
|
||||
|
||||
#This switches the command parser to a user-defined one.
|
||||
# You have to restart the server for this to take effect.
|
||||
# You have to restart the server for this to take effect.
|
||||
COMMAND_PARSER = utils.mod_import(*settings.COMMAND_PARSER.rsplit('.', 1))
|
||||
|
||||
# There are a few system-hardcoded command names. These
|
||||
# allow for custom behaviour when the command handler hits
|
||||
# special situations -- it then calls a normal Command
|
||||
# that you can customize!
|
||||
# that you can customize!
|
||||
# Import these variables and use them rather than trying
|
||||
# to remember the actual string constants.
|
||||
# to remember the actual string constants.
|
||||
|
||||
CMD_NOINPUT = "__noinput_command"
|
||||
CMD_NOMATCH = "__nomatch_command"
|
||||
|
|
@ -61,12 +61,12 @@ CMD_MULTIMATCH = "__multimatch_command"
|
|||
CMD_CHANNEL = "__send_to_channel_command"
|
||||
# this is the name of the command the engine calls when the player
|
||||
# connects. It is expected to show the login screen.
|
||||
CMD_LOGINSTART = "__unloggedin_look_command"
|
||||
CMD_LOGINSTART = "__unloggedin_look_command"
|
||||
|
||||
|
||||
class NoCmdSets(Exception):
|
||||
"No cmdsets found. Critical error."
|
||||
pass
|
||||
pass
|
||||
class ExecSystemCommand(Exception):
|
||||
"Run a system command"
|
||||
def __init__(self, syscmd, sysarg):
|
||||
|
|
@ -77,10 +77,10 @@ class ExecSystemCommand(Exception):
|
|||
@inlineCallbacks
|
||||
def get_and_merge_cmdsets(caller):
|
||||
"""
|
||||
Gather all relevant cmdsets and merge them. Note
|
||||
Gather all relevant cmdsets and merge them. Note
|
||||
that this is only relevant for logged-in callers.
|
||||
"""
|
||||
# The calling object's cmdset
|
||||
# The calling object's cmdset
|
||||
try:
|
||||
yield caller.at_cmdset_get()
|
||||
except Exception:
|
||||
|
|
@ -89,17 +89,17 @@ def get_and_merge_cmdsets(caller):
|
|||
caller_cmdset = caller.cmdset.current
|
||||
except AttributeError:
|
||||
caller_cmdset = None
|
||||
|
||||
|
||||
# Create cmdset for all player's available channels
|
||||
channel_cmdset = None
|
||||
if not caller_cmdset.no_channels:
|
||||
channel_cmdset = yield CHANNELHANDLER.get_cmdset(caller)
|
||||
|
||||
# Gather cmdsets from location, objects in location or carried
|
||||
local_objects_cmdsets = [None]
|
||||
# Gather cmdsets from location, objects in location or carried
|
||||
local_objects_cmdsets = [None]
|
||||
location = None
|
||||
if hasattr(caller, "location"):
|
||||
location = caller.location
|
||||
location = caller.location
|
||||
if location and not caller_cmdset.no_objs:
|
||||
# Gather all cmdsets stored on objects in the room and
|
||||
# also in the caller's inventory and the location itself
|
||||
|
|
@ -113,19 +113,19 @@ def get_and_merge_cmdsets(caller):
|
|||
local_objects_cmdsets = yield [obj.cmdset.current for obj in local_objlist
|
||||
if (obj.cmdset.current and obj.locks.check(caller, 'call', no_superuser_bypass=True))]
|
||||
for cset in local_objects_cmdsets:
|
||||
#This is necessary for object sets, or we won't be able to separate
|
||||
#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
|
||||
|
||||
# Player object's commandsets
|
||||
# Player object's commandsets
|
||||
try:
|
||||
player_cmdset = caller.player.cmdset.current
|
||||
except AttributeError:
|
||||
player_cmdset = None
|
||||
|
||||
cmdsets = [caller_cmdset] + [player_cmdset] + [channel_cmdset] + local_objects_cmdsets
|
||||
# weed out all non-found sets
|
||||
# weed out all non-found sets
|
||||
cmdsets = yield [cmdset for cmdset in cmdsets if cmdset]
|
||||
# sort cmdsets after reverse priority (highest prio are merged in last)
|
||||
cmdsets = yield sorted(cmdsets, key=lambda x: x.priority)
|
||||
|
|
@ -134,9 +134,9 @@ def get_and_merge_cmdsets(caller):
|
|||
# Merge all command sets into one, beginning with the lowest-prio one
|
||||
cmdset = cmdsets.pop(0)
|
||||
for merging_cmdset in cmdsets:
|
||||
#print "<%s(%s,%s)> onto <%s(%s,%s)>" % (merging_cmdset.key, merging_cmdset.priority, merging_cmdset.mergetype,
|
||||
# cmdset.key, cmdset.priority, cmdset.mergetype)
|
||||
cmdset = yield merging_cmdset + cmdset
|
||||
#print "<%s(%s,%s)> onto <%s(%s,%s)>" % (merging_cmdset.key, merging_cmdset.priority, merging_cmdset.mergetype,
|
||||
# cmdset.key, cmdset.priority, cmdset.mergetype)
|
||||
cmdset = yield merging_cmdset + cmdset
|
||||
else:
|
||||
cmdset = None
|
||||
|
||||
|
|
@ -146,26 +146,26 @@ def get_and_merge_cmdsets(caller):
|
|||
returnValue(cmdset)
|
||||
|
||||
|
||||
# Main command-handler function
|
||||
# Main command-handler function
|
||||
|
||||
@inlineCallbacks
|
||||
def cmdhandler(caller, raw_string, testing=False):
|
||||
"""
|
||||
This is the main function to handle any string sent to the engine.
|
||||
|
||||
This is the main function to handle any string sent to the engine.
|
||||
|
||||
caller - calling object
|
||||
raw_string - the command string given on the command line
|
||||
testing - if we should actually execute the command or not.
|
||||
testing - if we should actually execute the command or not.
|
||||
if True, the command instance will be returned instead.
|
||||
|
||||
Note that this function returns a deferred!
|
||||
"""
|
||||
Note that this function returns a deferred!
|
||||
"""
|
||||
try: # catch bugs in cmdhandler itself
|
||||
try: # catch special-type commands
|
||||
|
||||
cmdset = yield get_and_merge_cmdsets(caller)
|
||||
if not cmdset:
|
||||
# this is bad and shouldn't happen.
|
||||
# this is bad and shouldn't happen.
|
||||
raise NoCmdSets
|
||||
|
||||
raw_string = raw_string.strip()
|
||||
|
|
@ -182,7 +182,7 @@ def cmdhandler(caller, raw_string, testing=False):
|
|||
if not matches:
|
||||
# No commands match our entered command
|
||||
syscmd = yield cmdset.get(CMD_NOMATCH)
|
||||
if syscmd:
|
||||
if syscmd:
|
||||
sysarg = raw_string
|
||||
else:
|
||||
sysarg = "Huh? (Type \"help\" for help)"
|
||||
|
|
@ -197,43 +197,43 @@ def cmdhandler(caller, raw_string, testing=False):
|
|||
else:
|
||||
sysarg = yield at_multimatch_cmd(caller, matches)
|
||||
raise ExecSystemCommand(syscmd, sysarg)
|
||||
|
||||
# At this point, we have a unique command match.
|
||||
|
||||
# At this point, we have a unique command match.
|
||||
match = matches[0]
|
||||
cmdname, args, cmd = match[0], match[1], match[2]
|
||||
|
||||
# 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
|
||||
# found cmd is already a system command in its own right.
|
||||
syscmd = yield cmdset.get(CMD_CHANNEL)
|
||||
# even if a user-defined syscmd is not defined, the
|
||||
# found cmd is already a system command in its own right.
|
||||
syscmd = yield cmdset.get(CMD_CHANNEL)
|
||||
if syscmd:
|
||||
# replace system command with custom version
|
||||
cmd = syscmd
|
||||
cmd = syscmd
|
||||
sysarg = "%s:%s" % (cmdname, args)
|
||||
raise ExecSystemCommand(cmd, sysarg)
|
||||
|
||||
# A normal command.
|
||||
|
||||
# Assign useful variables to the instance
|
||||
cmd.caller = caller
|
||||
cmd.caller = caller
|
||||
cmd.cmdstring = cmdname
|
||||
cmd.args = args
|
||||
cmd.cmdset = cmdset
|
||||
|
||||
if hasattr(cmd, 'obj') and hasattr(cmd.obj, 'scripts'):
|
||||
# cmd.obj are automatically made available.
|
||||
# we make sure to validate its scripts.
|
||||
# we make sure to validate its scripts.
|
||||
yield cmd.obj.scripts.validate()
|
||||
|
||||
|
||||
if testing:
|
||||
# only return the command instance
|
||||
returnValue(cmd)
|
||||
|
||||
|
||||
# pre-command hook
|
||||
yield cmd.at_pre_cmd()
|
||||
|
||||
# Parse and execute
|
||||
# Parse and execute
|
||||
yield cmd.parse()
|
||||
# (return value is normally None)
|
||||
ret = yield cmd.func()
|
||||
|
|
@ -246,15 +246,15 @@ def cmdhandler(caller, raw_string, testing=False):
|
|||
# accessible by the next command.
|
||||
caller.ndb.last_cmd = yield copy(cmd)
|
||||
else:
|
||||
caller.ndb.last_cmd = None
|
||||
|
||||
caller.ndb.last_cmd = None
|
||||
|
||||
# Done! This returns a deferred. By default, Evennia does
|
||||
# not use this at all.
|
||||
returnValue(ret)
|
||||
|
||||
except ExecSystemCommand, exc:
|
||||
except ExecSystemCommand, exc:
|
||||
# Not a normal command: run a system command, if available,
|
||||
# or fall back to a return string.
|
||||
# or fall back to a return string.
|
||||
syscmd = exc.syscmd
|
||||
sysarg = exc.sysarg
|
||||
if syscmd:
|
||||
|
|
@ -265,9 +265,9 @@ def cmdhandler(caller, raw_string, testing=False):
|
|||
|
||||
if hasattr(syscmd, 'obj') and hasattr(syscmd.obj, 'scripts'):
|
||||
# cmd.obj is automatically made available.
|
||||
# we make sure to validate its scripts.
|
||||
# we make sure to validate its scripts.
|
||||
yield syscmd.obj.scripts.validate()
|
||||
|
||||
|
||||
if testing:
|
||||
# only return the command instance
|
||||
returnValue(syscmd)
|
||||
|
|
@ -282,21 +282,21 @@ def cmdhandler(caller, raw_string, testing=False):
|
|||
except NoCmdSets:
|
||||
# Critical error.
|
||||
string = "No command sets found! This is a sign of a critical bug.\n"
|
||||
string += "The error was logged.\n"
|
||||
string += "The error was logged.\n"
|
||||
string += "If logging out/in doesn't solve the problem, try to "
|
||||
string += "contact the server admin through some other means "
|
||||
string += "for assistance."
|
||||
caller.msg(string)
|
||||
logger.log_errmsg("No cmdsets found: %s" % caller)
|
||||
|
||||
|
||||
except Exception:
|
||||
# We should not end up here. If we do, it's a programming bug.
|
||||
string = "%s\nAbove traceback is from an untrapped error."
|
||||
string = "%s\nAbove traceback is from an untrapped error."
|
||||
string += " Please file a bug report."
|
||||
logger.log_trace(string)
|
||||
caller.msg(string % format_exc())
|
||||
|
||||
except Exception:
|
||||
except Exception:
|
||||
# This catches exceptions in cmdhandler exceptions themselves
|
||||
string = "%s\nAbove traceback is from a Command handler bug."
|
||||
string += " Please contact an admin and/or file a bug report."
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ from src.utils.logger import log_trace
|
|||
|
||||
def cmdparser(raw_string, cmdset, caller, match_index=None):
|
||||
"""
|
||||
This function is called by the cmdhandler once it has
|
||||
This function is called by the cmdhandler once it has
|
||||
gathered all valid cmdsets for the calling player. raw_string
|
||||
is the unparsed text entered by the caller.
|
||||
is the unparsed text entered by the caller.
|
||||
|
||||
The cmdparser understand the following command combinations (where
|
||||
[] marks optional parts.
|
||||
|
|
@ -19,20 +19,20 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
|
|||
[cmdname[ cmdname2 cmdname3 ...] [the rest]
|
||||
|
||||
A command may consist of any number of space-separated words of any
|
||||
length, and contain any character.
|
||||
length, and contain any character.
|
||||
|
||||
The parser makes use of the cmdset to find command candidates. The
|
||||
parser return a list of matches. Each match is a tuple with its
|
||||
first three elements being the parsed cmdname (lower case),
|
||||
the remaining arguments, and the matched cmdobject from the cmdset.
|
||||
first three elements being the parsed cmdname (lower case),
|
||||
the remaining arguments, and the matched cmdobject from the cmdset.
|
||||
"""
|
||||
|
||||
|
||||
def create_match(cmdname, string, cmdobj):
|
||||
"""
|
||||
Evaluates the quality of a match by counting how many chars of cmdname
|
||||
Evaluates the quality of a match by counting how many chars of cmdname
|
||||
matches string (counting from beginning of string). We also calculate
|
||||
a ratio from 0-1 describing how much cmdname matches string.
|
||||
We return a tuple (cmdname, count, ratio, args, cmdobj).
|
||||
a ratio from 0-1 describing how much cmdname matches string.
|
||||
We return a tuple (cmdname, count, ratio, args, cmdobj).
|
||||
|
||||
"""
|
||||
cmdlen, strlen = len(cmdname), len(string)
|
||||
|
|
@ -41,13 +41,13 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
|
|||
return (cmdname, args, cmdobj, cmdlen, mratio)
|
||||
|
||||
if not raw_string:
|
||||
return None
|
||||
return None
|
||||
|
||||
matches = []
|
||||
|
||||
# match everything that begins with a matching cmdname.
|
||||
l_raw_string = raw_string.lower()
|
||||
for cmd in cmdset:
|
||||
for cmd in cmdset:
|
||||
try:
|
||||
matches.extend([create_match(cmdname, raw_string, cmd)
|
||||
for cmdname in [cmd.key] + cmd.aliases
|
||||
|
|
@ -58,13 +58,13 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
|
|||
log_trace()
|
||||
|
||||
if not matches:
|
||||
# no matches found.
|
||||
# no matches found.
|
||||
if '-' in raw_string:
|
||||
# This could be due to the user trying to identify the
|
||||
# command with a #num-<command> style syntax.
|
||||
mindex, new_raw_string = raw_string.split("-", 1)
|
||||
if mindex.isdigit():
|
||||
mindex = int(mindex) - 1
|
||||
mindex = int(mindex) - 1
|
||||
# feed result back to parser iteratively
|
||||
return cmdparser(new_raw_string, cmdset, caller, match_index=mindex)
|
||||
|
||||
|
|
@ -85,22 +85,22 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
|
|||
if len(matches) > 1:
|
||||
# still multiple matches. Fall back to ratio-based quality.
|
||||
matches = sorted(matches, key=lambda m: m[4])
|
||||
# only pick the highest rated ratio match
|
||||
# only pick the highest rated ratio match
|
||||
quality = [mat[4] for mat in matches]
|
||||
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.
|
||||
matches = [matches[match_index]]
|
||||
matches = [matches[match_index]]
|
||||
|
||||
# no matter what we have at this point, we have to return it.
|
||||
return matches
|
||||
return matches
|
||||
|
||||
|
||||
|
||||
|
||||
#------------------------------------------------------------
|
||||
# Search parsers and support methods
|
||||
# Search parsers and support methods
|
||||
#------------------------------------------------------------
|
||||
#
|
||||
# Default functions for formatting and processing searches.
|
||||
|
|
@ -109,7 +109,7 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
|
|||
# replace from the settings file by setting the variables
|
||||
#
|
||||
# SEARCH_AT_RESULTERROR_HANDLER
|
||||
# SEARCH_MULTIMATCH_PARSER
|
||||
# SEARCH_MULTIMATCH_PARSER
|
||||
#
|
||||
# The the replacing modules must have the same inputs and outputs as
|
||||
# those in this module.
|
||||
|
|
@ -118,57 +118,57 @@ def cmdparser(raw_string, cmdset, caller, match_index=None):
|
|||
def at_search_result(msg_obj, ostring, results, global_search=False):
|
||||
"""
|
||||
Called by search methods after a result of any type has been found.
|
||||
|
||||
|
||||
Takes a search result (a list) and
|
||||
formats eventual errors.
|
||||
|
||||
msg_obj - object to receive feedback.
|
||||
ostring - original search string
|
||||
msg_obj - object to receive feedback.
|
||||
ostring - original search string
|
||||
results - list of found matches (0, 1 or more)
|
||||
global_search - if this was a global_search or not
|
||||
(if it is, there might be an idea of supplying
|
||||
dbrefs instead of only numbers)
|
||||
|
||||
Multiple matches are returned to the searching object
|
||||
as
|
||||
as
|
||||
1-object
|
||||
2-object
|
||||
3-object
|
||||
2-object
|
||||
3-object
|
||||
etc
|
||||
|
||||
"""
|
||||
string = ""
|
||||
if not results:
|
||||
# no results.
|
||||
if not results:
|
||||
# no results.
|
||||
string = "Could not find '%s'." % ostring
|
||||
results = None
|
||||
results = None
|
||||
|
||||
elif len(results) > 1:
|
||||
# we have more than one match. We will display a
|
||||
# list of the form 1-objname, 2-objname etc.
|
||||
# list of the form 1-objname, 2-objname etc.
|
||||
|
||||
# check if the msg_object may se dbrefs
|
||||
show_dbref = global_search
|
||||
|
||||
string += "More than one match for '%s'" % ostring
|
||||
string += " (please narrow target):"
|
||||
string += " (please narrow target):"
|
||||
for num, result in enumerate(results):
|
||||
invtext = ""
|
||||
invtext = ""
|
||||
dbreftext = ""
|
||||
if hasattr(result, "location") and result.location == msg_obj:
|
||||
invtext = " (carried)"
|
||||
invtext = " (carried)"
|
||||
if show_dbref:
|
||||
dbreftext = "(#%i)" % result.id
|
||||
string += "\n %i-%s%s%s" % (num+1, result.name,
|
||||
dbreftext, invtext)
|
||||
results = None
|
||||
dbreftext = "(#%i)" % result.id
|
||||
string += "\n %i-%s%s%s" % (num+1, result.name,
|
||||
dbreftext, invtext)
|
||||
results = None
|
||||
else:
|
||||
# we have exactly one match.
|
||||
results = results[0]
|
||||
|
||||
if string:
|
||||
if string:
|
||||
msg_obj.msg(string.strip())
|
||||
return results
|
||||
return results
|
||||
|
||||
def at_multimatch_input(ostring):
|
||||
"""
|
||||
|
|
@ -186,9 +186,9 @@ def at_multimatch_input(ostring):
|
|||
the lowest number, rather than 0 as in Python).
|
||||
|
||||
This parser version will identify search strings on the following
|
||||
forms
|
||||
forms
|
||||
|
||||
2-object
|
||||
2-object
|
||||
|
||||
This will be parsed to (2, "object") and, if applicable, will tell
|
||||
the engine to pick the second from a list of same-named matches of
|
||||
|
|
@ -197,7 +197,7 @@ def at_multimatch_input(ostring):
|
|||
Ex for use in a game session:
|
||||
|
||||
> look
|
||||
You see: ball, ball, ball and ball.
|
||||
You see: ball, ball, ball and ball.
|
||||
> get ball
|
||||
There where multiple matches for ball:
|
||||
1-ball
|
||||
|
|
@ -205,7 +205,7 @@ def at_multimatch_input(ostring):
|
|||
3-ball
|
||||
4-ball
|
||||
> get 3-ball
|
||||
You get the ball.
|
||||
You get the ball.
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -213,7 +213,7 @@ def at_multimatch_input(ostring):
|
|||
return (None, ostring)
|
||||
if not '-' in ostring:
|
||||
return (None, ostring)
|
||||
try:
|
||||
try:
|
||||
index = ostring.find('-')
|
||||
number = int(ostring[:index])-1
|
||||
return (number, ostring[index+1:])
|
||||
|
|
@ -229,7 +229,7 @@ def at_multimatch_cmd(caller, matches):
|
|||
Format multiple command matches to a useful error.
|
||||
"""
|
||||
string = "There where multiple matches:"
|
||||
for num, match in enumerate(matches):
|
||||
for num, match in enumerate(matches):
|
||||
# each match is a tuple (candidate, cmd)
|
||||
cmdname, arg, cmd, dum, dum = match
|
||||
|
||||
|
|
@ -237,7 +237,7 @@ def at_multimatch_cmd(caller, matches):
|
|||
if is_channel:
|
||||
is_channel = " (channel)"
|
||||
else:
|
||||
is_channel = ""
|
||||
is_channel = ""
|
||||
if cmd.is_exit and cmd.destination:
|
||||
is_exit = " (exit to %s)" % cmd.destination
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@ on-the-fly CmdSet that is some combination of the
|
|||
previous ones. Their function are borrowed to a large parts from mathematical
|
||||
Set theory, it should not be much of a problem to understand.
|
||||
|
||||
See CmdHandler for practical examples on how to apply cmdsets
|
||||
See CmdHandler for practical examples on how to apply cmdsets
|
||||
together to create interesting in-game effects.
|
||||
"""
|
||||
|
||||
import copy
|
||||
from src.utils.utils import inherits_from, is_iter
|
||||
from src.utils.utils import inherits_from, is_iter
|
||||
|
||||
RECURSIVE_PROTECTION = False
|
||||
RECURSIVE_PROTECTION = False
|
||||
|
||||
class CmdSetMeta(type):
|
||||
"""
|
||||
|
|
@ -29,14 +29,14 @@ class CmdSetMeta(type):
|
|||
Fixes some things in the cmdclass
|
||||
"""
|
||||
# by default we key the cmdset the same as the
|
||||
# name of its class.
|
||||
# name of its class.
|
||||
if not hasattr(mcs, 'key') or not mcs.key:
|
||||
mcs.key = mcs.__name__
|
||||
mcs.path = "%s.%s" % (mcs.__module__, mcs.__name__)
|
||||
|
||||
if not type(mcs.key_mergetypes) == dict:
|
||||
mcs.key_mergetypes = {}
|
||||
|
||||
|
||||
super(CmdSetMeta, mcs).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
|
|
@ -46,12 +46,12 @@ def union(cmdset_a, cmdset_b, duplicates=False):
|
|||
"C = A U B. CmdSet A is assumed to have higher priority"
|
||||
cmdset_c = cmdset_a.copy_this()
|
||||
# we make copies, not refs by use of [:]
|
||||
cmdset_c.commands = cmdset_a.commands[:]
|
||||
cmdset_c.commands = cmdset_a.commands[:]
|
||||
if 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])
|
||||
return cmdset_c
|
||||
return cmdset_c
|
||||
|
||||
def intersect(cmdset_a, cmdset_b, duplicates=False):
|
||||
"C = A (intersect) B. A is assumed higher priority"
|
||||
|
|
@ -62,7 +62,7 @@ def intersect(cmdset_a, cmdset_b, duplicates=False):
|
|||
cmdset_c.add(cmdset_b.get(cmd))
|
||||
else:
|
||||
cmdset_c.commands = [cmd for cmd in cmdset_a if cmd in cmdset_b]
|
||||
return cmdset_c
|
||||
return cmdset_c
|
||||
|
||||
def replace(cmdset_a, cmdset_b, cmdset_c):
|
||||
"C = A + B where the result is A."
|
||||
|
|
@ -80,24 +80,24 @@ def instantiate(cmd):
|
|||
"""
|
||||
checks so that object is an instantiated command
|
||||
and not, say a cmdclass. If it is, instantiate it.
|
||||
Other types, like strings, are passed through.
|
||||
"""
|
||||
Other types, like strings, are passed through.
|
||||
"""
|
||||
try:
|
||||
return cmd()
|
||||
except TypeError:
|
||||
return cmd
|
||||
return cmd
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
In the examples, cmdset A always have higher priority than cmdset B.
|
||||
|
||||
mergetype (partly from Set theory):
|
||||
key - the name of the cmdset. This can be used on its own for game operations
|
||||
|
||||
mergetype (partly from Set theory):
|
||||
|
||||
Union - The two command sets are merged so that as many
|
||||
commands as possible of each cmdset ends up in the
|
||||
|
|
@ -125,13 +125,13 @@ class CmdSet(object):
|
|||
excempt from all merge operations - they are
|
||||
ALWAYS included across mergers and only affected
|
||||
if same-named system commands replace them.
|
||||
|
||||
|
||||
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,
|
||||
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.
|
||||
|
||||
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
|
||||
merger (i.e. A above) automatically taking
|
||||
|
|
@ -146,7 +146,7 @@ class CmdSet(object):
|
|||
select which ball to kick ... Allowing duplicates
|
||||
only makes sense for Union and Intersect, the setting
|
||||
is ignored for the other mergetypes.
|
||||
|
||||
|
||||
key_mergetype (dict) - allows the cmdset to define a unique
|
||||
mergetype for particular cmdsets. Format is
|
||||
{CmdSetkeystring:mergetype}. Priorities still apply.
|
||||
|
|
@ -155,14 +155,14 @@ class CmdSet(object):
|
|||
Myevilcmdset no matter what overall mergetype this set
|
||||
has.
|
||||
|
||||
no_objs - don't include any commands from nearby objects
|
||||
no_objs - don't include any commands from nearby objects
|
||||
when searching for suitable commands
|
||||
no_exits - ignore the names of exits when matching against
|
||||
commands
|
||||
no_channels - ignore the name of channels when matching against
|
||||
commands (WARNING- this is dangerous since the
|
||||
player can then not even ask staff for help if
|
||||
something goes wrong)
|
||||
something goes wrong)
|
||||
|
||||
|
||||
"""
|
||||
|
|
@ -176,14 +176,14 @@ class CmdSet(object):
|
|||
no_exits = False
|
||||
no_objs = False
|
||||
no_channels = False
|
||||
permanent = False
|
||||
|
||||
permanent = False
|
||||
|
||||
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
|
||||
instance of cmdset is related. It is often a player but may also be a
|
||||
regular object.
|
||||
"""
|
||||
if key:
|
||||
|
|
@ -194,12 +194,12 @@ class CmdSet(object):
|
|||
# initialize system
|
||||
self.at_cmdset_creation()
|
||||
|
||||
def at_cmdset_creation(self):
|
||||
def at_cmdset_creation(self):
|
||||
"""
|
||||
Hook method - this should be overloaded in the inheriting
|
||||
class, and should take care of populating the cmdset
|
||||
by use of self.add().
|
||||
"""
|
||||
"""
|
||||
pass
|
||||
|
||||
def add(self, cmd):
|
||||
|
|
@ -207,20 +207,20 @@ class CmdSet(object):
|
|||
Add a command, a list of commands or a cmdset to this cmdset.
|
||||
|
||||
Note that if cmd already exists in set,
|
||||
it will replace the old one (no priority checking etc
|
||||
at this point; this is often used to overload
|
||||
default commands).
|
||||
it will replace the old one (no priority checking etc
|
||||
at this point; this is often used to overload
|
||||
default commands).
|
||||
|
||||
If cmd is another cmdset class or -instance, the commands
|
||||
of that command set is added to this one, as if they were part
|
||||
of the original cmdset definition. No merging or priority checks
|
||||
are made, rather later added commands will simply replace
|
||||
existing ones to make a unique set.
|
||||
are made, rather later added commands will simply replace
|
||||
existing ones to make a unique set.
|
||||
"""
|
||||
|
||||
|
||||
if inherits_from(cmd, "src.commands.cmdset.CmdSet"):
|
||||
# cmd is a command set so merge all commands in that set
|
||||
# to this one. We raise a visible error if we created
|
||||
# to this one. We raise a visible error if we created
|
||||
# an infinite loop (adding cmdset to itself somehow)
|
||||
try:
|
||||
cmd = instantiate(cmd)
|
||||
|
|
@ -234,46 +234,46 @@ class CmdSet(object):
|
|||
else:
|
||||
cmds = [instantiate(cmd)]
|
||||
for cmd in cmds:
|
||||
# add all commands
|
||||
# add all commands
|
||||
if not hasattr(cmd, 'obj'):
|
||||
cmd.obj = self.cmdsetobj
|
||||
try:
|
||||
ic = self.commands.index(cmd)
|
||||
self.commands[ic] = cmd # replace
|
||||
self.commands[ic] = cmd # replace
|
||||
except ValueError:
|
||||
self.commands.append(cmd)
|
||||
# extra run to make sure to avoid doublets
|
||||
# extra run to make sure to avoid doublets
|
||||
self.commands = list(set(self.commands))
|
||||
#print "In cmdset.add(cmd):", self.key, cmd
|
||||
|
||||
def remove(self, cmd):
|
||||
"""
|
||||
Remove a command instance from the cmdset.
|
||||
cmd can be either a cmd instance or a key string.
|
||||
cmd can be either a cmd instance or a key string.
|
||||
"""
|
||||
cmd = instantiate(cmd)
|
||||
self.commands = [oldcmd for oldcmd in self.commands if oldcmd != cmd]
|
||||
|
||||
|
||||
def get(self, cmd):
|
||||
"""
|
||||
Return the command in this cmdset that matches the
|
||||
given command. cmd may be either a command instance or
|
||||
a key string.
|
||||
a key string.
|
||||
"""
|
||||
cmd = instantiate(cmd)
|
||||
for thiscmd in self.commands:
|
||||
if thiscmd == cmd:
|
||||
return thiscmd
|
||||
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
|
||||
commands starting with double underscore __.
|
||||
These are excempt from merge operations.
|
||||
These are excempt from merge operations.
|
||||
"""
|
||||
return [cmd for cmd in self.commands if cmd.key.startswith('__')]
|
||||
|
||||
|
|
@ -293,11 +293,11 @@ class CmdSet(object):
|
|||
cmdset.duplicates = self.duplicates
|
||||
cmdset.key_mergetypes = self.key_mergetypes.copy() #copy.deepcopy(self.key_mergetypes)
|
||||
return cmdset
|
||||
|
||||
|
||||
def make_unique(self, caller):
|
||||
"""
|
||||
This is an unsafe command meant to clean out a cmdset of
|
||||
doublet commands after it has been created. It is useful
|
||||
doublet commands after it has been created. It is useful
|
||||
for commands inheriting cmdsets from the cmdhandler where
|
||||
obj-based cmdsets always are added double. Doublets will
|
||||
be weeded out with preference to commands defined on caller,
|
||||
|
|
@ -313,14 +313,14 @@ class CmdSet(object):
|
|||
else:
|
||||
unique[cmd.key] = cmd
|
||||
self.commands = unique.values()
|
||||
|
||||
|
||||
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
Show all commands in cmdset when printing it.
|
||||
Show all commands in cmdset when printing it.
|
||||
"""
|
||||
return ", ".join([str(cmd) for cmd in sorted(self.commands, key=lambda o:o.key)])
|
||||
|
||||
|
||||
def __iter__(self):
|
||||
"""
|
||||
Allows for things like 'for cmd in cmdset':
|
||||
|
|
@ -331,14 +331,14 @@ class CmdSet(object):
|
|||
"""
|
||||
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'
|
||||
"""
|
||||
"""
|
||||
return any(cmd == othercmd for cmd in self.commands)
|
||||
|
||||
|
||||
def __add__(self, cmdset_b):
|
||||
"""
|
||||
Merge this cmdset (A) with another cmdset (B) using the + operator,
|
||||
|
||||
C = A + B
|
||||
C = A + B
|
||||
|
||||
Here, we (by convention) say that 'A is merged onto B to form
|
||||
C'. The actual merge operation used in the 'addition' depends
|
||||
|
|
@ -356,9 +356,9 @@ class CmdSet(object):
|
|||
# preserve system __commands
|
||||
sys_commands = self.get_system_cmds() + cmdset_b.get_system_cmds()
|
||||
|
||||
if self.priority >= cmdset_b.priority:
|
||||
if self.priority >= cmdset_b.priority:
|
||||
# A higher or equal priority than B
|
||||
mergetype = self.key_mergetypes.get(cmdset_b.key, self.mergetype)
|
||||
mergetype = self.key_mergetypes.get(cmdset_b.key, self.mergetype)
|
||||
if mergetype == "Intersect":
|
||||
cmdset_c = intersect(self, cmdset_b, cmdset_b.duplicates)
|
||||
elif mergetype == "Replace":
|
||||
|
|
@ -369,7 +369,7 @@ class CmdSet(object):
|
|||
cmdset_c = union(self, cmdset_b, cmdset_b.duplicates)
|
||||
else:
|
||||
# B higher priority than A
|
||||
mergetype = cmdset_b.key_mergetypes.get(self.key, cmdset_b.mergetype)
|
||||
mergetype = cmdset_b.key_mergetypes.get(self.key, cmdset_b.mergetype)
|
||||
if mergetype == "Intersect":
|
||||
cmdset_c = intersect(cmdset_b, self, self.duplicates)
|
||||
elif mergetype == "Replace":
|
||||
|
|
@ -382,9 +382,9 @@ class CmdSet(object):
|
|||
# we store actual_mergetype since key_mergetypes
|
||||
# might be different from the main mergetype.
|
||||
# This is used for diagnosis.
|
||||
cmdset_c.actual_mergetype = mergetype
|
||||
cmdset_c.actual_mergetype = mergetype
|
||||
|
||||
# return the system commands to the cmdset
|
||||
cmdset_c.add(sys_commands)
|
||||
|
||||
return cmdset_c
|
||||
return cmdset_c
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ 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
|
||||
import traceback
|
||||
from src.utils import logger, utils
|
||||
from src.commands.cmdset import CmdSet
|
||||
from src.server.models import ServerConfig
|
||||
|
|
@ -74,21 +74,21 @@ 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
|
||||
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.
|
||||
used to check if this is a valid python path or not.
|
||||
function returns None if an error was encountered or path not found.
|
||||
"""
|
||||
"""
|
||||
|
||||
try:
|
||||
try:
|
||||
try:
|
||||
#print "importing %s: CACHED_CMDSETS=%s" % (python_path, CACHED_CMDSETS)
|
||||
wanted_cache_key = python_path
|
||||
wanted_cache_key = python_path
|
||||
cmdsetclass = CACHED_CMDSETS.get(wanted_cache_key, None)
|
||||
errstring = ""
|
||||
if not cmdsetclass:
|
||||
|
|
@ -96,11 +96,11 @@ def import_cmdset(python_path, cmdsetobj, emit_to_obj=None, no_logging=False):
|
|||
# Not in cache. Reload from disk.
|
||||
modulepath, classname = python_path.rsplit('.', 1)
|
||||
module = __import__(modulepath, fromlist=[True])
|
||||
cmdsetclass = module.__dict__[classname]
|
||||
CACHED_CMDSETS[wanted_cache_key] = cmdsetclass
|
||||
cmdsetclass = module.__dict__[classname]
|
||||
CACHED_CMDSETS[wanted_cache_key] = cmdsetclass
|
||||
#instantiate the cmdset (and catch its errors)
|
||||
if callable(cmdsetclass):
|
||||
cmdsetclass = cmdsetclass(cmdsetobj)
|
||||
cmdsetclass = cmdsetclass(cmdsetobj)
|
||||
return cmdsetclass
|
||||
|
||||
except ImportError:
|
||||
|
|
@ -111,20 +111,20 @@ def import_cmdset(python_path, cmdsetobj, emit_to_obj=None, no_logging=False):
|
|||
errstring = "Error in loading cmdset: No cmdset class '%s' in %s."
|
||||
errstring = errstring % (classname, modulepath)
|
||||
raise
|
||||
except Exception:
|
||||
except Exception:
|
||||
errstring = "\n%s\nCompile/Run error when loading cmdset '%s'."
|
||||
errstring = errstring % (traceback.format_exc(), python_path)
|
||||
raise
|
||||
except Exception:
|
||||
except Exception:
|
||||
if errstring and not no_logging:
|
||||
print errstring
|
||||
logger.log_trace()
|
||||
print errstring
|
||||
logger.log_trace()
|
||||
if emit_to_obj and not ServerConfig.objects.conf("server_starting_mode"):
|
||||
object.__getattribute__(emit_to_obj, "msg")(errstring)
|
||||
object.__getattribute__(emit_to_obj, "msg")(errstring)
|
||||
logger.log_errmsg("Error: %s" % errstring)
|
||||
#cannot raise - it kills the server if no base cmdset exists!
|
||||
|
||||
# classes
|
||||
# classes
|
||||
|
||||
class CmdSetHandler(object):
|
||||
"""
|
||||
|
|
@ -134,35 +134,35 @@ class CmdSetHandler(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.
|
||||
the 'current' cmdset.
|
||||
"""
|
||||
|
||||
def __init__(self, obj):
|
||||
"""
|
||||
This method is called whenever an object is recreated.
|
||||
This method is called whenever an object is recreated.
|
||||
|
||||
obj - this is a reference to the game object this handler
|
||||
belongs to.
|
||||
"""
|
||||
self.obj = obj
|
||||
self.obj = obj
|
||||
|
||||
# the id of the "merged" current cmdset for easy access.
|
||||
# the id of the "merged" current cmdset for easy access.
|
||||
self.key = None
|
||||
# this holds the "merged" current command set
|
||||
# this holds the "merged" current command set
|
||||
self.current = None
|
||||
# this holds a history of CommandSets
|
||||
self.cmdset_stack = [CmdSet(cmdsetobj=self.obj, key="Empty")]
|
||||
# this tracks which mergetypes are actually in play in the stack
|
||||
self.mergetype_stack = ["Union"]
|
||||
self.mergetype_stack = ["Union"]
|
||||
|
||||
# the subset of the cmdset_paths that are to be stored in the database
|
||||
self.permanent_paths = [""]
|
||||
|
||||
|
||||
#self.update(init_mode=True) is then called from the object __init__.
|
||||
|
||||
def __str__(self):
|
||||
"Display current commands"
|
||||
|
||||
"Display current commands"
|
||||
|
||||
string = ""
|
||||
mergelist = []
|
||||
if len(self.cmdset_stack) > 1:
|
||||
|
|
@ -176,18 +176,18 @@ class CmdSetHandler(object):
|
|||
if cmdset.permanent:
|
||||
permstring = "perm"
|
||||
if mergetype != cmdset.mergetype:
|
||||
mergetype = "%s^" % (mergetype)
|
||||
mergetype = "%s^" % (mergetype)
|
||||
string += "\n %i: <%s (%s, prio %i, %s)>: %s" % \
|
||||
(snum, cmdset.key, mergetype,
|
||||
cmdset.priority, permstring, cmdset)
|
||||
cmdset.priority, permstring, cmdset)
|
||||
mergelist.append(str(snum))
|
||||
string += "\n"
|
||||
|
||||
|
||||
# Display the currently active cmdset, limited by self.obj's permissions
|
||||
mergetype = self.mergetype_stack[-1]
|
||||
mergetype = self.mergetype_stack[-1]
|
||||
if mergetype != self.current.mergetype:
|
||||
merged_on = self.cmdset_stack[-2].key
|
||||
mergetype = "custom %s on cmdset '%s'" % (mergetype, merged_on)
|
||||
mergetype = "custom %s on cmdset '%s'" % (mergetype, merged_on)
|
||||
if mergelist:
|
||||
string += " <Merged %s (%s, prio %i)>: %s" % ("+".join(mergelist), mergetype, self.current.priority, self.current)
|
||||
else:
|
||||
|
|
@ -196,74 +196,74 @@ class CmdSetHandler(object):
|
|||
permstring = "perm"
|
||||
string += " <%s (%s, prio %i, %s)>: %s" % (self.current.key, mergetype, self.current.priority, permstring,
|
||||
", ".join(cmd.key for cmd in sorted(self.current, key=lambda o:o.key)))
|
||||
return string.strip()
|
||||
return string.strip()
|
||||
|
||||
def update(self, init_mode=False):
|
||||
def update(self, init_mode=False):
|
||||
"""
|
||||
Re-adds all sets in the handler to have an updated
|
||||
current set.
|
||||
|
||||
init_mode is used right after this handler was
|
||||
created; it imports all permanent cmdsets from db.
|
||||
current set.
|
||||
|
||||
init_mode is used right after this handler was
|
||||
created; it imports all permanent cmdsets from db.
|
||||
"""
|
||||
if init_mode:
|
||||
# reimport all permanent cmdsets
|
||||
storage = self.obj.cmdset_storage
|
||||
#print "cmdset_storage:", self.obj.cmdset_storage
|
||||
#print "cmdset_storage:", self.obj.cmdset_storage
|
||||
if storage:
|
||||
self.cmdset_stack = []
|
||||
self.cmdset_stack = []
|
||||
for pos, path in enumerate(storage):
|
||||
if pos == 0 and not path:
|
||||
self.cmdset_stack = [CmdSet(cmdsetobj=self.obj, key="Empty")]
|
||||
elif path:
|
||||
cmdset = self.import_cmdset(path)
|
||||
cmdset = self.import_cmdset(path)
|
||||
if cmdset:
|
||||
cmdset.permanent = True
|
||||
self.cmdset_stack.append(cmdset)
|
||||
|
||||
|
||||
# merge the stack into a new merged cmdset
|
||||
new_current = None
|
||||
new_current = None
|
||||
self.mergetype_stack = []
|
||||
for cmdset in self.cmdset_stack:
|
||||
for cmdset in self.cmdset_stack:
|
||||
try:
|
||||
# for cmdset's '+' operator, order matters.
|
||||
new_current = cmdset + new_current
|
||||
# for cmdset's '+' operator, order matters.
|
||||
new_current = cmdset + new_current
|
||||
except TypeError:
|
||||
continue
|
||||
self.mergetype_stack.append(new_current.actual_mergetype)
|
||||
self.current = new_current
|
||||
|
||||
|
||||
def import_cmdset(self, cmdset_path, emit_to_obj=None):
|
||||
"""
|
||||
Method wrapper for import_cmdset.
|
||||
Method wrapper for import_cmdset.
|
||||
load a cmdset from a module.
|
||||
cmdset_path - the python path to an cmdset object.
|
||||
cmdset_path - the python path to an cmdset object.
|
||||
emit_to_obj - object to send error messages to
|
||||
"""
|
||||
if not emit_to_obj:
|
||||
emit_to_obj = self.obj
|
||||
return import_cmdset(cmdset_path, self.obj, emit_to_obj)
|
||||
|
||||
|
||||
def add(self, cmdset, emit_to_obj=None, permanent=False):
|
||||
"""
|
||||
Add a cmdset to the handler, on top of the old ones.
|
||||
Default is to not make this permanent, i.e. the set
|
||||
will not survive a server reset.
|
||||
Default is to not make this permanent, i.e. the set
|
||||
will not survive a server reset.
|
||||
|
||||
cmdset - can be a cmdset object or the python path to
|
||||
such an object.
|
||||
emit_to_obj - an object to receive error messages.
|
||||
emit_to_obj - an object to receive error messages.
|
||||
permanent - this cmdset will remain across a server reboot
|
||||
|
||||
Note: An interesting feature of this method is if you were to
|
||||
send it an *already instantiated cmdset* (i.e. not a class),
|
||||
the current cmdsethandler's obj attribute will then *not* be
|
||||
transferred over to this already instantiated set (this is
|
||||
because it might be used elsewhere and can cause strange effects).
|
||||
because it might be used elsewhere and can cause strange effects).
|
||||
This means you could in principle have the handler
|
||||
launch command sets tied to a *different* object than the
|
||||
handler. Not sure when this would be useful, but it's a 'quirk'
|
||||
that has to be documented.
|
||||
that has to be documented.
|
||||
"""
|
||||
if callable(cmdset):
|
||||
if not utils.inherits_from(cmdset, CmdSet):
|
||||
|
|
@ -278,13 +278,13 @@ class CmdSetHandler(object):
|
|||
cmdset.permanent = True
|
||||
storage = self.obj.cmdset_storage
|
||||
if not storage:
|
||||
storage = ["", cmdset.path]
|
||||
storage = ["", cmdset.path]
|
||||
else:
|
||||
storage.append(cmdset.path)
|
||||
self.obj.cmdset_storage = storage
|
||||
else:
|
||||
cmdset.permanent = False
|
||||
self.cmdset_stack.append(cmdset)
|
||||
cmdset.permanent = False
|
||||
self.cmdset_stack.append(cmdset)
|
||||
self.update()
|
||||
|
||||
def add_default(self, cmdset, emit_to_obj=None, permanent=True):
|
||||
|
|
@ -292,11 +292,11 @@ class CmdSetHandler(object):
|
|||
Add a new default cmdset. If an old default existed,
|
||||
it is replaced. If permanent is set, the set will survive a reboot.
|
||||
cmdset - can be a cmdset object or the python path to
|
||||
an instance of such an object.
|
||||
emit_to_obj - an object to receive error messages.
|
||||
an instance of such an object.
|
||||
emit_to_obj - an object to receive error messages.
|
||||
permanent - save cmdset across reboots
|
||||
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!")
|
||||
|
|
@ -311,9 +311,9 @@ class CmdSetHandler(object):
|
|||
else:
|
||||
self.cmdset_stack = [cmdset]
|
||||
self.mergetype_stack = [cmdset.mergetype]
|
||||
|
||||
|
||||
if permanent:
|
||||
cmdset.permanent = True
|
||||
cmdset.permanent = True
|
||||
storage = self.obj.cmdset_storage
|
||||
if storage:
|
||||
storage[0] = cmdset.path
|
||||
|
|
@ -321,12 +321,12 @@ class CmdSetHandler(object):
|
|||
storage = [cmdset.path]
|
||||
self.obj.cmdset_storage = storage
|
||||
else:
|
||||
cmdset.permanent = False
|
||||
self.update()
|
||||
|
||||
cmdset.permanent = False
|
||||
self.update()
|
||||
|
||||
def delete(self, cmdset=None):
|
||||
"""
|
||||
Remove a cmdset from the handler.
|
||||
Remove a cmdset from the handler.
|
||||
|
||||
cmdset can be supplied either as a cmdset-key,
|
||||
an instance of the CmdSet or a python path
|
||||
|
|
@ -338,17 +338,17 @@ class CmdSetHandler(object):
|
|||
|
||||
"""
|
||||
if len(self.cmdset_stack) < 2:
|
||||
# don't allow deleting default cmdsets here.
|
||||
# don't allow deleting default cmdsets here.
|
||||
return
|
||||
|
||||
if not cmdset:
|
||||
# remove the last one in the stack
|
||||
# remove the last one in the stack
|
||||
cmdset = self.cmdset_stack.pop()
|
||||
if cmdset.permanent:
|
||||
storage = self.obj.cmdset_storage
|
||||
storage.pop()
|
||||
self.obj.cmdset_storage = storage
|
||||
else:
|
||||
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]
|
||||
|
|
@ -358,21 +358,21 @@ class CmdSetHandler(object):
|
|||
storage = []
|
||||
|
||||
if any(cset.permanent for cset in delcmdsets):
|
||||
# only hit database if there's need to
|
||||
storage = self.obj.cmdset_storage
|
||||
for cset in delcmdsets:
|
||||
# only hit database if there's need to
|
||||
storage = self.obj.cmdset_storage
|
||||
for cset in delcmdsets:
|
||||
if cset.permanent:
|
||||
try:
|
||||
storage.remove(cset.path)
|
||||
storage.remove(cset.path)
|
||||
except ValueError:
|
||||
pass
|
||||
for cset in delcmdsets:
|
||||
# clean the in-memory stack
|
||||
# clean the in-memory stack
|
||||
try:
|
||||
self.cmdset_stack.remove(cset)
|
||||
except ValueError:
|
||||
pass
|
||||
# re-sync the cmdsethandler.
|
||||
pass
|
||||
# re-sync the cmdsethandler.
|
||||
self.update()
|
||||
|
||||
def delete_default(self):
|
||||
|
|
@ -385,9 +385,9 @@ class CmdSetHandler(object):
|
|||
storage[0] = ""
|
||||
else:
|
||||
storage = [""]
|
||||
self.cmdset_storage = storage
|
||||
self.cmdset_storage = storage
|
||||
self.cmdset_stack[0] = CmdSet(cmdsetobj=self.obj, key="Empty")
|
||||
else:
|
||||
else:
|
||||
self.cmdset_stack = [CmdSet(cmdsetobj=self.obj, key="Empty")]
|
||||
self.update()
|
||||
|
||||
|
|
@ -405,21 +405,21 @@ class CmdSetHandler(object):
|
|||
self.cmdset_stack = [self.cmdset_stack[0]]
|
||||
self.mergetype_stack = [self.cmdset_stack[0].mergetype]
|
||||
storage = self.obj.cmdset_storage
|
||||
if storage:
|
||||
if storage:
|
||||
storage = storage[0]
|
||||
self.obj.cmdset_storage = storage
|
||||
self.obj.cmdset_storage = storage
|
||||
self.update()
|
||||
|
||||
def has_cmdset(self, cmdset_key, must_be_default=False):
|
||||
"""
|
||||
checks so the cmdsethandler contains a cmdset with the given key.
|
||||
must_be_default - only match against the default cmdset.
|
||||
must_be_default - only match against the default cmdset.
|
||||
"""
|
||||
if must_be_default:
|
||||
return self.cmdset_stack and self.cmdset_stack[0].key == cmdset_key
|
||||
else:
|
||||
return any([cmdset.key == cmdset_key for cmdset in self.cmdset_stack])
|
||||
|
||||
|
||||
|
||||
def all(self):
|
||||
"""
|
||||
|
|
@ -429,16 +429,16 @@ class CmdSetHandler(object):
|
|||
|
||||
def reset(self):
|
||||
"""
|
||||
Force reload of all cmdsets in handler. This should be called
|
||||
after CACHED_CMDSETS have been cleared (normally by @reload).
|
||||
Force reload of all cmdsets in handler. This should be called
|
||||
after CACHED_CMDSETS have been cleared (normally by @reload).
|
||||
"""
|
||||
new_cmdset_stack = []
|
||||
new_mergetype_stack = []
|
||||
new_mergetype_stack = []
|
||||
for cmdset in self.cmdset_stack:
|
||||
if cmdset.key == "Empty":
|
||||
new_cmdset_stack.append(cmdset)
|
||||
new_mergetype_stack.append("Union")
|
||||
else:
|
||||
else:
|
||||
new_cmdset_stack.append(self.import_cmdset(cmdset.path))
|
||||
new_mergetype_stack.append(cmdset.mergetype)
|
||||
self.cmdset_stack = new_cmdset_stack
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
"""
|
||||
The base Command class.
|
||||
|
||||
All commands in Evennia inherit from the 'Command' class in this module.
|
||||
All commands in Evennia inherit from the 'Command' class in this module.
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -12,19 +12,19 @@ from src.utils.utils import is_iter
|
|||
class CommandMeta(type):
|
||||
"""
|
||||
This metaclass makes some minor on-the-fly convenience fixes to the command
|
||||
class in case the admin forgets to put things in lowercase etc.
|
||||
"""
|
||||
class in case the admin forgets to put things in lowercase etc.
|
||||
"""
|
||||
def __init__(mcs, *args, **kwargs):
|
||||
"""
|
||||
Simply make sure all data are stored as lowercase and
|
||||
do checking on all properties that should be in list form.
|
||||
Sets up locks to be more forgiving.
|
||||
Sets up locks to be more forgiving.
|
||||
"""
|
||||
mcs.key = mcs.key.lower()
|
||||
if mcs.aliases and not is_iter(mcs.aliases):
|
||||
try:
|
||||
mcs.aliases = mcs.aliases.split(',')
|
||||
except Exception:
|
||||
except Exception:
|
||||
mcs.aliases = []
|
||||
mcs.aliases = [str(alias).strip() for alias in mcs.aliases]
|
||||
if not hasattr(mcs, "save_for_next"):
|
||||
|
|
@ -61,19 +61,19 @@ class CommandMeta(type):
|
|||
# define their own parser method to handle the input. The
|
||||
# advantage of this is inheritage; commands that have similar
|
||||
# structure can parse the input string the same way, minimizing
|
||||
# parsing errors.
|
||||
|
||||
# parsing errors.
|
||||
|
||||
class Command(object):
|
||||
"""
|
||||
Base command
|
||||
|
||||
Usage:
|
||||
command [args]
|
||||
|
||||
|
||||
This is the base command class. Inherit from this
|
||||
to create new commands.
|
||||
|
||||
The cmdhandler makes the following variables available to the
|
||||
to create new commands.
|
||||
|
||||
The cmdhandler makes the following variables available to the
|
||||
command methods (so you can always assume them to be there):
|
||||
self.caller - the game object calling the command
|
||||
self.cmdstring - the command name used to trigger this command (allows
|
||||
|
|
@ -84,10 +84,20 @@ class Command(object):
|
|||
seldomly, notably for help-type commands, to create dynamic
|
||||
help entries and lists)
|
||||
cmd.obj - the object on which this command is defined. If a default command,
|
||||
this is usually the same as caller.
|
||||
this is usually the same as caller.
|
||||
|
||||
(Note that 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)
|
||||
The following class properties can/should be defined on your child class:
|
||||
|
||||
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")
|
||||
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?)
|
||||
|
||||
(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
|
||||
|
|
@ -103,20 +113,20 @@ class Command(object):
|
|||
|
||||
# this normally does not need to be changed. It allows to turn off
|
||||
# auto-help entry creation for individual commands.
|
||||
auto_help = True
|
||||
# There is also the property 'obj'. This gets set by the system
|
||||
auto_help = True
|
||||
# There is also the property 'obj'. This gets set by the system
|
||||
# on the fly to tie this particular command to a certain in-game entity.
|
||||
# self.obj should NOT be defined here since it will not be overwritten
|
||||
# if it already exists.
|
||||
|
||||
# self.obj should NOT be defined here since it will not be overwritten
|
||||
# if it already exists.
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.lockhandler = LockHandler(self)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
"Print the command"
|
||||
return self.key
|
||||
|
||||
|
||||
def __eq__(self, cmd):
|
||||
"""
|
||||
Compare two command instances to each other by matching their
|
||||
|
|
@ -132,7 +142,7 @@ class Command(object):
|
|||
"""
|
||||
This implements searches like 'if query in cmd'. It's a fuzzy matching
|
||||
used by the help system, returning True if query can be found
|
||||
as a substring of the commands key or its aliases.
|
||||
as a substring of the commands key or its aliases.
|
||||
|
||||
input can be either a command object or a command name.
|
||||
"""
|
||||
|
|
@ -156,11 +166,11 @@ class Command(object):
|
|||
This hook is called by the cmdhandler to determine if srcobj
|
||||
is allowed to execute this command. It should return a boolean
|
||||
value and is not normally something that need to be changed since
|
||||
it's using the Evennia permission system directly.
|
||||
it's using the Evennia permission system directly.
|
||||
"""
|
||||
return self.lockhandler.check(srcobj, access_type, default=default)
|
||||
|
||||
# Common Command hooks
|
||||
# Common Command hooks
|
||||
|
||||
def at_pre_cmd(self):
|
||||
"""
|
||||
|
|
@ -170,7 +180,7 @@ class Command(object):
|
|||
|
||||
def at_post_cmd(self):
|
||||
"""
|
||||
This hook is called after the command has finished executing
|
||||
This hook is called after the command has finished executing
|
||||
(after self.func()).
|
||||
"""
|
||||
pass
|
||||
|
|
@ -181,31 +191,31 @@ class Command(object):
|
|||
want, this function is run. If many of your commands have
|
||||
a similar syntax (for example 'cmd arg1 = arg2') you should simply
|
||||
define this once and just let other commands of the same form
|
||||
inherit from this. See the docstring of this module for
|
||||
which object properties are available to use
|
||||
inherit from this. See the docstring of this module for
|
||||
which object properties are available to use
|
||||
(notably self.args).
|
||||
"""
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def func(self):
|
||||
"""
|
||||
This is the actual executing part of the command.
|
||||
This is the actual executing part of the command.
|
||||
It is called directly after self.parse(). See the docstring
|
||||
of this module for which object properties are available
|
||||
(beyond those set in self.parse())
|
||||
"""
|
||||
(beyond those set in self.parse())
|
||||
"""
|
||||
# a simple test command to show the available properties
|
||||
string = "-" * 50
|
||||
string += "\n{w%s{n - Command variables from evennia:\n" % self.key
|
||||
string += "\n{w%s{n - Command variables from evennia:\n" % self.key
|
||||
string += "-" * 50
|
||||
string += "\nname of cmd (self.key): {w%s{n\n" % self.key
|
||||
string += "\nname of cmd (self.key): {w%s{n\n" % self.key
|
||||
string += "cmd aliases (self.aliases): {w%s{n\n" % self.aliases
|
||||
string += "cmd perms (self.permissions): {w%s{n\n" % self.permissions
|
||||
string += "help category (self.help_category): {w%s{n\n" % self.help_category
|
||||
string += "object calling (self.caller): {w%s{n\n" % self.caller
|
||||
string += "object storing cmdset (self.obj): {w%s{n\n" % self.obj
|
||||
string += "command string given (self.cmdstring): {w%s{n\n" % self.cmdstring
|
||||
string += "command string given (self.cmdstring): {w%s{n\n" % self.cmdstring
|
||||
# show cmdset.key instead of cmdset to shorten output
|
||||
string += utils.fill("current cmdset (self.cmdset): {w%s{n\n" % self.cmdset)
|
||||
|
||||
|
||||
self.caller.msg(string)
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
#
|
||||
# This is Evennia's default connection screen. It is imported
|
||||
# and run from game/gamesrc/world/connection_screens.py.
|
||||
# This is Evennia's default connection screen. It is imported
|
||||
# and run from game/gamesrc/world/connection_screens.py.
|
||||
#
|
||||
|
||||
from src.utils import utils
|
||||
from src.utils import utils
|
||||
|
||||
DEFAULT_SCREEN = \
|
||||
"""{b=============================================================={n
|
||||
Welcome to {gEvennia{n, version %s!
|
||||
Welcome to {gEvennia{n, version %s!
|
||||
|
||||
If you have an existing account, connect to it by typing:
|
||||
{wconnect <email> <password>{n
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue