完善 @TCommand 注解

新增 TCommandHandler 类用于动态命令注册
This commit is contained in:
坏黑
2018-08-27 00:21:06 +08:00
parent 20ec68ff7f
commit 1e50bd526b
33 changed files with 474 additions and 788 deletions

View File

@@ -25,14 +25,21 @@ import java.util.stream.Collectors;
* @Author sky
* @Since 2018-05-07 21:38
*/
public abstract class BaseMainCommand implements IMainCommand, CommandExecutor, TabExecutor {
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(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));
@@ -99,6 +106,11 @@ public abstract class BaseMainCommand implements IMainCommand, CommandExecutor,
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) {
@@ -134,11 +146,6 @@ public abstract class BaseMainCommand implements IMainCommand, CommandExecutor,
return true;
}
@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(ISubCommand::getLabel).collect(Collectors.toList()) : null;
}
@Override
public String toString() {
return "registerCommand=" + "BaseMainCommand{" + registerCommand + ", linkClasses=" + linkClasses + ", subCommands=" + subCommands + '}';
@@ -161,6 +168,12 @@ public abstract class BaseMainCommand implements IMainCommand, CommandExecutor,
return Objects.hash(getRegisterCommand(), getLinkClasses(), getSubCommands());
}
// *********************************
//
// Private Methods
//
// *********************************
private String getEmptyLine() {
return TabooLib.getVerint() < 10800 ? "~" : "";
}

View File

@@ -1,7 +1,10 @@
package me.skymc.taboolib.commands.internal;
import com.ilummc.tlib.resources.TLocale;
import me.skymc.taboolib.commands.internal.type.CommandArgument;
import me.skymc.taboolib.commands.internal.type.CommandType;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import java.util.Arrays;
import java.util.stream.Collectors;
@@ -11,28 +14,91 @@ import java.util.stream.IntStream;
* @author Bkm016
* @since 2018-04-17
*/
public abstract class BaseSubCommand implements ISubCommand {
public abstract class BaseSubCommand {
/**
* 指令名
*
* @return 文本
*/
abstract public String getLabel();
/**
* 指令描述
*
* @return 文本
*/
abstract public String getDescription();
/**
* 指令参数
*
* @return {@link CommandArgument}
*/
abstract public CommandArgument[] getArguments();
/**
* 指令执行方法
*
* @param sender 指令使用者
* @param command 指令对象
* @param label 主命令
* @param args 参数(不含主命令及子命令)
*/
abstract public void onCommand(CommandSender sender, Command command, String label, String[] args);
/**
* 指令执行者
*
* @return {@link CommandType}
*/
public CommandType getType() {
return CommandType.ALL;
}
/**
* 参数是否屏蔽子命令名
*
* @return boolean
*/
public boolean ignoredLabel() {
return true;
}
/**
* 是否需要玩家在线
*
* @return boolean
*/
public boolean requiredPlayer() {
return false;
}
/**
* 需要权限
*
* @return boolean
*/
public String getPermission() {
return null;
}
/**
* 参数是否符合
*
* @param args 参数
* @return boolean
*/
public boolean isParameterConform(String[] args) {
return IntStream.range(0, getArguments().length).noneMatch(i -> getArguments()[i].isRequired() && (args == null || args.length <= i));
}
/**
* 获取帮助文本
*
* @param label 子命令标题
* @return String
*/
public String getCommandString(String label) {
String stringBuilder = Arrays.stream(getArguments()).map(parameter -> parameter.toString() + " ").collect(Collectors.joining());
return TLocale.asString("COMMANDS.INTERNAL.COMMAND-HELP", label, getLabel(), stringBuilder.trim(), getDescription());

View File

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

View File

@@ -1,44 +0,0 @@
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,71 +0,0 @@
package me.skymc.taboolib.commands.internal;
import me.skymc.taboolib.fileutils.FileUtils;
import me.skymc.taboolib.listener.TListener;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.plugin.Plugin;
/**
* @Author sky
* @Since 2018-05-23 2:43
*/
@TListener(register = "onLoad")
public class TBaseCommand implements Listener {
void onLoad() {
registerCommands();
}
/**
* 向服务端注册 BaseMainCommand 类
*
* @param command 命令全称(需在 plugin.yml 内注册)
* @param baseMainCommand 命令对象
* @return {@link BaseMainCommand}
*/
public static BaseMainCommand registerCommand(String command, BaseMainCommand baseMainCommand) {
return BaseMainCommand.createCommandExecutor(command, baseMainCommand);
}
/**
* 注册所有插件的所有 TCommand 命令
*/
public static void registerCommands() {
for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
try {
registerCommand(plugin);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 注册插件的所有 TCommand 命令
*
* @param plugin 插件
*/
public static void registerCommand(Plugin plugin) {
for (Class pluginClass : FileUtils.getClasses(plugin)) {
if (BaseMainCommand.class.isAssignableFrom(pluginClass) && pluginClass.isAnnotationPresent(TCommand.class)) {
TCommand tCommand = (TCommand) pluginClass.getAnnotation(TCommand.class);
try {
registerCommand(tCommand.name(), (BaseMainCommand) pluginClass.newInstance());
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
@EventHandler
public void onEnable(PluginEnableEvent e) {
try {
registerCommand(e.getPlugin());
} catch (Exception ignored) {
}
}
}

View File

@@ -4,6 +4,7 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;
/**
* @Author sky
@@ -15,4 +16,13 @@ public @interface TCommand {
String name();
String permission() default "";
String permissionMessage() default "";
String description() default "";
String usage() default "";
String[] aliases() default "";
}

View File

@@ -0,0 +1,181 @@
package me.skymc.taboolib.commands.internal;
import com.ilummc.tlib.resources.TLocale;
import me.skymc.taboolib.fileutils.FileUtils;
import me.skymc.taboolib.listener.TListener;
import me.skymc.taboolib.methods.ReflectionUtils;
import me.skymc.taboolib.string.ArrayUtils;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.server.PluginEnableEvent;
import org.bukkit.plugin.Plugin;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* @Author sky
* @Since 2018-05-23 2:43
*/
@TListener
public class TCommandHandler implements Listener {
private static SimpleCommandMap commandMap;
public TCommandHandler() {
try {
Field commandMap = Bukkit.getPluginManager().getClass().getDeclaredField("commandMap");
commandMap.setAccessible(true);
TCommandHandler.commandMap = (SimpleCommandMap) commandMap.get(Bukkit.getPluginManager());
} catch (Exception e) {
e.printStackTrace();
}
try {
registerCommands();
} catch (Exception e) {
e.printStackTrace();
}
}
@EventHandler
public void onEnable(PluginEnableEvent e) {
try {
registerCommand(e.getPlugin());
} catch (Exception ignored) {
}
}
public static boolean registerPluginCommand(Plugin plugin, String command, CommandExecutor commandExecutor) {
return registerPluginCommand(plugin, command, "", "/" + command, new ArrayList<>(), null, null, commandExecutor, null);
}
public static boolean registerPluginCommand(Plugin plugin, String command, CommandExecutor commandExecutor, TabExecutor tabExecutor) {
return registerPluginCommand(plugin, command, "", "/" + command, new ArrayList<>(), null, null, commandExecutor, tabExecutor);
}
public static boolean registerPluginCommand(Plugin plugin, String command, String description, CommandExecutor commandExecutor, TabExecutor tabExecutor) {
return registerPluginCommand(plugin, command, description, "/" + command, new ArrayList<>(), null, null, commandExecutor, tabExecutor);
}
public static boolean registerPluginCommand(Plugin plugin, String command, String description, String usage, CommandExecutor commandExecutor, TabExecutor tabExecutor) {
return registerPluginCommand(plugin, command, description, usage, new ArrayList<>(), null, null, commandExecutor, tabExecutor);
}
public static boolean registerPluginCommand(Plugin plugin, String command, String description, String usage, List<String> aliases, CommandExecutor commandExecutor, TabExecutor tabExecutor) {
return registerPluginCommand(plugin, command, description, usage, aliases, null, null, commandExecutor, tabExecutor);
}
/**
* 向服务端动态注册命令
*
* @param plugin 所属插件
* @param command 命令名称
* @param description 命令描述
* @param usage 命令用法
* @param aliases 别名
* @param permission 权限
* @param permissionMessage 权限提示
* @param commandExecutor 命令执行器
* @param tabExecutor 补全执行器
* @return 注册结果(boolean)
*/
public static boolean registerPluginCommand(Plugin plugin, String command, String description, String usage, List<String> aliases, String permission, String permissionMessage, CommandExecutor commandExecutor, TabExecutor tabExecutor) {
try {
Constructor<PluginCommand> constructor = PluginCommand.class.getDeclaredConstructor(String.class, Plugin.class);
constructor.setAccessible(true);
PluginCommand pluginCommand = constructor.newInstance(command, plugin);
pluginCommand.setExecutor(commandExecutor);
pluginCommand.setTabCompleter(tabExecutor);
ReflectionUtils.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "description", description);
ReflectionUtils.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "usageMessage", usage);
ReflectionUtils.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "aliases", aliases);
ReflectionUtils.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "activeAliases", aliases);
ReflectionUtils.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "permission", permission);
ReflectionUtils.setValue(pluginCommand, pluginCommand.getClass().getSuperclass(), true, "permissionMessage", permissionMessage);
commandMap.register(command, pluginCommand);
TLocale.Logger.info("COMMANDS.INTERNAL.COMMAND-CREATE", plugin.getName(), command);
return true;
} catch (Exception e) {
TLocale.Logger.info("COMMANDS.INTERNAL.COMMAND-CREATE-FAILED", plugin.getName(), command, e.getMessage());
return false;
}
}
/**
* 向服务端注册 BaseMainCommand 类
*
* @param command 命令全称(需在 plugin.yml 内注册)
* @param baseMainCommand 命令对象
* @return {@link BaseMainCommand}
*/
public static BaseMainCommand registerCommand(TCommand tCommand, String command, BaseMainCommand baseMainCommand, Plugin plugin) {
if (Bukkit.getPluginCommand(command) == null) {
registerPluginCommand(
plugin,
command,
ArrayUtils.skipEmpty(tCommand.description(), "Registered by TabooLib."),
ArrayUtils.skipEmpty(tCommand.usage(), "/" + command),
ArrayUtils.skipEmpty(ArrayUtils.asList(tCommand.aliases()), new ArrayList<>()),
ArrayUtils.skipEmpty(tCommand.permission()),
ArrayUtils.skipEmpty(tCommand.permissionMessage()),
baseMainCommand,
baseMainCommand);
}
return BaseMainCommand.createCommandExecutor(command, baseMainCommand);
}
/**
* 注册所有插件的所有 TCommand 命令
*/
public static void registerCommands() {
for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
try {
registerCommand(plugin);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 注册插件的所有 TCommand 命令
*
* @param plugin 插件
*/
public static void registerCommand(Plugin plugin) {
for (Class pluginClass : FileUtils.getClasses(plugin)) {
if (BaseMainCommand.class.isAssignableFrom(pluginClass) && pluginClass.isAnnotationPresent(TCommand.class)) {
TCommand tCommand = (TCommand) pluginClass.getAnnotation(TCommand.class);
try {
registerCommand(tCommand, tCommand.name(), (BaseMainCommand) pluginClass.newInstance(), plugin);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/**
* 获取插件注册的命令
*
* @param command 命令名称
* @return {@link Command}
*/
public static Command getPluginCommand(String command) {
return commandMap.getCommand(command);
}
// *********************************
//
// Getter and Setter
//
// *********************************
public static SimpleCommandMap getCommandMap() {
return commandMap;
}
}