mirror of
https://github.com/ViaVersion/ViaVersion.git
synced 2024-11-22 10:05:12 +01:00
Merge branch 'master' of https://github.com/HugoDaBosss/ViaVersion
This commit is contained in:
commit
f15e11272a
@ -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:
|
||||
--------
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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<ChannelFuture> 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) {
|
||||
|
@ -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<Object> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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<SocketChannel> {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
|
183
src/main/java/us/myles/ViaVersion/metadata/MetadataRewriter.java
Normal file
183
src/main/java/us/myles/ViaVersion/metadata/MetadataRewriter.java
Normal file
@ -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<Entry> list, ByteBuf output) {
|
||||
short id = -1;
|
||||
int data = -1;
|
||||
Iterator<Entry> 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<Entry> readMetadata1_8(EntityType entityType, ByteBuf buf) {
|
||||
List<Entry> 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -18,4 +18,8 @@ public enum Type {
|
||||
public int getTypeID() {
|
||||
return typeID;
|
||||
}
|
||||
|
||||
public static Type byId(int id) {
|
||||
return values()[id];
|
||||
}
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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();
|
||||
|
@ -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<MetadataRewriter.Entry> list = MetadataRewriter.readMetadata1_8(type, input);
|
||||
MetadataRewriter.writeMetadata1_9(type, list, output);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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<Object> callDecode(ByteToMessageDecoder decoder, ChannelHandlerContext ctx, Object input) {
|
||||
List<Object> output = new ArrayList<Object>();
|
||||
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<Object> 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<Integer> 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
|
||||
|
@ -1,4 +1,6 @@
|
||||
name: ViaVersion
|
||||
main: us.myles.ViaVersion.ViaVersionPlugin
|
||||
author: _MylesC
|
||||
version: 0.3.7
|
||||
version: 0.4.5
|
||||
load: startup
|
||||
loadbefore: [ProtocolLib, ProxyPipe]
|
Loading…
Reference in New Issue
Block a user