From 440cd45bda8f985fe9786c7cbf4e7855ffd4c463 Mon Sep 17 00:00:00 2001 From: qianmo <67282958@qq.com> Date: Thu, 31 Aug 2023 20:00:09 +0800 Subject: [PATCH] =?UTF-8?q?23/8/31=E6=9B=B4=E6=96=B0=20=E7=89=88=E6=9C=AC6?= =?UTF-8?q?.0.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 完善了 AbstractCommendExecutor,新增了类型检查,并发限制,异步支持,执行冷却,可选参数。 --- .../abstracts/AbstractCommendExecutor.java | 299 +++++++++++++----- .../ultitools/annotations/command/CmdCD.java | 12 + .../annotations/command/CmdSender.java | 11 + .../annotations/command/OptionalParam.java | 11 + .../annotations/command/RunAsync.java | 11 + .../annotations/command/UsageLimit.java | 17 + .../commands/PluginInstallCommands.java | 17 +- UltiTools-API/src/main/resources/lang/en.json | 4 + UltiTools-API/src/main/resources/lang/zh.json | 4 + 9 files changed, 299 insertions(+), 87 deletions(-) create mode 100644 UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/CmdCD.java create mode 100644 UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/CmdSender.java create mode 100644 UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/OptionalParam.java create mode 100644 UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/RunAsync.java create mode 100644 UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/UsageLimit.java diff --git a/UltiTools-API/src/main/java/com/ultikits/ultitools/abstracts/AbstractCommendExecutor.java b/UltiTools-API/src/main/java/com/ultikits/ultitools/abstracts/AbstractCommendExecutor.java index 1a98be0..af98398 100644 --- a/UltiTools-API/src/main/java/com/ultikits/ultitools/abstracts/AbstractCommendExecutor.java +++ b/UltiTools-API/src/main/java/com/ultikits/ultitools/abstracts/AbstractCommendExecutor.java @@ -3,15 +3,13 @@ package com.ultikits.ultitools.abstracts; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; import com.ultikits.ultitools.UltiTools; -import com.ultikits.ultitools.annotations.command.CmdExecutor; -import com.ultikits.ultitools.annotations.command.CmdMapping; -import com.ultikits.ultitools.annotations.command.CmdParam; -import com.ultikits.ultitools.annotations.command.CmdTarget; +import com.ultikits.ultitools.annotations.command.*; import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -22,11 +20,18 @@ import java.util.*; public abstract class AbstractCommendExecutor implements TabExecutor { private final BiMap mappings = HashBiMap.create(); + private final BiMap SenderLock = HashBiMap.create(); + private final BiMap CmdCoolDown = HashBiMap.create(); + private boolean ServerLock = false; public AbstractCommendExecutor() { scanCommandMappings(); } + public AbstractCommendExecutor getInstance() { + return this; + } + private void scanCommandMappings() { Class clazz = this.getClass(); Method[] methods = clazz.getDeclaredMethods(); @@ -44,6 +49,9 @@ public abstract class AbstractCommendExecutor implements TabExecutor { if (formatArgs[i].startsWith("<") && formatArgs[i].endsWith(">")) { params.put(formatArgs[i].substring(1, formatArgs[i].length() - 1), args[i]); } + if (formatArgs[i].startsWith("[") && formatArgs[i].endsWith("]")) { + params.put(formatArgs[i].substring(1, formatArgs[i].length() - 1), args[i]); + } } return params; } @@ -52,21 +60,42 @@ public abstract class AbstractCommendExecutor implements TabExecutor { for (Map.Entry entry : mappings.entrySet()) { String format = entry.getKey(); String[] formatArgs = format.split(" "); - if (formatArgs.length != args.length) { - continue; - } - boolean match = true; - for (int i = 0; i < formatArgs.length; i++) { - String formatArg = formatArgs[i]; - String actualArg = args[i]; - if (formatArg.startsWith("<") && formatArg.endsWith(">")) { + String lastArg = formatArgs[formatArgs.length - 1]; + boolean match; + if (lastArg.startsWith("[") && lastArg.endsWith("]")) { + if (formatArgs.length - args.length == 1) { continue; } - if (!formatArg.equals(actualArg)) { - match = false; - break; + match = true; + for (int i = 0; i < formatArgs.length - 1; i++) { + String formatArg = formatArgs[i]; + String actualArg = args[i]; + if (formatArg.startsWith("<") && formatArg.endsWith(">")) { + continue; + } + if (!formatArg.equalsIgnoreCase(actualArg)) { + match = false; + break; + } + } + } else { + if (formatArgs.length != args.length) { + continue; + } + match = true; + for (int i = 0; i < formatArgs.length; i++) { + String formatArg = formatArgs[i]; + String actualArg = args[i]; + if (formatArg.startsWith("<") && formatArg.endsWith(">")) { + continue; + } + if (!formatArg.equalsIgnoreCase(actualArg)) { + match = false; + break; + } } } + if (match) { return entry.getValue(); } @@ -165,6 +194,135 @@ public abstract class AbstractCommendExecutor implements TabExecutor { return true; } + private boolean checkLock(CommandSender sender, Method method) { + if (method.isAnnotationPresent(UsageLimit.class)) { + if (method.getAnnotation(UsageLimit.class).value().equals(UsageLimit.LimitType.SENDER)) { + if (sender instanceof Player) { + sender.sendMessage(ChatColor.RED + UltiTools.getInstance().i18n("请先等待上一条命令执行完毕!")); + return SenderLock.get(((Player) sender).getUniqueId()).equals(method); + } + return false; + } + if (method.getAnnotation(UsageLimit.class).value().equals(UsageLimit.LimitType.ALL)) { + sender.sendMessage(ChatColor.RED + UltiTools.getInstance().i18n("请先等待其他玩家发送的命令执行完毕!")); + return ServerLock; + } + } + return false; + } + + private boolean checkCD(CommandSender sender) { + if (!(sender instanceof Player)) { + return false; + } + Player player = (Player) sender; + if(CmdCoolDown.containsKey(player.getUniqueId())) { + sender.sendMessage(ChatColor.RED + UltiTools.getInstance().i18n("操作频繁,请稍后再试")); + return true; + } + return false; + } + + private Object[] parseParams(String[] strings, Method method, CommandSender commandSender) { + Map params = getParams(strings, mappings.inverse().get(method)); + Parameter[] parameters = method.getParameters(); + if (parameters.length == 0) { + return new Object[0]; + } + List ParamList = new ArrayList<>(); + for (Parameter parameter : parameters) { + if (parameter.getType().equals(Player.class) ) { + Player player = (Player) commandSender; + ParamList.add(parameter.isAnnotationPresent(CmdSender.class) ? player : null); + continue; + } + if (parameter.getType().equals(CommandSender.class)) { + ParamList.add(parameter.isAnnotationPresent(CmdSender.class) ? commandSender : null); + continue; + } + if (parameter.isAnnotationPresent(CmdParam.class)) { + CmdParam cmdParam = parameter.getAnnotation(CmdParam.class); + String value = params.get(cmdParam.value()); + try { + + if (parameter.getType() == float.class || parameter.getType() == Float.class) { + ParamList.add(Float.parseFloat(value)); + continue; + } + if (parameter.getType() == double.class || parameter.getType() == Double.class) { + ParamList.add(Double.parseDouble(value)); + continue; + } + if (parameter.getType() == int.class || parameter.getType() == Integer.class) { + ParamList.add(Integer.parseInt(value)); + continue; + } + } catch (NumberFormatException e) { + commandSender.sendMessage( + ChatColor.RED + String.format( + UltiTools.getInstance().i18n("参数 \"%s\" 格式错误:\"%s\" 不是一个有效的 %s 类型"), + cmdParam.value(), value, parameter.getType().getName() + )); + return null; + } + ParamList.add(value); + } else { + ParamList.add(null); + } + if (parameter.isAnnotationPresent(OptionalParam.class)) { + if (parameter.getType() == Map.class) { + String format = method.getAnnotation(CmdMapping.class).format(); + String OptionParams = params.get(format.split(" ")[format.split(" ").length - 1]); + ParamList.add(parseOptionalParams(OptionParams)); + } else { + ParamList.add(null); + } + } + } + return ParamList.toArray(); + } + + private Map> parseOptionalParams(String OptionalParam) { + Map> resultMap = new HashMap<>(); + + String[] optionGroups = OptionalParam.split(";"); + for (String optionGroup : optionGroups) { + String[] parts = optionGroup.split("="); + if (parts.length == 2) { + String optionName = parts[0]; + String[] arguments = parts[1].split(","); + + resultMap.put(optionName, Arrays.asList(arguments)); + } + } + + return resultMap; + } + + private void setCoolDown(CommandSender commandSender, Method method) { + if (!(commandSender instanceof Player)) { + return; + } + CmdCD cmdCD = method.getAnnotation(CmdCD.class); + if (cmdCD.value() == 0) { + return; + } + Player player = (Player) commandSender; + CmdCoolDown.put(player.getUniqueId(), method); + new BukkitRunnable() { + int time = cmdCD.value(); + @Override + public void run() { + if (time > 0) { + time--; + } else { + CmdCoolDown.remove(player.getUniqueId(), method); + this.cancel(); + } + } + }.runTaskTimerAsynchronously(UltiTools.getInstance(), 0L, 20L); + } + abstract protected void handleHelp(CommandSender sender); protected void sendErrorMessage(CommandSender sender, Command command) { @@ -187,82 +345,69 @@ public abstract class AbstractCommendExecutor implements TabExecutor { @Override public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) { - if(!checkSender(commandSender)){ + if (strings.length == 1 && getHelpCommand().equals(strings[0])){ + handleHelp(commandSender); return true; } - if (!checkPermission(commandSender)) { + Method method = matchMethod(strings); + if (method == null) { + commandSender.sendMessage(ChatColor.RED + String.format(UltiTools.getInstance().i18n("未知指令,请使用/%s %s获取帮助"), command.getName(), getHelpCommand())); + handleHelp(commandSender); return true; } - if (!checkOp(commandSender)) { + if (!checkSender(commandSender) && !checkSender(commandSender, method)) { return true; } - if (strings.length > 0 && getHelpCommand().equals(strings[0])){ - handleHelp(commandSender); + if (!checkPermission(commandSender) && !checkPermission(commandSender, method)) { return true; } - Method method = matchMethod(strings); - if (method == null) { - commandSender.sendMessage(ChatColor.RED + UltiTools.getInstance().i18n("未知指令!")); - handleHelp(commandSender); + if (!checkOp(commandSender) && !checkOp(commandSender, method)) { return true; } - Map params = getParams(strings, mappings.inverse().get(method)); - Parameter[] parameters = method.getParameters(); - ArrayList ParamList = new ArrayList<>(); - if (parameters.length == 0) { - try { - if (!checkSender(commandSender, method)) { - return true; - } - if (!checkPermission(commandSender, method)) { - return true; - } - if (!checkOp(commandSender, method)) { - return true; - } - method.invoke(this); - } catch (IllegalAccessException | InvocationTargetException e) { - sendErrorMessage(commandSender, command); - throw new RuntimeException(e); - } + if (checkLock(commandSender, method)) { return true; } - for (Parameter parameter : parameters) { - if (parameter.getType().equals(Player.class)) { - Player player = (Player) commandSender; - ParamList.add(player); - continue; - } - if (parameter.getType().equals(CommandSender.class)) { - ParamList.add(commandSender); - continue; - } - if (parameter.getType().equals(Command.class)) { - ParamList.add(command); - continue; - } - if (parameter.isAnnotationPresent(CmdParam.class)) { - CmdParam cmdParam = parameter.getAnnotation(CmdParam.class); - String value = params.get(cmdParam.value()); - ParamList.add(value); - } else { - ParamList.add(null); - } + if (checkCD(commandSender)) { + return true; } - try { - if (!checkSender(commandSender, method)) { - return true; - } - if (!checkPermission(commandSender, method)) { - return true; - } - if (!checkOp(commandSender, method)) { - return true; + Object[] params = parseParams(strings, method, commandSender); + BukkitRunnable bukkitRunnable = new BukkitRunnable() { + @Override + public void run() { + if (method.isAnnotationPresent(UsageLimit.class)) { + if (method.getAnnotation(UsageLimit.class).value().equals(UsageLimit.LimitType.ALL)) { + ServerLock = true; + } + if (method.getAnnotation(UsageLimit.class).value().equals(UsageLimit.LimitType.SENDER)) { + if (commandSender instanceof Player) { + SenderLock.put(((Player) commandSender).getUniqueId(), method); + } + } + } + try { + setCoolDown(commandSender, method); + method.invoke(getInstance(), params); + } catch (IllegalAccessException | InvocationTargetException e) { + sendErrorMessage(commandSender, command); + throw new RuntimeException(e); + } finally { + if (method.isAnnotationPresent(UsageLimit.class)) { + if (method.getAnnotation(UsageLimit.class).value().equals(UsageLimit.LimitType.ALL)) { + ServerLock = false; + } + if (method.getAnnotation(UsageLimit.class).value().equals(UsageLimit.LimitType.SENDER)) { + if (commandSender instanceof Player) { + SenderLock.remove(((Player) commandSender).getUniqueId()); + } + } + } + } } - method.invoke(this, ParamList.toArray()); - } catch (IllegalAccessException | InvocationTargetException e) { - sendErrorMessage(commandSender, command); - throw new RuntimeException(e); + }; + if (method.isAnnotationPresent(RunAsync.class)) { + bukkitRunnable.runTaskAsynchronously(UltiTools.getInstance()); + } else { + bukkitRunnable.runTask(UltiTools.getInstance()); } return true; } diff --git a/UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/CmdCD.java b/UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/CmdCD.java new file mode 100644 index 0000000..8262caa --- /dev/null +++ b/UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/CmdCD.java @@ -0,0 +1,12 @@ +package com.ultikits.ultitools.annotations.command; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface CmdCD { + int value() default 0; +} diff --git a/UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/CmdSender.java b/UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/CmdSender.java new file mode 100644 index 0000000..0f664a1 --- /dev/null +++ b/UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/CmdSender.java @@ -0,0 +1,11 @@ +package com.ultikits.ultitools.annotations.command; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface CmdSender { +} diff --git a/UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/OptionalParam.java b/UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/OptionalParam.java new file mode 100644 index 0000000..bd13902 --- /dev/null +++ b/UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/OptionalParam.java @@ -0,0 +1,11 @@ +package com.ultikits.ultitools.annotations.command; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface OptionalParam { +} diff --git a/UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/RunAsync.java b/UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/RunAsync.java new file mode 100644 index 0000000..9f4c571 --- /dev/null +++ b/UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/RunAsync.java @@ -0,0 +1,11 @@ +package com.ultikits.ultitools.annotations.command; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface RunAsync { +} \ No newline at end of file diff --git a/UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/UsageLimit.java b/UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/UsageLimit.java new file mode 100644 index 0000000..6119d6c --- /dev/null +++ b/UltiTools-API/src/main/java/com/ultikits/ultitools/annotations/command/UsageLimit.java @@ -0,0 +1,17 @@ +package com.ultikits.ultitools.annotations.command; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface UsageLimit { + LimitType value(); + enum LimitType { + NONE, + SENDER, + ALL + } +} \ No newline at end of file diff --git a/UltiTools-API/src/main/java/com/ultikits/ultitools/commands/PluginInstallCommands.java b/UltiTools-API/src/main/java/com/ultikits/ultitools/commands/PluginInstallCommands.java index 9b2984e..94116d1 100644 --- a/UltiTools-API/src/main/java/com/ultikits/ultitools/commands/PluginInstallCommands.java +++ b/UltiTools-API/src/main/java/com/ultikits/ultitools/commands/PluginInstallCommands.java @@ -2,10 +2,7 @@ package com.ultikits.ultitools.commands; import com.ultikits.ultitools.UltiTools; import com.ultikits.ultitools.abstracts.AbstractCommendExecutor; -import com.ultikits.ultitools.annotations.command.CmdExecutor; -import com.ultikits.ultitools.annotations.command.CmdMapping; -import com.ultikits.ultitools.annotations.command.CmdParam; -import com.ultikits.ultitools.annotations.command.CmdTarget; +import com.ultikits.ultitools.annotations.command.*; import com.ultikits.ultitools.entities.PluginEntity; import com.ultikits.ultitools.utils.PluginInstallUtils; import org.bukkit.ChatColor; @@ -18,7 +15,7 @@ import java.util.List; @CmdTarget(CmdTarget.CmdTargetType.BOTH) public class PluginInstallCommands extends AbstractCommendExecutor { @CmdMapping(format = "list ") - public void listPlugins(CommandSender sender, @CmdParam("page") String page) { + public void listPlugins(@CmdSender CommandSender sender, @CmdParam("page") String page) { int pageInt = 1; if (page != null && !page.isEmpty()) { try { @@ -51,12 +48,12 @@ public class PluginInstallCommands extends AbstractCommendExecutor { } @CmdMapping(format = "list") - public void listPlugins(CommandSender sender) { + public void listPlugins(@CmdSender CommandSender sender) { listPlugins(sender, "1"); } @CmdMapping(format = "install ") - public void installPlugin(CommandSender sender, @CmdParam("plugin") String plugin, @CmdParam("version") String version) { + public void installPlugin(@CmdSender CommandSender sender, @CmdParam("plugin") String plugin, @CmdParam("version") String version) { if (PluginInstallUtils.installPlugin(plugin, version)) { sender.sendMessage(ChatColor.GREEN + UltiTools.getInstance().i18n("安装成功!请重启服务器!")); } else { @@ -65,7 +62,7 @@ public class PluginInstallCommands extends AbstractCommendExecutor { } @CmdMapping(format = "install ") - public void installPlugin(CommandSender sender, @CmdParam("plugin") String plugin) { + public void installPlugin(@CmdSender CommandSender sender, @CmdParam("plugin") String plugin) { if (PluginInstallUtils.installLatestPlugin(plugin)) { sender.sendMessage(ChatColor.GREEN + UltiTools.getInstance().i18n("安装成功!请重启服务器!")); } else { @@ -74,7 +71,7 @@ public class PluginInstallCommands extends AbstractCommendExecutor { } @CmdMapping(format = "versions ") - public void listVersions(CommandSender sender, @CmdParam("plugin") String plugin) { + public void listVersions(@CmdSender CommandSender sender, @CmdParam("plugin") String plugin) { List pluginVersions = PluginInstallUtils.getPluginVersions(plugin); if (pluginVersions == null) { sender.sendMessage(ChatColor.RED + UltiTools.getInstance().i18n("获取版本列表失败!")); @@ -101,7 +98,7 @@ public class PluginInstallCommands extends AbstractCommendExecutor { } @CmdMapping(format = "uninstall ") - public void uninstallPlugin(CommandSender sender, @CmdParam("plugin") String plugin) { + public void uninstallPlugin(@CmdSender CommandSender sender, @CmdParam("plugin") String plugin) { try { if (PluginInstallUtils.uninstallPlugin(plugin)) { sender.sendMessage(ChatColor.GREEN + UltiTools.getInstance().i18n("卸载成功!请手动删除本地文件,否则重启之后还会启用!")); diff --git a/UltiTools-API/src/main/resources/lang/en.json b/UltiTools-API/src/main/resources/lang/en.json index 5457c6b..f86af0a 100644 --- a/UltiTools-API/src/main/resources/lang/en.json +++ b/UltiTools-API/src/main/resources/lang/en.json @@ -17,6 +17,10 @@ "你没有权限!": "You don't have permission to do that!", "未知指令,请使用/%s %s获取帮助": "Unknown command, please enter /%s %s for help", "指令执行错误,请使用/%s %s获取帮助": "Command execution error, please enter /%s %s for help", + "请先等待上一条命令执行完毕!": "Please wait for last Command Processing!", + "请先等待其他玩家发送的命令执行完毕!": "Please wait for last Command Processing which sent by other players!", + "操作频繁,请稍后再试": "Frequent operations, please try again later", + "参数 \"%s\" 格式错误:\"%s\" 不是一个有效的 %s 类型": "Parameter \"%s\" has a formatting error: \"%s\" is not a valid %s type.", "=== UltiTools 命令列表 ===\n/ul reload 重载插件模块\n================": "=== UltiTools Commands ===\n/ul reload Reload modules\n================", "========|可用插件列表|========\n": "========|Available Plugin List|========\n", ". 名字:": ". Name:", diff --git a/UltiTools-API/src/main/resources/lang/zh.json b/UltiTools-API/src/main/resources/lang/zh.json index 875e806..84dd857 100644 --- a/UltiTools-API/src/main/resources/lang/zh.json +++ b/UltiTools-API/src/main/resources/lang/zh.json @@ -17,5 +17,9 @@ "你没有权限!": "你没有权限!", "指令执行错误,请使用/%s %s获取帮助": "指令执行错误,请使用/%s %s获取帮助", "未知指令,请使用/%s %s获取帮助": "未知指令,请使用/%s %s获取帮助", + "请先等待上一条命令执行完毕!": "请先等待上一条命令执行完毕!", + "请先等待其他玩家发送的命令执行完毕!": "请先等待其他玩家发送的命令执行完毕!", + "操作频繁,请稍后再试": "操作频繁,请稍后再试", + "参数 \"%s\" 格式错误:\"%s\" 不是一个有效的 %s 类型": "参数 \"%s\" 格式错误:\"%s\" 不是一个有效的 %s 类型", "=== UltiTools 命令列表 ===\n/ul reload 重载插件模块\n================": "=== UltiTools 命令列表 ===\n/ul reload 重载插件模块\n================" }