package me.skymc.taboolib.commands.internal; import com.google.common.base.Preconditions; import com.ilummc.tlib.resources.TLocale; import me.skymc.taboolib.Main; import me.skymc.taboolib.TabooLib; import me.skymc.taboolib.commands.internal.type.CommandField; import me.skymc.taboolib.commands.internal.type.CommandRegister; import me.skymc.taboolib.commands.internal.type.CommandType; import me.skymc.taboolib.string.ArrayUtils; import me.skymc.taboolib.string.StringUtils; import org.bukkit.Bukkit; import org.bukkit.command.*; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.scheduler.BukkitRunnable; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import java.util.stream.Collectors; /** * @Author sky * @Since 2018-05-07 21:38 */ public abstract class BaseMainCommand implements CommandExecutor, TabExecutor { private PluginCommand registerCommand; private List> linkClasses = new CopyOnWriteArrayList<>(); private List subCommands = new CopyOnWriteArrayList<>(); /** * 指令标题 * * @return 文本 */ abstract public String getCommandTitle(); public static BaseMainCommand createCommandExecutor(String command, BaseMainCommand baseMainCommand) { Preconditions.checkArgument(Bukkit.getPluginCommand(command) != null, "PluginCommand \"" + command + "\" not found"); Preconditions.checkArgument(baseMainCommand != null, "Executor cannot be null"); Preconditions.checkArgument(baseMainCommand.getClass() != BaseMainCommand.class, "Executor can not be \"BaseMainCommand.class\""); baseMainCommand.setRegisterCommand(Bukkit.getPluginCommand(command)); baseMainCommand.getRegisterCommand().setExecutor(baseMainCommand); baseMainCommand.getRegisterCommand().setTabCompleter(baseMainCommand); baseMainCommand.getLinkClasses().add(baseMainCommand.getClass()); baseMainCommand.disguisedPlugin(); loadCommandRegister(baseMainCommand); return baseMainCommand; } public static void loadCommandRegister(BaseMainCommand baseMainCommand) { List methods = new ArrayList<>(); List fields = new ArrayList<>(); baseMainCommand.getLinkClasses().forEach(clazz -> Arrays.stream(clazz.getDeclaredMethods()).filter(method -> method.getAnnotation(CommandRegister.class) != null).forEach(methods::add)); if (methods.size() > 0) { methods.sort(Comparator.comparingDouble(a -> a.getAnnotation(CommandRegister.class).priority())); methods.forEach(x -> { try { x.setAccessible(true); x.invoke(baseMainCommand); } catch (Exception ignored) { } }); } baseMainCommand.getLinkClasses().forEach(clazz -> Arrays.stream(clazz.getDeclaredFields()).filter(field -> field.getAnnotation(CommandRegister.class) != null && field.getType().equals(BaseSubCommand.class)).forEach(field -> fields.add(new CommandField(field, clazz)))); if (fields.size() > 0) { fields.sort(Comparator.comparingDouble(commandField -> commandField.getField().getAnnotation(CommandRegister.class).priority())); fields.forEach(commandField -> { try { commandField.getField().setAccessible(true); baseMainCommand.registerSubCommand((BaseSubCommand) commandField.getField().get(commandField.getParent().newInstance())); } catch (Exception ignored) { } }); } if (methods.size() + fields.size() > 0 && !TabooLib.isTabooLib(baseMainCommand.getRegisterCommand().getPlugin())) { TLocale.Logger.info("COMMANDS.INTERNAL.COMMAND-REGISTER", baseMainCommand.getRegisterCommand().getPlugin().getName(), baseMainCommand.getRegisterCommand().getName(), String.valueOf(methods.size() + fields.size())); } } public void setRegisterCommand(PluginCommand registerCommand) { this.registerCommand = registerCommand; } public PluginCommand getRegisterCommand() { return registerCommand; } public List> getLinkClasses() { return linkClasses; } public List getSubCommands() { return subCommands; } public void registerSubCommand(BaseSubCommand subCommand) { if (subCommand != null) { Preconditions.checkArgument(subCommand.getLabel() != null, "Command label can not be null"); Preconditions.checkArgument(subCommand.getDescription() != null, "Command description can not be null"); Preconditions.checkArgument(subCommand.getArguments() != null, "Command arguments can not be null"); } subCommands.add(subCommand); } @Override public List onTabComplete(CommandSender commandSender, Command command, String s, String[] args) { return args.length == 1 ? subCommands.stream().filter(subCommand -> subCommand != null && hasPermission(commandSender, subCommand) && (args[0].isEmpty() || subCommand.getLabel().toLowerCase().startsWith(args[0].toLowerCase()))).map(BaseSubCommand::getLabel).collect(Collectors.toList()) : null; } @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { if (args.length == 0) { helpCommand(sender, label); } else { for (BaseSubCommand subCommand : subCommands) { if (subCommand == null || !args[0].equalsIgnoreCase(subCommand.getLabel()) || !hasPermission(sender, subCommand)) { continue; } if (!isConfirmType(sender, subCommand.getType())) { TLocale.sendTo(sender, "COMMANDS.INTERNAL.TYPE-ERROR", args[0], TLocale.asString("COMMANDS.INTERNAL.TYPE-" + subCommand.getType())); return true; } String[] subCommandArgs = ArrayUtils.removeFirst(args); if (subCommand.isParameterConform(subCommandArgs)) { subCommand.onCommand(sender, command, label, subCommand.ignoredLabel() ? subCommandArgs : args); } else { TLocale.sendTo(sender, "COMMANDS.INTERNAL.ERROR-USAGE", args[0], subCommand.getCommandString(label)); } return true; } new BukkitRunnable() { @Override public void run() { List commandCompute = subCommands.stream().filter(x -> x != null && hasPermission(sender, x)).sorted((b, a) -> Double.compare(StringUtils.similarDegree(args[0], a.getLabel()), StringUtils.similarDegree(args[0], b.getLabel()))).collect(Collectors.toList()); if (commandCompute.size() > 0) { TLocale.sendTo(sender, "COMMANDS.INTERNAL.ERROR-COMMAND", args[0], commandCompute.get(0).getCommandString(label).trim()); } } }.runTaskAsynchronously(Main.getInst()); } return true; } @Override public String toString() { return "registerCommand=" + "BaseMainCommand{" + registerCommand + ", linkClasses=" + linkClasses + ", subCommands=" + subCommands + '}'; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof BaseMainCommand)) { return false; } BaseMainCommand that = (BaseMainCommand) o; return Objects.equals(getLinkClasses(), that.getLinkClasses()) && Objects.equals(getRegisterCommand(), that.getRegisterCommand()) && Objects.equals(getSubCommands(), that.getSubCommands()); } @Override public int hashCode() { return Objects.hash(getRegisterCommand(), getLinkClasses(), getSubCommands()); } // ********************************* // // Private Methods // // ********************************* private String getEmptyLine() { return TabooLib.getVerint() < 10800 ? "~" : ""; } private boolean isConfirmType(CommandSender sender, CommandType commandType) { return commandType == CommandType.ALL || (sender instanceof Player && commandType == CommandType.PLAYER) || (sender instanceof ConsoleCommandSender && commandType == CommandType.CONSOLE); } private void helpCommand(CommandSender sender, String label) { sender.sendMessage(getEmptyLine()); sender.sendMessage(getCommandTitle()); sender.sendMessage(getEmptyLine()); subCommands.stream().filter(subCommands -> hasPermission(sender, subCommands)).map(subCommand -> subCommand == null ? getEmptyLine() : subCommand.getCommandString(label)).forEach(sender::sendMessage); sender.sendMessage(getEmptyLine()); } private void disguisedPlugin() { linkClasses.forEach(clazz -> disguisedPlugin(clazz, (JavaPlugin) registerCommand.getPlugin())); } private void disguisedPlugin(Class targetClass, JavaPlugin plugin) { try { Field pluginField = targetClass.getClassLoader().getClass().getDeclaredField("plugin"); pluginField.setAccessible(true); pluginField.set(targetClass.newInstance(), plugin); } catch (Exception ignored) { } } private boolean hasPermission(CommandSender sender, BaseSubCommand baseSubCommand) { return baseSubCommand == null || baseSubCommand.getPermission() == null || sender.hasPermission(baseSubCommand.getPermission()); } }