Mirror von
https://github.com/ViaVersion/ViaVersion.git
synchronisiert 2024-12-26 16:12:42 +01:00
Using javassist add compatibility for Spigot builds with protocol compatibility (eg. 1.9.1 & 1.9.2)
Also fix issue with protocol passthrough *whew*
Dieser Commit ist enthalten in:
Ursprung
c7ee816aba
Commit
00cc545795
@ -20,6 +20,7 @@ import us.myles.ViaVersion.api.command.ViaVersionCommand;
|
|||||||
import us.myles.ViaVersion.api.data.UserConnection;
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
import us.myles.ViaVersion.api.protocol.ProtocolRegistry;
|
||||||
import us.myles.ViaVersion.boss.ViaBossBar;
|
import us.myles.ViaVersion.boss.ViaBossBar;
|
||||||
|
import us.myles.ViaVersion.classgenerator.ClassGenerator;
|
||||||
import us.myles.ViaVersion.commands.ViaCommandHandler;
|
import us.myles.ViaVersion.commands.ViaCommandHandler;
|
||||||
import us.myles.ViaVersion.handlers.ViaVersionInitializer;
|
import us.myles.ViaVersion.handlers.ViaVersionInitializer;
|
||||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||||
@ -48,6 +49,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
|
|||||||
private List<Pair<Field, Object>> injectedLists = new ArrayList<>();
|
private List<Pair<Field, Object>> injectedLists = new ArrayList<>();
|
||||||
private ViaCommandHandler commandHandler;
|
private ViaCommandHandler commandHandler;
|
||||||
private boolean debug = false;
|
private boolean debug = false;
|
||||||
|
private boolean compatSpigotBuild = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoad() {
|
public void onLoad() {
|
||||||
@ -65,8 +67,16 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 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)
|
||||||
|
ClassGenerator.generate();
|
||||||
|
|
||||||
getLogger().info("ViaVersion " + getDescription().getVersion() + " is now loaded, injecting.");
|
getLogger().info("ViaVersion " + getDescription().getVersion() + (compatSpigotBuild ? "compat" : "") + " is now loaded, injecting.");
|
||||||
injectPacketHandler();
|
injectPacketHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,6 +358,11 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI, ViaVe
|
|||||||
return commandHandler;
|
return commandHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCompatSpigotBuild() {
|
||||||
|
return compatSpigotBuild;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isCheckForUpdates() {
|
public boolean isCheckForUpdates() {
|
||||||
return getConfig().getBoolean("checkforupdates", true);
|
return getConfig().getBoolean("checkforupdates", true);
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,7 @@ public class PacketWrapper {
|
|||||||
readableObjects.clear();
|
readableObjects.clear();
|
||||||
// If the buffer has readable bytes, copy them.
|
// If the buffer has readable bytes, copy them.
|
||||||
if(inputBuffer.readableBytes() > 0){
|
if(inputBuffer.readableBytes() > 0){
|
||||||
read(Type.REMAINING_BYTES);
|
passthrough(Type.REMAINING_BYTES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,4 +318,13 @@ public class PacketWrapper {
|
|||||||
PipelineUtil.getContextBefore("decompress", user().getChannel().pipeline()).fireChannelRead(output);
|
PipelineUtil.getContextBefore("decompress", user().getChannel().pipeline()).fireChannelRead(output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "PacketWrapper{" +
|
||||||
|
"packetValues=" + packetValues +
|
||||||
|
", readableObjects=" + readableObjects +
|
||||||
|
", id=" + id +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,4 +101,12 @@ public interface ViaVersionAPI {
|
|||||||
* @return command handler
|
* @return command handler
|
||||||
*/
|
*/
|
||||||
ViaVersionCommand getCommandHandler();
|
ViaVersionCommand getCommandHandler();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get if this version is a compatibility build for spigot.
|
||||||
|
* Eg. 1.9.1 / 1.9.2 allow certain versions to connect
|
||||||
|
*
|
||||||
|
* @return True if it is
|
||||||
|
*/
|
||||||
|
boolean isCompatSpigotBuild();
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
package us.myles.ViaVersion.api.data;
|
package us.myles.ViaVersion.api.data;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandler;
|
import io.netty.channel.ChannelHandler;
|
||||||
import io.netty.channel.socket.SocketChannel;
|
import io.netty.channel.socket.SocketChannel;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package us.myles.ViaVersion.classgenerator;
|
||||||
|
|
||||||
|
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||||
|
import io.netty.handler.codec.MessageToByteEncoder;
|
||||||
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
|
import us.myles.ViaVersion.classgenerator.HandlerConstructor;
|
||||||
|
import us.myles.ViaVersion.handlers.ViaDecodeHandler;
|
||||||
|
import us.myles.ViaVersion.handlers.ViaEncodeHandler;
|
||||||
|
|
||||||
|
public class BasicHandlerConstructor implements HandlerConstructor {
|
||||||
|
@Override
|
||||||
|
public ViaEncodeHandler newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder) {
|
||||||
|
return new ViaEncodeHandler(info, minecraftEncoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ViaDecodeHandler newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder) {
|
||||||
|
return new ViaDecodeHandler(info, minecraftDecoder);
|
||||||
|
}
|
||||||
|
}
|
88
src/main/java/us/myles/ViaVersion/classgenerator/ClassGenerator.java
Normale Datei
88
src/main/java/us/myles/ViaVersion/classgenerator/ClassGenerator.java
Normale Datei
@ -0,0 +1,88 @@
|
|||||||
|
package us.myles.ViaVersion.classgenerator;
|
||||||
|
|
||||||
|
import javassist.*;
|
||||||
|
import javassist.expr.ConstructorCall;
|
||||||
|
import javassist.expr.ExprEditor;
|
||||||
|
import us.myles.ViaVersion.api.ViaVersion;
|
||||||
|
import us.myles.ViaVersion.handlers.ViaDecodeHandler;
|
||||||
|
import us.myles.ViaVersion.handlers.ViaEncodeHandler;
|
||||||
|
import us.myles.ViaVersion.util.ReflectionUtil;
|
||||||
|
|
||||||
|
public class ClassGenerator {
|
||||||
|
private static HandlerConstructor constructor = new BasicHandlerConstructor();
|
||||||
|
|
||||||
|
public static HandlerConstructor getConstructor() {
|
||||||
|
return constructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void generate() {
|
||||||
|
if(!ViaVersion.getInstance().isCompatSpigotBuild()) return; // Use Basic Handler as not needed.
|
||||||
|
|
||||||
|
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"));
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return generated.toClass(HandlerConstructor.class.getClassLoader());
|
||||||
|
} catch (NotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (CannotCompileException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
package us.myles.ViaVersion.classgenerator;
|
||||||
|
|
||||||
|
import io.netty.handler.codec.ByteToMessageDecoder;
|
||||||
|
import io.netty.handler.codec.MessageToByteEncoder;
|
||||||
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
|
|
||||||
|
public interface HandlerConstructor {
|
||||||
|
public MessageToByteEncoder newEncodeHandler(UserConnection info, MessageToByteEncoder minecraftEncoder);
|
||||||
|
public ByteToMessageDecoder newDecodeHandler(UserConnection info, ByteToMessageDecoder minecraftDecoder);
|
||||||
|
}
|
@ -4,6 +4,7 @@ import io.netty.buffer.ByteBuf;
|
|||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.MessageToByteEncoder;
|
import io.netty.handler.codec.MessageToByteEncoder;
|
||||||
import us.myles.ViaVersion.api.PacketWrapper;
|
import us.myles.ViaVersion.api.PacketWrapper;
|
||||||
|
import us.myles.ViaVersion.api.ViaVersion;
|
||||||
import us.myles.ViaVersion.api.data.UserConnection;
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
import us.myles.ViaVersion.api.type.Type;
|
import us.myles.ViaVersion.api.type.Type;
|
||||||
import us.myles.ViaVersion.exception.CancelException;
|
import us.myles.ViaVersion.exception.CancelException;
|
||||||
@ -11,6 +12,7 @@ import us.myles.ViaVersion.packets.Direction;
|
|||||||
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
|
||||||
import us.myles.ViaVersion.util.PipelineUtil;
|
import us.myles.ViaVersion.util.PipelineUtil;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
public class ViaEncodeHandler extends MessageToByteEncoder {
|
public class ViaEncodeHandler extends MessageToByteEncoder {
|
||||||
@ -25,6 +27,11 @@ public class ViaEncodeHandler extends MessageToByteEncoder {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void encode(final ChannelHandlerContext ctx, Object o, final ByteBuf bytebuf) throws Exception {
|
protected void encode(final ChannelHandlerContext ctx, Object o, final ByteBuf bytebuf) throws Exception {
|
||||||
|
if (ViaVersion.getInstance().isCompatSpigotBuild()) {
|
||||||
|
Field ver = minecraftEncoder.getClass().getDeclaredField("version");
|
||||||
|
ver.setAccessible(true);
|
||||||
|
ver.set(minecraftEncoder, ver.get(this));
|
||||||
|
}
|
||||||
// handle the packet type
|
// handle the packet type
|
||||||
if (!(o instanceof ByteBuf)) {
|
if (!(o instanceof ByteBuf)) {
|
||||||
// call minecraft encoder
|
// call minecraft encoder
|
||||||
|
@ -7,6 +7,8 @@ import io.netty.handler.codec.ByteToMessageDecoder;
|
|||||||
import io.netty.handler.codec.MessageToByteEncoder;
|
import io.netty.handler.codec.MessageToByteEncoder;
|
||||||
import us.myles.ViaVersion.api.data.UserConnection;
|
import us.myles.ViaVersion.api.data.UserConnection;
|
||||||
import us.myles.ViaVersion.api.protocol.ProtocolPipeline;
|
import us.myles.ViaVersion.api.protocol.ProtocolPipeline;
|
||||||
|
import us.myles.ViaVersion.classgenerator.ClassGenerator;
|
||||||
|
import us.myles.ViaVersion.classgenerator.HandlerConstructor;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
@ -36,9 +38,11 @@ public class ViaVersionInitializer extends ChannelInitializer<SocketChannel> {
|
|||||||
new ProtocolPipeline(info);
|
new ProtocolPipeline(info);
|
||||||
// Add originals
|
// Add originals
|
||||||
this.method.invoke(this.original, socketChannel);
|
this.method.invoke(this.original, socketChannel);
|
||||||
|
|
||||||
|
HandlerConstructor constructor = ClassGenerator.getConstructor();
|
||||||
// Add our transformers
|
// Add our transformers
|
||||||
ViaEncodeHandler encoder = new ViaEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder"));
|
MessageToByteEncoder encoder = constructor.newEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder"));
|
||||||
ViaDecodeHandler decoder = new ViaDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder"));
|
ByteToMessageDecoder decoder = constructor.newDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder"));
|
||||||
ViaPacketHandler chunkHandler = new ViaPacketHandler(info);
|
ViaPacketHandler chunkHandler = new ViaPacketHandler(info);
|
||||||
|
|
||||||
socketChannel.pipeline().replace("encoder", "encoder", encoder);
|
socketChannel.pipeline().replace("encoder", "encoder", encoder);
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren