diff --git a/pom.xml b/pom.xml index 8402a09..fb69517 100644 --- a/pom.xml +++ b/pom.xml @@ -7,37 +7,6 @@ 1.9.7 ${project.artifactId} - - - org.apache.maven.plugins - maven-source-plugin - 2.4 - - - package - - jar-no-fork - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.10.3 - - false - - - - attach-javadocs - - jar - - - - - Jenkins diff --git a/src/main/java/pw/yumc/YumCore/bukkit/compatible/C.java b/src/main/java/pw/yumc/YumCore/bukkit/compatible/C.java index 4b2ca6f..b05426b 100644 --- a/src/main/java/pw/yumc/YumCore/bukkit/compatible/C.java +++ b/src/main/java/pw/yumc/YumCore/bukkit/compatible/C.java @@ -23,67 +23,54 @@ import java.util.UUID; */ public class C { public static boolean init; - private static boolean above_1_16 = false; private static Class nmsIChatBaseComponent; private static Constructor packetTypeConstructor; private static Method chatSerializer; private static Method getHandle; - private static Method nmsChatMessageTypeClassValueOf; private static String version; private static boolean newversion; private static Field playerConnection; private static Method sendPacket; - private static Object[] chatMessageTypes; static { try { - version = getNMSVersion(); - Integer subVersion = Integer.parseInt(version.split("_")[1]); - newversion = subVersion > 7; - Class nmsChatSerializer = subVersion < 17 ? - Class.forName(a(newversion ? "IChatBaseComponent$ChatSerializer" : "ChatSerializer")) : - Class.forName("net.minecraft.network.chat.IChatBaseComponent$ChatSerializer"); - chatSerializer = nmsChatSerializer.getMethod("a", String.class); - nmsIChatBaseComponent = subVersion < 17 ? - Class.forName(a("IChatBaseComponent")) : - Class.forName("net.minecraft.network.chat.IChatBaseComponent"); - Class packetType = subVersion < 17 ? - Class.forName(a("PacketPlayOutChat")) : - Class.forName("net.minecraft.network.protocol.game.PacketPlayOutChat"); - Arrays.stream(packetType.getConstructors()).forEach(c -> { - if (c.getParameterTypes().length == 2) { - packetTypeConstructor = c; + try { + version = getNMSVersion(); + Integer subVersion = Integer.parseInt(version.split("_")[1]); + newversion = subVersion > 7; + Class nmsChatSerializer = subVersion < 17 ? + Class.forName(a(newversion ? "IChatBaseComponent$ChatSerializer" : "ChatSerializer")) : + Class.forName("net.minecraft.network.chat.IChatBaseComponent$ChatSerializer"); + chatSerializer = nmsChatSerializer.getMethod("a", String.class); + nmsIChatBaseComponent = subVersion < 17 ? + Class.forName(a("IChatBaseComponent")) : + Class.forName("net.minecraft.network.chat.IChatBaseComponent"); + Class packetType = subVersion < 17 ? + Class.forName(a("PacketPlayOutChat")) : + Class.forName("net.minecraft.network.protocol.game.PacketPlayOutChat"); + Arrays.stream(packetType.getConstructors()).forEach(c -> { + if (c.getParameterTypes().length == 2) { + packetTypeConstructor = c; + } + if (c.getParameterTypes().length == 3) { + packetTypeConstructor = c; + } + }); + Class typeCraftPlayer = Class.forName(b("entity.CraftPlayer")); + Class typeNMSPlayer = subVersion < 17 ? Class.forName(a("EntityPlayer")) : Class.forName("net.minecraft.server.level.EntityPlayer"); + Class typePlayerConnection = subVersion < 17 ? Class.forName(a("PlayerConnection")) : Class.forName("net.minecraft.server.network.PlayerConnection"); + getHandle = typeCraftPlayer.getMethod("getHandle"); + playerConnection = subVersion < 17 ? typeNMSPlayer.getField("playerConnection") : typeNMSPlayer.getField("b"); + if (subVersion < 17) { + sendPacket = typePlayerConnection.getMethod("sendPacket", Class.forName(a("Packet"))); + } else if (subVersion == 17) { + sendPacket = typePlayerConnection.getMethod("sendPacket", Class.forName("net.minecraft.network.protocol.Packet")); + } else { + sendPacket = typePlayerConnection.getMethod("a", Class.forName("net.minecraft.network.protocol.Packet")); } - if (c.getParameterTypes().length == 3) { - packetTypeConstructor = c; - above_1_16 = true; - } - }); - Class nmsChatMessageTypeClass = packetTypeConstructor.getParameterTypes()[1]; - if (nmsChatMessageTypeClass.isEnum()) { - chatMessageTypes = nmsChatMessageTypeClass.getEnumConstants(); - } else { - switch (nmsChatMessageTypeClass.getName()) { - case "int": - nmsChatMessageTypeClass = Integer.class; - break; - case "byte": - nmsChatMessageTypeClass = Byte.class; - break; - } - nmsChatMessageTypeClassValueOf = nmsChatMessageTypeClass.getDeclaredMethod("valueOf", String.class); - } - Class typeCraftPlayer = Class.forName(b("entity.CraftPlayer")); - Class typeNMSPlayer = subVersion < 17 ? Class.forName(a("EntityPlayer")) : Class.forName("net.minecraft.server.level.EntityPlayer"); - Class typePlayerConnection = subVersion < 17 ? Class.forName(a("PlayerConnection")) : Class.forName("net.minecraft.server.network.PlayerConnection"); - getHandle = typeCraftPlayer.getMethod("getHandle"); - playerConnection = subVersion < 17 ? typeNMSPlayer.getField("playerConnection") : typeNMSPlayer.getField("b"); - if (subVersion < 17) { - sendPacket = typePlayerConnection.getMethod("sendPacket", Class.forName(a("Packet"))); - } else if (subVersion == 17) { - sendPacket = typePlayerConnection.getMethod("sendPacket", Class.forName("net.minecraft.network.protocol.Packet")); - } else { - sendPacket = typePlayerConnection.getMethod("a", Class.forName("net.minecraft.network.protocol.Packet")); + } catch (Exception ex) { + Log.d(ex); + Chat.getBukkitChatInvoke(); } init = true; } catch (Exception e) { @@ -122,17 +109,7 @@ public class C { * 2. ActionBar */ public static void sendJson(org.bukkit.entity.Player receivingPacket, String json, int type) { - try { - Object serialized = chatSerializer.invoke(null, json); - Object player = getHandle.invoke(receivingPacket); - Object connection = playerConnection.get(player); - Object typeObj = chatMessageTypes == null ? nmsChatMessageTypeClassValueOf.invoke(null, String.valueOf(type)) : chatMessageTypes[type]; - sendPacket.invoke(connection, above_1_16 - ? packetTypeConstructor.newInstance(serialized, typeObj, receivingPacket.getUniqueId()) - : packetTypeConstructor.newInstance(serialized, typeObj)); - } catch (Exception ex) { - Log.d("Json发包错误 " + version, ex); - } + Chat.getBukkitChatInvoke().send(receivingPacket, json, type); } public static class ActionBar { diff --git a/src/main/java/pw/yumc/YumCore/bukkit/compatible/Chat.java b/src/main/java/pw/yumc/YumCore/bukkit/compatible/Chat.java new file mode 100644 index 0000000..f818391 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/bukkit/compatible/Chat.java @@ -0,0 +1,272 @@ +package pw.yumc.YumCore.bukkit.compatible; + +import lombok.SneakyThrows; +import net.md_5.bungee.api.chat.BaseComponent; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +public class Chat { + private static final String version; + private static final BukkitChatInvoke bukkitChatInvoke; + + static { + version = getNMSVersion(); + int subVersion = Integer.parseInt(version.split("_")[1]); + if (subVersion >= 19) { + bukkitChatInvoke = new BukkitChatInvoke_1_19(); + } else if (subVersion >= 17) { + bukkitChatInvoke = new BukkitChatInvoke_1_17_1(); + } else if (subVersion >= 16) { + bukkitChatInvoke = new BukkitChatInvoke_1_16_5(); + } else if (subVersion >= 8) { + bukkitChatInvoke = new BukkitChatInvoke_1_8(); + } else { + bukkitChatInvoke = new BukkitChatInvoke_1_7_10(); + } + bukkitChatInvoke.init(); + } + + public static BukkitChatInvoke getBukkitChatInvoke() { + return bukkitChatInvoke; + } + + /** + * 获得NMS版本号 + * + * @return NMS版本号 + */ + public static String getNMSVersion() { + return Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3]; + } + + public static Class nmsCls(String str) throws ClassNotFoundException { + return Class.forName("net.minecraft.server." + version + "." + str); + } + + public static Class obcCls(String str) throws ClassNotFoundException { + return Class.forName("org.bukkit.craftbukkit." + version + "." + str); + } + + public static abstract class BukkitChatInvoke { + protected boolean downgrade = false; + + protected Method chatSerializer; + protected Constructor packetTypeConstructor; + protected Method getHandle; + protected Field playerConnection; + protected Method sendPacket; + protected Object[] chatMessageTypes; + + protected Method componentSerializer; + + BukkitChatInvoke() { + init(); + } + + public void init() { + try { + Class nmsChatSerializerClass = this.getNmsChatSerializerClass(); + this.chatSerializer = this.getNmsChatSerializerMethod(nmsChatSerializerClass); + Constructor[] constructors = this.getPacketPlayOutChatClass().getConstructors(); + for (Constructor constructor : constructors) { + if (constructor.getParameterCount() == 2 || constructor.getParameterCount() == 3) { + this.packetTypeConstructor = constructor; + if (this.isMatchPacketPlayOutChatClassConstructor(constructor)) { + break; + } + } + } + this.getHandle = this.getGetHandleMethod(); + this.playerConnection = this.getPlayerConnectionField(this.getHandle.getReturnType()); + this.sendPacket = this.getSendPacketMethod(this.playerConnection.getType(), this.getPacketClass()); + } catch (Throwable ex) { + this.downgrade = true; + try { + this.componentSerializer = Class.forName("net.md_5.bungee.chat.ComponentSerializer").getMethod("parse", String.class); + } catch (ClassNotFoundException | NoSuchMethodException e) { + e.printStackTrace(); + } + } + } + + @SneakyThrows + void json(Player receivingPacket, String json) { + if (this.downgrade) { + receivingPacket.spigot().sendMessage((BaseComponent[]) this.componentSerializer.invoke(null, json)); + } else { + this.send(receivingPacket, json, 0); + } + } + + @SneakyThrows + void send(Player receivingPacket, String json, int type) { + this.sendPacket(receivingPacket, this.getPacketPlayOutChat(receivingPacket, json, type)); + } + + @SneakyThrows + void sendPacket(Player receivingPacket, Object packet) { + this.sendPacket.invoke(playerConnection.get(getHandle.invoke(receivingPacket)), packet); + } + + abstract boolean isMatchPacketPlayOutChatClassConstructor(Constructor constructor); + + abstract Class getNmsChatSerializerClass(); + + abstract Method getNmsChatSerializerMethod(Class nmsChatSerializerClass); + + abstract Class getPacketPlayOutChatClass(); + + abstract Field getPlayerConnectionField(Class nmsEntityPlayerClass); + + abstract Method getGetHandleMethod(); + + abstract Class getPacketClass(); + + abstract Method getSendPacketMethod(Class playerConnectionClass, Class packetClass); + + abstract Object getPacketPlayOutChat(Player player, String json, int type); + } + + public static class BukkitChatInvokeBase extends BukkitChatInvoke { + @Override + protected boolean isMatchPacketPlayOutChatClassConstructor(Constructor constructor) { + Class[] types = constructor.getParameterTypes(); + if (types[1].isEnum()) { + this.chatMessageTypes = types[1].getEnumConstants(); + return true; + } + return types[1].getName().equals("int"); + } + + @Override + @SneakyThrows + Class getNmsChatSerializerClass() { + return nmsCls("ChatSerializer"); + } + + @Override + @SneakyThrows + Method getNmsChatSerializerMethod(Class nmsChatSerializerClass) { + return nmsChatSerializerClass.getMethod("a", String.class); + } + + @Override + @SneakyThrows + Class getPacketPlayOutChatClass() { + return nmsCls("PacketPlayOutChat"); + } + + @Override + @SneakyThrows + Field getPlayerConnectionField(Class nmsEntityPlayerClass) { + return nmsEntityPlayerClass.getField("playerConnection"); + } + + @Override + @SneakyThrows + Method getGetHandleMethod() { + return obcCls("entity.CraftPlayer").getMethod("getHandle"); + } + + @Override + @SneakyThrows + Class getPacketClass() { + return nmsCls("Packet"); + } + + @Override + @SneakyThrows + Method getSendPacketMethod(Class playerConnectionClass, Class packetClass) { + return playerConnectionClass.getMethod("sendPacket", packetClass); + } + + @Override + @SneakyThrows + Object getPacketPlayOutChat(Player player, String json, int type) { + return packetTypeConstructor.newInstance(this.chatSerializer.invoke(null, json), type); + } + } + + public static class BukkitChatInvoke_1_7_10 extends BukkitChatInvokeBase { + + } + + public static class BukkitChatInvoke_1_8 extends BukkitChatInvoke_1_7_10 { + @Override + @SneakyThrows + Object getPacketPlayOutChat(Player player, String json, int type) { + return packetTypeConstructor.newInstance(this.chatSerializer.invoke(null, json), this.chatMessageTypes[type]); + } + + @Override + @SneakyThrows + Class getNmsChatSerializerClass() { + return nmsCls("IChatBaseComponent$ChatSerializer"); + } + } + + public static class BukkitChatInvoke_1_16_5 extends BukkitChatInvoke_1_8 { + @Override + @SneakyThrows + Object getPacketPlayOutChat(Player player, String json, int type) { + return packetTypeConstructor.newInstance(this.chatSerializer.invoke(null, json), this.chatMessageTypes[type], player.getUniqueId()); + } + } + + public static class BukkitChatInvoke_1_17_1 extends BukkitChatInvoke_1_16_5 { + @Override + @SneakyThrows + Class getPacketPlayOutChatClass() { + return Class.forName("net.minecraft.network.protocol.game.PacketPlayOutChat"); + } + + @Override + @SneakyThrows + Class getNmsChatSerializerClass() { + return Class.forName("net.minecraft.network.chat.IChatBaseComponent$ChatSerializer"); + } + + @Override + @SneakyThrows + Field getPlayerConnectionField(Class nmsEntityPlayerClass) { + return nmsEntityPlayerClass.getField("b"); + } + + @Override + @SneakyThrows + Class getPacketClass() { + return Class.forName("net.minecraft.network.protocol.Packet"); + } + } + + public static class BukkitChatInvoke_1_19 extends BukkitChatInvoke_1_17_1 { + @Override + protected boolean isMatchPacketPlayOutChatClassConstructor(Constructor constructor) { + Class[] types = constructor.getParameterTypes(); + return types[0] == String.class && types[1] == int.class; + } + + @Override + @SneakyThrows + Method getSendPacketMethod(Class playerConnectionClass, Class packetClass) { + return playerConnectionClass.getMethod("a", packetClass); + } + + @Override + @SneakyThrows + Class getPacketPlayOutChatClass() { + return Class.forName("net.minecraft.network.protocol.game.ClientboundSystemChatPacket"); + } + + @Override + @SneakyThrows + Object getPacketPlayOutChat(Player player, String json, int type) { + Object component = this.chatSerializer.invoke(null, json); + return this.packetTypeConstructor.newInstance(component, type == 0 ? 1 : type); + } + } +} diff --git a/src/main/java/pw/yumc/YumCore/update/SubscribeTask.java b/src/main/java/pw/yumc/YumCore/update/SubscribeTask.java index 72138c1..437e0b1 100644 --- a/src/main/java/pw/yumc/YumCore/update/SubscribeTask.java +++ b/src/main/java/pw/yumc/YumCore/update/SubscribeTask.java @@ -108,7 +108,7 @@ public class SubscribeTask implements Runnable, Listener { @EventHandler public void onJoin(PlayerJoinEvent e) { final Player player = e.getPlayer(); - if (player.isOp() && updateFile.isUpdated()) { + if (player.isOp() && versionInfo.hasNewVersion() && updateFile.isUpdated()) { Bukkit.getScheduler().runTaskLater(instance, () -> versionInfo.notify(player), 10); } } @@ -255,10 +255,13 @@ public class SubscribeTask implements Runnable, Listener { */ private Document document; + private boolean hasNewVersion; + public VersionInfo(Plugin plugin, String branch, boolean isSecret) { this.name = plugin.getName(); this.version = plugin.getDescription().getVersion().split("-")[0]; this.info = String.format(isSecret ? pom : url, name, branch); + this.hasNewVersion = false; } /** @@ -372,7 +375,10 @@ public class SubscribeTask implements Runnable, Listener { Log.console("§4注意: §c当前版本为开发版本 且未开启全局调试 已自动下载最新稳定版!"); return result; } - if (needUpdate(result, version)) {return result;} + if (needUpdate(result, version)) { + this.hasNewVersion = true; + return result; + } } catch (Exception e) { Log.d(e); } @@ -382,5 +388,9 @@ public class SubscribeTask implements Runnable, Listener { public void update() throws ParserConfigurationException, IOException, SAXException { document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(info); } + + public boolean hasNewVersion() { + return hasNewVersion; + } } }