Files
TabooLib/src/main/java/me/skymc/taboolib/commands/internal/BaseMainCommand.java
2018-09-22 18:19:21 +08:00

212 lines
9.6 KiB
Java

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<Class<?>> linkClasses = new CopyOnWriteArrayList<>();
private List<BaseSubCommand> 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<Method> methods = new ArrayList<>();
List<CommandField> 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<Class<?>> getLinkClasses() {
return linkClasses;
}
public List<BaseSubCommand> 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<String> 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<BaseSubCommand> 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());
}
}