diff options
Diffstat (limited to 'wrapper_command.py')
-rw-r--r-- | wrapper_command.py | 237 |
1 files changed, 229 insertions, 8 deletions
diff --git a/wrapper_command.py b/wrapper_command.py index dd51534..90eaf01 100644 --- a/wrapper_command.py +++ b/wrapper_command.py @@ -1,11 +1,232 @@ from wrapper_player import * +from helpers import * -def command(command = "help"): - def decorator(wrapped): - @hook.command(command) - def wrapper(sender, command, label, args): +root_commands = Command_dict() # {"command": command_object} + +def check_arguments(command, arguments): + prev_required = True + type_message_seen = False + prev_arg = arguments[0] if len(arguments) > 0 else None + for arg_info in arguments[1:]: + + if not prev_arg.required and arg_info.required: + raise Argument_exception("Command: %s; There may not be required arguments after non-required arguments" % command) + + if prev_arg.type == Argument.MESSAGE: + raise Argument_exception("Command: %s; An argument of type MESSAGE may not be followed by other arguments" % command) + + prev_arg = arg_info + +#-------------------------------------------------------------------------------------- + +class Command_dict(dict): + #{"cmd1" : cmd_object} + def get_command_object(self, alias): + for cmd_name, cmd_obj in self.iteritems(): + if alias == cmd_name or alias in cmd_obj.aliases: + return cmd_obj + raise KeyError("Subcommand '%s' was not found" % alias) + +#-------------------------------------------------------------------------------------- + +class Command(object): + + def __init__(self, + command, + aliases = (), + arguments = ( + Argument("target", Argument.string, "the player to teleport to"), + Argument("second target", Argument.string, "the player to teleport", False), + ), + parent = None): + + self.command = command.lower() + self.arguments = arguments + + check_arguments(self.command, self.arguments) + + prev_required = True + for arg_info in self.arguments: + if not prev_required and arg_info.required: + raise Argument_exception("Command: %s; There may not be required arguments after non-required arguments" % self.command) + + self.aliases = tuple(alias.lower() for alias in aliases) + self.parent = parent + self.sub_commands = Command_dict() + + if self.parent == None: + root_commands[self.command] = self + else: try: - return wrapped(sender = py_players[sender], command = command, label = label, args = args) - except: - print(print_traceback()) - return decorator
\ No newline at end of file + parent_route = self.parent.split(" ") + parent_sub_commands = root_commands + parent_obj = None + for cmd_name in parent_route: + parent_obj = parent_sub_commands.get_command_object(cmd_name) + parent_sub_commands = parent_obj.sub_commands + parent_obj.sub_commands[self.command] = self + + except command_exception, e: + error("Error occurred while setting up command hierarchy. " + e.message + "\n" + trace()) + + def __call__(self, handler): + self.handler = handler + + if parent == None: + @hook.command(self.command, self.aliases) + def run(sender, command, label, args): + try: + message = self.execute(sender, command, label, args) + except Command_exception as e: + message = e.message + except Exception: + error(trace()) + return True + if message: + sender.sendMessage(message) + return True + + return handler + + def execute(self, sender, command, label, args): + try: + return self.sub_commands.get_command_object(args[0].lower()).execute(sender, command, label, args[1:]) + except (KeyError, IndexError): + self.execute_checks(sender, command, label, args) + + def execute_checks(self, sender, command, label, args): + #TODO + + scape = Command_scape(args, self.arguments) + if is_player(sender): + sender = py_players[sender] + + return self.handler(sender, self, scape) + + def syntax(self): + return " ".join(tuple(arg_info.syntax() for arg_info in self.arguments)) + +#-------------------------------------------------------------------------------------- + +class Command_scape(list): + + def __init__(self, args, arg_layout): + super(list, self).__init__() + self.raw = args + self.arg_layout = arg_layout + + has_message = False + for i in range(len(arg_layout)): + arg_info = arg_layout[i] + + given = (len(args) >= i + 1) + if arg_info.required and not given: + raise Argument_exception("You must specify the " + arg_info.name) + + if not given: + self.append(None) + continue + + given_arg = args[i] + arg_type = arg_info.type + + if arg_type == Argument.STRING: + self.append(given_arg) + + elif arg_type == Argument.INTEGER: + try: + value = int(given_arg) + except ValueError: + raise Argument_exception("The %s has to be a round number" % arg_info.name) + self.append(value) + + elif arg_type == Argument.FLOAT: + try: + value = float(given_arg) + except ValueError: + raise Argument_exception("The %s has to be a number" % arg_info.name) + self.append(value) + + elif arg_type == Argument.PLAYER: + target = server.getPlayer(given_arg) + if target == None: + raise Argument_exception("The %s has to be an online player" % arg_info.name) + self.append(py_players[target]) + + elif arg_type == Argument.OFFLINE_PLAYER: + try: + # Code to get the PY PLAYER by name. Possibly, uid(server.getOfflinePlayer(given_arg)) can be used? + pass + except KeyError: + raise Argument_exception("The %s has to be an existing player" % arg_info.name) + self.append(None) + + elif arg_type == Argument.MESSAGE: + self.append(" ".join(args[i:])) + has_message = True + else: + error("Argument type not found: %d" % arg_type) + raise Argument_exception("A weird thing has happened, please contact an administrator") + + if not has_message: + self.remainder = args[len(arg_layout):] + else: + self.remainder = None + + def has_flag(self, flag, check_all = False): + return (("-" + flag) in self.raw) if check_all else (("-" + flag) in self.remainder) + + def get_raw(self): + return self.raw + + def get_arg_layout(self): + return self.arg_layout + +#-------------------------------------------------------------------------------------- + +class Command_exception(Exception): + + def __init__(self, message): + self.message = message + +class Argument_exception(Exception): + + def __init__(self, message): + self.message = message + +#-------------------------------------------------------------------------------------- + +class Argument(): + + STRING = 0 + INTEGER = 1 + FLOAT = 2 + PLAYER = 3 + OFFLINE_PLAYER = 4 + MESSAGE = 5 + + def __init__(self, name, type, definition, required = True): + self.name = name + self.type = type + self.definition = definition + self.required = required + + def syntax(self): + syntax = self.name + if self.type == Argument.MESSAGE: + syntax += "..." + return (("<%s>" if self.required else "[%s]") % syntax) + +#-------------------------------------------------------------------------------------- + +class Validate(): + + @staticmethod + def is_true(expression, fail_message): + if not expression: + raise Command_exception(fail_message) + + @staticmethod + def not_none(obj, fail_message): + if obj == None: + raise Command_exception(fail_message) |