命令系统重做

This commit is contained in:
坏黑
2018-05-10 00:44:57 +08:00
parent b14164fbbd
commit 41e53b9165
100 changed files with 1765 additions and 707 deletions

View File

@@ -0,0 +1,162 @@
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.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.scheduler.BukkitRunnable;
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 IMainCommand, CommandExecutor, TabExecutor {
private PluginCommand registerCommand;
private List<Class<?>> linkClasses = new CopyOnWriteArrayList<>();
private List<BaseSubCommand> subCommands = new CopyOnWriteArrayList<>();
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());
loadCommandRegister(baseMainCommand);
return baseMainCommand;
}
public static void loadCommandRegister(BaseMainCommand baseMainCommand) {
List<Method> methods = 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) {
}
});
}
if (methods.size() > 0) {
TLocale.Logger.info("COMMANDS.INTERNAL.COMMAND-REGISTER", baseMainCommand.getRegisterCommand().getPlugin().getName(), baseMainCommand.getRegisterCommand().getName(), String.valueOf(methods.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 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())) {
continue;
}
if (!isConfirmType(sender, subCommand.getType())) {
TLocale.sendTo(sender, "COMMANDS.INTERNAL.ONLY-PLAYER", 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(Objects::nonNull).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 List<String> onTabComplete(CommandSender commandSender, Command command, String s, String[] args) {
return args.length == 1 ? subCommands.stream().filter(internalCommandExecutor -> internalCommandExecutor != null && (args[0].isEmpty() || internalCommandExecutor.getLabel().startsWith(args[0]))).map(ISubCommand::getLabel).collect(Collectors.toList()) : null;
}
@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 String getEmptyLine() {
return TabooLib.getVerint() < 10800 ? "~" : "";
}
private boolean isConfirmType(CommandSender sender, CommandType commandType) {
return commandType == CommandType.ALL || sender instanceof ConsoleCommandSender && commandType == CommandType.CONSOLE;
}
private void helpCommand(CommandSender sender, String label) {
sender.sendMessage(getEmptyLine());
sender.sendMessage(getCommandTitle());
sender.sendMessage(getEmptyLine());
subCommands.stream().map(subCommand -> subCommand == null ? getEmptyLine() : subCommand.getCommandString(label)).forEach(sender::sendMessage);
sender.sendMessage(getEmptyLine());
}
}

View File

@@ -1,15 +1,22 @@
package me.skymc.taboolib.commands.internal;
import me.skymc.taboolib.commands.internal.type.CommandArgument;
import me.skymc.taboolib.commands.internal.type.CommandType;
import java.util.stream.IntStream;
/**
* @author Bkm016
* @since 2018-04-17
*/
public abstract class InternalSubCommandExecutor implements InternalSubCommand {
public abstract class BaseSubCommand implements ISubCommand {
public InternalSubCommandType getType() {
return InternalSubCommandType.ALL;
public CommandType getType() {
return CommandType.ALL;
}
public boolean ignoredLabel() {
return true;
}
public boolean requiredPlayer() {
@@ -27,7 +34,7 @@ public abstract class InternalSubCommandExecutor implements InternalSubCommand {
stringBuilder.append(" ");
stringBuilder.append(getLabel());
stringBuilder.append(" ");
for (InternalArgument parameter : getArguments()) {
for (CommandArgument parameter : getArguments()) {
stringBuilder.append(parameter.toString());
stringBuilder.append(" ");
}
@@ -35,4 +42,4 @@ public abstract class InternalSubCommandExecutor implements InternalSubCommand {
stringBuilder.append(getDescription());
return stringBuilder.toString();
}
}
}

View File

@@ -4,8 +4,13 @@ package me.skymc.taboolib.commands.internal;
* @Author sky
* @Since 2018-05-07 21:36
*/
public interface InternalCommand {
public interface IMainCommand {
/**
* 指令标题
*
* @return 文本
*/
String getCommandTitle();
}

View File

@@ -0,0 +1,44 @@
package me.skymc.taboolib.commands.internal;
import me.skymc.taboolib.commands.internal.type.CommandArgument;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
/**
* @author Bkm016
* @since 2018-04-17
*/
public interface ISubCommand {
/**
* 指令名
*
* @return 文本
*/
String getLabel();
/**
* 指令描述
*
* @return 文本
*/
String getDescription();
/**
* 指令参数
*
* @return {@link CommandArgument}
*/
CommandArgument[] getArguments();
/**
* 指令执行方法
*
* @param sender 指令使用者
* @param command 指令对象
* @param label 主命令
* @param args 参数(不含主命令及子命令)
*/
void onCommand(CommandSender sender, Command command, String label, String[] args);
}

View File

@@ -1,29 +0,0 @@
package me.skymc.taboolib.commands.internal;
/**
* @author Bkm016
* @since 2018-04-17
*/
public class InternalArgument {
private String name;
private boolean required;
public String getName() {
return name;
}
public boolean isRequired() {
return required;
}
public InternalArgument(String name, boolean required) {
this.name = name;
this.required = required;
}
@Override
public String toString() {
return required ? "§7[§8" + name + "§7]" : "§7<§8" + name + "§7>";
}
}

View File

@@ -1,111 +0,0 @@
package me.skymc.taboolib.commands.internal;
import com.ilummc.tlib.resources.TLocale;
import me.skymc.taboolib.Main;
import me.skymc.taboolib.TabooLib;
import me.skymc.taboolib.string.ArrayUtils;
import me.skymc.taboolib.string.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @Author sky
* @Since 2018-05-07 21:38
*/
public abstract class InternalCommandExecutor implements InternalCommand, CommandExecutor, TabExecutor {
private InternalCommandExecutor subExecutor;
private List<InternalSubCommandExecutor> subCommandExecutors = new ArrayList<>();
public static InternalCommandExecutor createCommandExecutor(String command, InternalCommandExecutor internalCommandExecutor) {
assert Bukkit.getPluginCommand(command) == null : "PluginCommand \"" + command + "\"not found";
assert internalCommandExecutor != null : "Executor can not be null";
assert internalCommandExecutor.getCommandTitle() != null : "Executor title can not be null";
assert internalCommandExecutor.getClass() != InternalCommandExecutor.class : "SubExecutor can not be \"InternalCommandExecutor.class\"";
internalCommandExecutor.setSubExecutor(internalCommandExecutor);
Bukkit.getPluginCommand(command).setExecutor(internalCommandExecutor);
Bukkit.getPluginCommand(command).setTabCompleter(internalCommandExecutor);
return internalCommandExecutor;
}
public void setSubExecutor(InternalCommandExecutor subExecutor) {
this.subExecutor = subExecutor;
}
public InternalCommandExecutor getSubExecutor() {
return subExecutor;
}
public List<InternalSubCommandExecutor> getSubCommandExecutors() {
return subCommandExecutors;
}
public void registerSubCommandExecutor(InternalSubCommandExecutor subCommandExecutor) {
assert subCommandExecutor.getLabel() != null : "Command label can not be null";
assert subCommandExecutor.getDescription() != null : "Command description can not be null";
assert subCommandExecutor.getArguments() != null : "Command arguments can not be null";
subCommandExecutors.add(subCommandExecutor);
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (args.length == 0) {
helpCommand(sender, label);
} else {
for (InternalSubCommandExecutor subCommand : subCommandExecutors) {
if (subCommand == null || !args[0].equalsIgnoreCase(subCommand.getLabel())) {
continue;
}
if (!isConfirmType(sender, subCommand.getType())) {
TLocale.sendTo(sender, "COMMANDS.INTERNAL.ONLY-PLAYER", 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, subCommandArgs);
} else {
TLocale.sendTo(sender, "COMMANDS.INTERNAL.ERROR-USAGE", args[0], subCommand.getCommandString(label));
}
return true;
}
new BukkitRunnable() {
@Override
public void run() {
List<InternalSubCommandExecutor> commandCompute = subCommandExecutors.stream().filter(Objects::nonNull).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 List<String> onTabComplete(CommandSender commandSender, Command command, String s, String[] args) {
return args.length == 1 ? subCommandExecutors.stream().filter(internalCommandExecutor -> internalCommandExecutor != null && (args[0].isEmpty() || internalCommandExecutor.getLabel().startsWith(args[0]))).map(InternalSubCommand::getLabel).collect(Collectors.toList()) : null;
}
private String getEmptyLine() {
return TabooLib.getVerint() < 10800 ? "~" : "";
}
private void helpCommand(CommandSender sender, String label) {
sender.sendMessage(getEmptyLine());
sender.sendMessage(subExecutor.getCommandTitle());
sender.sendMessage(getEmptyLine());
subCommandExecutors.stream().map(subCommand -> subCommand == null ? getEmptyLine() : subCommand.getCommandString(label)).forEach(sender::sendMessage);
sender.sendMessage(getEmptyLine());
}
private boolean isConfirmType(CommandSender sender, InternalSubCommandType commandType) {
return commandType == InternalSubCommandType.ALL || sender instanceof ConsoleCommandSender && commandType == InternalSubCommandType.CONSOLE;
}
}

View File

@@ -1,20 +0,0 @@
package me.skymc.taboolib.commands.internal;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
/**
* @author Bkm016
* @since 2018-04-17
*/
public interface InternalSubCommand {
String getLabel();
String getDescription();
InternalArgument[] getArguments();
void onCommand(CommandSender sender, Command command, String label, String[] args);
}

View File

@@ -1,11 +0,0 @@
package me.skymc.taboolib.commands.internal;
/**
* @author Bkm016
* @since 2018-04-17
*/
public enum InternalSubCommandType {
CONSOLE, PLAYER, ALL
}

View File

@@ -0,0 +1,52 @@
package me.skymc.taboolib.commands.internal.type;
import java.util.Objects;
/**
* @author Bkm016
* @since 2018-04-17
*/
public class CommandArgument {
private String name;
private boolean required;
public String getName() {
return name;
}
public boolean isRequired() {
return required;
}
public CommandArgument(String name) {
this(name, true);
}
public CommandArgument(String name, boolean required) {
this.name = name;
this.required = required;
}
@Override
public String toString() {
return required ? "§7[§8" + name + "§7]" : "§7<§8" + name + "§7>";
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof CommandArgument)) {
return false;
}
CommandArgument that = (CommandArgument) o;
return Objects.equals(getName(), that.getName()) && isRequired() == that.isRequired();
}
@Override
public int hashCode() {
return Objects.hash(getName(), isRequired());
}
}

View File

@@ -0,0 +1,18 @@
package me.skymc.taboolib.commands.internal.type;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author sky
* @Since 2018-05-09 22:38
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CommandRegister {
double priority() default 0;
}

View File

@@ -0,0 +1,11 @@
package me.skymc.taboolib.commands.internal.type;
/**
* @author Bkm016
* @since 2018-04-17
*/
public enum CommandType {
CONSOLE, PLAYER, ALL
}