AsmClassTransformer
This commit is contained in:
parent
250d168c2e
commit
da8890b30a
@ -2,6 +2,7 @@
|
||||
<dictionary name="csh20">
|
||||
<words>
|
||||
<w>autoload</w>
|
||||
<w>craftbukkit</w>
|
||||
<w>mvdw</w>
|
||||
<w>papi</w>
|
||||
<w>sendable</w>
|
||||
|
@ -66,6 +66,21 @@ public class TConfigInjector {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void reloadConfig(Plugin plugin, Object object) {
|
||||
try {
|
||||
Config config = object.getClass().getAnnotation(Config.class);
|
||||
Validate.notNull(config);
|
||||
File file = new File(plugin.getDataFolder(), config.name());
|
||||
Map<String, Object> map = ConfigUtils.confToMap(ConfigUtils.loadYaml(plugin, file));
|
||||
Object obj = ConfigUtils.mapToObj(map, object);
|
||||
if (!config.readOnly()) saveConfig(plugin, obj);
|
||||
} catch (NullPointerException e) {
|
||||
TLocale.Logger.warn("CONFIG.LOAD-FAIL-NO-ANNOTATION", plugin.toString(), object.getClass().getSimpleName());
|
||||
} catch (Exception e) {
|
||||
TLocale.Logger.warn("CONFIG.LOAD-FAIL", plugin.toString(), object.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
public static Object unserialize(Plugin plugin, Class<?> clazz) {
|
||||
try {
|
||||
Config config = clazz.getAnnotation(Config.class);
|
||||
|
@ -72,11 +72,7 @@ public class TDependencyInjector {
|
||||
obj,
|
||||
object -> {
|
||||
try {
|
||||
Object newObj = TConfigInjector.loadConfig(plugin, object.getClass());
|
||||
for (Field f : newObj.getClass().getDeclaredFields()) {
|
||||
f.setAccessible(true);
|
||||
f.set(obj, f.get(newObj));
|
||||
}
|
||||
TConfigInjector.reloadConfig(plugin, object);
|
||||
TLocale.Logger.info("CONFIG.RELOAD-SUCCESS", plugin.toString(), config.name());
|
||||
} catch (Exception ignored) {
|
||||
TLocale.Logger.warn("CONFIG.RELOAD-FAIL", plugin.toString(), config.name());
|
||||
|
50
src/main/java/com/ilummc/tlib/nms/ActionBar.java
Normal file
50
src/main/java/com/ilummc/tlib/nms/ActionBar.java
Normal file
@ -0,0 +1,50 @@
|
||||
package com.ilummc.tlib.nms;
|
||||
|
||||
import com.ilummc.tlib.util.asm.AsmClassTransformer;
|
||||
import me.skymc.taboolib.TabooLib;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public abstract class ActionBar {
|
||||
|
||||
private static ActionBar instance;
|
||||
|
||||
static {
|
||||
if (TabooLib.getVerint() > 11100) {
|
||||
instance = (ActionBar) AsmClassTransformer.builder().from(Impl_1_12.class).fromVersion("v1_12_R1")
|
||||
.toVersion(Bukkit.getServer().getClass().getName().split("\\.")[3]).build().transform();
|
||||
} else {
|
||||
instance = (ActionBar) AsmClassTransformer.builder().from(Impl_1_8.class).fromVersion("v1_8_R3")
|
||||
.toVersion(Bukkit.getServer().getClass().getName().split("\\.")[3]).build().transform();
|
||||
}
|
||||
System.out.println(instance.getClass());
|
||||
}
|
||||
|
||||
public static void sendActionBar(Player player, String text) {
|
||||
instance.send(player, text);
|
||||
}
|
||||
|
||||
public abstract void send(Player player, String text);
|
||||
|
||||
public static class Impl_1_8 extends ActionBar {
|
||||
|
||||
@Override
|
||||
public void send(Player player, String text) {
|
||||
net.minecraft.server.v1_8_R3.ChatComponentText component = new net.minecraft.server.v1_8_R3.ChatComponentText(text);
|
||||
net.minecraft.server.v1_8_R3.PacketPlayOutChat packet = new net.minecraft.server.v1_8_R3.PacketPlayOutChat(component, (byte) 2);
|
||||
((org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Impl_1_12 extends ActionBar {
|
||||
|
||||
@Override
|
||||
public void send(Player player, String text) {
|
||||
net.minecraft.server.v1_12_R1.ChatComponentText component = new net.minecraft.server.v1_12_R1.ChatComponentText(text);
|
||||
net.minecraft.server.v1_12_R1.PacketPlayOutChat packet = new net.minecraft.server.v1_12_R1.PacketPlayOutChat(component,
|
||||
net.minecraft.server.v1_12_R1.ChatMessageType.a((byte) 2));
|
||||
((org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer) player).getHandle().playerConnection.sendPacket(packet);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -72,6 +72,8 @@ public class TLocaleLoader {
|
||||
TLocaleInstance localeInstance = new TLocaleInstance(plugin);
|
||||
localeInstance.load(configuration);
|
||||
map.put(plugin.getName(), localeInstance);
|
||||
TLib.getTLib().getLogger().info(Strings.replaceWithOrder(TLib.getTLib().getInternalLang().getString("SUCCESS-LOADING-LANG"),
|
||||
plugin.getName(), lang, String.valueOf(localeInstance.size())));
|
||||
}
|
||||
File finalFile = file;
|
||||
String finalLang = lang;
|
||||
@ -84,7 +86,6 @@ public class TLocaleLoader {
|
||||
TLib.getTLib().getLogger().info(Strings.replaceWithOrder(TLib.getTLib().getInternalLang().getString("SUCCESS-LOADING-LANG"),
|
||||
plugin.getName(), finalLang, String.valueOf(localeInstance.size())));
|
||||
});
|
||||
TLib.getTLib().getLogger().info(Strings.replaceWithOrder(TLib.getTLib().getInternalLang().getString("SUCCESS-LOADING-LANG"), plugin.getName(), lang));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
TLib.getTLib().getLogger().error(Strings.replaceWithOrder(TLib.getTLib().getInternalLang().getString("ERROR-LOADING-LANG"),
|
||||
|
13
src/main/java/com/ilummc/tlib/util/asm/AsmClassLoader.java
Normal file
13
src/main/java/com/ilummc/tlib/util/asm/AsmClassLoader.java
Normal file
@ -0,0 +1,13 @@
|
||||
package com.ilummc.tlib.util.asm;
|
||||
|
||||
public class AsmClassLoader extends ClassLoader {
|
||||
|
||||
public AsmClassLoader() {
|
||||
super(AsmClassLoader.class.getClassLoader());
|
||||
}
|
||||
|
||||
public Class<?> createNewClass(String name, byte[] arr) {
|
||||
return defineClass(name, arr, 0, arr.length, AsmClassLoader.class.getProtectionDomain());
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,153 @@
|
||||
package com.ilummc.tlib.util.asm;
|
||||
|
||||
public class AsmClassTransformer {
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Map;
|
||||
|
||||
public class AsmClassTransformer extends ClassVisitor implements Opcodes {
|
||||
|
||||
private final Class<?> from;
|
||||
|
||||
private final String fromVer, toVer;
|
||||
|
||||
private final ClassWriter writer;
|
||||
|
||||
private String newClassName, prevName;
|
||||
|
||||
private AsmClassTransformer(Class<?> from, String fromVer, String toVer, ClassWriter classWriter) {
|
||||
super(Opcodes.ASM6, classWriter);
|
||||
writer = classWriter;
|
||||
this.from = from;
|
||||
this.fromVer = fromVer;
|
||||
this.toVer = toVer;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder().toVersion(Bukkit.getServer().getClass().getName().split("\\.")[3]);
|
||||
}
|
||||
|
||||
public Object transform() {
|
||||
try {
|
||||
ClassReader classReader = new ClassReader(from.getResourceAsStream("/" + from.getName().replace('.', '/') + ".class"));
|
||||
newClassName = from.getName() + "_TabooLibRemap_" + this.hashCode() + "_" + toVer;
|
||||
prevName = from.getName().replace('.', '/');
|
||||
classReader.accept(this, ClassReader.SKIP_DEBUG);
|
||||
Class<?> clazz = new AsmClassLoader().createNewClass(newClassName, writer.toByteArray());
|
||||
Field field = from.getClassLoader().getClass().getDeclaredField("classes");
|
||||
field.setAccessible(true);
|
||||
((Map<String, Class<?>>) field.get(from.getClassLoader())).put(newClassName, clazz);
|
||||
Constructor<?> constructor = clazz.getDeclaredConstructor();
|
||||
constructor.setAccessible(true);
|
||||
return constructor.newInstance();
|
||||
} catch (IOException | NoSuchFieldException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
super.visit(version, access, newClassName.replace('.', '/'), replace(signature),
|
||||
prevName, replace(interfaces));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
|
||||
MethodVisitor visitor = super.visitMethod(access, name, replace(descriptor), replace(signature), replace(exceptions));
|
||||
return new AsmMethodTransformer(visitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
|
||||
return super.visitField(access, name, replace(descriptor), replace(signature), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClass(String name, String outerName, String innerName, int access) {
|
||||
super.visitInnerClass(replace(name), outerName, replace(name).substring(outerName.length() + 1), access);
|
||||
}
|
||||
|
||||
private String replace(String text) {
|
||||
if (text != null)
|
||||
return text.replace("net/minecraft/server/" + fromVer, "net/minecraft/server/" + toVer)
|
||||
.replace("org/bukkit/craftbukkit/" + fromVer, "org/bukkit/craftbukkit/" + toVer)
|
||||
.replace(prevName, newClassName.replace('.', '/'));
|
||||
else return null;
|
||||
}
|
||||
|
||||
private String[] replace(String[] text) {
|
||||
if (text != null) {
|
||||
for (int i = 0; i < text.length; i++) {
|
||||
text[i] = replace(text[i]);
|
||||
}
|
||||
return text;
|
||||
} else return null;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
private Class<?> from;
|
||||
|
||||
private String fromVersion, toVersion;
|
||||
|
||||
public Builder from(Class<?> clazz) {
|
||||
this.from = clazz;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder fromVersion(String ver) {
|
||||
fromVersion = ver;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder toVersion(String ver) {
|
||||
toVersion = ver;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AsmClassTransformer build() {
|
||||
return new AsmClassTransformer(from, fromVersion, toVersion, new ClassWriter(ClassWriter.COMPUTE_MAXS));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class AsmMethodTransformer extends MethodVisitor {
|
||||
|
||||
AsmMethodTransformer(MethodVisitor visitor) {
|
||||
super(Opcodes.ASM6, visitor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
|
||||
super.visitMethodInsn(opcode, replace(owner), name, replace(descriptor), isInterface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLdcInsn(Object value) {
|
||||
if (value instanceof String)
|
||||
super.visitLdcInsn(replace((String) value));
|
||||
else super.visitLdcInsn(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeInsn(int opcode, String type) {
|
||||
super.visitTypeInsn(opcode, replace(type));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
|
||||
super.visitFieldInsn(opcode, replace(owner), name, replace(descriptor));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, int index) {
|
||||
super.visitLocalVariable(name, replace(descriptor), replace(signature), start, end, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,52 +1,20 @@
|
||||
package me.skymc.taboolib.display;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
import com.ilummc.tlib.nms.ActionBar;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import me.skymc.taboolib.TabooLib;
|
||||
import me.skymc.taboolib.nms.NMSUtils;
|
||||
|
||||
/**
|
||||
* @author Bkm016
|
||||
* @since 2018-04-26
|
||||
*/
|
||||
public class ActionUtils {
|
||||
|
||||
private static Class<?> Packet = NMSUtils.getNMSClass("Packet");
|
||||
private static Class<?> ChatComponentText = NMSUtils.getNMSClass("ChatComponentText");
|
||||
private static Class<?> ChatMessageType = NMSUtils.getNMSClass("ChatMessageType");
|
||||
private static Class<?> PacketPlayOutChat = NMSUtils.getNMSClass("PacketPlayOutChat");
|
||||
private static Class<?> IChatBaseComponent = NMSUtils.getNMSClass("IChatBaseComponent");
|
||||
|
||||
public static void send(Player player, String action) {
|
||||
if (player == null) {
|
||||
if (player == null)
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Object ab = ChatComponentText.getConstructor(String.class).newInstance(action);
|
||||
Constructor<?> ac = null;
|
||||
Object abPacket = null;
|
||||
if (TabooLib.getVerint() > 11100) {
|
||||
ac = PacketPlayOutChat.getConstructor(IChatBaseComponent, ChatMessageType);
|
||||
abPacket = ac.newInstance(ab, ChatMessageType.getMethod("a", Byte.TYPE).invoke(null, (byte) 2));
|
||||
} else {
|
||||
ac = PacketPlayOutChat.getConstructor(IChatBaseComponent, Byte.TYPE);
|
||||
abPacket = ac.newInstance(ab, (byte) 2);
|
||||
}
|
||||
sendPacket(player, abPacket);
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private static void sendPacket(Player player, Object packet) {
|
||||
try {
|
||||
Object handle = player.getClass().getMethod("getHandle", new Class[0]).invoke(player);
|
||||
Object playerConnection = handle.getClass().getField("playerConnection").get(handle);
|
||||
playerConnection.getClass().getMethod("sendPacket", Packet).invoke(playerConnection, packet);
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
ActionBar.sendActionBar(player, action);
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,9 @@
|
||||
package me.skymc.taboolib.display;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import me.skymc.taboolib.nms.NMSUtils;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import me.skymc.taboolib.nms.NMSUtils;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
/**
|
||||
* @author Bkm016
|
||||
@ -53,8 +51,7 @@ public class TitleUtils {
|
||||
subtitlePacket = subtitleConstructor.newInstance(times, chatSubtitle, fadeinst, stayst, fadeoutst);
|
||||
sendPacket(p, subtitlePacket);
|
||||
}
|
||||
}
|
||||
catch (Exception ignored) {
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@ package me.skymc.taboolib.fileutils;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.io.Files;
|
||||
import com.ilummc.tlib.TLib;
|
||||
import com.ilummc.tlib.bean.Property;
|
||||
import com.ilummc.tlib.util.Ref;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.MemoryConfiguration;
|
||||
@ -86,13 +87,20 @@ public class ConfigUtils {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T mapToObj(Map<String, Object> map, T obj) {
|
||||
Class<?> clazz = obj.getClass();
|
||||
map.forEach((string, value) -> Ref.getFieldBySerializedName(clazz, string).ifPresent(field -> {
|
||||
if (!field.isAccessible())
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
if (Property.class.isAssignableFrom(field.getType())) {
|
||||
Property<Object> property = (Property) field.get(obj);
|
||||
if (property != null) property.set(value);
|
||||
else field.set(obj, Property.of(value));
|
||||
} else {
|
||||
field.set(obj, value);
|
||||
}
|
||||
} catch (IllegalAccessException ignored) {
|
||||
}
|
||||
}));
|
||||
@ -108,7 +116,9 @@ public class ConfigUtils {
|
||||
for (Field field : Ref.getDeclaredFields(object.getClass(), excludedModifiers, false)) {
|
||||
try {
|
||||
if (!field.isAccessible()) field.setAccessible(true);
|
||||
map.put(Ref.getSerializedName(field), field.get(object));
|
||||
Object obj = field.get(object);
|
||||
if (obj instanceof Property) obj = ((Property) obj).get();
|
||||
map.put(Ref.getSerializedName(field), obj);
|
||||
} catch (IllegalAccessException ignored) {
|
||||
}
|
||||
}
|
||||
|
@ -1,22 +1,14 @@
|
||||
package me.skymc.taboolib.fileutils;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import ch.njol.util.Closeable;
|
||||
import me.skymc.taboolib.message.MsgUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
||||
import ch.njol.util.Closeable;
|
||||
import me.skymc.taboolib.message.MsgUtils;
|
||||
|
||||
public class FileUtils {
|
||||
|
||||
public static String ip() {
|
||||
@ -248,6 +240,11 @@ public class FileUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getStringFromURL(String url, String def) {
|
||||
String s = getStringFromURL(url, 1024);
|
||||
return s == null ? def : s;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载文件
|
||||
*
|
||||
|
@ -1,14 +1,12 @@
|
||||
package me.skymc.taboolib.update;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import me.skymc.taboolib.Main;
|
||||
import me.skymc.taboolib.TabooLib;
|
||||
import me.skymc.taboolib.fileutils.FileUtils;
|
||||
import me.skymc.taboolib.message.MsgUtils;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
/**
|
||||
* @author sky
|
||||
@ -16,6 +14,8 @@ import me.skymc.taboolib.message.MsgUtils;
|
||||
*/
|
||||
public class UpdateTask {
|
||||
|
||||
private static final String API = "https://api.github.com/repos/Bkm016/TabooLib/releases/latest";
|
||||
|
||||
/**
|
||||
* 检测更新
|
||||
*/
|
||||
@ -27,14 +27,10 @@ public class UpdateTask {
|
||||
if (!Main.getInst().getConfig().getBoolean("UPDATE-CHECK")) {
|
||||
return;
|
||||
}
|
||||
String value = FileUtils.getStringFromURL("https://github.com/Bkm016/TabooLib/releases", 1024);
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
Pattern pattern = Pattern.compile("<a href=\"/Bkm016/TabooLib/releases/tag/(\\S+)\">");
|
||||
Matcher matcher = pattern.matcher(value);
|
||||
if (matcher.find()) {
|
||||
double newVersion = Double.valueOf(matcher.group(1));
|
||||
String value = FileUtils.getStringFromURL(API, "{}");
|
||||
JsonObject json = new JsonParser().parse(value).getAsJsonObject();
|
||||
if (json.entrySet().size() > 0) {
|
||||
double newVersion = Double.parseDouble(json.get("tag_name").getAsString());
|
||||
if (TabooLib.getPluginVersion() >= newVersion) {
|
||||
MsgUtils.send("插件已是最新版, 无需更新!");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user