diff --git a/common/src/main/java/com/dfsek/terra/api/command/CommandManager.java b/common/src/main/java/com/dfsek/terra/api/command/CommandManager.java index c46724d6c..d2ff2c820 100644 --- a/common/src/main/java/com/dfsek/terra/api/command/CommandManager.java +++ b/common/src/main/java/com/dfsek/terra/api/command/CommandManager.java @@ -9,7 +9,7 @@ import java.util.List; public interface CommandManager { void execute(String command, CommandSender sender, List args) throws CommandException; - void register(String name, Class clazz); + void register(String name, Class clazz) throws MalformedCommandException; List tabComplete(String command, CommandSender sender, List args) throws MalformedCommandException, CommandException; } diff --git a/common/src/main/java/com/dfsek/terra/api/command/CommandTemplate.java b/common/src/main/java/com/dfsek/terra/api/command/CommandTemplate.java index bb01ab198..836192b6b 100644 --- a/common/src/main/java/com/dfsek/terra/api/command/CommandTemplate.java +++ b/common/src/main/java/com/dfsek/terra/api/command/CommandTemplate.java @@ -1,5 +1,7 @@ package com.dfsek.terra.api.command; +import com.dfsek.terra.api.platform.CommandSender; + public interface CommandTemplate { - void execute(ExecutionState state); + void execute(CommandSender sender); } diff --git a/common/src/main/java/com/dfsek/terra/api/command/ExecutionState.java b/common/src/main/java/com/dfsek/terra/api/command/ExecutionState.java index b262249fd..89216bd89 100644 --- a/common/src/main/java/com/dfsek/terra/api/command/ExecutionState.java +++ b/common/src/main/java/com/dfsek/terra/api/command/ExecutionState.java @@ -24,21 +24,8 @@ public final class ExecutionState { args.put(arg, value); } - @SuppressWarnings("unchecked") - public T getArgument(String argument, Class clazz) { - - Object value = args.get(argument); - if(value == null) throw new IllegalArgumentException("Argument \"" + argument + "\" does not exist!"); - - if(clazz == int.class || clazz == Integer.class) { - value = Integer.parseInt(value.toString()); - } else if(clazz == double.class || clazz == Double.class) { - value = Double.parseDouble(value.toString()); - } - - // TODO: type loaders - - return clazz.cast(value); + public String getArgument(String argument) { + return args.get(argument); } public boolean hasSwitch(String flag) { diff --git a/common/src/main/java/com/dfsek/terra/api/command/TerraCommandManager.java b/common/src/main/java/com/dfsek/terra/api/command/TerraCommandManager.java index 82f7784ec..2def7fad1 100644 --- a/common/src/main/java/com/dfsek/terra/api/command/TerraCommandManager.java +++ b/common/src/main/java/com/dfsek/terra/api/command/TerraCommandManager.java @@ -5,9 +5,12 @@ import com.dfsek.terra.api.command.annotation.Argument; import com.dfsek.terra.api.command.annotation.Command; import com.dfsek.terra.api.command.annotation.Subcommand; import com.dfsek.terra.api.command.annotation.Switch; +import com.dfsek.terra.api.command.annotation.inject.ArgumentTarget; +import com.dfsek.terra.api.command.annotation.inject.SwitchTarget; import com.dfsek.terra.api.command.annotation.type.DebugCommand; import com.dfsek.terra.api.command.annotation.type.PlayerCommand; import com.dfsek.terra.api.command.annotation.type.WorldCommand; +import com.dfsek.terra.api.command.arg.ArgumentParser; import com.dfsek.terra.api.command.exception.CommandException; import com.dfsek.terra.api.command.exception.InvalidArgumentsException; import com.dfsek.terra.api.command.exception.MalformedCommandException; @@ -16,8 +19,10 @@ import com.dfsek.terra.api.injection.Injector; import com.dfsek.terra.api.injection.exception.InjectionException; import com.dfsek.terra.api.platform.CommandSender; import com.dfsek.terra.api.platform.entity.Player; +import com.dfsek.terra.api.util.ReflectionUtil; import com.dfsek.terra.world.TerraWorld; +import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; @@ -66,7 +71,7 @@ public class TerraCommandManager implements CommandManager { ExecutionState state = new ExecutionState(sender); if(!commandClass.isAnnotationPresent(Command.class)) { - invoke(commandClass, state); + invoke(commandClass, state, commandHolder); return; } @@ -74,7 +79,7 @@ public class TerraCommandManager implements CommandManager { if(command.arguments().length == 0 && command.subcommands().length == 0) { if(args.isEmpty()) { - invoke(commandClass, state); + invoke(commandClass, state, commandHolder); return; } else throw new InvalidArgumentsException("Expected 0 arguments, found " + args.size()); } @@ -119,24 +124,53 @@ public class TerraCommandManager implements CommandManager { state.addSwitch(commandHolder.switches.get(val)); } - invoke(commandClass, state); + invoke(commandClass, state, commandHolder); } - private void invoke(Class clazz, ExecutionState state) throws MalformedCommandException { + private void invoke(Class clazz, ExecutionState state, CommandHolder holder) throws MalformedCommandException { try { - System.out.println("invocation"); CommandTemplate template = clazz.getConstructor().newInstance(); pluginInjector.inject(template); - template.execute(state); + for(Field field : ReflectionUtil.getFields(clazz)) { + if(field.isAnnotationPresent(ArgumentTarget.class)) { + ArgumentTarget argumentTarget = field.getAnnotation(ArgumentTarget.class); + if(!holder.argumentMap.containsKey(argumentTarget.value())) { + throw new MalformedCommandException("Argument Target specifies nonexistent argument \"" + argumentTarget.value() + "\""); + } + + String argument = argumentTarget.value(); + + ArgumentParser argumentParser = holder.argumentMap.get(argumentTarget.value()).argumentParser().getConstructor().newInstance(); + + field.setAccessible(true); + field.set(template, argumentParser.parse(state.getSender(), state.getArgument(argument))); + } + if(field.isAnnotationPresent(SwitchTarget.class)) { + SwitchTarget switchTarget = field.getAnnotation(SwitchTarget.class); + if(!holder.switches.containsValue(switchTarget.value())) { + System.out.println(holder.switches); + throw new MalformedCommandException("Switch Target specifies nonexistent switch \"" + switchTarget.value() + "\""); + } + + if(!(field.getType() == boolean.class)) { + throw new MalformedCommandException("Switch Target must be of type boolean."); + } + + field.setAccessible(true); + field.setBoolean(template, state.hasSwitch(switchTarget.value())); + } + } + + template.execute(state.getSender()); } catch(InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | InjectionException e) { throw new MalformedCommandException("Unable to reflectively instantiate command: ", e); } } @Override - public void register(String name, Class clazz) { + public void register(String name, Class clazz) throws MalformedCommandException { commands.put(name, new CommandHolder(clazz)); } @@ -177,12 +211,15 @@ public class TerraCommandManager implements CommandManager { private final Map subcommands = new HashMap<>(); private final Map switches = new HashMap<>(); private final List arguments; + private final Map argumentMap = new HashMap<>(); - private CommandHolder(Class clazz) { + private CommandHolder(Class clazz) throws MalformedCommandException { this.clazz = clazz; if(clazz.isAnnotationPresent(Command.class)) { Command command = clazz.getAnnotation(Command.class); for(Subcommand subcommand : command.subcommands()) { + if(subcommands.containsKey(subcommand.value())) + throw new MalformedCommandException("Duplicate subcommand: " + subcommand); CommandHolder holder = new CommandHolder(subcommand.clazz()); subcommands.put(subcommand.value(), holder); for(String alias : subcommand.aliases()) { @@ -190,11 +227,16 @@ public class TerraCommandManager implements CommandManager { } } for(Switch aSwitch : command.switches()) { + if(switches.containsKey(aSwitch.value())) throw new MalformedCommandException("Duplicate switch: " + aSwitch); switches.put(aSwitch.value(), aSwitch.value()); for(String alias : aSwitch.aliases()) { switches.put(alias, aSwitch.value()); } } + for(Argument argument : command.arguments()) { + if(argumentMap.containsKey(argument.value())) throw new MalformedCommandException("Duplicate argument: " + argument); + argumentMap.put(argument.value(), argument); + } arguments = Arrays.asList(command.arguments()); } else arguments = Collections.emptyList(); } diff --git a/common/src/main/java/com/dfsek/terra/api/command/annotation/Argument.java b/common/src/main/java/com/dfsek/terra/api/command/annotation/Argument.java index 6ace3b0ce..a2625ee26 100644 --- a/common/src/main/java/com/dfsek/terra/api/command/annotation/Argument.java +++ b/common/src/main/java/com/dfsek/terra/api/command/annotation/Argument.java @@ -1,5 +1,7 @@ package com.dfsek.terra.api.command.annotation; +import com.dfsek.terra.api.command.arg.ArgumentParser; +import com.dfsek.terra.api.command.arg.StringArgumentParser; import com.dfsek.terra.api.command.tab.NothingCompleter; import com.dfsek.terra.api.command.tab.TabCompleter; @@ -15,7 +17,7 @@ public @interface Argument { boolean required() default true; - Class type() default String.class; - Class tabCompleter() default NothingCompleter.class; + + Class> argumentParser() default StringArgumentParser.class; } diff --git a/common/src/main/java/com/dfsek/terra/api/command/annotation/inject/ArgumentTarget.java b/common/src/main/java/com/dfsek/terra/api/command/annotation/inject/ArgumentTarget.java new file mode 100644 index 000000000..89dbc5245 --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/api/command/annotation/inject/ArgumentTarget.java @@ -0,0 +1,12 @@ +package com.dfsek.terra.api.command.annotation.inject; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ArgumentTarget { + String value(); +} diff --git a/common/src/main/java/com/dfsek/terra/api/command/annotation/inject/SwitchTarget.java b/common/src/main/java/com/dfsek/terra/api/command/annotation/inject/SwitchTarget.java new file mode 100644 index 000000000..67478373a --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/api/command/annotation/inject/SwitchTarget.java @@ -0,0 +1,12 @@ +package com.dfsek.terra.api.command.annotation.inject; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface SwitchTarget { + String value(); +} diff --git a/common/src/main/java/com/dfsek/terra/api/command/arg/ArgumentParser.java b/common/src/main/java/com/dfsek/terra/api/command/arg/ArgumentParser.java new file mode 100644 index 000000000..3fcc5aeef --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/api/command/arg/ArgumentParser.java @@ -0,0 +1,7 @@ +package com.dfsek.terra.api.command.arg; + +import com.dfsek.terra.api.platform.CommandSender; + +public interface ArgumentParser { + T parse(CommandSender sender, String arg); +} diff --git a/common/src/main/java/com/dfsek/terra/api/command/arg/DoubleArgumentParser.java b/common/src/main/java/com/dfsek/terra/api/command/arg/DoubleArgumentParser.java new file mode 100644 index 000000000..3f229b444 --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/api/command/arg/DoubleArgumentParser.java @@ -0,0 +1,10 @@ +package com.dfsek.terra.api.command.arg; + +import com.dfsek.terra.api.platform.CommandSender; + +public class DoubleArgumentParser implements ArgumentParser { + @Override + public Double parse(CommandSender sender, String arg) { + return arg == null ? null : Double.parseDouble(arg); + } +} diff --git a/common/src/main/java/com/dfsek/terra/api/command/arg/IntegerArgumentParser.java b/common/src/main/java/com/dfsek/terra/api/command/arg/IntegerArgumentParser.java new file mode 100644 index 000000000..24e3186ca --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/api/command/arg/IntegerArgumentParser.java @@ -0,0 +1,10 @@ +package com.dfsek.terra.api.command.arg; + +import com.dfsek.terra.api.platform.CommandSender; + +public class IntegerArgumentParser implements ArgumentParser { + @Override + public Integer parse(CommandSender sender, String arg) { + return arg == null ? null : Integer.parseInt(arg); + } +} diff --git a/common/src/main/java/com/dfsek/terra/api/command/arg/StringArgumentParser.java b/common/src/main/java/com/dfsek/terra/api/command/arg/StringArgumentParser.java new file mode 100644 index 000000000..736b335d0 --- /dev/null +++ b/common/src/main/java/com/dfsek/terra/api/command/arg/StringArgumentParser.java @@ -0,0 +1,10 @@ +package com.dfsek.terra.api.command.arg; + +import com.dfsek.terra.api.platform.CommandSender; + +public class StringArgumentParser implements ArgumentParser { + @Override + public String parse(CommandSender sender, String arg) { + return arg; + } +} diff --git a/common/src/main/java/com/dfsek/terra/commands/ReloadCommand.java b/common/src/main/java/com/dfsek/terra/commands/ReloadCommand.java index 119429dc6..512ccfbd2 100644 --- a/common/src/main/java/com/dfsek/terra/commands/ReloadCommand.java +++ b/common/src/main/java/com/dfsek/terra/commands/ReloadCommand.java @@ -1,13 +1,13 @@ package com.dfsek.terra.commands; import com.dfsek.terra.api.command.CommandTemplate; -import com.dfsek.terra.api.command.ExecutionState; import com.dfsek.terra.api.command.annotation.Command; +import com.dfsek.terra.api.platform.CommandSender; @Command() public class ReloadCommand implements CommandTemplate { @Override - public void execute(ExecutionState state) { + public void execute(CommandSender sender) { } } diff --git a/common/src/main/java/com/dfsek/terra/commands/StructureCommand.java b/common/src/main/java/com/dfsek/terra/commands/StructureCommand.java index a2d176ea7..9b9e7355c 100644 --- a/common/src/main/java/com/dfsek/terra/commands/StructureCommand.java +++ b/common/src/main/java/com/dfsek/terra/commands/StructureCommand.java @@ -1,9 +1,9 @@ package com.dfsek.terra.commands; import com.dfsek.terra.api.command.CommandTemplate; -import com.dfsek.terra.api.command.ExecutionState; import com.dfsek.terra.api.command.annotation.Command; import com.dfsek.terra.api.command.annotation.Subcommand; +import com.dfsek.terra.api.platform.CommandSender; import com.dfsek.terra.commands.structure.StructureExportCommand; import com.dfsek.terra.commands.structure.StructureLoadCommand; @@ -23,7 +23,7 @@ import com.dfsek.terra.commands.structure.StructureLoadCommand; ) public class StructureCommand implements CommandTemplate { @Override - public void execute(ExecutionState state) { + public void execute(CommandSender sender) { } } diff --git a/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileCommand.java b/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileCommand.java index b5bd9d270..4caad6957 100644 --- a/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileCommand.java +++ b/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileCommand.java @@ -1,12 +1,12 @@ package com.dfsek.terra.commands.profiler; import com.dfsek.terra.api.command.CommandTemplate; -import com.dfsek.terra.api.command.ExecutionState; import com.dfsek.terra.api.command.annotation.Command; import com.dfsek.terra.api.command.annotation.Subcommand; import com.dfsek.terra.api.command.annotation.type.DebugCommand; import com.dfsek.terra.api.command.annotation.type.PlayerCommand; import com.dfsek.terra.api.command.annotation.type.WorldCommand; +import com.dfsek.terra.api.platform.CommandSender; @Command( subcommands = { @@ -22,7 +22,7 @@ import com.dfsek.terra.api.command.annotation.type.WorldCommand; @DebugCommand public class ProfileCommand implements CommandTemplate { @Override - public void execute(ExecutionState state) { + public void execute(CommandSender sender) { } } diff --git a/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileQueryCommand.java b/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileQueryCommand.java index b0004799f..16f383b2d 100644 --- a/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileQueryCommand.java +++ b/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileQueryCommand.java @@ -2,12 +2,12 @@ package com.dfsek.terra.commands.profiler; import com.dfsek.terra.api.TerraPlugin; import com.dfsek.terra.api.command.CommandTemplate; -import com.dfsek.terra.api.command.ExecutionState; import com.dfsek.terra.api.command.annotation.Command; import com.dfsek.terra.api.command.annotation.type.DebugCommand; import com.dfsek.terra.api.command.annotation.type.PlayerCommand; import com.dfsek.terra.api.command.annotation.type.WorldCommand; import com.dfsek.terra.api.injection.annotations.Inject; +import com.dfsek.terra.api.platform.CommandSender; import com.dfsek.terra.api.platform.entity.Player; import com.dfsek.terra.world.TerraWorld; @@ -20,9 +20,9 @@ public class ProfileQueryCommand implements CommandTemplate { private TerraPlugin main; @Override - public void execute(ExecutionState state) { - Player player = (Player) state.getSender(); + public void execute(CommandSender sender) { + Player player = (Player) sender; TerraWorld world = main.getWorld(player.getWorld()); - state.getSender().sendMessage(world.getProfiler().getResultsFormatted()); + player.sendMessage(world.getProfiler().getResultsFormatted()); } } diff --git a/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileResetCommand.java b/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileResetCommand.java index 4d2349291..1a4c47e6e 100644 --- a/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileResetCommand.java +++ b/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileResetCommand.java @@ -2,12 +2,12 @@ package com.dfsek.terra.commands.profiler; import com.dfsek.terra.api.TerraPlugin; import com.dfsek.terra.api.command.CommandTemplate; -import com.dfsek.terra.api.command.ExecutionState; import com.dfsek.terra.api.command.annotation.Command; import com.dfsek.terra.api.command.annotation.type.DebugCommand; import com.dfsek.terra.api.command.annotation.type.PlayerCommand; import com.dfsek.terra.api.command.annotation.type.WorldCommand; import com.dfsek.terra.api.injection.annotations.Inject; +import com.dfsek.terra.api.platform.CommandSender; import com.dfsek.terra.api.platform.entity.Player; import com.dfsek.terra.world.TerraWorld; @@ -20,10 +20,10 @@ public class ProfileResetCommand implements CommandTemplate { private TerraPlugin main; @Override - public void execute(ExecutionState state) { - Player player = (Player) state.getSender(); + public void execute(CommandSender sender) { + Player player = (Player) sender; TerraWorld world = main.getWorld(player.getWorld()); world.getProfiler().reset(); - state.getSender().sendMessage("Profiler reset."); + player.sendMessage("Profiler reset."); } } diff --git a/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileStartCommand.java b/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileStartCommand.java index bb42588a1..36dcec85b 100644 --- a/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileStartCommand.java +++ b/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileStartCommand.java @@ -2,12 +2,12 @@ package com.dfsek.terra.commands.profiler; import com.dfsek.terra.api.TerraPlugin; import com.dfsek.terra.api.command.CommandTemplate; -import com.dfsek.terra.api.command.ExecutionState; import com.dfsek.terra.api.command.annotation.Command; import com.dfsek.terra.api.command.annotation.type.DebugCommand; import com.dfsek.terra.api.command.annotation.type.PlayerCommand; import com.dfsek.terra.api.command.annotation.type.WorldCommand; import com.dfsek.terra.api.injection.annotations.Inject; +import com.dfsek.terra.api.platform.CommandSender; import com.dfsek.terra.api.platform.entity.Player; import com.dfsek.terra.world.TerraWorld; @@ -20,10 +20,10 @@ public class ProfileStartCommand implements CommandTemplate { private TerraPlugin main; @Override - public void execute(ExecutionState state) { - Player player = (Player) state.getSender(); + public void execute(CommandSender sender) { + Player player = (Player) sender; TerraWorld world = main.getWorld(player.getWorld()); world.getProfiler().setProfiling(true); - state.getSender().sendMessage("Profiling enabled."); + player.sendMessage("Profiling enabled."); } } diff --git a/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileStopCommand.java b/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileStopCommand.java index 80330e40a..64e46fe39 100644 --- a/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileStopCommand.java +++ b/common/src/main/java/com/dfsek/terra/commands/profiler/ProfileStopCommand.java @@ -2,12 +2,12 @@ package com.dfsek.terra.commands.profiler; import com.dfsek.terra.api.TerraPlugin; import com.dfsek.terra.api.command.CommandTemplate; -import com.dfsek.terra.api.command.ExecutionState; import com.dfsek.terra.api.command.annotation.Command; import com.dfsek.terra.api.command.annotation.type.DebugCommand; import com.dfsek.terra.api.command.annotation.type.PlayerCommand; import com.dfsek.terra.api.command.annotation.type.WorldCommand; import com.dfsek.terra.api.injection.annotations.Inject; +import com.dfsek.terra.api.platform.CommandSender; import com.dfsek.terra.api.platform.entity.Player; import com.dfsek.terra.world.TerraWorld; @@ -20,10 +20,10 @@ public class ProfileStopCommand implements CommandTemplate { private TerraPlugin main; @Override - public void execute(ExecutionState state) { - Player player = (Player) state.getSender(); + public void execute(CommandSender sender) { + Player player = (Player) sender; TerraWorld world = main.getWorld(player.getWorld()); world.getProfiler().setProfiling(false); - state.getSender().sendMessage("Profiling disabled."); + player.sendMessage("Profiling disabled."); } } diff --git a/common/src/main/java/com/dfsek/terra/commands/structure/StructureExportCommand.java b/common/src/main/java/com/dfsek/terra/commands/structure/StructureExportCommand.java index fa368668b..499493cb8 100644 --- a/common/src/main/java/com/dfsek/terra/commands/structure/StructureExportCommand.java +++ b/common/src/main/java/com/dfsek/terra/commands/structure/StructureExportCommand.java @@ -1,13 +1,13 @@ package com.dfsek.terra.commands.structure; import com.dfsek.terra.api.command.CommandTemplate; -import com.dfsek.terra.api.command.ExecutionState; import com.dfsek.terra.api.command.annotation.Command; +import com.dfsek.terra.api.platform.CommandSender; @Command public class StructureExportCommand implements CommandTemplate { @Override - public void execute(ExecutionState state) { + public void execute(CommandSender sender) { System.out.println("export command"); } } diff --git a/common/src/main/java/com/dfsek/terra/commands/structure/StructureLoadCommand.java b/common/src/main/java/com/dfsek/terra/commands/structure/StructureLoadCommand.java index 2c9d06b67..3f8382588 100644 --- a/common/src/main/java/com/dfsek/terra/commands/structure/StructureLoadCommand.java +++ b/common/src/main/java/com/dfsek/terra/commands/structure/StructureLoadCommand.java @@ -1,18 +1,20 @@ package com.dfsek.terra.commands.structure; import com.dfsek.terra.api.command.CommandTemplate; -import com.dfsek.terra.api.command.ExecutionState; import com.dfsek.terra.api.command.annotation.Argument; import com.dfsek.terra.api.command.annotation.Command; import com.dfsek.terra.api.command.annotation.Switch; +import com.dfsek.terra.api.command.annotation.inject.ArgumentTarget; +import com.dfsek.terra.api.command.arg.IntegerArgumentParser; +import com.dfsek.terra.api.platform.CommandSender; @Command( arguments = { @Argument( value = "rotation", required = false, - type = int.class, - tabCompleter = RotationCompleter.class + tabCompleter = RotationCompleter.class, + argumentParser = IntegerArgumentParser.class ) }, switches = { @@ -22,8 +24,11 @@ import com.dfsek.terra.api.command.annotation.Switch; } ) public class StructureLoadCommand implements CommandTemplate { - @Override - public void execute(ExecutionState state) { + @ArgumentTarget("rotation") + private Integer rotation; + @Override + public void execute(CommandSender sender) { + System.out.println(rotation); } } diff --git a/common/src/test/java/command/CommandTest.java b/common/src/test/java/command/CommandTest.java index 42a419c49..343b4971a 100644 --- a/common/src/test/java/command/CommandTest.java +++ b/common/src/test/java/command/CommandTest.java @@ -2,15 +2,19 @@ package command; import com.dfsek.terra.api.command.CommandManager; import com.dfsek.terra.api.command.CommandTemplate; -import com.dfsek.terra.api.command.ExecutionState; import com.dfsek.terra.api.command.TerraCommandManager; import com.dfsek.terra.api.command.annotation.Argument; import com.dfsek.terra.api.command.annotation.Command; import com.dfsek.terra.api.command.annotation.Subcommand; import com.dfsek.terra.api.command.annotation.Switch; +import com.dfsek.terra.api.command.annotation.inject.ArgumentTarget; +import com.dfsek.terra.api.command.annotation.inject.SwitchTarget; +import com.dfsek.terra.api.command.arg.DoubleArgumentParser; +import com.dfsek.terra.api.command.arg.IntegerArgumentParser; import com.dfsek.terra.api.command.exception.CommandException; import com.dfsek.terra.api.command.exception.InvalidArgumentsException; import com.dfsek.terra.api.command.exception.MalformedCommandException; +import com.dfsek.terra.api.platform.CommandSender; import org.junit.jupiter.api.Test; import java.util.Arrays; @@ -86,29 +90,35 @@ public class CommandTest { @Command( arguments = { @Argument(value = "arg0"), - @Argument(value = "arg1", type = int.class), - @Argument(value = "arg2", type = double.class, required = false) + @Argument(value = "arg1", argumentParser = IntegerArgumentParser.class), + @Argument(value = "arg2", required = false, argumentParser = DoubleArgumentParser.class) } ) public static final class DemoCommand implements CommandTemplate { + @ArgumentTarget("arg0") + private String arg0; + + @ArgumentTarget("arg1") + private Integer arg1; + + @ArgumentTarget("arg2") + private Double arg2; + + @Override - public void execute(ExecutionState state) { - System.out.println(state.getArgument("arg0", String.class)); - System.out.println(state.getArgument("arg1", int.class)); - try { - System.out.println(state.getArgument("arg2", double.class)); - } catch(IllegalArgumentException e) { - System.out.println("arg2 undefined."); - } + public void execute(CommandSender sender) { + System.out.println(arg0); + System.out.println(arg1); + System.out.println(arg2); } } @Command( arguments = { @Argument(value = "arg0"), - @Argument(value = "arg1", type = int.class), - @Argument(value = "arg2", type = double.class, required = false) + @Argument(value = "arg1"), + @Argument(value = "arg2", required = false) }, switches = { @Switch(value = "a", aliases = {"aSwitch"}), @@ -116,33 +126,44 @@ public class CommandTest { } ) public static final class DemoSwitchCommand implements CommandTemplate { + @ArgumentTarget("arg0") + private String arg0; + + @ArgumentTarget("arg1") + private String arg1; + + @ArgumentTarget("arg2") + private String arg2; + + @SwitchTarget("a") + private boolean a; + + @SwitchTarget("b") + private boolean b; + @Override - public void execute(ExecutionState state) { - System.out.println(state.getArgument("arg0", String.class)); - System.out.println(state.getArgument("arg1", int.class)); - try { - System.out.println(state.getArgument("arg2", double.class)); - } catch(IllegalArgumentException e) { - System.out.println("arg2 undefined."); - } + public void execute(CommandSender sender) { + System.out.println(arg0); + System.out.println(arg1); + System.out.println(arg2); - System.out.println("A: " + state.hasSwitch("a")); - System.out.println("B: " + state.hasSwitch("b")); + System.out.println("A: " + a); + System.out.println("B: " + b); } } @Command( arguments = { @Argument(value = "arg0"), - @Argument(value = "arg2", type = double.class, required = false), // optional arguments must be last. this command is invalid. - @Argument(value = "arg1", type = int.class) + @Argument(value = "arg2", required = false), // optional arguments must be last. this command is invalid. + @Argument(value = "arg1") } ) public static final class DemoInvalidCommand implements CommandTemplate { @Override - public void execute(ExecutionState state) { + public void execute(CommandSender sender) { throw new Error("this should never be reached"); } } @@ -150,8 +171,8 @@ public class CommandTest { @Command( arguments = { @Argument(value = "arg0"), - @Argument(value = "arg1", type = int.class), - @Argument(value = "arg2", type = double.class, required = false), + @Argument(value = "arg1"), + @Argument(value = "arg2", required = false), }, subcommands = { @Subcommand( @@ -167,38 +188,47 @@ public class CommandTest { } ) public static final class DemoParentCommand implements CommandTemplate { + @ArgumentTarget("arg0") + private String arg0; + + @ArgumentTarget("arg1") + private String arg1; + + @ArgumentTarget("arg2") + private String arg2; + @Override - public void execute(ExecutionState state) { - System.out.println("Parent command"); - System.out.println(state.getArgument("arg0", String.class)); - System.out.println(state.getArgument("arg1", int.class)); - try { - System.out.println(state.getArgument("arg2", double.class)); - } catch(IllegalArgumentException e) { - System.out.println("arg2 undefined."); - } + public void execute(CommandSender sender) { + System.out.println(arg0); + System.out.println(arg1); + System.out.println(arg2); } } @Command( arguments = { @Argument(value = "arg0"), - @Argument(value = "arg1", type = int.class), - @Argument(value = "arg2", type = double.class, required = false), + @Argument(value = "arg1"), + @Argument(value = "arg2", required = false), } ) public static final class DemoChildCommand implements CommandTemplate { + @ArgumentTarget("arg0") + private String arg0; + + @ArgumentTarget("arg1") + private String arg1; + + @ArgumentTarget("arg2") + private String arg2; + + @Override - public void execute(ExecutionState state) { - System.out.println("Child command"); - System.out.println(state.getArgument("arg0", String.class)); - System.out.println(state.getArgument("arg1", int.class)); - try { - System.out.println(state.getArgument("arg2", double.class)); - } catch(IllegalArgumentException e) { - System.out.println("arg2 undefined."); - } + public void execute(CommandSender sender) { + System.out.println(arg0); + System.out.println(arg1); + System.out.println(arg2); } } } diff --git a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/TerraBukkitPlugin.java b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/TerraBukkitPlugin.java index 3d14e49fd..5b436b084 100644 --- a/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/TerraBukkitPlugin.java +++ b/platforms/bukkit/src/main/java/com/dfsek/terra/bukkit/TerraBukkitPlugin.java @@ -8,6 +8,7 @@ import com.dfsek.terra.api.addons.annotations.Author; import com.dfsek.terra.api.addons.annotations.Version; import com.dfsek.terra.api.command.CommandManager; import com.dfsek.terra.api.command.TerraCommandManager; +import com.dfsek.terra.api.command.exception.MalformedCommandException; import com.dfsek.terra.api.event.EventManager; import com.dfsek.terra.api.event.TerraEventManager; import com.dfsek.terra.api.platform.block.BlockData; @@ -170,8 +171,17 @@ public class TerraBukkitPlugin extends JavaPlugin implements TerraPlugin { CommandManager manager = new TerraCommandManager(this); - manager.register("profile", ProfileCommand.class); - manager.register("structure", StructureCommand.class); + + try { + manager.register("structure", StructureCommand.class); + manager.register("profile", ProfileCommand.class); + } catch(MalformedCommandException e) { // This should never happen. + logger().severe("Errors occurred while registering commands."); + e.printStackTrace(); + logger().severe("Please report this to Terra."); + Bukkit.getPluginManager().disablePlugin(this); + return; + } BukkitCommandAdapter command = new BukkitCommandAdapter(manager);