diff --git a/pom.xml b/pom.xml index d486151..46a3fc2 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 pw.yumc YumCore - 1.0 + 1.1 YumCore ${project.name} diff --git a/src/main/java/pw/yumc/YumCore/commands/CommandArgument.java b/src/main/java/pw/yumc/YumCore/commands/CommandArgument.java index 2547c07..6caa052 100644 --- a/src/main/java/pw/yumc/YumCore/commands/CommandArgument.java +++ b/src/main/java/pw/yumc/YumCore/commands/CommandArgument.java @@ -15,12 +15,14 @@ public class CommandArgument { private final Command command; private final String alias; private final String[] args; + private final CommandParse parses; public CommandArgument(final CommandSender sender, final Command command, final String alias, final String[] args) { this.sender = sender; this.command = command; this.alias = alias; this.args = args; + parses = null; } /** diff --git a/src/main/java/pw/yumc/YumCore/commands/CommandInfo.java b/src/main/java/pw/yumc/YumCore/commands/CommandInfo.java index d039b3e..af413fe 100644 --- a/src/main/java/pw/yumc/YumCore/commands/CommandInfo.java +++ b/src/main/java/pw/yumc/YumCore/commands/CommandInfo.java @@ -43,8 +43,9 @@ public class CommandInfo { private final Cmd command; private final Help help; private final int sort; + private final CommandParse parse; - public CommandInfo(final Method method, final Object origin, final Cmd command, final Help help, final boolean async, final int sort) { + public CommandInfo(final Method method, final Object origin, final Cmd command, final Help help, final boolean async, final int sort, final CommandParse parse) { this.method = method; this.origin = origin; this.name = "".equals(command.value()) ? method.getName().toLowerCase() : command.value(); @@ -55,6 +56,7 @@ public class CommandInfo { this.help = help; this.async = async; this.sort = sort; + this.parse = parse; } private CommandInfo() { @@ -68,6 +70,7 @@ public class CommandInfo { this.help = null; this.async = false; this.sort = 0; + this.parse = null; } /** @@ -85,7 +88,8 @@ public class CommandInfo { final Help help = method.getAnnotation(Help.class); final Async async = method.getAnnotation(Async.class); final Sort sort = method.getAnnotation(Sort.class); - return new CommandInfo(method, origin, command, help != null ? help : Help.DEFAULT, async != null, sort != null ? sort.value() : 50); + final CommandParse cp = CommandParse.get(method); + return new CommandInfo(method, origin, command, help != null ? help : Help.DEFAULT, async != null, sort != null ? sort.value() : 50, cp); } return null; } @@ -117,7 +121,7 @@ public class CommandInfo { @Override public void run() { try { - method.invoke(origin, cmdArgs); + method.invoke(origin, cmdArgs.getSender(), parse.parse(cmdArgs)); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { throw new CommandException(e); } diff --git a/src/main/java/pw/yumc/YumCore/commands/CommandManager.java b/src/main/java/pw/yumc/YumCore/commands/CommandManager.java index 1284732..701853c 100644 --- a/src/main/java/pw/yumc/YumCore/commands/CommandManager.java +++ b/src/main/java/pw/yumc/YumCore/commands/CommandManager.java @@ -1,5 +1,8 @@ package pw.yumc.YumCore.commands; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; @@ -10,11 +13,15 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.PluginCommand; +import org.bukkit.command.SimpleCommandMap; import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.util.StringUtil; @@ -29,8 +36,33 @@ import pw.yumc.YumCore.bukkit.compatible.C; * @author 喵♂呜 */ public class CommandManager implements TabExecutor { - private final static String argumentTypeError = "注解命令方法 %s 位于 %s 的参数错误 应只有 CommandArgument 参数!"; + private final static String argumentTypeError = "注解命令方法 %s 位于 %s 的参数错误 第一个参数应实现 CommandSender 接口!"; private final static String returnTypeError = "注解命令补全 %s 位于 %s 的返回值错误 应实现 List 接口!"; + private static Constructor PluginCommandConstructor; + private static Map knownCommands; + private static Map lookupNames; + static { + try { + final PluginManager pluginManager = Bukkit.getPluginManager(); + + final Field lookupNamesField = pluginManager.getClass().getDeclaredField("lookupNames"); + lookupNamesField.setAccessible(true); + lookupNames = (Map) lookupNamesField.get(pluginManager); + + final Field commandMapField = pluginManager.getClass().getDeclaredField("commandMap"); + commandMapField.setAccessible(true); + final SimpleCommandMap commandMap = (SimpleCommandMap) commandMapField.get(pluginManager); + + final Field knownCommandsField = commandMap.getClass().getDeclaredField("knownCommands"); + knownCommandsField.setAccessible(true); + knownCommands = (Map) knownCommandsField.get(commandMap); + + PluginCommandConstructor = PluginCommand.class.getConstructor(String.class, Plugin.class); + } catch (NoSuchMethodException | SecurityException | NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) { + Log.d("初始化命令管理器失败!"); + Log.debug(e); + } + } /** * 插件实例类 */ @@ -62,7 +94,7 @@ public class CommandManager implements TabExecutor { /** * 插件命令 */ - private final PluginCommand cmd; + private PluginCommand cmd; /** * 命令管理器 @@ -73,7 +105,14 @@ public class CommandManager implements TabExecutor { public CommandManager(final String name) { cmd = plugin.getCommand(name); if (cmd == null) { - throw new IllegalStateException("未找到命令 必须在plugin.yml先注册 " + name + " 命令!"); + try { + knownCommands.put(name, PluginCommandConstructor.newInstance(name, plugin)); + lookupNames.put(name, plugin); + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + } + if ((cmd = plugin.getCommand(name)) == null) { + throw new IllegalStateException("未找到命令 必须在plugin.yml先注册 " + name + " 命令!"); + } } cmd.setExecutor(this); cmd.setTabCompleter(this); @@ -106,9 +145,8 @@ public class CommandManager implements TabExecutor { help.send(sender, command, label, args); return true; } - final CommandArgument cmdArgs = new CommandArgument(sender, command, label, moveStrings(args, 1)); final CommandInfo ci = checkCache(subcmd); - return ci.execute(cmdArgs); + return ci.execute(new CommandArgument(sender, command, label, moveStrings(args, 1))); } @Override @@ -245,7 +283,7 @@ public class CommandManager implements TabExecutor { final CommandInfo ci = CommandInfo.parse(method, clazz); if (ci != null) { final Class[] params = method.getParameterTypes(); - if (params.length == 1 && params[0].equals(CommandArgument.class)) { + if (params.length > 0 && params[0].equals(CommandArgument.class)) { if (method.getReturnType() == boolean.class) { defCmd = ci; return true; diff --git a/src/main/java/pw/yumc/YumCore/commands/CommandParse.java b/src/main/java/pw/yumc/YumCore/commands/CommandParse.java new file mode 100644 index 0000000..e548b4a --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/commands/CommandParse.java @@ -0,0 +1,143 @@ +package pw.yumc.YumCore.commands; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import pw.yumc.YumCore.commands.exception.CommandException; +import pw.yumc.YumCore.commands.exception.CommandParseException; + +/** + * 命令参数解析 + * + * @author 喵♂呜 + * @since 2016年10月5日 下午4:02:04 + */ +public class CommandParse { + private static Map allparses; + static { + new IntegerParse(); + new LongParse(); + new BooleanParse(); + new PlayerParse(); + new StringParse(); + } + public List parse = new LinkedList<>(); + public List parsed = new LinkedList<>(); + + public CommandParse(final Class[] classes, final Annotation[][] annons) { + for (final Class classe : classes) { + final Class clazz = classe; + if (!allparses.containsKey(clazz)) { + throw new CommandParseException(String.format("无法解析的参数类型 %s !", clazz.getName())); + } + parse.add(allparses.get(clazz)); + } + } + + public static CommandParse get(final Method method) { + return new CommandParse(method.getParameterTypes(), method.getParameterAnnotations()); + } + + public static void registerParse(final Class clazz, final Parse parse) { + allparses.put(clazz, parse); + } + + public Object[] parse(final CommandArgument cmdArgs) { + final String args[] = cmdArgs.getArgs(); + if (args.length == 0) { + return null; + } + final List pobjs = new LinkedList<>(); + pobjs.add(cmdArgs.getSender()); + for (int i = 0; i < args.length; i++) { + try { + if (i < parse.size()) { + pobjs.add(parse.get(i).parse(args[i])); + } + } catch (final Exception e) { + throw new CommandException(String.format(e.getMessage(), i + 1)); + } + } + return pobjs.toArray(); + } + + public static class BooleanParse implements Parse { + public BooleanParse() { + allparses.put(Boolean.class, this); + allparses.put(boolean.class, this); + } + + @Override + public Boolean parse(final String arg) { + try { + return Boolean.parseBoolean(arg); + } catch (final Exception e) { + throw new CommandParseException("第 %s 个参数必须为True或者False!"); + } + } + } + + public static class IntegerParse implements Parse { + public IntegerParse() { + allparses.put(Integer.class, this); + allparses.put(int.class, this); + } + + @Override + public Integer parse(final String arg) { + try { + return Integer.parseInt(arg); + } catch (final Exception e) { + throw new CommandParseException("第 %s 个参数必须为数字!"); + } + } + } + + public static class LongParse implements Parse { + public LongParse() { + allparses.put(Long.class, this); + allparses.put(long.class, this); + } + + @Override + public Long parse(final String arg) { + try { + return Long.parseLong(arg); + } catch (final Exception e) { + throw new CommandParseException("第 %s 个参数必须为数字!"); + } + } + } + + public static interface Parse { + public RT parse(String arg) throws CommandParseException; + } + + public static class PlayerParse implements Parse { + public PlayerParse() { + allparses.put(Player.class, this); + } + + @Override + public Player parse(final String arg) { + return Bukkit.getPlayerExact(arg); + } + } + + public static class StringParse implements Parse { + public StringParse() { + allparses.put(String.class, this); + } + + @Override + public String parse(final String arg) { + return arg; + } + } +} diff --git a/src/main/java/pw/yumc/YumCore/commands/exception/CommandParseException.java b/src/main/java/pw/yumc/YumCore/commands/exception/CommandParseException.java new file mode 100644 index 0000000..236fbf0 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/commands/exception/CommandParseException.java @@ -0,0 +1,22 @@ +package pw.yumc.YumCore.commands.exception; + +/** + * 命令参数解析异常 + * + * @author 喵♂呜 + * @since 2016年10月5日 下午5:15:43 + */ +public class CommandParseException extends CommandException { + + public CommandParseException(final Exception e) { + super(e); + } + + public CommandParseException(final String string) { + super(string); + } + + public CommandParseException(final String string, final Exception e) { + super(string, e); + } +} diff --git a/src/main/java/pw/yumc/YumCore/config/AbstractInjectConfig.java b/src/main/java/pw/yumc/YumCore/config/inject/AbstractInjectConfig.java similarity index 94% rename from src/main/java/pw/yumc/YumCore/config/AbstractInjectConfig.java rename to src/main/java/pw/yumc/YumCore/config/inject/AbstractInjectConfig.java index 6f7eabe..2b3765d 100644 --- a/src/main/java/pw/yumc/YumCore/config/AbstractInjectConfig.java +++ b/src/main/java/pw/yumc/YumCore/config/inject/AbstractInjectConfig.java @@ -1,4 +1,4 @@ -package pw.yumc.YumCore.config; +package pw.yumc.YumCore.config.inject; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -12,6 +12,9 @@ import org.bukkit.ChatColor; import org.bukkit.configuration.ConfigurationSection; import pw.yumc.YumCore.bukkit.Log; +import pw.yumc.YumCore.config.ConfigNode; +import pw.yumc.YumCore.config.Default; +import pw.yumc.YumCore.config.Nullable; /** * 抽象注入配置 @@ -177,7 +180,6 @@ public abstract class AbstractInjectConfig { * @throws IllegalAccessException */ private void hanldeValue(final String path, final Field field, Object value) throws IllegalAccessException, IllegalArgumentException, InstantiationException, InvocationTargetException, NoSuchMethodException, SecurityException, ParseException { - final Object origin = field.get(this); final Class type = field.getType(); if (!type.equals(value.getClass())) { value = convertType(type, path, value); @@ -186,7 +188,7 @@ public abstract class AbstractInjectConfig { value = ChatColor.translateAlternateColorCodes('&', (String) value); } field.set(this, value); - Log.d("设置字段 %s 由 %s 为 %s ", field.getName(), origin, value); + Log.d("设置字段 %s 为 %s ", field.getName(), value); } /** diff --git a/src/main/java/pw/yumc/YumCore/config/InjectConfig.java b/src/main/java/pw/yumc/YumCore/config/inject/InjectConfig.java similarity index 87% rename from src/main/java/pw/yumc/YumCore/config/InjectConfig.java rename to src/main/java/pw/yumc/YumCore/config/inject/InjectConfig.java index c2fe347..334bde9 100644 --- a/src/main/java/pw/yumc/YumCore/config/InjectConfig.java +++ b/src/main/java/pw/yumc/YumCore/config/inject/InjectConfig.java @@ -1,7 +1,9 @@ -package pw.yumc.YumCore.config; +package pw.yumc.YumCore.config.inject; import java.io.File; +import pw.yumc.YumCore.config.FileConfig; + /** * 配置自动载入类 * diff --git a/src/main/java/pw/yumc/YumCore/config/InjectConfigurationSection.java b/src/main/java/pw/yumc/YumCore/config/inject/InjectConfigurationSection.java similarity index 89% rename from src/main/java/pw/yumc/YumCore/config/InjectConfigurationSection.java rename to src/main/java/pw/yumc/YumCore/config/inject/InjectConfigurationSection.java index 919ec63..ba0675d 100644 --- a/src/main/java/pw/yumc/YumCore/config/InjectConfigurationSection.java +++ b/src/main/java/pw/yumc/YumCore/config/inject/InjectConfigurationSection.java @@ -1,4 +1,4 @@ -package pw.yumc.YumCore.config; +package pw.yumc.YumCore.config.inject; import org.bukkit.configuration.ConfigurationSection;