commit 73eeac24848cda9efde099e3254bfcb4359590e8 Author: 502647092 Date: Sat Jul 23 17:26:04 2016 +0800 init: 项目初始化... Signed-off-by: 502647092 diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..4ff26bf --- /dev/null +++ b/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7876f5f --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +# Eclipse stuff +/.settings + +# netbeans +/nbproject + +# we use maven! +/build.xml + +# maven +/target +/repo + +# vim +.*.sw[a-p] + +# various other potential build files +/build +/bin +/dist +/manifest.mf + +/world + +# Mac filesystem dust +*.DS_Store + +# intellij +*.iml +*.ipr +*.iws +.idea/ + +# Project Stuff +/src/main/resources/Soulbound + +# Atlassian Stuff +/atlassian-ide-plugin.xml \ No newline at end of file diff --git a/.project b/.project new file mode 100644 index 0000000..8f13168 --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + YumCore + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.m2e.core.maven2Nature + org.eclipse.jdt.core.javanature + + diff --git a/lib/PlaceholderAPI.jar b/lib/PlaceholderAPI.jar new file mode 100644 index 0000000..87bd3ab Binary files /dev/null and b/lib/PlaceholderAPI.jar differ diff --git a/lib/ProtocolLib-3.6.5-SNAPSHOT.jar b/lib/ProtocolLib-3.6.5-SNAPSHOT.jar new file mode 100644 index 0000000..ec73d32 Binary files /dev/null and b/lib/ProtocolLib-3.6.5-SNAPSHOT.jar differ diff --git a/lib/craftbukkit-1.7.10.jar b/lib/craftbukkit-1.7.10.jar new file mode 100644 index 0000000..23109e2 Binary files /dev/null and b/lib/craftbukkit-1.7.10.jar differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..0bc2e52 --- /dev/null +++ b/pom.xml @@ -0,0 +1,117 @@ + + 4.0.0 + pw.yumc + YumCore + 1.0 + YumCore + + ${project.name} + + + src/main/resources + true + + + + + maven-compiler-plugin + 3.3 + + 1.7 + 1.7 + + + + org.apache.maven.plugins + maven-source-plugin + 2.2.1 + + + source + compile + + jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.3 + + + javadocs + package + + jar + + + false + + + + + + + + Jenkins + http://ci.yumc.pw + + + UTF-8 + UTF-8 + 开发版本 + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/groups/public/ + + + yumc-repo + http://repo.yumc.pw/content/groups/public/ + + + + + jtb + YUMC + http://repo.yumc.pw/content/repositories/yumcenter/ + + + + + org.spigotmc + spigot-api + 1.10.2-R0.1-SNAPSHOT + + + net.milkbowl.vault + Vault + 1.5.6 + + + org.bukkit + bukkit + 1.7.10 + system + ${project.basedir}/lib/craftbukkit-1.7.10.jar + + + com.comphenix.protocol + ProtocolLib + 3.6.5-SNAPSHOT + system + ${project.basedir}/lib/ProtocolLib-3.6.5-SNAPSHOT.jar + + + me.clip + PlaceholderAPI + 1.8.6 + system + ${project.basedir}/lib/PlaceholderAPI.jar + + + \ No newline at end of file diff --git a/src/main/java/pw/yumc/YumCore/YumCore.java b/src/main/java/pw/yumc/YumCore/YumCore.java new file mode 100644 index 0000000..19a028a --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/YumCore.java @@ -0,0 +1,11 @@ +package pw.yumc.YumCore; + +/** + * YumCore核心类库 + * + * @since 2016年7月23日 下午1:03:41 + * @author 喵♂呜 + */ +public class YumCore { + +} diff --git a/src/main/java/pw/yumc/YumCore/bukkit/Log.java b/src/main/java/pw/yumc/YumCore/bukkit/Log.java new file mode 100644 index 0000000..55ac101 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/bukkit/Log.java @@ -0,0 +1,48 @@ +package pw.yumc.YumCore.bukkit; + +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * 插件日志输出类 + * + * @since 2016年7月23日 上午9:11:01 + * @author 喵♂呜 + */ +public class Log { + private static Logger logger = P.instance.getLogger(); + + public static void addHandler(final Handler handler) throws SecurityException { + logger.addHandler(handler); + } + + public static void info(final String msg) { + logger.info(msg); + } + + public static void log(final Level level, final String msg) { + logger.log(level, msg); + } + + public static void log(final Level level, final String msg, final Object param1) { + logger.log(level, msg, param1); + } + + public static void log(final Level level, final String msg, final Object[] params) { + logger.log(level, msg, params); + } + + public static void log(final Level level, final String msg, final Throwable thrown) { + logger.log(level, msg, thrown); + } + + public static void severe(final String msg) { + logger.severe(msg); + } + + public static void warning(final String msg) { + logger.warning(msg); + } + +} diff --git a/src/main/java/pw/yumc/YumCore/bukkit/P.java b/src/main/java/pw/yumc/YumCore/bukkit/P.java new file mode 100644 index 0000000..860717e --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/bukkit/P.java @@ -0,0 +1,29 @@ +package pw.yumc.YumCore.bukkit; + +import java.lang.reflect.Field; + +import org.bukkit.plugin.java.JavaPlugin; + +/** + * 插件Instance获取类 + * + * @since 2016年7月23日 上午9:09:57 + * @author 喵♂呜 + */ +public class P { + /** + * 插件实例 + */ + public static JavaPlugin instance; + + static { + final Object pluginClassLoader = P.class.getClassLoader(); + try { + final Field field = pluginClassLoader.getClass().getDeclaredField("plugin"); + field.setAccessible(true); + instance = (JavaPlugin) field.get(pluginClassLoader); + } catch (final Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/pw/yumc/YumCore/bukkit/compatible/C.java b/src/main/java/pw/yumc/YumCore/bukkit/compatible/C.java new file mode 100644 index 0000000..479dc97 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/bukkit/compatible/C.java @@ -0,0 +1,96 @@ +package pw.yumc.YumCore.bukkit.compatible; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collection; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.Server; + +import com.google.common.base.Charsets; + +import pw.yumc.YumCore.bukkit.Log; + +/** + * Bukkit兼容类 + * + * @since 2016年7月23日 下午1:04:56 + * @author 喵♂呜 + */ +public class C { + /** + * Bukkit Player兼容类 + * + * @since 2016年7月23日 下午4:33:40 + * @author 喵♂呜 + */ + public static class Player { + private static Class gameProfileClass; + private static Constructor gameProfileConstructor; + private static Constructor craftOfflinePlayerConstructor; + + private static Method getOnlinePlayers; + + static { + try { + // getOnlinePlayers start + getOnlinePlayers = Bukkit.class.getDeclaredMethod("getOnlinePlayers"); + if (getOnlinePlayers.getReturnType() != Player[].class) { + getOnlinePlayers = Bukkit.class.getDeclaredMethod("_INVALID_getOnlinePlayers"); + } + // getOnlinePlayers end + // getOfflinePlayer start + try { + gameProfileClass = Class.forName("net.minecraft.util.com.mojang.authlib.GameProfile"); + } catch (final ClassNotFoundException e) { + try { + gameProfileClass = Class.forName("com.mojang.authlib.GameProfile"); + } catch (final ClassNotFoundException e1) { + } + } + gameProfileConstructor = gameProfileClass.getDeclaredConstructor(new Class[] { UUID.class, String.class }); + gameProfileConstructor.setAccessible(true); + final Class craftServer = Bukkit.getServer().getClass(); + final Class craftOfflinePlayer = Class.forName(craftServer.getName().replace("CraftServer", "CraftOfflinePlayer")); + craftOfflinePlayerConstructor = craftOfflinePlayer.getDeclaredConstructor(new Class[] { craftServer, gameProfileClass }); + craftOfflinePlayerConstructor.setAccessible(true); + // getOfflinePlayer end + } catch (NoSuchMethodException | SecurityException | ClassNotFoundException e) { + Log.warning(Player.class.getSimpleName() + "兼容性工具初始化失败 可能造成部分功能不可用!"); + } + } + + /** + * 获取离线玩家(跳过网络获取) + * + * @param playerName + * 玩家名称 + * @return {@link OfflinePlayer} + */ + public static OfflinePlayer getOfflinePlayer(final String playerName) { + try { + final Object gameProfile = gameProfileConstructor.newInstance(new Object[] { UUID.nameUUIDFromBytes(("OfflinePlayer:" + playerName).getBytes(Charsets.UTF_8)), playerName }); + final Object offlinePlayer = craftOfflinePlayerConstructor.newInstance(new Object[] { Bukkit.getServer(), gameProfile }); + return (OfflinePlayer) offlinePlayer; + } catch (final Throwable var5) { + return Bukkit.getOfflinePlayer(playerName); + } + } + + /** + * 获取在线玩家 + * + * @return 在线玩家 + */ + public static Collection getOnlinePlayers() { + try { + return Arrays.asList((org.bukkit.entity.Player[]) getOnlinePlayers.invoke(null)); + } catch (final Throwable e) { + return Bukkit.getOnlinePlayers(); + } + } + } +} diff --git a/src/main/java/pw/yumc/YumCore/commands/CommandArgument.java b/src/main/java/pw/yumc/YumCore/commands/CommandArgument.java new file mode 100644 index 0000000..85dd15c --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/commands/CommandArgument.java @@ -0,0 +1,80 @@ +package pw.yumc.YumCore.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import pw.yumc.YumCore.commands.exception.IllegalPermissionException; +import pw.yumc.YumCore.commands.exception.IllegalSenderException; + +/** + * 子命令调用事件类 + * + * @since 2015年8月22日上午8:29:44 + * @author 喵♂呜 + */ +public class CommandArgument { + private final CommandSender sender; + private final Command command; + private final String alias; + private final String[] args; + + 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; + } + + public boolean check(final CommandInfo info) { + if (sender instanceof Player) { + if (info.getCommand().onlyConsoleExecutable()) { + throw new IllegalSenderException("§c玩家无法使用此命令(§4请使用控制台执行§c)!"); + } + } else if (info.getCommand().onlyPlayerExecutable()) { + throw new IllegalSenderException("§c玩家无法使用此命令(§4请使用控制台执行§c)!"); + } + final String perm = info.getCommand().permission(); + if (perm != null && !sender.hasPermission(perm)) { + throw new IllegalPermissionException("§c你需要有 " + perm + " 的权限才能执行此命令!"); + } + return true; + } + + /** + * 命令别名 + * + * @return alias + */ + public String getAlias() { + return alias; + } + + /** + * 命令参数 + * + * @return args + */ + public String[] getArgs() { + return args; + } + + /** + * 命令实体 + * + * @return command + */ + public Command getCommand() { + return command; + } + + /** + * 命令发送者 + * + * @return sender + */ + public CommandSender getSender() { + return sender; + } + +} diff --git a/src/main/java/pw/yumc/YumCore/commands/CommandHelp.java b/src/main/java/pw/yumc/YumCore/commands/CommandHelp.java new file mode 100644 index 0000000..55c80e5 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/commands/CommandHelp.java @@ -0,0 +1,121 @@ +package pw.yumc.YumCore.commands; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.Plugin; + +import pw.yumc.YumCore.bukkit.P; +import pw.yumc.YumCore.commands.annotation.Help; + +/** + * 命令帮助生成类 + * + * @since 2016年7月23日 上午10:12:32 + * @author 喵♂呜 + */ +public class CommandHelp { + /** + * 插件实例 + */ + Plugin plugin = P.instance; + /** + * 消息配置 + */ + String prefix = String.format("§6[§b%s§6] ", P.instance.getName()); + String commandNotFound = prefix + "§c当前插件未注册任何子命令!"; + String pageNotFound = prefix + "§c不存在的帮助页面 §b请输入 /%s help §e1-%s"; + String helpTitle = String.format("§6========= %s §6插件帮助列表=========", prefix); + String helpBody = "§6/%1$s §a%2$s §e%3$s §6- §b%4$s"; + String helpFooter = "§6查看更多的帮助页面 §b请输入 /%s help §e1-%s"; + /** + * 已排序的命令列表 + */ + List cmdlist; + /** + * 帮助页面数量 + */ + private final int HELPPAGECOUNT; + /** + * 帮助页面每页行数 + */ + private final int LINES_PER_PAGE = 7; + /** + * 帮助列表缓存 + */ + private final Map cacheHelp = new HashMap<>(); + + public CommandHelp(final Collection list) { + cmdlist = new LinkedList<>(list); + Collections.sort(cmdlist, new CommandComparator()); + this.HELPPAGECOUNT = (int) Math.ceil((double) cmdlist.size() / LINES_PER_PAGE); + } + + /** + * 发送帮助 + * + * @param ca + * 命令参数 + */ + public void send(final CommandSender sender, final Command command, final String label, final String[] args) { + if (this.HELPPAGECOUNT == 0) { + sender.sendMessage(commandNotFound); + return; + } + int page = 1; + try { + page = Integer.parseInt(args[1]); + page = page == 0 ? 1 : page; + } catch (final Exception e) { + } + final String helpkey = label + page; + if (!cacheHelp.containsKey(helpkey)) { + final List helpList = new ArrayList<>(); + if (page > this.HELPPAGECOUNT || page < 1) { + // 帮助页面不存在 + helpList.add(String.format(commandNotFound, HELPPAGECOUNT)); + } else { + // 帮助标题 + helpList.add(helpTitle); + final int start = this.LINES_PER_PAGE * (page - 1); + final int end = start + this.LINES_PER_PAGE; + for (int i = start; i < end; i++) { + if (this.cmdlist.size() > i) { + final CommandInfo ci = cmdlist.get(i); + final String aliases = Arrays.toString(ci.getCommand().aliases()); + final String cmd = ci.getName() + (aliases.length() == 2 ? "" : "§7" + aliases); + final Help help = ci.getHelp(); + // 帮助列表 + helpList.add(String.format(helpBody, label, cmd, help.possibleArguments(), help.description())); + } + } + } + // 帮助结尾 + helpList.add(String.format(helpFooter, label, HELPPAGECOUNT)); + cacheHelp.put(helpkey, helpList.toArray(new String[0])); + } + sender.sendMessage(cacheHelp.get(helpkey)); + } + + /** + * 命令排序比较器 + * + * @since 2016年7月23日 下午4:17:18 + * @author 喵♂呜 + */ + static class CommandComparator implements Comparator { + @Override + public int compare(final CommandInfo o1, final CommandInfo o2) { + return Integer.valueOf(o1.getSort()).compareTo(Integer.valueOf(o2.getSort())); + } + } +} diff --git a/src/main/java/pw/yumc/YumCore/commands/CommandInfo.java b/src/main/java/pw/yumc/YumCore/commands/CommandInfo.java new file mode 100644 index 0000000..9cb129e --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/commands/CommandInfo.java @@ -0,0 +1,130 @@ +package pw.yumc.YumCore.commands; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; + +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; + +import pw.yumc.YumCore.bukkit.P; +import pw.yumc.YumCore.commands.annotation.Async; +import pw.yumc.YumCore.commands.annotation.Cmd; +import pw.yumc.YumCore.commands.annotation.Help; +import pw.yumc.YumCore.commands.annotation.Sort; +import pw.yumc.YumCore.commands.exception.CommandException; + +/** + * 命令信息存储类 + * + * @since 2016年7月23日 上午9:56:42 + * @author 喵♂呜 + */ +public class CommandInfo { + public static CommandInfo Unknow = new CommandInfo(); + private final Object origin; + private final Method method; + private final String name; + private final List aliases; + private final boolean async; + private final Cmd command; + private final Help help; + private final int sort; + + public CommandInfo(final Method method, final Object origin, final Cmd command, final Help help, final boolean async, final int sort) { + this.method = method; + this.origin = origin; + this.name = "".equals(command.name()) ? method.getName().toLowerCase() : command.name(); + this.aliases = Arrays.asList(command.aliases()); + this.command = command; + this.help = help; + this.async = async; + this.sort = sort; + } + + private CommandInfo() { + this.method = null; + this.origin = null; + this.name = "unknow"; + this.aliases = null; + this.command = null; + this.help = null; + this.async = false; + this.sort = 0; + } + + public static CommandInfo parse(final Method method, final Object origin) { + final Class clazz = method.getClass(); + final Cmd command = clazz.getAnnotation(Cmd.class); + if (command != null) { + final Help help = clazz.getAnnotation(Help.class); + final Async async = clazz.getAnnotation(Async.class); + final Sort sort = clazz.getAnnotation(Sort.class); + return new CommandInfo(method, origin, command, help != null ? help : Help.DEFAULT, async != null, sort != null ? sort.sort() : 50); + } + return null; + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof CommandInfo) { + return name.equalsIgnoreCase(((CommandInfo) obj).getName()); + } + return super.equals(obj); + } + + public boolean execute(final CommandSender sender, final Command command, final String label, final String[] args) { + if (method == null) { + return false; + } + final CommandArgument cmdArgs = new CommandArgument(sender, command, label, args); + final Runnable runnable = new Runnable() { + @Override + public void run() { + try { + try { + cmdArgs.check(CommandInfo.this); + } catch (final CommandException e) { + sender.sendMessage(e.getMessage()); + return; + } + method.invoke(origin, cmdArgs); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new CommandException(e); + } + } + }; + if (async) { + Bukkit.getScheduler().runTaskAsynchronously(P.instance, runnable); + } else { + runnable.run(); + } + return true; + } + + public Cmd getCommand() { + return command; + } + + public Help getHelp() { + return help; + } + + public String getName() { + return name; + } + + public int getSort() { + return sort; + } + + public boolean isAsync() { + return async; + } + + public boolean isValid(final String cmd) { + return name.equalsIgnoreCase(cmd) || aliases.contains(cmd); + } +} diff --git a/src/main/java/pw/yumc/YumCore/commands/CommandManager.java b/src/main/java/pw/yumc/YumCore/commands/CommandManager.java new file mode 100644 index 0000000..bafbdce --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/commands/CommandManager.java @@ -0,0 +1,198 @@ +package pw.yumc.YumCore.commands; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.PluginCommand; +import org.bukkit.command.TabExecutor; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.util.StringUtil; + +import pw.yumc.YumCore.bukkit.Log; +import pw.yumc.YumCore.bukkit.P; +import pw.yumc.YumCore.bukkit.compatible.C; +import pw.yumc.YumCore.commands.api.CommandExecutor; + +/** + * 命令管理类 + * + * @since 2016年7月23日 上午9:06:03 + * @author 喵♂呜 + */ +public class CommandManager implements TabExecutor { + private final String argumentTypeError = "注解命令方法 %s 位于 %s 的参数错误 应只有 CommandArgument 参数!"; + private final String returnTypeError = "注解命令补全 %s 位于 %s 的返回值错误 应实现 List 接口!"; + /** + * 插件实例类 + */ + JavaPlugin plugin = P.instance; + /** + * 命令列表 + */ + Set cmdlist = new HashSet<>(); + /** + * Tab列表 + */ + Set tablist = new HashSet<>(); + /** + * 命令缓存列表 + */ + Map cmdcache = new HashMap<>(); + /** + * 命令帮助 + */ + CommandHelp help = new CommandHelp(cmdlist); + + /** + * 命令管理器 + * + * @param name + * 注册的命令 + */ + public CommandManager(final String name) { + final PluginCommand cmd = plugin.getCommand(name); + if (cmd == null) { + throw new IllegalStateException("未找到命令 必须在plugin.yml先注册 " + name + " 命令!"); + } + cmd.setExecutor(this); + cmd.setTabCompleter(this); + } + + /** + * 命令管理器 + * + * @param name + * 注册的命令 + * @param executor + * 命令执行类 + */ + public CommandManager(final String name, final CommandExecutor executor) { + this(name); + registerCommands(executor); + } + + @Override + public boolean onCommand(final CommandSender sender, final Command command, final String label, final String[] args) { + if (args.length == 0) { + help.send(sender, command, label, args); + return true; + } + final String subcmd = args[0].toLowerCase(); + if (subcmd.equalsIgnoreCase("help")) { + help.send(sender, command, label, args); + return true; + } + final String[] subargs = moveStrings(args, 1); + if (!cmdcache.containsKey(label)) { + for (final CommandInfo cmdinfo : cmdlist) { + if (cmdinfo.isValid(label)) { + cmdcache.put(label, cmdinfo); + break; + } + } + cmdcache.put(label, CommandInfo.Unknow); + } + return cmdcache.get(label).execute(sender, command, label, subargs); + } + + @Override + public List onTabComplete(final CommandSender sender, final Command command, final String alias, final String[] args) { + final List completions = new ArrayList<>(); + final String token = args[args.length - 1]; + if (args.length == 1) { + final Set commands = this.cmdcache.keySet(); + StringUtil.copyPartialMatches(args[0], commands, completions); + } else if (args.length >= 2) { + for (final TabInfo tab : tablist) { + StringUtil.copyPartialMatches(token, tab.execute(sender, command, token, args), completions); + } + StringUtil.copyPartialMatches(token, getPlayerTabComplete(sender, command, alias, args), completions); + } + Collections.sort(completions, String.CASE_INSENSITIVE_ORDER); + return completions; + } + + /** + * 通过注解读取命令并注册 + * + * @param clazz + * 子命令处理类 + */ + public void registerCommands(final CommandExecutor clazz) { + final Method[] methods = clazz.getClass().getDeclaredMethods(); + for (final Method method : methods) { + 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 (cmdlist.add(ci)) { + cmdcache.put(ci.getName(), ci); + continue; + } + } else { + Log.warning(String.format(argumentTypeError, method.getName(), clazz.getClass().getName())); + } + } + final TabInfo ti = TabInfo.parse(method, clazz); + if (ti != null) { + if (!method.getReturnType().equals(List.class)) { + Log.warning(String.format(returnTypeError, method.getName(), clazz.getClass().getName())); + continue; + } + tablist.add(ti); + } + } + help = new CommandHelp(cmdlist); + } + + /** + * 获取玩家命令补全 + * + * @param sender + * 命令发送者 + * @param command + * 命令 + * @param alias + * 别名 + * @param args + * 数组 + * @return 在线玩家数组 + */ + private List getPlayerTabComplete(final CommandSender sender, final Command command, final String alias, final String[] args) { + final String lastWord = args[args.length - 1]; + final Player senderPlayer = sender instanceof Player ? (Player) sender : null; + final ArrayList matchedPlayers = new ArrayList<>(); + for (final Player player : C.Player.getOnlinePlayers()) { + final String name = player.getName(); + if ((senderPlayer == null || senderPlayer.canSee(player)) && StringUtil.startsWithIgnoreCase(name, lastWord)) { + matchedPlayers.add(name); + } + } + return matchedPlayers; + } + + /** + * 转移数组 + * + * @param args + * 原数组 + * @param start + * 数组开始位置 + * @return 转移后的数组字符串 + */ + private String[] moveStrings(final String[] args, final int start) { + final String[] ret = new String[args.length - start]; + System.arraycopy(args, start, ret, 0, ret.length); + return ret; + } + +} diff --git a/src/main/java/pw/yumc/YumCore/commands/TabInfo.java b/src/main/java/pw/yumc/YumCore/commands/TabInfo.java new file mode 100644 index 0000000..67e8dc6 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/commands/TabInfo.java @@ -0,0 +1,80 @@ +package pw.yumc.YumCore.commands; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; + +import org.bukkit.command.CommandSender; + +import pw.yumc.YumCore.bukkit.P; +import pw.yumc.YumCore.commands.annotation.Tab; + +/** + * Tab补全 + * + * @since 2016年7月23日 上午9:56:42 + * @author 喵♂呜 + */ +public class TabInfo { + private final Object origin; + private final Method method; + + public TabInfo(final Method method, final Object origin) { + this.method = method; + this.origin = origin; + } + + /** + * 解析TabInfo + * + * @param method + * 方法 + * @param origin + * 对象 + * @return {@link TabInfo} + */ + public static TabInfo parse(final Method method, final Object origin) { + final Class clazz = method.getClass(); + final Tab tab = clazz.getAnnotation(Tab.class); + if (tab != null) { + return new TabInfo(method, origin); + } + return null; + } + + @Override + public boolean equals(final Object obj) { + if (obj instanceof TabInfo) { + return method.equals(((TabInfo) obj).getMethod()); + } + return super.equals(obj); + } + + /** + * 获得补全List + * + * @param sender + * 发送者 + * @param command + * 命令 + * @param label + * 命令 + * @param args + * 参数 + * @return Tab补全信息 + */ + @SuppressWarnings("unchecked") + public List execute(final CommandSender sender, final org.bukkit.command.Command command, final String label, final String[] args) { + final CommandArgument cmdArgs = new CommandArgument(sender, command, label, args); + try { + return (List) method.invoke(origin, cmdArgs); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new RuntimeException("调用Tab自动补全发生错误 请反馈给开发者 " + Arrays.toString(P.instance.getDescription().getAuthors().toArray()) + " !", e); + } + } + + public Method getMethod() { + return method; + } +} diff --git a/src/main/java/pw/yumc/YumCore/commands/annotation/Async.java b/src/main/java/pw/yumc/YumCore/commands/annotation/Async.java new file mode 100644 index 0000000..645505d --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/commands/annotation/Async.java @@ -0,0 +1,18 @@ +package pw.yumc.YumCore.commands.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 异步命令注解 + * + * @since 2016年7月23日 上午9:00:27 + * @author 喵♂呜 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Async { + +} diff --git a/src/main/java/pw/yumc/YumCore/commands/annotation/Cmd.java b/src/main/java/pw/yumc/YumCore/commands/annotation/Cmd.java new file mode 100644 index 0000000..f84d6ce --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/commands/annotation/Cmd.java @@ -0,0 +1,46 @@ +package pw.yumc.YumCore.commands.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 命令注解 + * + * @since 2016年7月23日 上午8:59:05 + * @author 喵♂呜 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Cmd { + /** + * @return 命令别名 + */ + String[] aliases() default ""; + + /** + * @return 命令最小参数 + */ + int minimumArguments() default 0; + + /** + * @return 命令名称 + */ + String name() default ""; + + /** + * @return 只允许控制台执行 + */ + boolean onlyConsoleExecutable() default false; + + /** + * @return 只允许玩家执行 + */ + boolean onlyPlayerExecutable() default false; + + /** + * @return 当前命令权限 + */ + String permission() default ""; +} diff --git a/src/main/java/pw/yumc/YumCore/commands/annotation/Help.java b/src/main/java/pw/yumc/YumCore/commands/annotation/Help.java new file mode 100644 index 0000000..8561519 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/commands/annotation/Help.java @@ -0,0 +1,44 @@ +package pw.yumc.YumCore.commands.annotation; + +import java.lang.annotation.Annotation; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 命令帮助注解 + * + * @since 2016年7月23日 上午9:00:07 + * @author 喵♂呜 + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface Help { + public static Help DEFAULT = new Help() { + @Override + public Class annotationType() { + return getClass(); + } + + @Override + public String description() { + return "这家伙很懒"; + } + + @Override + public String possibleArguments() { + return "没有帮助信息"; + } + }; + + /** + * @return 命令描述 + */ + String description() default "无"; + + /** + * @return 当前命令可能需要的参数 + */ + String possibleArguments() default ""; +} diff --git a/src/main/java/pw/yumc/YumCore/commands/annotation/Sort.java b/src/main/java/pw/yumc/YumCore/commands/annotation/Sort.java new file mode 100644 index 0000000..01d6263 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/commands/annotation/Sort.java @@ -0,0 +1,13 @@ +package pw.yumc.YumCore.commands.annotation; + +/** + * + * @since 2016年7月23日 上午9:04:56 + * @author 喵♂呜 + */ +public @interface Sort { + /** + * @return 命令排序 + */ + int sort() default 50; +} diff --git a/src/main/java/pw/yumc/YumCore/commands/annotation/Tab.java b/src/main/java/pw/yumc/YumCore/commands/annotation/Tab.java new file mode 100644 index 0000000..a501ad1 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/commands/annotation/Tab.java @@ -0,0 +1,10 @@ +package pw.yumc.YumCore.commands.annotation; + +/** + * 自动补全注解 + * + * @since 2016年7月23日 上午9:43:40 + * @author 喵♂呜 + */ +public @interface Tab { +} diff --git a/src/main/java/pw/yumc/YumCore/commands/api/CommandExecutor.java b/src/main/java/pw/yumc/YumCore/commands/api/CommandExecutor.java new file mode 100644 index 0000000..364bbb4 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/commands/api/CommandExecutor.java @@ -0,0 +1,11 @@ +package pw.yumc.YumCore.commands.api; + +/** + * 命令执行类 + * + * @since 2016年7月23日 上午9:55:51 + * @author 喵♂呜 + */ +public interface CommandExecutor { + +} diff --git a/src/main/java/pw/yumc/YumCore/commands/exception/CommandException.java b/src/main/java/pw/yumc/YumCore/commands/exception/CommandException.java new file mode 100644 index 0000000..6593c79 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/commands/exception/CommandException.java @@ -0,0 +1,19 @@ +package pw.yumc.YumCore.commands.exception; + +/** + * 命令执行异常类 + * + * @since 2016年7月23日 上午10:50:23 + * @author 喵♂呜 + */ +public class CommandException extends RuntimeException { + + public CommandException(final Exception e) { + super(e); + } + + public CommandException(final String string) { + super(string); + } + +} diff --git a/src/main/java/pw/yumc/YumCore/commands/exception/IllegalArgumentException.java b/src/main/java/pw/yumc/YumCore/commands/exception/IllegalArgumentException.java new file mode 100644 index 0000000..98e5d77 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/commands/exception/IllegalArgumentException.java @@ -0,0 +1,14 @@ +package pw.yumc.YumCore.commands.exception; + +/** + * + * @since 2016年7月23日 上午11:00:34 + * @author 喵♂呜 + */ +public class IllegalArgumentException extends CommandException { + + public IllegalArgumentException(final String string) { + super(string); + } + +} diff --git a/src/main/java/pw/yumc/YumCore/commands/exception/IllegalPermissionException.java b/src/main/java/pw/yumc/YumCore/commands/exception/IllegalPermissionException.java new file mode 100644 index 0000000..576c0ed --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/commands/exception/IllegalPermissionException.java @@ -0,0 +1,12 @@ +package pw.yumc.YumCore.commands.exception; + +/** + * + * @since 2016年7月23日 上午10:50:23 + * @author 喵♂呜 + */ +public class IllegalPermissionException extends CommandException { + public IllegalPermissionException(final String string) { + super(string); + } +} diff --git a/src/main/java/pw/yumc/YumCore/commands/exception/IllegalSenderException.java b/src/main/java/pw/yumc/YumCore/commands/exception/IllegalSenderException.java new file mode 100644 index 0000000..ae0057f --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/commands/exception/IllegalSenderException.java @@ -0,0 +1,14 @@ +package pw.yumc.YumCore.commands.exception; + +/** + * + * @since 2016年7月23日 上午11:00:34 + * @author 喵♂呜 + */ +public class IllegalSenderException extends CommandException { + + public IllegalSenderException(final String string) { + super(string); + } + +}