调整:TLocale$logger 现在可以发送多行文本了 调整:TLocale 发送不存在的信息,错误提示由红色改为灰色,用于区分发送错误的提示颜色。 调整:TLocaleLoader 中的 getCallerPlugin 方法转移到 Ref 中 修复:BaseMainCommand 接口中 getType 方法失效的问题 修复:Main 中的语言提示无法更改的问题 新增:TPlugin 命令现在可以补全插件名了 新增:config.yml 现在会自动重载了(部分配置还需重启)
152 lines
5.4 KiB
Java
152 lines
5.4 KiB
Java
package com.ilummc.tlib.util;
|
|
|
|
import com.google.gson.annotations.SerializedName;
|
|
import com.ilummc.tlib.TLib;
|
|
import com.ilummc.tlib.resources.TLocale;
|
|
import com.ilummc.tlib.util.asm.AsmAnalyser;
|
|
import me.skymc.taboolib.Main;
|
|
import org.bukkit.plugin.java.JavaPlugin;
|
|
import org.objectweb.asm.ClassReader;
|
|
import org.objectweb.asm.ClassWriter;
|
|
import sun.reflect.Reflection;
|
|
|
|
import javax.annotation.concurrent.ThreadSafe;
|
|
import java.lang.reflect.Field;
|
|
import java.util.*;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import java.util.stream.Collectors;
|
|
|
|
@ThreadSafe
|
|
public class Ref {
|
|
|
|
private static final Map<String, List<Field>> cachedFields = new ConcurrentHashMap<>();
|
|
|
|
public static final int ACC_BRIDGE = 0x0040;
|
|
public static final int ACC_SYNTHETIC = 0x1000;
|
|
|
|
public static List<Field> getDeclaredFields(Class<?> clazz) {
|
|
return getDeclaredFields(clazz, 0, true);
|
|
}
|
|
|
|
public static List<Field> getDeclaredFields(String clazz, int excludeModifiers, boolean cache) {
|
|
try {
|
|
return getDeclaredFields(Class.forName(clazz), excludeModifiers, cache);
|
|
} catch (ClassNotFoundException e) {
|
|
return Collections.emptyList();
|
|
}
|
|
}
|
|
|
|
public static List<Field> getDeclaredFields(Class<?> clazz, int excludeModifiers, boolean cache) {
|
|
try {
|
|
|
|
// 特殊判断
|
|
if (clazz == TLib.class) {
|
|
return Arrays.asList(clazz.getDeclaredFields());
|
|
}
|
|
|
|
List<Field> fields;
|
|
if ((fields = cachedFields.get(clazz.getName())) != null) {
|
|
return fields;
|
|
}
|
|
ClassReader classReader = new ClassReader(clazz.getResourceAsStream("/" + clazz.getName().replace('.', '/') + ".class"));
|
|
AsmAnalyser analyser = new AsmAnalyser(new ClassWriter(ClassWriter.COMPUTE_MAXS), excludeModifiers);
|
|
classReader.accept(analyser, ClassReader.SKIP_DEBUG);
|
|
fields = analyser.getFields().stream().map(name -> {
|
|
try {
|
|
return clazz.getDeclaredField(name);
|
|
} catch (Throwable ignored) {
|
|
return null;
|
|
}
|
|
}).filter(Objects::nonNull).collect(Collectors.toList());
|
|
if (cache) {
|
|
cachedFields.putIfAbsent(clazz.getName(), fields);
|
|
}
|
|
return fields;
|
|
} catch (Exception | Error e) {
|
|
try {
|
|
List<Field> list = Arrays.stream(clazz.getDeclaredFields())
|
|
.filter(field -> (field.getModifiers() & excludeModifiers) == 0).collect(Collectors.toList());
|
|
cachedFields.putIfAbsent(clazz.getName(), list);
|
|
return list;
|
|
} catch (Error err) {
|
|
return Collections.emptyList();
|
|
}
|
|
}
|
|
}
|
|
|
|
public static Optional<Class<?>> getCallerClass(int depth) {
|
|
return Optional.ofNullable(CallerClass.impl.getCallerClass(depth + 1));
|
|
}
|
|
|
|
public static Class<?> getCallerClassNotOptional(int depth) {
|
|
return CallerClass.impl.getCallerClass(depth);
|
|
}
|
|
|
|
public static String getSerializedName(Field field) {
|
|
return field.isAnnotationPresent(SerializedName.class) ? field.getAnnotation(SerializedName.class).value() : field.getName();
|
|
}
|
|
|
|
public static Optional<Field> getFieldBySerializedName(Class<?> clazz, String name) {
|
|
for (Field field : Ref.getDeclaredFields(clazz, 0, false)) {
|
|
if (field.isAnnotationPresent(SerializedName.class)) {
|
|
if (field.getAnnotation(SerializedName.class).value().equals(name)) {
|
|
return Optional.of(field);
|
|
} else if (field.getName().equals(name)) {
|
|
return Optional.of(field);
|
|
}
|
|
}
|
|
}
|
|
return Optional.empty();
|
|
}
|
|
|
|
public static JavaPlugin getCallerPlugin(Class<?> callerClass) {
|
|
try {
|
|
Field pluginField = callerClass.getClassLoader().getClass().getDeclaredField("plugin");
|
|
pluginField.setAccessible(true);
|
|
return (JavaPlugin) pluginField.get(callerClass.getClassLoader());
|
|
} catch (Exception ignored) {
|
|
TLocale.Logger.error("LOCALE.CALLER-PLUGIN-NOT-FOUND", callerClass.getName());
|
|
}
|
|
return (JavaPlugin) Main.getInst();
|
|
}
|
|
|
|
private static abstract class CallerClass {
|
|
|
|
private static CallerClass impl;
|
|
|
|
static {
|
|
try {
|
|
Class.forName("sun.reflect.Reflection");
|
|
impl = new ReflectionImpl();
|
|
} catch (ClassNotFoundException e) {
|
|
impl = new StackTraceImpl();
|
|
}
|
|
}
|
|
|
|
abstract Class<?> getCallerClass(int i);
|
|
|
|
private static class ReflectionImpl extends CallerClass {
|
|
|
|
@SuppressWarnings({"deprecation", "restriction"})
|
|
@Override
|
|
Class<?> getCallerClass(int i) {
|
|
return Reflection.getCallerClass(i);
|
|
}
|
|
}
|
|
|
|
private static class StackTraceImpl extends CallerClass {
|
|
|
|
@Override
|
|
Class<?> getCallerClass(int i) {
|
|
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
|
|
try {
|
|
return Class.forName(elements[i].getClassName());
|
|
} catch (ClassNotFoundException e) {
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|