diff --git a/README.md b/README.md index 3680556e1..4bd878f48 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# ViaVersion 0.3.7 +# ViaVersion 0.4.5 **Allows the connection of 1.8 clients to 1.9** This plugin modifies netty to allow connection of 1.9 clients to 1.8, -**Don't use late bind nor ProtocolLib** +**Don't use late bind* **As of this point it doesn't have everything, I need to fix:** @@ -28,12 +28,11 @@ Contributors: -------- **Myself** (harhar) - **Matsv/StamBoom** - **HugoDaBosss** - **SanderGielisse** +**Paulomart** +**gigosaurus** License: -------- diff --git a/src/main/java/us/myles/ViaVersion/ConnectionInfo.java b/src/main/java/us/myles/ViaVersion/ConnectionInfo.java index 7e1dd89cb..4516fe804 100644 --- a/src/main/java/us/myles/ViaVersion/ConnectionInfo.java +++ b/src/main/java/us/myles/ViaVersion/ConnectionInfo.java @@ -9,11 +9,12 @@ import java.util.UUID; public class ConnectionInfo { private final SocketChannel channel; - private int protocol = 0; - private State state = State.HANDSHAKE; - private int compression = 0; private Object lastPacket; private java.util.UUID UUID; + private State state = State.HANDSHAKE; + private int protocol = 0; + private int compression = 0; + private boolean active = true; public ConnectionInfo(SocketChannel socketChannel) { this.channel = socketChannel; @@ -66,4 +67,12 @@ public class ConnectionInfo { public SocketChannel getChannel() { return channel; } + + public boolean isActive() { + return active; + } + + public void setActive(boolean active) { + this.active = active; + } } diff --git a/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java b/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java index 20af1c3d3..0bdaf7820 100644 --- a/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java +++ b/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java @@ -6,7 +6,6 @@ import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import org.bukkit.Bukkit; -import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -34,14 +33,17 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI { @Override public void onEnable() { ViaVersion.setInstance(this); - System.out.println("ViaVersion enabled, injecting. (Allows 1.8 to be accessed via 1.9)"); + if(System.getProperty("ViaVersion") != null){ + getLogger().severe("ViaVersion is already loaded, we don't support reloads. Please reboot if you wish to update."); + return; + } + + getLogger().info("ViaVersion enabled, injecting. (Allows 1.8 to be accessed via 1.9)"); try { injectPacketHandler(); + System.setProperty("ViaVersion", getDescription().getVersion()); } catch (Exception e) { - if(Bukkit.getPluginManager().getPlugin("ProtocolLib") != null){ - System.out.println("This plugin is not compatible with protocol lib."); - } - System.out.println("Unable to inject handlers, are you on 1.8? "); + getLogger().severe("Unable to inject handlers, are you on 1.8? "); e.printStackTrace(); } Bukkit.getPluginManager().registerEvents(new Listener() { @@ -59,7 +61,7 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI { List futures = ReflectionUtil.get(connection, "g", List.class); if (futures.size() == 0) { - throw new Exception("Could not find server to inject (late bind?)"); + throw new Exception("Could not find server to inject (Please ensure late-bind in your spigot.yml is false)"); } for (ChannelFuture future : futures) { diff --git a/src/main/java/us/myles/ViaVersion/handlers/ViaDecodeHandler.java b/src/main/java/us/myles/ViaVersion/handlers/ViaDecodeHandler.java new file mode 100644 index 000000000..ad39cd125 --- /dev/null +++ b/src/main/java/us/myles/ViaVersion/handlers/ViaDecodeHandler.java @@ -0,0 +1,62 @@ +package us.myles.ViaVersion.handlers; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; +import us.myles.ViaVersion.CancelException; +import us.myles.ViaVersion.ConnectionInfo; +import us.myles.ViaVersion.transformers.IncomingTransformer; +import us.myles.ViaVersion.util.PacketUtil; + +import java.nio.channels.ClosedChannelException; +import java.util.List; + +public class ViaDecodeHandler extends ByteToMessageDecoder { + private final IncomingTransformer incomingTransformer; + private final ByteToMessageDecoder minecraftDecoder; + private final ConnectionInfo info; + + public ViaDecodeHandler(ConnectionInfo info, ByteToMessageDecoder minecraftDecoder) { + this.info = info; + this.minecraftDecoder = minecraftDecoder; + this.incomingTransformer = new IncomingTransformer(info); + } + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf bytebuf, List list) throws Exception { + // use transformers + if (bytebuf.readableBytes() > 0) { + if (info.isActive()) { + int id = PacketUtil.readVarInt(bytebuf); + // Transform + ByteBuf newPacket = ctx.alloc().buffer(); + try { + incomingTransformer.transform(id, bytebuf, newPacket); + bytebuf = newPacket; + } catch (CancelException e) { + bytebuf.readBytes(bytebuf.readableBytes()); + throw e; + } + } + // call minecraft decoder + list.addAll(PacketUtil.callDecode(this.minecraftDecoder, ctx, bytebuf)); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + if (!(cause.getCause().getCause() instanceof CancelException) + && !(cause.getCause().getCause() instanceof ClosedChannelException)) { + if (!(cause.getCause() instanceof CancelException) + && !(cause.getCause() instanceof ClosedChannelException)) { + if (!(cause instanceof CancelException) + && !(cause instanceof ClosedChannelException)) { + if (cause instanceof Exception){ + cause.printStackTrace(); + } + } + } + } + } + +} diff --git a/src/main/java/us/myles/ViaVersion/handlers/ViaEncodeHandler.java b/src/main/java/us/myles/ViaVersion/handlers/ViaEncodeHandler.java new file mode 100644 index 000000000..4cc88c572 --- /dev/null +++ b/src/main/java/us/myles/ViaVersion/handlers/ViaEncodeHandler.java @@ -0,0 +1,87 @@ +package us.myles.ViaVersion.handlers; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; +import us.myles.ViaVersion.CancelException; +import us.myles.ViaVersion.ConnectionInfo; +import us.myles.ViaVersion.transformers.OutgoingTransformer; +import us.myles.ViaVersion.util.PacketUtil; +import us.myles.ViaVersion.util.ReflectionUtil; + +import java.lang.reflect.Constructor; +import java.nio.channels.ClosedChannelException; + +public class ViaEncodeHandler extends MessageToByteEncoder { + private final ConnectionInfo info; + private final MessageToByteEncoder minecraftEncoder; + private final OutgoingTransformer outgoingTransformer; + + public ViaEncodeHandler(ConnectionInfo info, MessageToByteEncoder minecraftEncoder) { + this.info = info; + this.minecraftEncoder = minecraftEncoder; + this.outgoingTransformer = new OutgoingTransformer(info); + } + + + @Override + protected void encode(ChannelHandlerContext ctx, Object o, ByteBuf bytebuf) throws Exception { + // handle the packet type + if (!(o instanceof ByteBuf)) { + info.setLastPacket(o); + /* This transformer is more for fixing issues which we find hard at packet level :) */ + if (o.getClass().getName().endsWith("PacketPlayOutMapChunkBulk") && info.isActive()) { + int[] locX = ReflectionUtil.get(o, "a", int[].class); + int[] locZ = ReflectionUtil.get(o, "b", int[].class); + + Object world = ReflectionUtil.get(o, "world", ReflectionUtil.nms("World")); + Class mapChunk = ReflectionUtil.nms("PacketPlayOutMapChunk"); + Constructor constructor = mapChunk.getDeclaredConstructor(ReflectionUtil.nms("Chunk"), boolean.class, int.class); + for (int i = 0; i < locX.length; i++) { + int x = locX[i]; + int z = locZ[i]; + // world invoke function + Object chunk = ReflectionUtil.nms("World").getDeclaredMethod("getChunkAt", int.class, int.class).invoke(world, x, z); + Object packet = constructor.newInstance(chunk, true, 65535); + ctx.pipeline().writeAndFlush(packet); + } + bytebuf.readBytes(bytebuf.readableBytes()); + throw new CancelException(); + } + // call minecraft encoder + PacketUtil.callEncode(this.minecraftEncoder, ctx, o, bytebuf); + } + if (bytebuf.readableBytes() == 0) { + throw new CancelException(); + } + if (info.isActive()) { + int id = PacketUtil.readVarInt(bytebuf); + // Transform + ByteBuf oldPacket = bytebuf.copy(); + bytebuf.clear(); + try { + outgoingTransformer.transform(id, oldPacket, bytebuf); + } catch (CancelException e) { + bytebuf.readBytes(bytebuf.readableBytes()); + throw e; + } finally { + oldPacket.release(); + } + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + if (!(cause.getCause().getCause() instanceof CancelException) + && !(cause.getCause().getCause() instanceof ClosedChannelException)) { + if (!(cause.getCause() instanceof CancelException) + && !(cause.getCause() instanceof ClosedChannelException)) { + if (!(cause instanceof CancelException) + && !(cause instanceof ClosedChannelException)) { + if (cause instanceof Exception) + cause.printStackTrace(); + } + } + } + } +} diff --git a/src/main/java/us/myles/ViaVersion/handlers/ViaInboundHandler.java b/src/main/java/us/myles/ViaVersion/handlers/ViaInboundHandler.java deleted file mode 100644 index 8423e5dc4..000000000 --- a/src/main/java/us/myles/ViaVersion/handlers/ViaInboundHandler.java +++ /dev/null @@ -1,51 +0,0 @@ -package us.myles.ViaVersion.handlers; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; -import io.netty.channel.ChannelHandler; -import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandlerAdapter; -import us.myles.ViaVersion.CancelException; -import us.myles.ViaVersion.ConnectionInfo; -import us.myles.ViaVersion.util.PacketUtil; -import us.myles.ViaVersion.transformers.IncomingTransformer; - -@ChannelHandler.Sharable -public class ViaInboundHandler extends ChannelInboundHandlerAdapter { - private final IncomingTransformer incomingTransformer; - - public ViaInboundHandler(ConnectionInfo info) { - this.incomingTransformer = new IncomingTransformer(info); - } - - @Override - public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { - boolean compression = ctx.pipeline().get("compress") != null; - - if (msg instanceof ByteBuf) { - ByteBuf bytebuf = (ByteBuf) msg; - if (compression) { - // decompress :) - bytebuf = PacketUtil.decompress(ctx, bytebuf); - } - int id = PacketUtil.readVarInt(bytebuf); - // Transform - ByteBuf newPacket = ctx.alloc().buffer(); - try { - incomingTransformer.transform(id, bytebuf, newPacket); - } catch (CancelException e) { - return; - } finally { - bytebuf.release(); - } - if (compression) { - // recompress :) - newPacket = PacketUtil.compress(ctx, newPacket); - } - msg = newPacket; - } - super.channelRead(ctx, msg); - } - - -} diff --git a/src/main/java/us/myles/ViaVersion/handlers/ViaOutboundHandler.java b/src/main/java/us/myles/ViaVersion/handlers/ViaOutboundHandler.java deleted file mode 100644 index c42b00dfb..000000000 --- a/src/main/java/us/myles/ViaVersion/handlers/ViaOutboundHandler.java +++ /dev/null @@ -1,53 +0,0 @@ -package us.myles.ViaVersion.handlers; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.*; -import us.myles.ViaVersion.CancelException; -import us.myles.ViaVersion.ConnectionInfo; -import us.myles.ViaVersion.util.PacketUtil; -import us.myles.ViaVersion.transformers.OutgoingTransformer; - -@ChannelHandler.Sharable -public class ViaOutboundHandler extends ChannelOutboundHandlerAdapter { - private final OutgoingTransformer outgoingTransformer; - private final ConnectionInfo info; - - public ViaOutboundHandler(ConnectionInfo info) { - this.info = info; - this.outgoingTransformer = new OutgoingTransformer(info); - } - - @Override - public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise channelPromise) throws Exception { - try { - if (channelPromise.isDone()) return; // don't break any <3s - boolean compression = ctx.pipeline().get("compress") != null; - if (msg instanceof ByteBuf) { - ByteBuf bytebuf = (ByteBuf) msg; - if (compression) { - // decompress :) - bytebuf = PacketUtil.decompress(ctx, bytebuf); - } - int id = PacketUtil.readVarInt(bytebuf); - // Transform - ByteBuf newPacket = ctx.alloc().buffer(); - try { - outgoingTransformer.transform(id, bytebuf, newPacket); - } catch (CancelException e) { - return; - } finally { - bytebuf.release(); - } - if (compression) { - // recompress :) - newPacket = PacketUtil.compress(ctx, newPacket); - } - msg = newPacket; - } - super.write(ctx, msg, channelPromise); - } catch (Exception e) { - e.printStackTrace(); - } - } - -} diff --git a/src/main/java/us/myles/ViaVersion/handlers/ViaOutboundPacketHandler.java b/src/main/java/us/myles/ViaVersion/handlers/ViaOutboundPacketHandler.java deleted file mode 100644 index 45ed2b823..000000000 --- a/src/main/java/us/myles/ViaVersion/handlers/ViaOutboundPacketHandler.java +++ /dev/null @@ -1,43 +0,0 @@ -package us.myles.ViaVersion.handlers; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.*; -import us.myles.ViaVersion.ConnectionInfo; -import us.myles.ViaVersion.util.ReflectionUtil; - -import java.lang.reflect.Constructor; - -@ChannelHandler.Sharable -public class ViaOutboundPacketHandler extends ChannelOutboundHandlerAdapter { - private final ConnectionInfo info; - - public ViaOutboundPacketHandler(ConnectionInfo info) { - this.info = info; - } - - @Override - public void write(ChannelHandlerContext channelHandlerContext, Object o, ChannelPromise channelPromise) throws Exception { - if (!(o instanceof ByteBuf)) { - info.setLastPacket(o); - /* This transformer is more for fixing issues which we find hard at byte level :) */ - if (o.getClass().getName().endsWith("PacketPlayOutMapChunkBulk")) { - int[] locX = ReflectionUtil.get(o, "a", int[].class); - int[] locZ = ReflectionUtil.get(o, "b", int[].class); - - Object world = ReflectionUtil.get(o, "world", ReflectionUtil.nms("World")); - Class mapChunk = ReflectionUtil.nms("PacketPlayOutMapChunk"); - Constructor constructor = mapChunk.getDeclaredConstructor(ReflectionUtil.nms("Chunk"), boolean.class, int.class); - for (int i = 0; i < locX.length; i++) { - int x = locX[i]; - int z = locZ[i]; - // world invoke function - Object chunk = ReflectionUtil.nms("World").getDeclaredMethod("getChunkAt", int.class, int.class).invoke(world, x, z); - Object packet = constructor.newInstance(chunk, true, 65535); - channelHandlerContext.write(packet); - } - return; - } - } - super.write(channelHandlerContext, o, channelPromise); - } -} diff --git a/src/main/java/us/myles/ViaVersion/handlers/ViaVersionInitializer.java b/src/main/java/us/myles/ViaVersion/handlers/ViaVersionInitializer.java index cb915227a..585ce7c48 100644 --- a/src/main/java/us/myles/ViaVersion/handlers/ViaVersionInitializer.java +++ b/src/main/java/us/myles/ViaVersion/handlers/ViaVersionInitializer.java @@ -3,6 +3,8 @@ package us.myles.ViaVersion.handlers; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.socket.SocketChannel; +import io.netty.handler.codec.ByteToMessageDecoder; +import io.netty.handler.codec.MessageToByteEncoder; import us.myles.ViaVersion.ConnectionInfo; import java.lang.reflect.Method; @@ -27,12 +29,10 @@ public class ViaVersionInitializer extends ChannelInitializer { // Add originals this.method.invoke(this.oldInit, socketChannel); // Add our transformers - ViaInboundHandler inbound = new ViaInboundHandler(info); - ViaOutboundHandler outbound = new ViaOutboundHandler(info); - ViaOutboundPacketHandler outbound2 = new ViaOutboundPacketHandler(info); - socketChannel.pipeline().addBefore("decoder", "via_incoming", inbound); - socketChannel.pipeline().addBefore("packet_handler", "via_outgoing2", outbound2); - socketChannel.pipeline().addBefore("encoder", "via_outgoing", outbound); + ViaEncodeHandler encoder = new ViaEncodeHandler(info, (MessageToByteEncoder) socketChannel.pipeline().get("encoder")); + ViaDecodeHandler decoder = new ViaDecodeHandler(info, (ByteToMessageDecoder) socketChannel.pipeline().get("decoder")); + socketChannel.pipeline().replace("encoder", "encoder", encoder); + socketChannel.pipeline().replace("decoder", "decoder", decoder); } } diff --git a/src/main/java/us/myles/ViaVersion/metadata/MetaIndex.java b/src/main/java/us/myles/ViaVersion/metadata/MetaIndex.java index 20116e829..0224f5401 100644 --- a/src/main/java/us/myles/ViaVersion/metadata/MetaIndex.java +++ b/src/main/java/us/myles/ViaVersion/metadata/MetaIndex.java @@ -88,6 +88,8 @@ public enum MetaIndex { WITHER_TARGET2(Wither.class, 18, Type.Int, 12, NewType.VarInt), WITHER_TARGET3(Wither.class, 19, Type.Int, 13, NewType.VarInt), WITHER_INVULN_TIME(Wither.class, 20, Type.Int, 14, NewType.VarInt), + // wither skull + WITHERSKULL_INVULN(WitherSkull.class, 10, Type.Byte, 5, NewType.Boolean), // guardian GUARDIAN_INFO(Guardian.class, 16, Type.Int, 11, NewType.Byte), GUARDIAN_TARGET(Guardian.class, 17, Type.Int, 12, NewType.VarInt), diff --git a/src/main/java/us/myles/ViaVersion/metadata/MetadataRewriter.java b/src/main/java/us/myles/ViaVersion/metadata/MetadataRewriter.java new file mode 100644 index 000000000..7a4d6770d --- /dev/null +++ b/src/main/java/us/myles/ViaVersion/metadata/MetadataRewriter.java @@ -0,0 +1,183 @@ +package us.myles.ViaVersion.metadata; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; + +import org.bukkit.entity.EntityType; +import org.bukkit.util.EulerAngle; +import org.bukkit.util.Vector; + +import io.netty.buffer.ByteBuf; + +import us.myles.ViaVersion.util.PacketUtil; + +public class MetadataRewriter { + + public static void writeMetadata1_9(EntityType type, List list, ByteBuf output) { + short id = -1; + int data = -1; + Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + Entry entry = iterator.next(); // + MetaIndex metaIndex = entry.index; + try { + if (metaIndex.getNewType() != NewType.Discontinued) { + if (metaIndex.getNewType() != NewType.BlockID || id != -1 && data == -1 || id == -1 && data != -1) { // block ID is only written if we have both parts + output.writeByte(metaIndex.getNewIndex()); + output.writeByte(metaIndex.getNewType().getTypeID()); + } + Object value = entry.value; + switch (metaIndex.getNewType()) { + case Byte: + // convert from int, byte + if (metaIndex.getOldType() == Type.Byte) { + output.writeByte(((Byte) value).byteValue()); + } + if (metaIndex.getOldType() == Type.Int) { + output.writeByte(((Integer) value).byteValue()); + } + break; + case OptUUID: + String owner = (String) value; + UUID toWrite = null; + if (owner.length() != 0) { + try { + toWrite = UUID.fromString(owner); + } catch (Exception ignored) { + } + } + output.writeBoolean(toWrite != null); + if (toWrite != null) + PacketUtil.writeUUID((UUID) toWrite, output); + break; + case BlockID: + // if we have both sources :)) + if (metaIndex.getOldType() == Type.Byte) { + data = ((Byte) value).byteValue(); + } + if (metaIndex.getOldType() == Type.Short) { + id = ((Short) value).shortValue(); + } + if (id != -1 && data != -1) { + int combined = id << 4 | data; + data = -1; + id = -1; + PacketUtil.writeVarInt(combined, output); + } + break; + case VarInt: + // convert from int, short, byte + if (metaIndex.getOldType() == Type.Byte) { + PacketUtil.writeVarInt(((Byte) value).intValue(), output); + } + if (metaIndex.getOldType() == Type.Short) { + PacketUtil.writeVarInt(((Short) value).intValue(), output); + } + if (metaIndex.getOldType() == Type.Int) { + PacketUtil.writeVarInt(((Integer) value).intValue(), output); + } + break; + case Float: + output.writeFloat(((Float) value).floatValue()); + break; + case String: + PacketUtil.writeString((String) value, output); + break; + case Boolean: + output.writeBoolean(((Byte) value).byteValue() != 0); + break; + case Slot: + PacketUtil.writeItem(value, output); + break; + case Position: + Vector vector = (Vector) value; + output.writeInt((int) vector.getX()); + output.writeInt((int) vector.getY()); + output.writeInt((int) vector.getZ()); + break; + case Vector3F: + EulerAngle angle = (EulerAngle) value; + output.writeFloat((float) angle.getX()); + output.writeFloat((float) angle.getY()); + output.writeFloat((float) angle.getZ()); + break; + default: + System.out.println("[Out] Unhandled MetaDataType: " + metaIndex.getNewType()); + break; + } + } + } catch (Exception e) { + if (type != null) { + System.out.println("An error occurred with entity meta data for " + type); + if (metaIndex != null) { + System.out.println("Old ID: " + metaIndex.getIndex() + " New ID: " + metaIndex.getNewIndex()); + System.out.println("Old Type: " + metaIndex.getOldType() + " New Type: " + metaIndex.getNewType()); + } + } + e.printStackTrace(); + } + } + output.writeByte(255); + } + + public static List readMetadata1_8(EntityType entityType, ByteBuf buf) { + List entries = new ArrayList<>(); + byte item; + while ((item = buf.readByte()) != 127) { + Type type = Type.byId((item & 0xE0) >> 5); + int id = item & 0x1F; + MetaIndex index = MetaIndex.getIndex(entityType, id); + switch (type) { + case Byte: + entries.add(new Entry(index, buf.readByte())); + break; + case Short: + entries.add(new Entry(index, buf.readShort())); + break; + case Int: + entries.add(new Entry(index, buf.readInt())); + break; + case Float: + entries.add(new Entry(index, buf.readFloat())); + break; + case String: + entries.add(new Entry(index, PacketUtil.readString(buf))); + break; + case Slot: + entries.add(new Entry(index, PacketUtil.readItem(buf))); + break; + case Position: { + int x = buf.readInt(); + int y = buf.readInt(); + int z = buf.readInt(); + entries.add(new Entry(index, new Vector(x, y, z))); + break; + } + case Rotation: { + float x = buf.readFloat(); + float y = buf.readFloat(); + float z = buf.readFloat(); + entries.add(new Entry(index, new EulerAngle(x, y, z))); + break; + } + default: + System.out.println("[Out] Unhandled MetaDataType: " + type); + break; + } + } + return entries; + } + + public static class Entry { + + private MetaIndex index; + private Object value; + + private Entry(MetaIndex index, Object value) { + this.index = index; + this.value = value; + } + } +} diff --git a/src/main/java/us/myles/ViaVersion/metadata/Type.java b/src/main/java/us/myles/ViaVersion/metadata/Type.java index 48ceb3ac5..94c2300a0 100644 --- a/src/main/java/us/myles/ViaVersion/metadata/Type.java +++ b/src/main/java/us/myles/ViaVersion/metadata/Type.java @@ -18,4 +18,8 @@ public enum Type { public int getTypeID() { return typeID; } + + public static Type byId(int id) { + return values()[id]; + } } diff --git a/src/main/java/us/myles/ViaVersion/packets/PacketType.java b/src/main/java/us/myles/ViaVersion/packets/PacketType.java index 05aa898e8..e0dbd4066 100644 --- a/src/main/java/us/myles/ViaVersion/packets/PacketType.java +++ b/src/main/java/us/myles/ViaVersion/packets/PacketType.java @@ -96,7 +96,7 @@ public enum PacketType { PLAY_COMBAT_EVENT(State.PLAY, Direction.OUTGOING, 0x42, 0x2C), PLAY_PLAYER_LIST_ITEM(State.PLAY, Direction.OUTGOING, 0x38, 0x2D), PLAY_PLAYER_POSITION_LOOK(State.PLAY, Direction.OUTGOING, 0x08, 0x2E), - PLAY_USE_BED(State.PLAY, Direction.OUTGOING, 0x2F, 0x2F), + PLAY_USE_BED(State.PLAY, Direction.OUTGOING, 0x0A, 0x2F), PLAY_DESTROY_ENTITIES(State.PLAY, Direction.OUTGOING, 0x13, 0x30), PLAY_REMOVE_ENTITY_EFFECT(State.PLAY, Direction.OUTGOING, 0x1E, 0x31), PLAY_RESOURCE_PACK_SEND(State.PLAY, Direction.OUTGOING, 0x48, 0x32), diff --git a/src/main/java/us/myles/ViaVersion/transformers/IncomingTransformer.java b/src/main/java/us/myles/ViaVersion/transformers/IncomingTransformer.java index 0fde66d16..b7c99669d 100644 --- a/src/main/java/us/myles/ViaVersion/transformers/IncomingTransformer.java +++ b/src/main/java/us/myles/ViaVersion/transformers/IncomingTransformer.java @@ -45,9 +45,7 @@ public class IncomingTransformer { if (protVer <= 102) { // not 1.9, remove pipes - info.getChannel().pipeline().remove("via_incoming"); - info.getChannel().pipeline().remove("via_outgoing"); - info.getChannel().pipeline().remove("via_outgoing2"); + info.setActive(false); } String serverAddress = PacketUtil.readString(input); PacketUtil.writeString(serverAddress, output); @@ -105,7 +103,7 @@ public class IncomingTransformer { try { Class setSlot = ReflectionUtil.nms("PacketPlayOutSetSlot"); Object setSlotPacket = setSlot.getConstructors()[1].newInstance(windowID, slot, null); - info.getChannel().writeAndFlush(setSlotPacket); // slot is empty + info.getChannel().pipeline().writeAndFlush(setSlotPacket); // slot is empty slot = -999; // we're evil, they'll throw item on the ground } catch (ClassNotFoundException e) { e.printStackTrace(); diff --git a/src/main/java/us/myles/ViaVersion/transformers/OutgoingTransformer.java b/src/main/java/us/myles/ViaVersion/transformers/OutgoingTransformer.java index 9a5dcc412..ceda3a0f8 100644 --- a/src/main/java/us/myles/ViaVersion/transformers/OutgoingTransformer.java +++ b/src/main/java/us/myles/ViaVersion/transformers/OutgoingTransformer.java @@ -10,9 +10,7 @@ import us.myles.ViaVersion.CancelException; import us.myles.ViaVersion.ConnectionInfo; import us.myles.ViaVersion.ViaVersionPlugin; import us.myles.ViaVersion.api.ViaVersion; -import us.myles.ViaVersion.metadata.MetaIndex; -import us.myles.ViaVersion.metadata.NewType; -import us.myles.ViaVersion.metadata.Type; +import us.myles.ViaVersion.metadata.MetadataRewriter; import us.myles.ViaVersion.packets.PacketType; import us.myles.ViaVersion.packets.State; import us.myles.ViaVersion.sounds.SoundEffect; @@ -21,7 +19,6 @@ import us.myles.ViaVersion.util.PacketUtil; import us.myles.ViaVersion.util.ReflectionUtil; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; import java.util.*; import static us.myles.ViaVersion.util.PacketUtil.*; @@ -211,15 +208,7 @@ public class OutgoingTransformer { int id = PacketUtil.readVarInt(input); PacketUtil.writeVarInt(id, output); - try { - List dw = ReflectionUtil.get(info.getLastPacket(), "b", List.class); - // get entity via entityID, not preferred but we need it. - transformMetadata(id, dw, output); - } catch (NoSuchFieldException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } + transformMetadata(id, input, output); return; } @@ -290,7 +279,6 @@ public class OutgoingTransformer { int id = PacketUtil.readVarInt(input); clientEntityTypes.put(id, EntityType.EXPERIENCE_ORB); PacketUtil.writeVarInt(id, output); - double x = input.readInt(); output.writeDouble(x / 32D); double y = input.readInt(); @@ -309,7 +297,6 @@ public class OutgoingTransformer { PacketUtil.writeVarInt(id, output); PacketUtil.writeUUID(getUUID(id), output); - String title = PacketUtil.readString(input); PacketUtil.writeString(title, output); @@ -360,16 +347,8 @@ public class OutgoingTransformer { output.writeShort(vY); short vZ = input.readShort(); output.writeShort(vZ); - try { - Object dataWatcher = ReflectionUtil.get(info.getLastPacket(), "l", ReflectionUtil.nms("DataWatcher")); - transformMetadata(id, dataWatcher, output); - } catch (NoSuchFieldException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } + + transformMetadata(id, input, output); return; } if (packet == PacketType.PLAY_UPDATE_SIGN) { @@ -413,16 +392,11 @@ public class OutgoingTransformer { output.writeByte(pitch); byte yaw = input.readByte(); output.writeByte(yaw); - try { - Object dataWatcher = ReflectionUtil.get(info.getLastPacket(), "i", ReflectionUtil.nms("DataWatcher")); - transformMetadata(id, dataWatcher, output); - } catch (NoSuchFieldException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } + + // next field is Current Item, this was removed in 1.9 so we'll ignore it + input.readShort(); + + transformMetadata(id, input, output); return; } @@ -516,136 +490,15 @@ public class OutgoingTransformer { return line; } - private void transformMetadata(int entityID, Object dw, ByteBuf output) { - // get entity - try { - transformMetadata(entityID, (List) ReflectionUtil.invoke(dw, "b"), output); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - } - - private void transformMetadata(int entityID, List dw, ByteBuf output) { + private void transformMetadata(int entityID, ByteBuf input, ByteBuf output) throws CancelException { EntityType type = clientEntityTypes.get(entityID); if (type == null) { System.out.println("Unable to get entity for ID: " + entityID); + output.writeByte(255); return; } - if (dw != null) { - short id = -1; - int data = -1; - - Iterator iterator = dw.iterator(); - while (iterator.hasNext()) { - Object watchableObj = iterator.next(); // - MetaIndex metaIndex = null; - try { - metaIndex = MetaIndex.getIndex(type, (int) ReflectionUtil.invoke(watchableObj, "a")); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - try { - if (metaIndex.getNewType() != NewType.Discontinued) { - if (metaIndex.getNewType() != NewType.BlockID || id != -1 && data == -1 || id == -1 && data != -1) { // block ID is only written if we have both parts - output.writeByte(metaIndex.getNewIndex()); - output.writeByte(metaIndex.getNewType().getTypeID()); - } - Object value = ReflectionUtil.invoke(watchableObj, "b"); - switch (metaIndex.getNewType()) { - case Byte: - // convert from int, byte - if (metaIndex.getOldType() == Type.Byte) { - output.writeByte(((Byte) value).byteValue()); - } - if (metaIndex.getOldType() == Type.Int) { - output.writeByte(((Integer) value).byteValue()); - } - break; - case OptUUID: - String owner = (String) value; - UUID toWrite = null; - if (owner.length() != 0) { - try { - toWrite = UUID.fromString(owner); - } catch (Exception ignored) { - } - } - output.writeBoolean(toWrite != null); - if (toWrite != null) - PacketUtil.writeUUID((UUID) toWrite, output); - break; - case BlockID: - // if we have both sources :)) - if (metaIndex.getOldType() == Type.Byte) { - data = ((Byte) value).byteValue(); - } - if (metaIndex.getOldType() == Type.Short) { - id = ((Short) value).shortValue(); - } - if (id != -1 && data != -1) { - int combined = id << 4 | data; - data = -1; - id = -1; - PacketUtil.writeVarInt(combined, output); - } - break; - case VarInt: - // convert from int, short, byte - if (metaIndex.getOldType() == Type.Byte) { - PacketUtil.writeVarInt(((Byte) value).intValue(), output); - } - if (metaIndex.getOldType() == Type.Short) { - PacketUtil.writeVarInt(((Short) value).intValue(), output); - } - if (metaIndex.getOldType() == Type.Int) { - PacketUtil.writeVarInt(((Integer) value).intValue(), output); - } - break; - case Float: - output.writeFloat(((Float) value).floatValue()); - break; - case String: - PacketUtil.writeString((String) value, output); - break; - case Boolean: - output.writeBoolean(((Byte) value).byteValue() != 0); - break; - case Slot: - PacketUtil.writeItem(value, output); - break; - case Position: - output.writeInt((int) ReflectionUtil.invoke(value, "getX")); - output.writeInt((int) ReflectionUtil.invoke(value, "getY")); - output.writeInt((int) ReflectionUtil.invoke(value, "getZ")); - break; - case Vector3F: - output.writeFloat((float) ReflectionUtil.invoke(value, "getX")); - output.writeFloat((float) ReflectionUtil.invoke(value, "getY")); - output.writeFloat((float) ReflectionUtil.invoke(value, "getZ")); - } - - } - } catch (Exception e) { - if (type != null) { - System.out.println("An error occurred with entity meta data for " + type); - System.out.println("Old ID: " + metaIndex.getIndex() + " New ID: " + metaIndex.getNewIndex()); - System.out.println("Old Type: " + metaIndex.getOldType() + " New Type: " + metaIndex.getNewType()); - } - e.printStackTrace(); - } - } - } - output.writeByte(255); - - + List list = MetadataRewriter.readMetadata1_8(type, input); + MetadataRewriter.writeMetadata1_9(type, list, output); } diff --git a/src/main/java/us/myles/ViaVersion/util/PacketUtil.java b/src/main/java/us/myles/ViaVersion/util/PacketUtil.java index 8da0ede76..1c2dde784 100644 --- a/src/main/java/us/myles/ViaVersion/util/PacketUtil.java +++ b/src/main/java/us/myles/ViaVersion/util/PacketUtil.java @@ -42,29 +42,38 @@ public class PacketUtil { } } - public static ByteBuf decompress(ChannelHandlerContext ctx, ByteBuf msg) { - ByteToMessageDecoder x = (ByteToMessageDecoder) ctx.pipeline().get("decompress"); + public static List callDecode(ByteToMessageDecoder decoder, ChannelHandlerContext ctx, Object input) { List output = new ArrayList(); try { - PacketUtil.DECODE_METHOD.invoke(x, ctx, msg, output); + PacketUtil.DECODE_METHOD.invoke(decoder, ctx, input, output); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } + return output; + } + + public static void callEncode(MessageToByteEncoder encoder, ChannelHandlerContext ctx, Object msg, ByteBuf output) { + try { + PacketUtil.ENCODE_METHOD.invoke(encoder, ctx, msg, output); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + + public static ByteBuf decompress(ChannelHandlerContext ctx, ByteBuf msg) { + ByteToMessageDecoder x = (ByteToMessageDecoder) ctx.pipeline().get("decompress"); + List output = callDecode(x, ctx, msg); return output.size() == 0 ? null : (ByteBuf) output.get(0); } public static ByteBuf compress(ChannelHandlerContext ctx, ByteBuf msg) { MessageToByteEncoder x = (MessageToByteEncoder) ctx.pipeline().get("compress"); ByteBuf output = ctx.alloc().buffer(); - try { - PacketUtil.ENCODE_METHOD.invoke(x, ctx, msg, output); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } + callEncode(x, ctx, msg, output); return output; } @@ -185,9 +194,9 @@ public class PacketUtil { } public static void writeVarIntArray(List integers, ByteBuf output) { - writeVarInt(integers.size(),output); - for (Integer i : integers){ - writeVarInt(i,output); + writeVarInt(integers.size(), output); + for (Integer i : integers) { + writeVarInt(i, output); } } @@ -364,6 +373,26 @@ public class PacketUtil { } } + public static Object readItem(ByteBuf output) { + try { + Class serializer = ReflectionUtil.nms("PacketDataSerializer"); + Object init = serializer.getDeclaredConstructor(ByteBuf.class).newInstance(output); + Method toCall = init.getClass().getDeclaredMethod("i"); + return toCall.invoke(init); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } + return null; + } + public static long[] readBlockPosition(ByteBuf buf) { long val = buf.readLong(); long x = (val >> 38); // signed diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 5f2537806..59982eef5 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,4 +1,6 @@ name: ViaVersion main: us.myles.ViaVersion.ViaVersionPlugin author: _MylesC -version: 0.3.7 \ No newline at end of file +version: 0.4.5 +load: startup +loadbefore: [ProtocolLib, ProxyPipe] \ No newline at end of file