diff --git a/README.md b/README.md index 1d23ee72c..3680556e1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ViaVersion 0.3.3 +# ViaVersion 0.3.7 **Allows the connection of 1.8 clients to 1.9** This plugin modifies netty to allow connection of 1.9 clients to 1.8, @@ -13,9 +13,6 @@ Remap spawn eggs If you have a bug with entities, please report the full stack trace -Some items with JSON data cause crashing due to the change in how strict minecraft is. - - This took hours of work, so if you enjoy this consider looking into contacting me and supporting my projects. @@ -32,10 +29,12 @@ Contributors: **Myself** (harhar) -**Matsv/StatBoom** +**Matsv/StamBoom** **HugoDaBosss** +**SanderGielisse** + License: -------- diff --git a/src/main/java/org/spacehq/mc/protocol/data/game/chunk/BlockStorage.java b/src/main/java/org/spacehq/mc/protocol/data/game/chunk/BlockStorage.java index 273b195d6..055991c5f 100644 --- a/src/main/java/org/spacehq/mc/protocol/data/game/chunk/BlockStorage.java +++ b/src/main/java/org/spacehq/mc/protocol/data/game/chunk/BlockStorage.java @@ -1,7 +1,7 @@ package org.spacehq.mc.protocol.data.game.chunk; import io.netty.buffer.ByteBuf; -import us.myles.ViaVersion.PacketUtil; +import us.myles.ViaVersion.util.PacketUtil; import java.io.IOException; import java.util.ArrayList; diff --git a/src/main/java/org/spacehq/mc/protocol/util/NetUtil.java b/src/main/java/org/spacehq/mc/protocol/util/NetUtil.java index f8f332ccf..67dad9ce0 100644 --- a/src/main/java/org/spacehq/mc/protocol/util/NetUtil.java +++ b/src/main/java/org/spacehq/mc/protocol/util/NetUtil.java @@ -39,7 +39,7 @@ public class NetUtil { public static Column readOldChunkData(int x, int z, boolean isFullChunk, int bitmask, byte[] input, boolean checkForSky, boolean hasSkyLight) { int pos = 0; - int expected = 0; + int expected = isFullChunk ? 256 : 0; boolean sky = false; ShortBuffer buf = ByteBuffer.wrap(input).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer(); // 0 = Calculate expected length and determine if the packet has skylight. @@ -85,7 +85,7 @@ public class NetUtil { } if(pass == 3) { - if(chunks[ind].getSkyLight() != null) { + if(sky) { NibbleArray3d skylight = chunks[ind].getSkyLight(); System.arraycopy(input, pos, skylight.getData(), 0, skylight.getData().length); pos += skylight.getData().length; diff --git a/src/main/java/us/myles/ViaVersion/ConnectionInfo.java b/src/main/java/us/myles/ViaVersion/ConnectionInfo.java index bdb0651cd..7e1dd89cb 100644 --- a/src/main/java/us/myles/ViaVersion/ConnectionInfo.java +++ b/src/main/java/us/myles/ViaVersion/ConnectionInfo.java @@ -1,5 +1,6 @@ package us.myles.ViaVersion; +import io.netty.channel.socket.SocketChannel; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import us.myles.ViaVersion.packets.State; @@ -7,12 +8,17 @@ import us.myles.ViaVersion.packets.State; 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; + public ConnectionInfo(SocketChannel socketChannel) { + this.channel = socketChannel; + } + public int getProtocol() { return protocol; } @@ -56,4 +62,8 @@ public class ConnectionInfo { public Player getPlayer() { return UUID == null ? null : Bukkit.getPlayer(UUID); } + + public SocketChannel getChannel() { + return channel; + } } diff --git a/src/main/java/us/myles/ViaVersion/Core.java b/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java similarity index 70% rename from src/main/java/us/myles/ViaVersion/Core.java rename to src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java index cff6755f8..20af1c3d3 100644 --- a/src/main/java/us/myles/ViaVersion/Core.java +++ b/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java @@ -8,18 +8,32 @@ 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; +import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.java.JavaPlugin; -import us.myles.ViaVersion.handlers.ViaVersionInitializer; +import us.myles.ViaVersion.api.ViaVersion; +import us.myles.ViaVersion.api.ViaVersionAPI; +import us.myles.ViaVersion.handlers.ViaVersionInitializer; +import us.myles.ViaVersion.util.ReflectionUtil; + +import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; -public class Core extends JavaPlugin { +public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI { + + private final Set portedPlayers = Collections.newSetFromMap(new ConcurrentHashMap()); + @Override public void onEnable() { + ViaVersion.setInstance(this); System.out.println("ViaVersion enabled, injecting. (Allows 1.8 to be accessed via 1.9)"); try { injectPacketHandler(); @@ -30,6 +44,12 @@ public class Core extends JavaPlugin { System.out.println("Unable to inject handlers, are you on 1.8? "); e.printStackTrace(); } + Bukkit.getPluginManager().registerEvents(new Listener() { + @EventHandler + public void onPlayerQuit(PlayerQuitEvent e) { + setPorted(e.getPlayer().getUniqueId(), false); + } + }, this); } public void injectPacketHandler() throws Exception { @@ -51,32 +71,22 @@ public class Core extends JavaPlugin { } } + @Override + public boolean isPorted(Player player) { + return portedPlayers.contains(player.getUniqueId()); + } - public static Entity getEntity(final UUID player, final int id) { - try { - return Bukkit.getScheduler().callSyncMethod(getPlugin(Core.class), new Callable() { - @Override - public Entity call() throws Exception { - Player p = Bukkit.getPlayer(player); - if (p == null) return null; - for (Entity e : p.getWorld().getEntities()) { - if (e.getEntityId() == id) { - return e; - } - } - return null; - } - }).get(10, TimeUnit.SECONDS); - } catch (Exception e) { - System.out.println("Error fetching entity "); - e.printStackTrace(); - return null; + public void setPorted(UUID id, boolean value) { + if (value) { + portedPlayers.add(id); + } else { + portedPlayers.remove(id); } } public static ItemStack getHandItem(final ConnectionInfo info) { try { - return Bukkit.getScheduler().callSyncMethod(getPlugin(Core.class), new Callable() { + return Bukkit.getScheduler().callSyncMethod(getPlugin(ViaVersionPlugin.class), new Callable() { @Override public ItemStack call() throws Exception { if (info.getPlayer() != null) { diff --git a/src/main/java/us/myles/ViaVersion/api/ViaVersion.java b/src/main/java/us/myles/ViaVersion/api/ViaVersion.java new file mode 100644 index 000000000..857e2ab86 --- /dev/null +++ b/src/main/java/us/myles/ViaVersion/api/ViaVersion.java @@ -0,0 +1,17 @@ +package us.myles.ViaVersion.api; + +public class ViaVersion { + + private static ViaVersionAPI INSTANCE; + + public static void setInstance(ViaVersionAPI api) { + if (INSTANCE != null) { + throw new IllegalStateException("Instance already set."); + } + INSTANCE = api; + } + + public static ViaVersionAPI getInstance() { + return INSTANCE; + } +} diff --git a/src/main/java/us/myles/ViaVersion/api/ViaVersionAPI.java b/src/main/java/us/myles/ViaVersion/api/ViaVersionAPI.java new file mode 100644 index 000000000..cdccc80ce --- /dev/null +++ b/src/main/java/us/myles/ViaVersion/api/ViaVersionAPI.java @@ -0,0 +1,8 @@ +package us.myles.ViaVersion.api; + +import org.bukkit.entity.Player; + +public interface ViaVersionAPI { + + boolean isPorted(Player player); +} diff --git a/src/main/java/us/myles/ViaVersion/handlers/ViaInboundHandler.java b/src/main/java/us/myles/ViaVersion/handlers/ViaInboundHandler.java index 5751b99b0..8423e5dc4 100644 --- a/src/main/java/us/myles/ViaVersion/handlers/ViaInboundHandler.java +++ b/src/main/java/us/myles/ViaVersion/handlers/ViaInboundHandler.java @@ -7,17 +7,15 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; import us.myles.ViaVersion.CancelException; import us.myles.ViaVersion.ConnectionInfo; -import us.myles.ViaVersion.PacketUtil; +import us.myles.ViaVersion.util.PacketUtil; import us.myles.ViaVersion.transformers.IncomingTransformer; @ChannelHandler.Sharable public class ViaInboundHandler extends ChannelInboundHandlerAdapter { private final IncomingTransformer incomingTransformer; - private final ViaVersionInitializer init; - public ViaInboundHandler(Channel c, ConnectionInfo info, ViaVersionInitializer init) { - this.init = init; - this.incomingTransformer = new IncomingTransformer(c, info, init); + public ViaInboundHandler(ConnectionInfo info) { + this.incomingTransformer = new IncomingTransformer(info); } @Override diff --git a/src/main/java/us/myles/ViaVersion/handlers/ViaOutboundHandler.java b/src/main/java/us/myles/ViaVersion/handlers/ViaOutboundHandler.java index 428fce04d..c42b00dfb 100644 --- a/src/main/java/us/myles/ViaVersion/handlers/ViaOutboundHandler.java +++ b/src/main/java/us/myles/ViaVersion/handlers/ViaOutboundHandler.java @@ -4,17 +4,17 @@ import io.netty.buffer.ByteBuf; import io.netty.channel.*; import us.myles.ViaVersion.CancelException; import us.myles.ViaVersion.ConnectionInfo; -import us.myles.ViaVersion.PacketUtil; +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 ViaVersionInitializer init; + private final ConnectionInfo info; - public ViaOutboundHandler(Channel c, ConnectionInfo info, ViaVersionInitializer init) { - this.init = init; - this.outgoingTransformer = new OutgoingTransformer(c, info, init); + public ViaOutboundHandler(ConnectionInfo info) { + this.info = info; + this.outgoingTransformer = new OutgoingTransformer(info); } @Override diff --git a/src/main/java/us/myles/ViaVersion/handlers/ViaOutboundPacketHandler.java b/src/main/java/us/myles/ViaVersion/handlers/ViaOutboundPacketHandler.java index 29f6b889d..45ed2b823 100644 --- a/src/main/java/us/myles/ViaVersion/handlers/ViaOutboundPacketHandler.java +++ b/src/main/java/us/myles/ViaVersion/handlers/ViaOutboundPacketHandler.java @@ -3,7 +3,7 @@ package us.myles.ViaVersion.handlers; import io.netty.buffer.ByteBuf; import io.netty.channel.*; import us.myles.ViaVersion.ConnectionInfo; -import us.myles.ViaVersion.ReflectionUtil; +import us.myles.ViaVersion.util.ReflectionUtil; import java.lang.reflect.Constructor; @@ -11,7 +11,7 @@ import java.lang.reflect.Constructor; public class ViaOutboundPacketHandler extends ChannelOutboundHandlerAdapter { private final ConnectionInfo info; - public ViaOutboundPacketHandler(Channel c, ConnectionInfo info) { + public ViaOutboundPacketHandler(ConnectionInfo info) { this.info = info; } diff --git a/src/main/java/us/myles/ViaVersion/handlers/ViaVersionInitializer.java b/src/main/java/us/myles/ViaVersion/handlers/ViaVersionInitializer.java index 5bf25b7b5..cb915227a 100644 --- a/src/main/java/us/myles/ViaVersion/handlers/ViaVersionInitializer.java +++ b/src/main/java/us/myles/ViaVersion/handlers/ViaVersionInitializer.java @@ -10,11 +10,6 @@ import java.lang.reflect.Method; public class ViaVersionInitializer extends ChannelInitializer { private final ChannelInitializer oldInit; private Method method; - private ConnectionInfo info; - private ViaInboundHandler inbound; - private ViaOutboundHandler outbound; - private SocketChannel socketChannel; - private ViaOutboundPacketHandler outbound2; public ViaVersionInitializer(ChannelInitializer oldInit) { this.oldInit = oldInit; @@ -28,24 +23,16 @@ public class ViaVersionInitializer extends ChannelInitializer { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { - info = new ConnectionInfo(); + ConnectionInfo info = new ConnectionInfo(socketChannel); // Add originals this.method.invoke(this.oldInit, socketChannel); // Add our transformers - this.socketChannel = socketChannel; - this.inbound = new ViaInboundHandler(socketChannel, info, this); - this.outbound = new ViaOutboundHandler(socketChannel, info, this); - this.outbound2 = new ViaOutboundPacketHandler(socketChannel, info); - socketChannel.pipeline().addBefore("decoder", "via_incoming", this.inbound); - socketChannel.pipeline().addBefore("packet_handler", "via_outgoing2", this.outbound2); - socketChannel.pipeline().addBefore("encoder", "via_outgoing", this.outbound); + 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); } - - public void remove(){ - socketChannel.pipeline().remove("via_incoming"); - socketChannel.pipeline().remove("via_outgoing"); - socketChannel.pipeline().remove("via_outgoing2"); - } - } diff --git a/src/main/java/us/myles/ViaVersion/metadata/MetaIndex.java b/src/main/java/us/myles/ViaVersion/metadata/MetaIndex.java index 50df771af..20116e829 100644 --- a/src/main/java/us/myles/ViaVersion/metadata/MetaIndex.java +++ b/src/main/java/us/myles/ViaVersion/metadata/MetaIndex.java @@ -72,7 +72,7 @@ public enum MetaIndex { // creeper CREEPER_FUSE(Creeper.class, 16, Type.Byte, 11, NewType.VarInt), // -1 idle, 1 is fuse CREEPER_ISPOWERED(Creeper.class, 17, Type.Byte, 12, NewType.Boolean), - CREEPER_ISIGNITED(Creeper.class, 18, Type.Byte, 13, NewType.Boolean), // TODO: Write on wiki.vg for current prot + CREEPER_ISIGNITED(Creeper.class, 18, Type.Byte, 13, NewType.Boolean), // ghast GHAST_ISATTACKING(Ghast.class, 16, Type.Byte, 11, NewType.Boolean), // slime @@ -89,7 +89,7 @@ public enum MetaIndex { WITHER_TARGET3(Wither.class, 19, Type.Int, 13, NewType.VarInt), WITHER_INVULN_TIME(Wither.class, 20, Type.Int, 14, NewType.VarInt), // guardian - GUARDIAN_INFO(Guardian.class, 16, Type.Byte, 11, NewType.Byte), + GUARDIAN_INFO(Guardian.class, 16, Type.Int, 11, NewType.Byte), GUARDIAN_TARGET(Guardian.class, 17, Type.Int, 12, NewType.VarInt), // boat BOAT_SINCEHIT(Boat.class, 17, Type.Int, 5, NewType.VarInt), @@ -159,16 +159,6 @@ public enum MetaIndex { return this.clazz; } - public static MetaIndex getIndex(Entity entity, int index) { - EntityType type; - if (entity instanceof Player) { - type = EntityType.PLAYER; - } else { - type = entity.getType(); - } - return getIndex(type, index); - } - public static MetaIndex getIndex(EntityType type, int index) { Class entityClass = type.getEntityClass(); if(entityClass == null){ diff --git a/src/main/java/us/myles/ViaVersion/packets/PacketType.java b/src/main/java/us/myles/ViaVersion/packets/PacketType.java index 052485fea..05aa898e8 100644 --- a/src/main/java/us/myles/ViaVersion/packets/PacketType.java +++ b/src/main/java/us/myles/ViaVersion/packets/PacketType.java @@ -20,7 +20,7 @@ public enum PacketType { /* Play serverbound */ PLAY_TP_CONFIRM(State.PLAY, Direction.INCOMING, -1, 0x00), PLAY_TAB_COMPLETE_REQUEST(State.PLAY, Direction.INCOMING, 0x14, 0x01), - PLAY_CLICHAT_MESSAGE_CLIENT(State.PLAY, Direction.INCOMING, 0x01, 0x02), + PLAY_CHAT_MESSAGE_CLIENT(State.PLAY, Direction.INCOMING, 0x01, 0x02), PLAY_CLIENT_STATUS(State.PLAY, Direction.INCOMING, 0x16, 0x03), PLAY_CLIENT_SETTINGS(State.PLAY, Direction.INCOMING, 0x15, 0x04), PLAY_CONFIRM_TRANS(State.PLAY, Direction.INCOMING, 0x0F, 0x05), diff --git a/src/main/java/us/myles/ViaVersion/transformers/IncomingTransformer.java b/src/main/java/us/myles/ViaVersion/transformers/IncomingTransformer.java index 9fa56fc9b..0fde66d16 100644 --- a/src/main/java/us/myles/ViaVersion/transformers/IncomingTransformer.java +++ b/src/main/java/us/myles/ViaVersion/transformers/IncomingTransformer.java @@ -1,28 +1,23 @@ package us.myles.ViaVersion.transformers; import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; - -import org.bukkit.Material; import org.bukkit.inventory.ItemStack; - -import us.myles.ViaVersion.*; -import us.myles.ViaVersion.handlers.ViaVersionInitializer; +import us.myles.ViaVersion.CancelException; +import us.myles.ViaVersion.ConnectionInfo; +import us.myles.ViaVersion.ViaVersionPlugin; import us.myles.ViaVersion.packets.PacketType; import us.myles.ViaVersion.packets.State; +import us.myles.ViaVersion.util.PacketUtil; +import us.myles.ViaVersion.util.ReflectionUtil; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class IncomingTransformer { - private final Channel channel; private final ConnectionInfo info; - private final ViaVersionInitializer init; - public IncomingTransformer(Channel channel, ConnectionInfo info, ViaVersionInitializer init) { - this.channel = channel; + public IncomingTransformer(ConnectionInfo info) { this.info = info; - this.init = init; } public void transform(int packetID, ByteBuf input, ByteBuf output) throws CancelException { @@ -49,8 +44,10 @@ public class IncomingTransformer { PacketUtil.writeVarInt(protVer <= 102 ? protVer : 47, output); // pretend to be older if (protVer <= 102) { - // Not 1.9 remove pipes - this.init.remove(); + // not 1.9, remove pipes + info.getChannel().pipeline().remove("via_incoming"); + info.getChannel().pipeline().remove("via_outgoing"); + info.getChannel().pipeline().remove("via_outgoing2"); } String serverAddress = PacketUtil.readString(input); PacketUtil.writeString(serverAddress, output); @@ -108,7 +105,7 @@ public class IncomingTransformer { try { Class setSlot = ReflectionUtil.nms("PacketPlayOutSetSlot"); Object setSlotPacket = setSlot.getConstructors()[1].newInstance(windowID, slot, null); - channel.writeAndFlush(setSlotPacket); // slot is empty + info.getChannel().writeAndFlush(setSlotPacket); // slot is empty slot = -999; // we're evil, they'll throw item on the ground } catch (ClassNotFoundException e) { e.printStackTrace(); @@ -178,7 +175,7 @@ public class IncomingTransformer { output.writeByte(face); int hand = PacketUtil.readVarInt(input); - ItemStack inHand = Core.getHandItem(info); + ItemStack inHand = ViaVersionPlugin.getHandItem(info); Object item = null; try { Method m = ReflectionUtil.obc("inventory.CraftItemStack").getDeclaredMethod("asNMSCopy", ItemStack.class); @@ -205,12 +202,12 @@ public class IncomingTransformer { } if (packet == PacketType.PLAY_USE_ITEM) { output.clear(); - PacketUtil.writeVarInt(PacketType.PLAY_PLAYER_BLOCK_PLACEMENT.getPacketID(), output); - // Simulate using item :) - output.writeLong(-1L); - output.writeByte(255); - // write item in hand - ItemStack inHand = Core.getHandItem(info); + PacketUtil.writeVarInt(PacketType.PLAY_PLAYER_BLOCK_PLACEMENT.getPacketID(), output); + // Simulate using item :) + output.writeLong(-1L); + output.writeByte(255); + // write item in hand + ItemStack inHand = ViaVersionPlugin.getHandItem(info); Object item = null; try { Method m = ReflectionUtil.obc("inventory.CraftItemStack").getDeclaredMethod("asNMSCopy", ItemStack.class); @@ -225,10 +222,10 @@ public class IncomingTransformer { e.printStackTrace(); } PacketUtil.writeItem(item, output); - - output.writeByte(-1); - output.writeByte(-1); - output.writeByte(-1); + + output.writeByte(-1); + output.writeByte(-1); + output.writeByte(-1); return; } output.writeBytes(input); diff --git a/src/main/java/us/myles/ViaVersion/transformers/OutgoingTransformer.java b/src/main/java/us/myles/ViaVersion/transformers/OutgoingTransformer.java index 7a40a28ff..9a5dcc412 100644 --- a/src/main/java/us/myles/ViaVersion/transformers/OutgoingTransformer.java +++ b/src/main/java/us/myles/ViaVersion/transformers/OutgoingTransformer.java @@ -2,43 +2,40 @@ package us.myles.ViaVersion.transformers; import com.google.gson.Gson; import com.google.gson.JsonObject; - import io.netty.buffer.ByteBuf; -import io.netty.channel.Channel; - -import org.bukkit.Bukkit; -import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.spacehq.mc.protocol.data.game.chunk.Column; import org.spacehq.mc.protocol.util.NetUtil; - -import us.myles.ViaVersion.*; -import us.myles.ViaVersion.handlers.ViaVersionInitializer; +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.sounds.SoundEffect; import us.myles.ViaVersion.metadata.Type; import us.myles.ViaVersion.packets.PacketType; import us.myles.ViaVersion.packets.State; +import us.myles.ViaVersion.sounds.SoundEffect; +import us.myles.ViaVersion.util.EntityUtil; +import us.myles.ViaVersion.util.PacketUtil; +import us.myles.ViaVersion.util.ReflectionUtil; import java.io.IOException; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.*; -import static us.myles.ViaVersion.PacketUtil.*; +import static us.myles.ViaVersion.util.PacketUtil.*; public class OutgoingTransformer { private static Gson gson = new Gson(); - private final Channel channel; private final ConnectionInfo info; - private final ViaVersionInitializer init; + private final ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance(); private boolean cancel = false; private Map uuidMap = new HashMap(); + private Map clientEntityTypes = new HashMap(); - public OutgoingTransformer(Channel channel, ConnectionInfo info, ViaVersionInitializer init) { - this.channel = channel; + public OutgoingTransformer(ConnectionInfo info) { this.info = info; - this.init = init; } public void transform(int packetID, ByteBuf input, ByteBuf output) throws CancelException { @@ -60,14 +57,13 @@ public class OutgoingTransformer { // By default no transform PacketUtil.writeVarInt(packetID, output); if (packet == PacketType.PLAY_NAMED_SOUND_EFFECT) { - String name = PacketUtil.readString(input); + String name = PacketUtil.readString(input); SoundEffect effect = SoundEffect.getByName(name); int catid = 0; String newname = name; - if(effect != null) - { - catid = effect.getCategory().getId(); - newname = effect.getNewName(); + if (effect != null) { + catid = effect.getCategory().getId(); + newname = effect.getNewName(); } PacketUtil.writeString(newname, output); PacketUtil.writeVarInt(catid, output); @@ -77,22 +73,37 @@ public class OutgoingTransformer { int passenger = input.readInt(); int vehicle = input.readInt(); boolean lead = input.readBoolean(); - if (!lead){ + if (!lead) { output.clear(); - writeVarInt(PacketType.PLAY_SET_PASSENGERS.getNewPacketID(),output); - writeVarInt(vehicle,output); - writeVarIntArray(Collections.singletonList(passenger),output); + writeVarInt(PacketType.PLAY_SET_PASSENGERS.getNewPacketID(), output); + writeVarInt(vehicle, output); + writeVarIntArray(Collections.singletonList(passenger), output); return; } output.writeInt(passenger); output.writeInt(vehicle); return; } - if (packet == PacketType.PLAY_DISCONNECT){ + if (packet == PacketType.PLAY_DISCONNECT) { String reason = readString(input); - if (reason.startsWith("\"")) - reason = "{\"text\":" + reason + "}"; - writeString(reason,output); + writeString(fixJson(reason), output); + return; + } + if (packet == PacketType.PLAY_TITLE) { + int action = PacketUtil.readVarInt(input); + PacketUtil.writeVarInt(action, output); + if (action == 0 || action == 1) { + String text = PacketUtil.readString(input); + PacketUtil.writeString(fixJson(text), output); + } + output.writeBytes(input); + return; + } + if (packet == PacketType.PLAY_PLAYER_LIST_HEADER_FOOTER) { + String header = readString(input); + String footer = readString(input); + writeString(fixJson(header), output); + writeString(fixJson(footer), output); return; } if (packet == PacketType.PLAY_ENTITY_TELEPORT) { @@ -173,7 +184,9 @@ public class OutgoingTransformer { if (packet == PacketType.LOGIN_SUCCESS) { String uu = PacketUtil.readString(input); PacketUtil.writeString(uu, output); - info.setUUID(UUID.fromString(uu)); + UUID uniqueId = UUID.fromString(uu); + info.setUUID(uniqueId); + plugin.setPorted(uniqueId, true); output.writeBytes(input); return; } @@ -201,13 +214,7 @@ public class OutgoingTransformer { try { List dw = ReflectionUtil.get(info.getLastPacket(), "b", List.class); // get entity via entityID, not preferred but we need it. - Entity entity = Core.getEntity(info.getUUID(), id); - if (entity != null) { - transformMetadata(entity, dw, output); - } else { - // Died before we could get to it. rip - throw new CancelException(); - } + transformMetadata(id, dw, output); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { @@ -215,13 +222,42 @@ public class OutgoingTransformer { } return; } - if (packet == PacketType.PLAY_SPAWN_OBJECT) { + + if (packet == PacketType.PLAY_SPAWN_GLOBAL_ENTITY) { int id = PacketUtil.readVarInt(input); PacketUtil.writeVarInt(id, output); + // only used for lightning + byte type = input.readByte(); + clientEntityTypes.put(id, EntityType.LIGHTNING); + output.writeByte(type); + + double x = input.readInt(); + output.writeDouble(x / 32D); + double y = input.readInt(); + output.writeDouble(y / 32D); + double z = input.readInt(); + output.writeDouble(z / 32D); + return; + } + if (packet == PacketType.PLAY_DESTROY_ENTITIES) { + int count = PacketUtil.readVarInt(input); + PacketUtil.writeVarInt(count, output); + + int[] toDestroy = PacketUtil.readVarInts(count, input); + for (int entityID : toDestroy) { + clientEntityTypes.remove(entityID); + PacketUtil.writeVarInt(entityID, output); + } + return; + } + if (packet == PacketType.PLAY_SPAWN_OBJECT) { + int id = PacketUtil.readVarInt(input); + PacketUtil.writeVarInt(id, output); PacketUtil.writeUUID(getUUID(id), output); byte type = input.readByte(); + clientEntityTypes.put(id, EntityUtil.getTypeFromID(type, true)); output.writeByte(type); double x = input.readInt(); @@ -237,13 +273,12 @@ public class OutgoingTransformer { int data = input.readInt(); output.writeInt(data); - + short vX = 0, vY = 0, vZ = 0; - if(data > 0) - { - vX = input.readShort(); - vY = input.readShort(); - vZ = input.readShort(); + if (data > 0) { + vX = input.readShort(); + vY = input.readShort(); + vZ = input.readShort(); } output.writeShort(vX); output.writeShort(vY); @@ -251,8 +286,9 @@ public class OutgoingTransformer { return; } - if (packet == PacketType.PLAY_SPAWN_XP_ORB) { // TODO: Verify + if (packet == PacketType.PLAY_SPAWN_XP_ORB) { int id = PacketUtil.readVarInt(input); + clientEntityTypes.put(id, EntityType.EXPERIENCE_ORB); PacketUtil.writeVarInt(id, output); double x = input.readInt(); @@ -267,13 +303,44 @@ public class OutgoingTransformer { return; } + if (packet == PacketType.PLAY_SPAWN_PAINTING) { + int id = PacketUtil.readVarInt(input); + clientEntityTypes.put(id, EntityType.PAINTING); + PacketUtil.writeVarInt(id, output); + + PacketUtil.writeUUID(getUUID(id), output); + + String title = PacketUtil.readString(input); + PacketUtil.writeString(title, output); + + long[] position = PacketUtil.readBlockPosition(input); + PacketUtil.writeBlockPosition(output, position[0], position[1], position[2]); + + byte direction = input.readByte(); + output.writeByte(direction); + + return; + } + if (packet == PacketType.PLAY_OPEN_WINDOW) { + int windowId = input.readUnsignedByte(); + String type = readString(input); + String windowTitle = readString(input); + + output.writeByte(windowId); + writeString(type, output); + writeString(fixJson(windowTitle), output); + output.writeBytes(input); + return; + } if (packet == PacketType.PLAY_SPAWN_MOB) { int id = PacketUtil.readVarInt(input); PacketUtil.writeVarInt(id, output); PacketUtil.writeUUID(getUUID(id), output); short type = input.readUnsignedByte(); + clientEntityTypes.put(id, EntityUtil.getTypeFromID(type, false)); output.writeByte(type); + double x = input.readInt(); output.writeDouble(x / 32D); double y = input.readInt(); @@ -295,7 +362,7 @@ public class OutgoingTransformer { output.writeShort(vZ); try { Object dataWatcher = ReflectionUtil.get(info.getLastPacket(), "l", ReflectionUtil.nms("DataWatcher")); - transformMetadata(dataWatcher, output); + transformMetadata(id, dataWatcher, output); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { @@ -310,21 +377,28 @@ public class OutgoingTransformer { output.writeLong(location); for (int i = 0; i < 4; i++) { String line = PacketUtil.readString(input); - if (line == null || line.equalsIgnoreCase("null")) { - line = "{\"text\":\"\"}"; - } else { - if (!line.startsWith("\"") && !line.startsWith("{")) - line = "\"" + line + "\""; - if (line.startsWith("\"")) - line = "{\"text\":" + line + "}"; - } - PacketUtil.writeString(line, output); + PacketUtil.writeString(fixJson(line), output); } } + if (packet == PacketType.PLAY_CHAT_MESSAGE) { + String chat = PacketUtil.readString(input); + PacketUtil.writeString(fixJson(chat), output); + + byte pos = input.readByte(); + output.writeByte(pos); + return; + } + if (packet == PacketType.PLAY_JOIN_GAME) { + int id = input.readInt(); + clientEntityTypes.put(id, EntityType.PLAYER); + output.writeInt(id); + output.writeBytes(input); + return; + } if (packet == PacketType.PLAY_SPAWN_PLAYER) { int id = PacketUtil.readVarInt(input); PacketUtil.writeVarInt(id, output); - + clientEntityTypes.put(id, EntityType.PLAYER); UUID playerUUID = PacketUtil.readUUID(input); PacketUtil.writeUUID(playerUUID, output); @@ -341,7 +415,7 @@ public class OutgoingTransformer { output.writeByte(yaw); try { Object dataWatcher = ReflectionUtil.get(info.getLastPacket(), "i", ReflectionUtil.nms("DataWatcher")); - transformMetadata(dataWatcher, output); + transformMetadata(id, dataWatcher, output); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { @@ -352,7 +426,7 @@ public class OutgoingTransformer { return; } - if(packet == PacketType.PLAY_MAP) { + if (packet == PacketType.PLAY_MAP) { int damage = PacketUtil.readVarInt(input); PacketUtil.writeVarInt(damage, output); byte scale = input.readByte(); @@ -430,30 +504,37 @@ public class OutgoingTransformer { output.writeBytes(input); } - private void transformMetadata(Object dw, ByteBuf output) { + private String fixJson(String line) { + if (line == null || line.equalsIgnoreCase("null")) { + line = "{\"text\":\"\"}"; + } else { + if (!line.startsWith("\"") && !line.startsWith("{")) + line = "\"" + line + "\""; + if (line.startsWith("\"")) + line = "{\"text\":" + line + "}"; + } + return line; + } + + private void transformMetadata(int entityID, Object dw, ByteBuf output) { // get entity try { - Class nmsClass = ReflectionUtil.nms("Entity"); - Object nmsEntity = ReflectionUtil.get(dw, "a", nmsClass); - Class craftClass = ReflectionUtil.obc("entity.CraftEntity"); - Method bukkitMethod = craftClass.getDeclaredMethod("getEntity", ReflectionUtil.obc("CraftServer"), nmsClass); - - Object entity = bukkitMethod.invoke(null, Bukkit.getServer(), nmsEntity); - transformMetadata((Entity) entity, (List) ReflectionUtil.invoke(dw, "b"), output); - } catch (NoSuchFieldException e) { - e.printStackTrace(); + transformMetadata(entityID, (List) ReflectionUtil.invoke(dw, "b"), output); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); } } - private void transformMetadata(Entity entity, List dw, ByteBuf output) { + private void transformMetadata(int entityID, List dw, ByteBuf output) { + EntityType type = clientEntityTypes.get(entityID); + if (type == null) { + System.out.println("Unable to get entity for ID: " + entityID); + return; + } if (dw != null) { short id = -1; int data = -1; @@ -463,7 +544,7 @@ public class OutgoingTransformer { Object watchableObj = iterator.next(); // MetaIndex metaIndex = null; try { - metaIndex = MetaIndex.getIndex(entity, (int) ReflectionUtil.invoke(watchableObj, "a")); + metaIndex = MetaIndex.getIndex(type, (int) ReflectionUtil.invoke(watchableObj, "a")); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { @@ -553,8 +634,8 @@ public class OutgoingTransformer { } } catch (Exception e) { - if (entity != null) { - System.out.println("An error occurred with entity meta data for " + entity.getType()); + 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()); } diff --git a/src/main/java/us/myles/ViaVersion/util/EntityUtil.java b/src/main/java/us/myles/ViaVersion/util/EntityUtil.java new file mode 100644 index 000000000..8095e4722 --- /dev/null +++ b/src/main/java/us/myles/ViaVersion/util/EntityUtil.java @@ -0,0 +1,91 @@ +package us.myles.ViaVersion.util; + +import org.bukkit.entity.EntityType; + +public class EntityUtil { + public static EntityType getTypeFromID(int typeID, boolean isObject) { + if (isObject) { + return getObjectFromID(typeID); + } else { + return EntityType.fromId(typeID); + } + } + + // based on http://wiki.vg/index.php?title=Entities + public static EntityType getObjectFromID(int objectID) { + EntityType type; + switch (objectID) { + case 2: + type = EntityType.DROPPED_ITEM; + break; + case 77: + type = EntityType.LEASH_HITCH; + break; + case 60: + type = EntityType.ARROW; + break; + case 61: + type = EntityType.SNOWBALL; + break; + case 63: + type = EntityType.FIREBALL; + break; + case 64: + type = EntityType.SMALL_FIREBALL; + break; + case 65: + type = EntityType.ENDER_PEARL; + break; + case 72: + type = EntityType.ENDER_SIGNAL; + break; + case 75: + type = EntityType.THROWN_EXP_BOTTLE; + break; + case 71: + type = EntityType.ITEM_FRAME; + break; + case 66: + type = EntityType.WITHER_SKULL; + break; + case 50: + type = EntityType.PRIMED_TNT; + break; + case 70: + type = EntityType.FALLING_BLOCK; + break; + case 76: + type = EntityType.FIREWORK; + break; + case 78: + type = EntityType.ARMOR_STAND; + break; + case 1: + type = EntityType.BOAT; + break; + case 10: + type = EntityType.MINECART; + break; + case 51: + type = EntityType.ENDER_CRYSTAL; + break; + case 73: + type = EntityType.SPLASH_POTION; + break; + case 62: + type = EntityType.EGG; + break; + case 90: + type = EntityType.FISHING_HOOK; + break; + default: + type = EntityType.fromId(objectID); + if (type == null) { + System.out.println("Unable to find entity type for " + objectID); + type = EntityType.UNKNOWN; + } + break; + } + return type; + } +} diff --git a/src/main/java/us/myles/ViaVersion/PacketUtil.java b/src/main/java/us/myles/ViaVersion/util/PacketUtil.java similarity index 94% rename from src/main/java/us/myles/ViaVersion/PacketUtil.java rename to src/main/java/us/myles/ViaVersion/util/PacketUtil.java index cacd6929a..8da0ede76 100644 --- a/src/main/java/us/myles/ViaVersion/PacketUtil.java +++ b/src/main/java/us/myles/ViaVersion/util/PacketUtil.java @@ -1,4 +1,4 @@ -package us.myles.ViaVersion; +package us.myles.ViaVersion.util; import com.google.common.base.Charsets; import com.google.common.base.Preconditions; @@ -363,4 +363,26 @@ public class PacketUtil { e.printStackTrace(); } } + + public static long[] readBlockPosition(ByteBuf buf) { + long val = buf.readLong(); + long x = (val >> 38); // signed + long y = (val >> 26) & 0xfff; // unsigned + // this shifting madness is used to preserve sign + long z = (val << 38) >> 38; // signed + return new long[]{x, y, z}; + } + + public static void writeBlockPosition(ByteBuf buf, long x, long y, long z) { + buf.writeLong(((x & 0x3ffffff) << 38) | ((y & 0xfff) << 26) | (z & 0x3ffffff)); + } + + public static int[] readVarInts(int amount, ByteBuf input) { + int data[] = new int[amount]; + for (int index = 0; index < amount; index++) { + data[index] = PacketUtil.readVarInt(input); + } + + return data; + } } diff --git a/src/main/java/us/myles/ViaVersion/ReflectionUtil.java b/src/main/java/us/myles/ViaVersion/util/ReflectionUtil.java similarity index 97% rename from src/main/java/us/myles/ViaVersion/ReflectionUtil.java rename to src/main/java/us/myles/ViaVersion/util/ReflectionUtil.java index a77c32ed0..e5f19187e 100644 --- a/src/main/java/us/myles/ViaVersion/ReflectionUtil.java +++ b/src/main/java/us/myles/ViaVersion/util/ReflectionUtil.java @@ -1,4 +1,4 @@ -package us.myles.ViaVersion; +package us.myles.ViaVersion.util; import org.bukkit.Bukkit; diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 4dcca77dc..5f2537806 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,4 +1,4 @@ name: ViaVersion -main: us.myles.ViaVersion.Core +main: us.myles.ViaVersion.ViaVersionPlugin author: _MylesC -version: 0.3.3 \ No newline at end of file +version: 0.3.7 \ No newline at end of file