diff --git a/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java b/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java index 3a8fc01d3..e16e25321 100644 --- a/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java +++ b/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java @@ -9,6 +9,7 @@ import lombok.Getter; import lombok.NonNull; import org.bukkit.Bukkit; import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.java.JavaPlugin; import us.myles.ViaVersion.api.Pair; @@ -48,6 +49,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI { private boolean compatSpigotBuild = false; private boolean spigot = true; private boolean lateBind = false; + private boolean protocolSupport = false; @Getter private ViaConfig conf; @@ -56,6 +58,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI { // Config magic conf = new ViaConfig(this); ViaVersion.setInstance(this); + // Handle reloads if (System.getProperty("ViaVersion") != null) { if (Bukkit.getPluginManager().getPlugin("ProtocolLib") != null) { @@ -69,19 +72,25 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI { } } + // Spigot detector try { Class.forName("org.spigotmc.SpigotConfig"); } catch (ClassNotFoundException e) { spigot = false; } + // Check if it's a spigot build with a protocol mod try { compatSpigotBuild = ReflectionUtil.nms("PacketEncoder").getDeclaredField("version") != null; } catch (Exception e) { compatSpigotBuild = false; } - // Generate classes needed (only works if it's compat) + + // Check if we're using protocol support too + protocolSupport = Bukkit.getPluginManager().getPlugin("ProtocolSupport") != null; + + // Generate classes needed (only works if it's compat or ps) ClassGenerator.generate(); lateBind = !isBinded(); @@ -435,6 +444,10 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI { } } + public boolean isProtocolSupport() { + return protocolSupport; + } + public Map getPortedPlayers() { return portedPlayers; } diff --git a/src/main/java/us/myles/ViaVersion/api/ViaVersionAPI.java b/src/main/java/us/myles/ViaVersion/api/ViaVersionAPI.java index f2063d95f..5e2dca295 100644 --- a/src/main/java/us/myles/ViaVersion/api/ViaVersionAPI.java +++ b/src/main/java/us/myles/ViaVersion/api/ViaVersionAPI.java @@ -125,4 +125,11 @@ public interface ViaVersionAPI { * @return True if spigot */ boolean isSpigot(); + + /** + * Gets if protocol support is also being used. + * + * @return True if it is being used. + */ + boolean isProtocolSupport(); } diff --git a/src/main/java/us/myles/ViaVersion/classgenerator/ClassGenerator.java b/src/main/java/us/myles/ViaVersion/classgenerator/ClassGenerator.java index 82a331ae5..d29089d02 100644 --- a/src/main/java/us/myles/ViaVersion/classgenerator/ClassGenerator.java +++ b/src/main/java/us/myles/ViaVersion/classgenerator/ClassGenerator.java @@ -3,6 +3,8 @@ package us.myles.ViaVersion.classgenerator; import javassist.*; import javassist.expr.ConstructorCall; import javassist.expr.ExprEditor; +import org.bukkit.Bukkit; +import org.bukkit.plugin.Plugin; import us.myles.ViaVersion.api.ViaVersion; import us.myles.ViaVersion.handlers.ViaDecodeHandler; import us.myles.ViaVersion.handlers.ViaEncodeHandler; @@ -10,72 +12,93 @@ import us.myles.ViaVersion.util.ReflectionUtil; public class ClassGenerator { private static HandlerConstructor constructor = new BasicHandlerConstructor(); + private static String psPackage = null; public static HandlerConstructor getConstructor() { return constructor; } public static void generate() { - if(!ViaVersion.getInstance().isCompatSpigotBuild()) return; // Use Basic Handler as not needed. + if (ViaVersion.getInstance().isCompatSpigotBuild() || ViaVersion.getInstance().isProtocolSupport()) { + try { + ClassPool pool = ClassPool.getDefault(); + for (Plugin p : Bukkit.getPluginManager().getPlugins()) { + pool.insertClassPath(new LoaderClassPath(p.getClass().getClassLoader())); + } - try { - ClassPool pool = ClassPool.getDefault(); - pool.insertClassPath(new LoaderClassPath(ClassGenerator.class.getClassLoader())); - // Generate the classes - transformSuperclass(pool, ViaDecodeHandler.class, ReflectionUtil.nms("PacketDecoder")); - transformSuperclass(pool, ViaEncodeHandler.class, ReflectionUtil.nms("PacketEncoder")); + if (ViaVersion.getInstance().isCompatSpigotBuild()) { + Class decodeSuper = ReflectionUtil.nms("PacketDecoder"); + Class encodeSuper = ReflectionUtil.nms("PacketEncoder"); + // Generate the classes + addSpigotCompatibility(pool, ViaDecodeHandler.class, decodeSuper); + addSpigotCompatibility(pool, ViaEncodeHandler.class, encodeSuper); + } else { + Class decodeSuper = Class.forName(getPSPackage() + ".wrapped.WrappedDecoder"); + Class encodeSuper = Class.forName(getPSPackage() + ".wrapped.WrappedEncoder"); + // Generate the classes + addPSCompatibility(pool, ViaDecodeHandler.class, decodeSuper); + addPSCompatibility(pool, ViaEncodeHandler.class, encodeSuper); + } - // Implement Constructor - CtClass generated = pool.makeClass("us.myles.ViaVersion.classgenerator.generated.GeneratedConstructor"); - CtClass handlerInterface = pool.get(HandlerConstructor.class.getName()); - generated.setInterfaces(new CtClass[]{handlerInterface}); - // Import required classes - pool.importPackage("us.myles.ViaVersion.classgenerator.generated"); - pool.importPackage("us.myles.ViaVersion.classgenerator"); - pool.importPackage("us.myles.ViaVersion.api.data"); - pool.importPackage("io.netty.handler.codec"); - // Implement Methods - generated.addMethod(CtMethod.make("public MessageToByteEncoder newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {\n" + - " return new ViaEncodeHandler(info, minecraftEncoder);\n" + - " }", generated)); - generated.addMethod(CtMethod.make("public ByteToMessageDecoder newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {\n" + - " return new ViaDecodeHandler(info, minecraftDecoder);\n" + - " }", generated)); + // Implement Constructor + CtClass generated = pool.makeClass("us.myles.ViaVersion.classgenerator.generated.GeneratedConstructor"); + CtClass handlerInterface = pool.get(HandlerConstructor.class.getName()); - constructor = (HandlerConstructor) generated.toClass(HandlerConstructor.class.getClassLoader()).newInstance(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (CannotCompileException e) { - e.printStackTrace(); - } catch (NotFoundException e) { - e.printStackTrace(); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); + generated.setInterfaces(new CtClass[]{handlerInterface}); + // Import required classes + pool.importPackage("us.myles.ViaVersion.classgenerator.generated"); + pool.importPackage("us.myles.ViaVersion.classgenerator"); + pool.importPackage("us.myles.ViaVersion.api.data"); + pool.importPackage("io.netty.handler.codec"); + // Implement Methods + generated.addMethod(CtMethod.make("public MessageToByteEncoder newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {\n" + + " return new ViaEncodeHandler(info, minecraftEncoder);\n" + + " }", generated)); + generated.addMethod(CtMethod.make("public ByteToMessageDecoder newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {\n" + + " return new ViaDecodeHandler(info, minecraftDecoder);\n" + + " }", generated)); + + constructor = (HandlerConstructor) generated.toClass(HandlerConstructor.class.getClassLoader()).newInstance(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (CannotCompileException e) { + e.printStackTrace(); + } catch (NotFoundException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } } } - private static Class transformSuperclass(ClassPool pool, Class input, Class superclass) { + private static Class addSpigotCompatibility(ClassPool pool, Class input, Class superclass) { String newName = "us.myles.ViaVersion.classgenerator.generated." + input.getSimpleName(); try { - CtClass toExtend = pool.get(superclass.getName()); CtClass generated = pool.getAndRename(input.getName(), newName); - generated.setSuperclass(toExtend); - // Modify constructor to call super - if(generated.getConstructors().length != 0) { - generated.getConstructors()[0].instrument(new ExprEditor() { - @Override - public void edit(ConstructorCall c) throws CannotCompileException { - if (c.isSuper()) { - // Constructor for both has a stats thing. - c.replace("super(null);"); - } - super.edit(c); + if (superclass != null) { + CtClass toExtend = pool.get(superclass.getName()); + generated.setSuperclass(toExtend); + + // If it's NMS satisfy constructor. + if (superclass.getName().startsWith("net.minecraft")) { + // Modify constructor to call super + if (generated.getConstructors().length != 0) { + generated.getConstructors()[0].instrument(new ExprEditor() { + @Override + public void edit(ConstructorCall c) throws CannotCompileException { + if (c.isSuper()) { + // Constructor for both has a stats thing. + c.replace("super(null);"); + } + super.edit(c); + } + }); } - }); + } } return generated.toClass(HandlerConstructor.class.getClassLoader()); } catch (NotFoundException e) { @@ -85,4 +108,58 @@ public class ClassGenerator { } return null; } + + private static Class addPSCompatibility(ClassPool pool, Class input, Class superclass) { + String newName = "us.myles.ViaVersion.classgenerator.generated." + input.getSimpleName(); + + try { + CtClass generated = pool.getAndRename(input.getName(), newName); + if (superclass != null) { + CtClass toExtend = pool.get(superclass.getName()); + generated.setSuperclass(toExtend); + + // Override setRealEncoder / setRealDecoder + pool.importPackage(getPSPackage()); + pool.importPackage(getPSPackage() + ".wrapped"); + if (superclass.getName().endsWith("Decoder")) { + // Decoder + generated.addMethod(CtMethod.make("public void setRealDecoder(IPacketDecoder dec) {\n" + + " WrappedDecoder decoder = new WrappedDecoder();" + + " decoder.setRealDecoder(dec);\n" + + " this.minecraftDecoder = decoder;\n" + + " }", generated)); + } else { + // Encoder + generated.addMethod(CtMethod.make("public void setRealEncoder(IPacketEncoder enc) {\n" + + " WrappedEncoder encoder = new WrappedEncoder();" + + " encoder.setRealEncoder(enc);\n" + + " this.minecraftEncoder = encoder;\n" + + " }", generated)); + } + } + return generated.toClass(HandlerConstructor.class.getClassLoader()); + } catch (NotFoundException e) { + e.printStackTrace(); + } catch (CannotCompileException e) { + e.printStackTrace(); + } + return null; + } + + public static String getPSPackage() { + if (psPackage == null) { + try { + Class.forName("protocolsupport.protocol.core.IPacketDecoder"); + psPackage = "protocolsupport.protocol.core"; + } catch (ClassNotFoundException e) { + try { + Class.forName("protocolsupport.protocol.pipeline.IPacketDecoder"); + psPackage = "protocolsupport.protocol.pipeline"; + } catch (ClassNotFoundException e1) { + psPackage = "unknown"; + } + } + } + return psPackage; + } } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index f96638542..1789438fd 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -4,6 +4,7 @@ author: _MylesC version: ${project.version} load: postworld loadbefore: [ProtocolLib, ProxyPipe, SpigotLib, PacketListenerApi, SkinRestorer] +softdepend: [ProtocolSupport] commands: viaversion: description: Shows ViaVersion Version and more.