mirror of
https://e.coding.net/circlecloud/YumCore.git
synced 2024-12-25 07:08:52 +00:00
feat: 兼容新的刷怪蛋 调整一些小问题
Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
parent
558157da8a
commit
857a903336
@ -1,184 +1,185 @@
|
||||
package pw.yumc.YumCore.bukkit;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.Arrays;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
/**
|
||||
* 插件Instance获取类
|
||||
*
|
||||
* @author 喵♂呜
|
||||
* @since 2016年7月23日 上午9:09:57
|
||||
*/
|
||||
public class P {
|
||||
/**
|
||||
* 插件实例
|
||||
*/
|
||||
public static JavaPlugin instance;
|
||||
/**
|
||||
* 插件配置方法
|
||||
*/
|
||||
public static Method getInjectConfigMethod;
|
||||
|
||||
static {
|
||||
Object pluginClassLoader = P.class.getClassLoader();
|
||||
try {
|
||||
Field field = pluginClassLoader.getClass().getDeclaredField("plugin");
|
||||
field.setAccessible(true);
|
||||
instance = (JavaPlugin) field.get(pluginClassLoader);
|
||||
try {
|
||||
getInjectConfigMethod = instance.getClass().getMethod("get" + instance.getName() + "Config");
|
||||
} catch (NoSuchMethodException e) {
|
||||
Log.d("配置方法 get%sConfig 未找到 将返回getConfig 调用结果!", instance.getName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d("P 类初始化失败 %s:%s", e.getClass().getName(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* 命令名称
|
||||
* @return 插件命令
|
||||
*/
|
||||
public static PluginCommand getCommand(String name) {
|
||||
return instance.getCommand(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <FC>
|
||||
* 配置源类型
|
||||
* @return 获得插件配置文件
|
||||
*/
|
||||
public static <FC> FC getConfig() {
|
||||
return (FC) instance.getConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <FC>
|
||||
* 注入配置源类型
|
||||
* @return 获得插件注入配置
|
||||
*/
|
||||
public static <FC> FC getInjectConfig() {
|
||||
try {
|
||||
return (FC) getInjectConfigMethod.invoke(instance);
|
||||
} catch (IllegalAccessException | InvocationTargetException ignored) {
|
||||
}
|
||||
return getConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 获得插件文件夹
|
||||
*/
|
||||
public static File getDataFolder() {
|
||||
return instance.getDataFolder();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 获得插件描述文件
|
||||
*/
|
||||
public static PluginDescriptionFile getDescription() {
|
||||
return instance.getDescription();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 获得插件日志器
|
||||
*/
|
||||
public static Logger getLogger() {
|
||||
return instance.getLogger();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 插件名称
|
||||
*/
|
||||
public static String getName() {
|
||||
return instance.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <PI>
|
||||
* 插件源类型
|
||||
* @return 获得插件
|
||||
*/
|
||||
public static <PI> PI getPlugin() {
|
||||
return (PI) instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 插件是否已启用
|
||||
*/
|
||||
public static boolean isEnabled() {
|
||||
return instance.isEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量注册监听器
|
||||
*
|
||||
* @param listeners
|
||||
* 监听器
|
||||
*/
|
||||
public static void registerEvents(Listener... listeners) {
|
||||
Arrays.stream(listeners).forEach(listener -> Bukkit.getPluginManager().registerEvents(listener, instance));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存文件
|
||||
*
|
||||
* @param dirs
|
||||
* 目录
|
||||
*/
|
||||
public static void saveFile(final String... dirs) {
|
||||
saveFile(false, dirs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存文件
|
||||
*
|
||||
* @param replace
|
||||
* 是否替换
|
||||
* @param dirs
|
||||
* 目录
|
||||
*/
|
||||
public static void saveFile(boolean replace, final String... dirs) {
|
||||
URL url = instance.getClass().getClassLoader().getResource("plugin.yml");
|
||||
if (url == null) { return; }
|
||||
String upath = url.getFile().substring(url.getFile().indexOf("/") + 1);
|
||||
String jarPath = URLDecoder.decode(upath.substring(0, upath.indexOf('!')));
|
||||
if (!new File(jarPath).exists()) {
|
||||
jarPath = "/" + jarPath;
|
||||
}
|
||||
try (JarFile jar = new JarFile(jarPath)) {
|
||||
jar.stream().forEach(je -> {
|
||||
if (!je.isDirectory()) {
|
||||
for (final String dir : dirs) {
|
||||
if (je.getName().startsWith(dir)) {
|
||||
if (!replace) {
|
||||
// 不替换 并且文件不存在
|
||||
if (!new File(getDataFolder(), je.getName()).exists()) {
|
||||
instance.saveResource(je.getName(), false);
|
||||
}
|
||||
} else {
|
||||
instance.saveResource(je.getName(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
Log.d(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
package pw.yumc.YumCore.bukkit;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.Arrays;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
/**
|
||||
* 插件Instance获取类
|
||||
*
|
||||
* @author 喵♂呜
|
||||
* @since 2016年7月23日 上午9:09:57
|
||||
*/
|
||||
public class P {
|
||||
/**
|
||||
* 插件实例
|
||||
*/
|
||||
public static JavaPlugin instance;
|
||||
/**
|
||||
* 插件配置方法
|
||||
*/
|
||||
public static Method getInjectConfigMethod;
|
||||
|
||||
static {
|
||||
Object pluginClassLoader = P.class.getClassLoader();
|
||||
try {
|
||||
Field field = pluginClassLoader.getClass().getDeclaredField("plugin");
|
||||
field.setAccessible(true);
|
||||
instance = (JavaPlugin) field.get(pluginClassLoader);
|
||||
try {
|
||||
getInjectConfigMethod = instance.getClass().getMethod("get" + instance.getName() + "Config");
|
||||
} catch (NoSuchMethodException e) {
|
||||
Log.d("配置方法 get%sConfig 未找到 将返回getConfig 调用结果!", instance.getName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d("P 类初始化失败 %s:%s", e.getClass().getName(), e.getMessage());
|
||||
Log.d(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* 命令名称
|
||||
* @return 插件命令
|
||||
*/
|
||||
public static PluginCommand getCommand(String name) {
|
||||
return instance.getCommand(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <FC>
|
||||
* 配置源类型
|
||||
* @return 获得插件配置文件
|
||||
*/
|
||||
public static <FC> FC getConfig() {
|
||||
return (FC) instance.getConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <FC>
|
||||
* 注入配置源类型
|
||||
* @return 获得插件注入配置
|
||||
*/
|
||||
public static <FC> FC getInjectConfig() {
|
||||
try {
|
||||
return (FC) getInjectConfigMethod.invoke(instance);
|
||||
} catch (IllegalAccessException | InvocationTargetException ignored) {
|
||||
}
|
||||
return getConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 获得插件文件夹
|
||||
*/
|
||||
public static File getDataFolder() {
|
||||
return instance.getDataFolder();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 获得插件描述文件
|
||||
*/
|
||||
public static PluginDescriptionFile getDescription() {
|
||||
return instance.getDescription();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 获得插件日志器
|
||||
*/
|
||||
public static Logger getLogger() {
|
||||
return instance.getLogger();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 插件名称
|
||||
*/
|
||||
public static String getName() {
|
||||
return instance.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <PI>
|
||||
* 插件源类型
|
||||
* @return 获得插件
|
||||
*/
|
||||
public static <PI> PI getPlugin() {
|
||||
return (PI) instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 插件是否已启用
|
||||
*/
|
||||
public static boolean isEnabled() {
|
||||
return instance.isEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量注册监听器
|
||||
*
|
||||
* @param listeners
|
||||
* 监听器
|
||||
*/
|
||||
public static void registerEvents(Listener... listeners) {
|
||||
Arrays.stream(listeners).forEach(listener -> Bukkit.getPluginManager().registerEvents(listener, instance));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存文件
|
||||
*
|
||||
* @param dirs
|
||||
* 目录
|
||||
*/
|
||||
public static void saveFile(final String... dirs) {
|
||||
saveFile(false, dirs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存文件
|
||||
*
|
||||
* @param replace
|
||||
* 是否替换
|
||||
* @param dirs
|
||||
* 目录
|
||||
*/
|
||||
public static void saveFile(boolean replace, final String... dirs) {
|
||||
URL url = instance.getClass().getClassLoader().getResource("plugin.yml");
|
||||
if (url == null) { return; }
|
||||
String upath = url.getFile().substring(url.getFile().indexOf("/") + 1);
|
||||
String jarPath = URLDecoder.decode(upath.substring(0, upath.indexOf('!')));
|
||||
if (!new File(jarPath).exists()) {
|
||||
jarPath = "/" + jarPath;
|
||||
}
|
||||
try (JarFile jar = new JarFile(jarPath)) {
|
||||
jar.stream().forEach(je -> {
|
||||
if (!je.isDirectory()) {
|
||||
for (final String dir : dirs) {
|
||||
if (je.getName().startsWith(dir)) {
|
||||
if (!replace) {
|
||||
// 不替换 并且文件不存在
|
||||
if (!new File(getDataFolder(), je.getName()).exists()) {
|
||||
instance.saveResource(je.getName(), false);
|
||||
}
|
||||
} else {
|
||||
instance.saveResource(je.getName(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
Log.d(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,265 +1,274 @@
|
||||
package pw.yumc.YumCore.commands;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import pw.yumc.YumCore.bukkit.Log;
|
||||
import pw.yumc.YumCore.commands.annotation.Option;
|
||||
import pw.yumc.YumCore.commands.exception.ParseException;
|
||||
|
||||
/**
|
||||
* 命令参数解析
|
||||
*
|
||||
* @author 喵♂呜
|
||||
* @since 2016年10月5日 下午4:02:04
|
||||
*/
|
||||
public class CommandParse {
|
||||
private static Map<Class, Class> allparses = new HashMap<>();
|
||||
private static Map<String, Class> primitiveMap = new HashMap<>();
|
||||
private boolean isMain;
|
||||
private List<Parse> parses = new LinkedList<>();
|
||||
|
||||
static {
|
||||
register(File.class, FileParse.class);
|
||||
register(Player.class, PlayerParse.class);
|
||||
register(String.class, StringParse.class);
|
||||
primitiveMap.put("boolean", Boolean.class);
|
||||
primitiveMap.put("byte", Byte.class);
|
||||
primitiveMap.put("char", Character.class);
|
||||
primitiveMap.put("short", Short.class);
|
||||
primitiveMap.put("int", Integer.class);
|
||||
primitiveMap.put("long", Long.class);
|
||||
primitiveMap.put("float", Float.class);
|
||||
primitiveMap.put("double", Double.class);
|
||||
}
|
||||
|
||||
public CommandParse(Class[] classes, Annotation[][] annons, boolean isMain) {
|
||||
this.isMain = isMain;
|
||||
// 第一个参数实现了CommandSender忽略
|
||||
for (int i = 1; i < classes.length; i++) {
|
||||
Class clazz = classes[i];
|
||||
if (clazz.isPrimitive()) {
|
||||
// boolean, byte, char, short, int, long, float, and double.
|
||||
clazz = primitiveMap.get(clazz.getName());
|
||||
}
|
||||
Annotation[] annotations = annons[i];
|
||||
Parse parse = null;
|
||||
if (allparses.containsKey(clazz)) {
|
||||
try {
|
||||
parse = (Parse) allparses.get(clazz).newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException | NullPointerException ignored) {
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
parse = new ValueOfParse(clazz, clazz.getDeclaredMethod("valueOf", String.class));
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
}
|
||||
}
|
||||
if (parse == null) { throw new ParseException(String.format("存在无法解析的参数类型 %s", clazz.getName())); }
|
||||
this.parses.add(parse.parseAnnotation(annotations).handleAttrs());
|
||||
}
|
||||
Log.d("命令解析器 %s", Log.getSimpleNames(parses.toArray()));
|
||||
}
|
||||
|
||||
public static CommandParse get(Method method) {
|
||||
return new CommandParse(method.getParameterTypes(), method.getParameterAnnotations(), method.getReturnType().equals(boolean.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 转化数组为字符串
|
||||
*
|
||||
* @param arr
|
||||
* 数组
|
||||
* @param split
|
||||
* 分割符
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String join(Object[] arr, String split) {
|
||||
StringBuilder str = new StringBuilder();
|
||||
for (Object s : arr) {
|
||||
str.append(s.toString());
|
||||
str.append(split);
|
||||
}
|
||||
return str.length() > split.length() ? str.toString().substring(0, str.length() - split.length()) : str.toString();
|
||||
}
|
||||
|
||||
public static void register(Class clazz, Class parse) {
|
||||
allparses.put(clazz, parse);
|
||||
}
|
||||
|
||||
public Object[] parse(CommandSender sender, String label, String[] args) {
|
||||
List<Object> pobjs = new LinkedList<>();
|
||||
pobjs.add(sender);
|
||||
for (int i = 0; i < parses.size(); i++) {
|
||||
try {
|
||||
Parse p = parses.get(i);
|
||||
String param = i < args.length ? args[i] : p.getDefault();
|
||||
// 参数大于解析器 并且为最后一个参数
|
||||
if (i + 1 == parses.size() && args.length >= parses.size()) {
|
||||
param = join(Arrays.copyOfRange(args, i, args.length), " ");
|
||||
}
|
||||
pobjs.add(param == null ? null : p.parse(sender, param));
|
||||
} catch (Exception e) {
|
||||
Log.fd(e);
|
||||
throw new ParseException(String.format("第 %s 个参数 %s", isMain ? 1 : 2 + i, e.getMessage()));
|
||||
}
|
||||
}
|
||||
Log.d("解析参数: %s => %s", Arrays.toString(args), Log.getSimpleNames(pobjs.toArray()));
|
||||
return pobjs.toArray();
|
||||
}
|
||||
|
||||
public static abstract class Parse<RT> {
|
||||
protected Map<String, String> attrs = new HashMap<>();
|
||||
protected String def;
|
||||
protected int max = Integer.MAX_VALUE;
|
||||
protected int min = 0;
|
||||
|
||||
public String getDefault() {
|
||||
return def;
|
||||
}
|
||||
|
||||
public abstract RT parse(CommandSender sender, String arg) throws ParseException;
|
||||
|
||||
public Parse<RT> parseAnnotation(Annotation[] annotations) {
|
||||
for (Annotation annotation : annotations) {
|
||||
if (annotation.annotationType() == Option.class) {
|
||||
String value = ((Option) annotation).value();
|
||||
for (String str : value.split(" ")) {
|
||||
if (str.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (str.contains(":")) {
|
||||
String[] args = str.split(":");
|
||||
attrs.put(args[0], args[1]);
|
||||
} else {
|
||||
attrs.put(str, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Parse<RT> handleAttrs() {
|
||||
if (attrs.containsKey("def")) {
|
||||
def = String.valueOf(attrs.get("def"));
|
||||
}
|
||||
if (attrs.containsKey("min")) {
|
||||
min = Integer.parseInt(String.valueOf(attrs.get("min")));
|
||||
}
|
||||
if (attrs.containsKey("max")) {
|
||||
max = Integer.parseInt(String.valueOf(attrs.get("max")));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> T throwException(String str, Object... objects) {
|
||||
throw new ParseException(String.format(str, objects));
|
||||
}
|
||||
|
||||
public void throwRange() {
|
||||
throwRange("");
|
||||
}
|
||||
|
||||
public <T> T throwRange(String str) {
|
||||
return throwException(str.isEmpty() ? "范围必须在 %s 到 %s 之间!" : str, min, max);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ValueOfParse extends Parse<Object> {
|
||||
private Class etype;
|
||||
private Enum[] elist;
|
||||
private Method method;
|
||||
private Method checker;
|
||||
|
||||
public ValueOfParse(Class etype, Method method) {
|
||||
this.etype = etype;
|
||||
try {
|
||||
checker = etype.getDeclaredMethod("doubleValue");
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
}
|
||||
this.method = method;
|
||||
if (etype.isEnum()) {
|
||||
this.elist = ((Class<Enum>) etype).getEnumConstants();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parse(CommandSender sender, String arg) {
|
||||
try {
|
||||
Object result = method.invoke(null, arg);
|
||||
if (checker != null) {
|
||||
double num = (double) checker.invoke(result);
|
||||
if (min > num || num > max) {
|
||||
throwRange();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} catch (IllegalArgumentException | InvocationTargetException | IllegalAccessException ex) {
|
||||
if (etype.isEnum() && elist.length < 21) {
|
||||
return throwException("%s 不是 %s 有效值为 %s", arg, etype.getSimpleName(), Arrays.toString(elist));
|
||||
} else {
|
||||
return throwException("%s 不是一个有效的 %s", arg, etype.getSimpleName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class FileParse extends Parse<File> {
|
||||
@Override
|
||||
public File parse(CommandSender sender, String arg) throws ParseException {
|
||||
File file = new File(arg);
|
||||
if (attrs.containsKey("check") && !file.exists()) { throw new ParseException("文件 " + arg + " 不存在!"); }
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PlayerParse extends Parse<Player> {
|
||||
boolean check = false;
|
||||
|
||||
@Override
|
||||
public Player parse(CommandSender sender, String arg) {
|
||||
Player p = Bukkit.getPlayerExact(arg);
|
||||
if (check && p == null) { return throwException("玩家 %s 不存在或不在线!", arg); }
|
||||
return p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parse<Player> handleAttrs() {
|
||||
super.handleAttrs();
|
||||
check = attrs.containsKey("check");
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public static class StringParse extends Parse<String> {
|
||||
List<String> options;
|
||||
|
||||
@Override
|
||||
public String parse(CommandSender sender, String arg) {
|
||||
if (min > arg.length() || arg.length() > max) { return throwRange("长度必须在 %s 和 %s 之间!"); }
|
||||
if (options != null && !options.contains(arg)) { return throwException("参数 %s 不是一个有效的选项 有效值为 %s", arg, options); }
|
||||
return arg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parse<String> handleAttrs() {
|
||||
super.handleAttrs();
|
||||
if (attrs.containsKey("option")) {
|
||||
options = Arrays.asList(attrs.get("option").split(","));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
package pw.yumc.YumCore.commands;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import pw.yumc.YumCore.bukkit.Log;
|
||||
import pw.yumc.YumCore.commands.annotation.Option;
|
||||
import pw.yumc.YumCore.commands.exception.ParseException;
|
||||
|
||||
/**
|
||||
* 命令参数解析
|
||||
*
|
||||
* @author 喵♂呜
|
||||
* @since 2016年10月5日 下午4:02:04
|
||||
*/
|
||||
public class CommandParse {
|
||||
private static Map<Class, Class> allparses = new HashMap<>();
|
||||
private static Map<String, Class> primitiveMap = new HashMap<>();
|
||||
private boolean isMain;
|
||||
private List<Parse> parses = new LinkedList<>();
|
||||
|
||||
static {
|
||||
register(File.class, FileParse.class);
|
||||
register(Player.class, PlayerParse.class);
|
||||
register(String.class, StringParse.class);
|
||||
primitiveMap.put("boolean", Boolean.class);
|
||||
primitiveMap.put("byte", Byte.class);
|
||||
primitiveMap.put("char", Character.class);
|
||||
primitiveMap.put("short", Short.class);
|
||||
primitiveMap.put("int", Integer.class);
|
||||
primitiveMap.put("long", Long.class);
|
||||
primitiveMap.put("float", Float.class);
|
||||
primitiveMap.put("double", Double.class);
|
||||
}
|
||||
|
||||
public CommandParse(Class[] classes, Annotation[][] annons, boolean isMain) {
|
||||
this.isMain = isMain;
|
||||
// 第一个参数实现了CommandSender忽略
|
||||
for (int i = 1; i < classes.length; i++) {
|
||||
Class clazz = classes[i];
|
||||
if (clazz.isPrimitive()) {
|
||||
// boolean, byte, char, short, int, long, float, and double.
|
||||
clazz = primitiveMap.get(clazz.getName());
|
||||
}
|
||||
Annotation[] annotations = annons[i];
|
||||
Parse parse = null;
|
||||
if (allparses.containsKey(clazz)) {
|
||||
try {
|
||||
parse = (Parse) allparses.get(clazz).newInstance();
|
||||
} catch (InstantiationException | IllegalAccessException | NullPointerException ignored) {
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
parse = new ValueOfParse(clazz, clazz.getDeclaredMethod("valueOf", String.class));
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
}
|
||||
}
|
||||
if (parse == null) { throw new ParseException(String.format("存在无法解析的参数类型 %s", clazz.getName())); }
|
||||
this.parses.add(parse.parseAnnotation(annotations).handleAttrs());
|
||||
}
|
||||
Log.d("命令解析器 %s", Log.getSimpleNames(parses.toArray()));
|
||||
}
|
||||
|
||||
public static CommandParse get(Method method) {
|
||||
return new CommandParse(method.getParameterTypes(), method.getParameterAnnotations(), method.getReturnType().equals(boolean.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 转化数组为字符串
|
||||
*
|
||||
* @param arr
|
||||
* 数组
|
||||
* @param split
|
||||
* 分割符
|
||||
* @return 字符串
|
||||
*/
|
||||
public static String join(Object[] arr, String split) {
|
||||
StringBuilder str = new StringBuilder();
|
||||
for (Object s : arr) {
|
||||
str.append(s.toString());
|
||||
str.append(split);
|
||||
}
|
||||
return str.length() > split.length() ? str.toString().substring(0, str.length() - split.length()) : str.toString();
|
||||
}
|
||||
|
||||
public static void register(Class clazz, Class parse) {
|
||||
allparses.put(clazz, parse);
|
||||
}
|
||||
|
||||
public Object[] parse(CommandSender sender, String label, String[] args) {
|
||||
List<Object> pobjs = new LinkedList<>();
|
||||
pobjs.add(sender);
|
||||
for (int i = 0; i < parses.size(); i++) {
|
||||
try {
|
||||
Parse p = parses.get(i);
|
||||
String param = i < args.length ? args[i] : null;
|
||||
param = param == null ? p.getDefault(sender) : param;
|
||||
// 参数大于解析器 并且为最后一个参数
|
||||
if (i + 1 == parses.size() && args.length >= parses.size()) {
|
||||
param = join(Arrays.copyOfRange(args, i, args.length), " ");
|
||||
}
|
||||
// 尝试让解析器解析Null参数
|
||||
try { pobjs.add(p.parse(sender, param)); } catch (NullPointerException npe) { pobjs.add(null); }
|
||||
} catch (Exception e) {
|
||||
Log.fd(e);
|
||||
throw new ParseException(String.format("第 %s 个参数 %s", isMain ? 1 : 2 + i, e.getMessage()));
|
||||
}
|
||||
}
|
||||
Log.d("解析参数: %s => %s", Arrays.toString(args), Log.getSimpleNames(pobjs.toArray()));
|
||||
return pobjs.toArray();
|
||||
}
|
||||
|
||||
public static abstract class Parse<RT> {
|
||||
protected Map<String, String> attrs = new HashMap<>();
|
||||
protected String def;
|
||||
protected int max = Integer.MAX_VALUE;
|
||||
protected int min = 0;
|
||||
|
||||
public String getDefault(CommandSender sender) {
|
||||
return def;
|
||||
}
|
||||
|
||||
public abstract RT parse(CommandSender sender, String arg) throws ParseException;
|
||||
|
||||
public Parse<RT> parseAnnotation(Annotation[] annotations) {
|
||||
for (Annotation annotation : annotations) {
|
||||
if (annotation.annotationType() == Option.class) {
|
||||
String value = ((Option) annotation).value();
|
||||
for (String str : value.split(" ")) {
|
||||
if (str.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (str.contains(":")) {
|
||||
String[] args = str.split(":");
|
||||
attrs.put(args[0], args[1]);
|
||||
} else {
|
||||
attrs.put(str, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Parse<RT> handleAttrs() {
|
||||
if (attrs.containsKey("def")) {
|
||||
def = String.valueOf(attrs.get("def"));
|
||||
}
|
||||
if (attrs.containsKey("min")) {
|
||||
min = Integer.parseInt(String.valueOf(attrs.get("min")));
|
||||
}
|
||||
if (attrs.containsKey("max")) {
|
||||
max = Integer.parseInt(String.valueOf(attrs.get("max")));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> T throwException(String str, Object... objects) {
|
||||
throw new ParseException(String.format(str, objects));
|
||||
}
|
||||
|
||||
public void throwRange() {
|
||||
throwRange("");
|
||||
}
|
||||
|
||||
public <T> T throwRange(String str) {
|
||||
return throwException(str.isEmpty() ? "范围必须在 %s 到 %s 之间!" : str, min, max);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ValueOfParse extends Parse<Object> {
|
||||
private Class eType;
|
||||
private Enum[] eList;
|
||||
private Method method;
|
||||
private Method checker;
|
||||
|
||||
public ValueOfParse(Class eType, Method method) {
|
||||
this.eType = eType;
|
||||
try {
|
||||
checker = eType.getDeclaredMethod("doubleValue");
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
}
|
||||
this.method = method;
|
||||
if (eType.isEnum()) {
|
||||
this.eList = ((Class<Enum>) eType).getEnumConstants();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object parse(CommandSender sender, String arg) {
|
||||
try {
|
||||
Object result = method.invoke(null, arg);
|
||||
if (checker != null) {
|
||||
double num = (double) checker.invoke(result);
|
||||
if (min > num || num > max) {
|
||||
throwRange();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} catch (IllegalArgumentException | InvocationTargetException | IllegalAccessException ex) {
|
||||
if (eType.isEnum() && eList.length < 21) {
|
||||
return throwException("%s 不是 %s 有效值为 %s", arg, eType.getSimpleName(), Arrays.toString(eList));
|
||||
} else {
|
||||
return throwException("%s 不是一个有效的 %s", arg, eType.getSimpleName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class FileParse extends Parse<File> {
|
||||
@Override
|
||||
public File parse(CommandSender sender, String arg) throws ParseException {
|
||||
File file = new File(arg);
|
||||
if (attrs.containsKey("check") && !file.exists()) { throw new ParseException("文件 " + arg + " 不存在!"); }
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PlayerParse extends Parse<Player> {
|
||||
boolean sender = false;
|
||||
boolean check = false;
|
||||
|
||||
@Override
|
||||
public Player parse(CommandSender sender, String arg) {
|
||||
Player p = Bukkit.getPlayerExact(arg);
|
||||
if (this.check && p == null) { return throwException("玩家 %s 不存在或不在线!", arg); }
|
||||
return p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parse<Player> handleAttrs() {
|
||||
super.handleAttrs();
|
||||
sender = attrs.containsKey("sender");
|
||||
check = attrs.containsKey("check");
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefault(CommandSender sender) {
|
||||
return this.sender && sender instanceof Player ? sender.getName() : super.getDefault(sender);
|
||||
}
|
||||
}
|
||||
|
||||
public static class StringParse extends Parse<String> {
|
||||
List<String> options;
|
||||
|
||||
@Override
|
||||
public String parse(CommandSender sender, String arg) {
|
||||
if (min > arg.length() || arg.length() > max) { return throwRange("长度必须在 %s 和 %s 之间!"); }
|
||||
if (options != null && !options.contains(arg)) { return throwException("参数 %s 不是一个有效的选项 有效值为 %s", arg, options); }
|
||||
return arg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parse<String> handleAttrs() {
|
||||
super.handleAttrs();
|
||||
if (attrs.containsKey("option")) {
|
||||
options = Arrays.asList(attrs.get("option").split(","));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,6 +70,9 @@ public class CommandSub implements TabExecutor {
|
||||
*/
|
||||
private List<String> cmdNameCache = new ArrayList<>();
|
||||
|
||||
public CommandSub() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 命令管理器
|
||||
*
|
||||
@ -178,9 +181,9 @@ public class CommandSub implements TabExecutor {
|
||||
if (defCmd != null) { return defCmd.execute(sender, label, args); }
|
||||
return help.send(sender, label, args);
|
||||
}
|
||||
String subcmd = args[0].toLowerCase();
|
||||
if (subcmd.equalsIgnoreCase("help")) { return help.send(sender, label, args); }
|
||||
CommandInfo cmd = getByCache(subcmd);
|
||||
String subCmd = args[0].toLowerCase();
|
||||
if ("help".equalsIgnoreCase(subCmd)) { return help.send(sender, label, args); }
|
||||
CommandInfo cmd = getByCache(subCmd);
|
||||
String[] subargs = args;
|
||||
if (cmd.equals(CommandInfo.Unknow) && defCmd != null) {
|
||||
cmd = defCmd;
|
||||
@ -238,7 +241,7 @@ public class CommandSub implements TabExecutor {
|
||||
CommandInfo ci = CommandInfo.parse(method, clazz);
|
||||
if (ci != null) {
|
||||
Class[] params = method.getParameterTypes();
|
||||
Log.d("注册子命令: %s 参数类型: %s", ci.getName(), Log.getSimpleNames((Object[]) params));
|
||||
Log.d("注册子命令: %s 参数类型: %s", ci.getName(), Log.getSimpleNames(params));
|
||||
try {
|
||||
Class<? extends CommandSender> sender = params[0];
|
||||
// 用于消除unuse警告
|
||||
|
@ -1,137 +1,143 @@
|
||||
package pw.yumc.YumCore.global;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.material.SpawnEgg;
|
||||
|
||||
import pw.yumc.YumCore.bukkit.Log;
|
||||
import pw.yumc.YumCore.config.FileConfig;
|
||||
import pw.yumc.YumCore.config.ext.YumConfig;
|
||||
|
||||
/**
|
||||
* 本地化工具类
|
||||
*
|
||||
* @since 2015年12月14日 下午1:33:52
|
||||
* @author 喵♂呜
|
||||
*/
|
||||
public class L10N {
|
||||
private static String CONFIG_NAME = "Item_zh_CN.yml";
|
||||
private static FileConfig custom;
|
||||
private static Map<String, String> content;
|
||||
|
||||
static {
|
||||
content = new HashMap<>();
|
||||
Log.i("异步初始化本地化工具...");
|
||||
load();
|
||||
}
|
||||
|
||||
private L10N() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取物品完整汉化名称(包括原版)
|
||||
*
|
||||
* @param i
|
||||
* 物品实体
|
||||
* @return 物品名称
|
||||
*/
|
||||
public static String getFullName(ItemStack i) {
|
||||
return getItemName(getItemType(i)) + (i.hasItemMeta() && i.getItemMeta().hasDisplayName() ? "§r(" + i.getItemMeta().getDisplayName() + "§r)" : "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取物品汉化名称
|
||||
*
|
||||
* @param i
|
||||
* 物品实体
|
||||
* @return 物品名称
|
||||
*/
|
||||
public static String getItemName(ItemStack i) {
|
||||
return getItemName(getItemType(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取物品汉化名称(优先显示名称)
|
||||
*
|
||||
* @param i
|
||||
* 物品实体
|
||||
* @return 物品名称
|
||||
*/
|
||||
public static String getName(ItemStack i) {
|
||||
return i.hasItemMeta() && i.getItemMeta().hasDisplayName() ? i.getItemMeta().getDisplayName() : getItemName(getItemType(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* 重载LocalUtil
|
||||
*/
|
||||
public static void reload() {
|
||||
Log.i("异步重载本地化工具...");
|
||||
content.clear();
|
||||
load();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取物品汉化名称
|
||||
*
|
||||
* @param iname
|
||||
* 物品类型名称
|
||||
* @return 物品名称
|
||||
*/
|
||||
private static String getItemName(String iname) {
|
||||
String aname = content.get(iname);
|
||||
if (aname == null) {
|
||||
aname = iname;
|
||||
if (custom != null) {
|
||||
custom.set(iname, iname);
|
||||
custom.save();
|
||||
}
|
||||
}
|
||||
return aname;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取物品类型名称
|
||||
*
|
||||
* @param i
|
||||
* 物品实体
|
||||
* @return 物品类型
|
||||
*/
|
||||
private static String getItemType(ItemStack i) {
|
||||
String name = i.getType().name();
|
||||
String dura = "";
|
||||
if (i.getType() == Material.MONSTER_EGG) {
|
||||
name = ((SpawnEgg) i.getData()).getSpawnedType().name();
|
||||
} else {
|
||||
int dur = i.getDurability();
|
||||
dura = (i.getMaxStackSize() != 1 && dur != 0) ? Integer.toString(dur) : "";
|
||||
}
|
||||
return (name + (dura.isEmpty() ? "" : "-" + dura)).toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 载入数据
|
||||
*/
|
||||
private static void load() {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Map<String, String> local = YumConfig.getLocal(CONFIG_NAME).getContentMap();
|
||||
if (local != null) {
|
||||
Log.i("本地汉化文件词条数量: " + local.size());
|
||||
content.putAll(local);
|
||||
}
|
||||
Map<String, String> remote = YumConfig.getRemote(CONFIG_NAME).getContentMap();
|
||||
if (remote != null) {
|
||||
Log.i("远程汉化文件词条数量: " + remote.size());
|
||||
content.putAll(remote);
|
||||
}
|
||||
Log.i("本地化工具初始化完毕...");
|
||||
} catch (Exception e) {
|
||||
Log.w("本地化工具初始化失败: %s %s", e.getClass().getName(), e.getMessage());
|
||||
Log.d(CONFIG_NAME, e);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
package pw.yumc.YumCore.global;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.SpawnEggMeta;
|
||||
import org.bukkit.material.SpawnEgg;
|
||||
|
||||
import pw.yumc.YumCore.bukkit.Log;
|
||||
import pw.yumc.YumCore.config.FileConfig;
|
||||
import pw.yumc.YumCore.config.ext.YumConfig;
|
||||
|
||||
/**
|
||||
* 本地化工具类
|
||||
*
|
||||
* @author 喵♂呜
|
||||
* @since 2015年12月14日 下午1:33:52
|
||||
*/
|
||||
public class L10N {
|
||||
private static String CONFIG_NAME = "Item_zh_CN.yml";
|
||||
private static FileConfig custom;
|
||||
private static Map<String, String> content;
|
||||
|
||||
static {
|
||||
content = new HashMap<>();
|
||||
Log.i("异步初始化本地化工具...");
|
||||
load();
|
||||
}
|
||||
|
||||
private L10N() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取物品完整汉化名称(包括原版)
|
||||
*
|
||||
* @param i
|
||||
* 物品实体
|
||||
* @return 物品名称
|
||||
*/
|
||||
public static String getFullName(ItemStack i) {
|
||||
return getItemName(getItemType(i)) + (i.hasItemMeta() && i.getItemMeta().hasDisplayName() ? "§r(" + i.getItemMeta()
|
||||
.getDisplayName() + "§r)" : "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取物品汉化名称
|
||||
*
|
||||
* @param i
|
||||
* 物品实体
|
||||
* @return 物品名称
|
||||
*/
|
||||
public static String getItemName(ItemStack i) {
|
||||
return getItemName(getItemType(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取物品汉化名称(优先显示名称)
|
||||
*
|
||||
* @param i
|
||||
* 物品实体
|
||||
* @return 物品名称
|
||||
*/
|
||||
public static String getName(ItemStack i) {
|
||||
return i.hasItemMeta() && i.getItemMeta().hasDisplayName() ? i.getItemMeta().getDisplayName() : getItemName(getItemType(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* 重载LocalUtil
|
||||
*/
|
||||
public static void reload() {
|
||||
Log.i("异步重载本地化工具...");
|
||||
content.clear();
|
||||
load();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取物品汉化名称
|
||||
*
|
||||
* @param iname
|
||||
* 物品类型名称
|
||||
* @return 物品名称
|
||||
*/
|
||||
private static String getItemName(String iname) {
|
||||
String aname = content.get(iname);
|
||||
if (aname == null) {
|
||||
aname = iname;
|
||||
if (custom != null) {
|
||||
custom.set(iname, iname);
|
||||
custom.save();
|
||||
}
|
||||
}
|
||||
return aname;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取物品类型名称
|
||||
*
|
||||
* @param i
|
||||
* 物品实体
|
||||
* @return 物品类型
|
||||
*/
|
||||
private static String getItemType(ItemStack i) {
|
||||
String name = i.getType().name();
|
||||
String dura = "";
|
||||
if (i.getType() == Material.MONSTER_EGG) {
|
||||
try {
|
||||
name = ((SpawnEgg) i.getData()).getSpawnedType().name();
|
||||
} catch (NullPointerException npe) {
|
||||
name = ((SpawnEggMeta) i.getItemMeta()).getSpawnedType().name();
|
||||
}
|
||||
} else {
|
||||
int dur = i.getDurability();
|
||||
dura = (i.getMaxStackSize() != 1 && dur != 0) ? Integer.toString(dur) : "";
|
||||
}
|
||||
return (name + (dura.isEmpty() ? "" : "-" + dura)).toUpperCase();
|
||||
}
|
||||
|
||||
/**
|
||||
* 载入数据
|
||||
*/
|
||||
private static void load() {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Map<String, String> local = YumConfig.getLocal(CONFIG_NAME).getContentMap();
|
||||
if (local != null) {
|
||||
Log.i("本地汉化文件词条数量: " + local.size());
|
||||
content.putAll(local);
|
||||
}
|
||||
Map<String, String> remote = YumConfig.getRemote(CONFIG_NAME).getContentMap();
|
||||
if (remote != null) {
|
||||
Log.i("远程汉化文件词条数量: " + remote.size());
|
||||
content.putAll(remote);
|
||||
}
|
||||
Log.i("本地化工具初始化完毕...");
|
||||
} catch (Exception e) {
|
||||
Log.w("本地化工具初始化失败: %s %s", e.getClass().getName(), e.getMessage());
|
||||
Log.d(CONFIG_NAME, e);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user