Basic compatibility with ProtocolSupport, doesn't seem to work with 1.6.4 due to issues with our Login Handler.

This commit is contained in:
Myles 2016-06-19 18:08:49 +01:00
parent 91344a0b50
commit 6534a5414e
4 changed files with 147 additions and 49 deletions

View File

@ -9,6 +9,7 @@ import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile; import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import us.myles.ViaVersion.api.Pair; import us.myles.ViaVersion.api.Pair;
@ -48,6 +49,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
private boolean compatSpigotBuild = false; private boolean compatSpigotBuild = false;
private boolean spigot = true; private boolean spigot = true;
private boolean lateBind = false; private boolean lateBind = false;
private boolean protocolSupport = false;
@Getter @Getter
private ViaConfig conf; private ViaConfig conf;
@ -56,6 +58,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
// Config magic // Config magic
conf = new ViaConfig(this); conf = new ViaConfig(this);
ViaVersion.setInstance(this); ViaVersion.setInstance(this);
// Handle reloads // Handle reloads
if (System.getProperty("ViaVersion") != null) { if (System.getProperty("ViaVersion") != null) {
if (Bukkit.getPluginManager().getPlugin("ProtocolLib") != null) { if (Bukkit.getPluginManager().getPlugin("ProtocolLib") != null) {
@ -69,19 +72,25 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
} }
} }
// Spigot detector // Spigot detector
try { try {
Class.forName("org.spigotmc.SpigotConfig"); Class.forName("org.spigotmc.SpigotConfig");
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
spigot = false; spigot = false;
} }
// Check if it's a spigot build with a protocol mod // Check if it's a spigot build with a protocol mod
try { try {
compatSpigotBuild = ReflectionUtil.nms("PacketEncoder").getDeclaredField("version") != null; compatSpigotBuild = ReflectionUtil.nms("PacketEncoder").getDeclaredField("version") != null;
} catch (Exception e) { } catch (Exception e) {
compatSpigotBuild = false; 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(); ClassGenerator.generate();
lateBind = !isBinded(); lateBind = !isBinded();
@ -435,6 +444,10 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI {
} }
} }
public boolean isProtocolSupport() {
return protocolSupport;
}
public Map<UUID, UserConnection> getPortedPlayers() { public Map<UUID, UserConnection> getPortedPlayers() {
return portedPlayers; return portedPlayers;
} }

View File

@ -125,4 +125,11 @@ public interface ViaVersionAPI {
* @return True if spigot * @return True if spigot
*/ */
boolean isSpigot(); boolean isSpigot();
/**
* Gets if protocol support is also being used.
*
* @return True if it is being used.
*/
boolean isProtocolSupport();
} }

View File

@ -3,6 +3,8 @@ package us.myles.ViaVersion.classgenerator;
import javassist.*; import javassist.*;
import javassist.expr.ConstructorCall; import javassist.expr.ConstructorCall;
import javassist.expr.ExprEditor; import javassist.expr.ExprEditor;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import us.myles.ViaVersion.api.ViaVersion; import us.myles.ViaVersion.api.ViaVersion;
import us.myles.ViaVersion.handlers.ViaDecodeHandler; import us.myles.ViaVersion.handlers.ViaDecodeHandler;
import us.myles.ViaVersion.handlers.ViaEncodeHandler; import us.myles.ViaVersion.handlers.ViaEncodeHandler;
@ -10,72 +12,93 @@ import us.myles.ViaVersion.util.ReflectionUtil;
public class ClassGenerator { public class ClassGenerator {
private static HandlerConstructor constructor = new BasicHandlerConstructor(); private static HandlerConstructor constructor = new BasicHandlerConstructor();
private static String psPackage = null;
public static HandlerConstructor getConstructor() { public static HandlerConstructor getConstructor() {
return constructor; return constructor;
} }
public static void generate() { 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 { if (ViaVersion.getInstance().isCompatSpigotBuild()) {
ClassPool pool = ClassPool.getDefault(); Class decodeSuper = ReflectionUtil.nms("PacketDecoder");
pool.insertClassPath(new LoaderClassPath(ClassGenerator.class.getClassLoader())); Class encodeSuper = ReflectionUtil.nms("PacketEncoder");
// Generate the classes // Generate the classes
transformSuperclass(pool, ViaDecodeHandler.class, ReflectionUtil.nms("PacketDecoder")); addSpigotCompatibility(pool, ViaDecodeHandler.class, decodeSuper);
transformSuperclass(pool, ViaEncodeHandler.class, ReflectionUtil.nms("PacketEncoder")); 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}); // Implement Constructor
// Import required classes CtClass generated = pool.makeClass("us.myles.ViaVersion.classgenerator.generated.GeneratedConstructor");
pool.importPackage("us.myles.ViaVersion.classgenerator.generated"); CtClass handlerInterface = pool.get(HandlerConstructor.class.getName());
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(); generated.setInterfaces(new CtClass[]{handlerInterface});
} catch (ClassNotFoundException e) { // Import required classes
e.printStackTrace(); pool.importPackage("us.myles.ViaVersion.classgenerator.generated");
} catch (CannotCompileException e) { pool.importPackage("us.myles.ViaVersion.classgenerator");
e.printStackTrace(); pool.importPackage("us.myles.ViaVersion.api.data");
} catch (NotFoundException e) { pool.importPackage("io.netty.handler.codec");
e.printStackTrace(); // Implement Methods
} catch (InstantiationException e) { generated.addMethod(CtMethod.make("public MessageToByteEncoder newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {\n" +
e.printStackTrace(); " return new ViaEncodeHandler(info, minecraftEncoder);\n" +
} catch (IllegalAccessException e) { " }", generated));
e.printStackTrace(); 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(); String newName = "us.myles.ViaVersion.classgenerator.generated." + input.getSimpleName();
try { try {
CtClass toExtend = pool.get(superclass.getName());
CtClass generated = pool.getAndRename(input.getName(), newName); CtClass generated = pool.getAndRename(input.getName(), newName);
generated.setSuperclass(toExtend); if (superclass != null) {
// Modify constructor to call super CtClass toExtend = pool.get(superclass.getName());
if(generated.getConstructors().length != 0) { generated.setSuperclass(toExtend);
generated.getConstructors()[0].instrument(new ExprEditor() {
@Override // If it's NMS satisfy constructor.
public void edit(ConstructorCall c) throws CannotCompileException { if (superclass.getName().startsWith("net.minecraft")) {
if (c.isSuper()) { // Modify constructor to call super
// Constructor for both has a stats thing. if (generated.getConstructors().length != 0) {
c.replace("super(null);"); generated.getConstructors()[0].instrument(new ExprEditor() {
} @Override
super.edit(c); 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()); return generated.toClass(HandlerConstructor.class.getClassLoader());
} catch (NotFoundException e) { } catch (NotFoundException e) {
@ -85,4 +108,58 @@ public class ClassGenerator {
} }
return null; 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;
}
} }

View File

@ -4,6 +4,7 @@ author: _MylesC
version: ${project.version} version: ${project.version}
load: postworld load: postworld
loadbefore: [ProtocolLib, ProxyPipe, SpigotLib, PacketListenerApi, SkinRestorer] loadbefore: [ProtocolLib, ProxyPipe, SpigotLib, PacketListenerApi, SkinRestorer]
softdepend: [ProtocolSupport]
commands: commands:
viaversion: viaversion:
description: Shows ViaVersion Version and more. description: Shows ViaVersion Version and more.