diff --git a/src/main/java/us/myles/ViaVersion/listeners/CommandBlockListener.java b/src/main/java/us/myles/ViaVersion/listeners/CommandBlockListener.java index afb6878a7..aea3e95c3 100644 --- a/src/main/java/us/myles/ViaVersion/listeners/CommandBlockListener.java +++ b/src/main/java/us/myles/ViaVersion/listeners/CommandBlockListener.java @@ -1,6 +1,7 @@ package us.myles.ViaVersion.listeners; import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufOutputStream; import io.netty.buffer.Unpooled; import lombok.RequiredArgsConstructor; import org.bukkit.block.Block; @@ -12,12 +13,15 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerJoinEvent; +import org.spacehq.opennbt.tag.builtin.ByteTag; +import org.spacehq.opennbt.tag.builtin.CompoundTag; import us.myles.ViaVersion.ViaVersionPlugin; import us.myles.ViaVersion.packets.PacketType; import us.myles.ViaVersion.util.PacketUtil; import us.myles.ViaVersion.util.ReflectionUtil; -import java.lang.reflect.InvocationTargetException; +import java.io.DataOutput; +import java.io.DataOutputStream; import java.lang.reflect.Method; @RequiredArgsConstructor @@ -41,22 +45,58 @@ public class CommandBlockListener implements Listener { if (e.getAction() == Action.RIGHT_CLICK_BLOCK && plugin.isPorted(e.getPlayer()) && e.getPlayer().isOp()) { try { sendCommandBlockPacket(e.getClickedBlock(), e.getPlayer()); - } catch (NoSuchFieldException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | ClassNotFoundException e1) { - e1.printStackTrace(); + } catch (Exception ex) { + ex.printStackTrace(); } } } - private void sendCommandBlockPacket(Block b, Player player) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException { + private void sendCommandBlockPacket(Block b, Player player) throws Exception { if (!(b.getState() instanceof CommandBlock)) return; CommandBlock cmd = (CommandBlock) b.getState(); Object tileEntityCommand = ReflectionUtil.get(cmd, "commandBlock", ReflectionUtil.nms("TileEntityCommand")); Object updatePacket = ReflectionUtil.invoke(tileEntityCommand, "getUpdatePacket"); - Object nmsPlayer = ReflectionUtil.invoke(player, "getHandle"); - Object playerConnection = ReflectionUtil.get(nmsPlayer, "playerConnection", ReflectionUtil.nms("PlayerConnection")); - Method sendPacket = playerConnection.getClass().getMethod("sendPacket", ReflectionUtil.nms("Packet")); - sendPacket.invoke(playerConnection, updatePacket); //Let the transformer do the work + ByteBuf buf = packetToByteBuf(updatePacket); + plugin.sendRawPacket(player, buf); + } + + private ByteBuf packetToByteBuf(Object updatePacket) throws Exception { + ByteBuf buf = Unpooled.buffer(); + PacketUtil.writeVarInt(PacketType.PLAY_UPDATE_BLOCK_ENTITY.getNewPacketID(), buf); //Packet ID + long[] pos = getPosition(ReflectionUtil.get(updatePacket, "a", ReflectionUtil.nms("BlockPosition"))); + PacketUtil.writeBlockPosition(buf, pos[0], pos[1], pos[2]); //Block position + buf.writeByte(2); //Action id always 2 + CompoundTag nbt = getNBT(ReflectionUtil.get(updatePacket, "c", ReflectionUtil.nms("NBTTagCompound"))); + if (nbt == null) { + buf.writeByte(0); //If nbt is null. Use 0 as nbt + return buf; + } + nbt.put(new ByteTag("powered", (byte) 0)); + nbt.put(new ByteTag("auto", (byte) 0)); + nbt.put(new ByteTag("conditionMet", (byte) 0)); + PacketUtil.writeNBT(buf, nbt); //NBT tag + return buf; + } + + private long[] getPosition(Object obj) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { + return new long[]{ + (long) ReflectionUtil.getSuper(obj, "a", int.class), //X + (long) ReflectionUtil.getSuper(obj, "c", int.class), //Y + (long) ReflectionUtil.getSuper(obj, "d", int.class) //Z + }; + } + + private CompoundTag getNBT(Object obj) throws Exception { + ByteBuf buf = Unpooled.buffer(); + Method m = ReflectionUtil.nms("NBTCompressedStreamTools").getMethod("a", ReflectionUtil.nms("NBTTagCompound"), DataOutput.class); + m.invoke(null, obj, new DataOutputStream(new ByteBufOutputStream(buf))); + try { + return PacketUtil.readNBT(buf); + } finally { + buf.release(); + } } } + diff --git a/src/main/java/us/myles/ViaVersion/transformers/OutgoingTransformer.java b/src/main/java/us/myles/ViaVersion/transformers/OutgoingTransformer.java index 26827c52f..d1db0e8c8 100644 --- a/src/main/java/us/myles/ViaVersion/transformers/OutgoingTransformer.java +++ b/src/main/java/us/myles/ViaVersion/transformers/OutgoingTransformer.java @@ -759,20 +759,7 @@ public class OutgoingTransformer { return; } if (action == 2) { //Update commandblock - try { - CompoundTag nbt = readNBT(input); - if (nbt == null) - throw new CancelException(); - //Thanks http://www.minecraftforum.net/forums/minecraft-discussion/redstone-discussion-and/command-blocks/2488148-1-9-nbt-changes-and-additions#TileAllCommandBlocks - nbt.put(new ByteTag("powered", (byte) 0)); - nbt.put(new ByteTag("auto", (byte) 0)); - nbt.put(new ByteTag("conditionMet", (byte) 0)); - writeNBT(output, nbt); - return; - } catch (IOException e) { - e.printStackTrace(); - throw new CancelException(); - } + throw new CancelException(); //Only update if player interact with commandblock (The commandblock window will update every time this packet is sent, this would prevent you from change things that update every tick) } output.writeBytes(input, input.readableBytes()); return; diff --git a/src/main/java/us/myles/ViaVersion/util/ReflectionUtil.java b/src/main/java/us/myles/ViaVersion/util/ReflectionUtil.java index ba9aa5005..59c2c2096 100644 --- a/src/main/java/us/myles/ViaVersion/util/ReflectionUtil.java +++ b/src/main/java/us/myles/ViaVersion/util/ReflectionUtil.java @@ -37,6 +37,12 @@ public class ReflectionUtil { return (T) field.get(null); } + public static T getSuper(Object o, String f, Class t) throws NoSuchFieldException, IllegalAccessException { + Field field = o.getClass().getSuperclass().getDeclaredField(f); + field.setAccessible(true); + return (T) field.get(o); + } + public static T get(Object instance, Class clazz, String f, Class t) throws NoSuchFieldException, IllegalAccessException { Field field = clazz.getDeclaredField(f); field.setAccessible(true);