diff --git a/src/main/java/us/myles/ViaVersion/ConnectionInfo.java b/src/main/java/us/myles/ViaVersion/ConnectionInfo.java index dd1db8b1c..1ee032a6b 100644 --- a/src/main/java/us/myles/ViaVersion/ConnectionInfo.java +++ b/src/main/java/us/myles/ViaVersion/ConnectionInfo.java @@ -78,8 +78,13 @@ public class ConnectionInfo { this.active = active; } - public void sendRawPacket(ByteBuf packet) { - ChannelHandler handler = channel.pipeline().get("encoder"); - channel.pipeline().context(handler).writeAndFlush(packet); + public void sendRawPacket(final ByteBuf packet) { + final ChannelHandler handler = channel.pipeline().get("encoder"); + channel.eventLoop().submit(new Runnable() { + @Override + public void run() { + channel.pipeline().context(handler).writeAndFlush(packet); + } + }); } } diff --git a/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java b/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java index e21122dc9..a84e350bc 100644 --- a/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java +++ b/src/main/java/us/myles/ViaVersion/ViaVersionPlugin.java @@ -15,9 +15,9 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.java.JavaPlugin; import us.myles.ViaVersion.api.ViaVersion; import us.myles.ViaVersion.api.ViaVersionAPI; +import us.myles.ViaVersion.armor.ArmorListener; import us.myles.ViaVersion.commands.ViaVersionCommand; import us.myles.ViaVersion.handlers.ViaVersionInitializer; -import us.myles.ViaVersion.listeners.ArmorFix; import us.myles.ViaVersion.util.ReflectionUtil; import java.lang.reflect.Field; @@ -48,13 +48,16 @@ public class ViaVersionPlugin extends JavaPlugin implements ViaVersionAPI { getLogger().severe("Unable to inject handlers, are you on 1.8? "); e.printStackTrace(); } + Bukkit.getPluginManager().registerEvents(new Listener() { @EventHandler public void onPlayerQuit(PlayerQuitEvent e) { removePortedClient(e.getPlayer().getUniqueId()); } }, this); - Bukkit.getPluginManager().registerEvents(new ArmorFix(), this); + + Bukkit.getPluginManager().registerEvents(new ArmorListener(this), this); + getCommand("viaversion").setExecutor(new ViaVersionCommand()); } diff --git a/src/main/java/us/myles/ViaVersion/armor/ArmorListener.java b/src/main/java/us/myles/ViaVersion/armor/ArmorListener.java new file mode 100644 index 000000000..a86542f5d --- /dev/null +++ b/src/main/java/us/myles/ViaVersion/armor/ArmorListener.java @@ -0,0 +1,106 @@ +package us.myles.ViaVersion.armor; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.bukkit.Bukkit; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.inventory.CraftingInventory; +import us.myles.ViaVersion.ViaVersionPlugin; +import us.myles.ViaVersion.api.ViaVersion; +import us.myles.ViaVersion.packets.PacketType; + +import java.util.UUID; + +import static us.myles.ViaVersion.util.PacketUtil.*; + +public class ArmorListener implements Listener { + + private final ViaVersionPlugin plugin; + + private static UUID armorAttribute = UUID.fromString("2AD3F246-FEE1-4E67-B886-69FD380BB150"); + + public ArmorListener(ViaVersionPlugin plugin) { + this.plugin = plugin; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onInventoryClick(InventoryClickEvent e) { + HumanEntity human = e.getWhoClicked(); + if (human instanceof Player && e.getInventory() instanceof CraftingInventory) { + final Player player = (Player) human; + if (ViaVersion.getInstance().isPorted(player)) { + if (e.getCurrentItem() != null) { + if (ArmorType.isArmor(e.getCurrentItem().getType())) { + sendDelayedArmorUpdate(player); + return; + } + } + if (e.getRawSlot() >= 5 && e.getRawSlot() <= 8) { + sendDelayedArmorUpdate(player); + return; + } + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onInteract(PlayerInteractEvent e) { + if (e.getItem() != null) { + if (e.getAction() == Action.RIGHT_CLICK_AIR || e.getAction() == Action.RIGHT_CLICK_BLOCK) { + if (ArmorType.isArmor(e.getMaterial())) { + final Player player = e.getPlayer(); + // Due to odd bugs it's 3 ticks later + Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { + @Override + public void run() { + if (ViaVersion.getInstance().isPorted(player)) { + sendArmorUpdate(player); + } + } + }, 3L); + } + } + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onJoin(PlayerJoinEvent e) { + sendDelayedArmorUpdate(e.getPlayer()); + } + + public void sendDelayedArmorUpdate(final Player player) { + Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { + @Override + public void run() { + if (ViaVersion.getInstance().isPorted(player)) { + sendArmorUpdate(player); + } + } + }); + } + + public static void sendArmorUpdate(Player player) { + int armor = ArmorType.calculateArmorPoints(player.getInventory().getArmorContents()); + + ByteBuf buf = Unpooled.buffer(); + writeVarInt(PacketType.PLAY_ENTITY_PROPERTIES.getNewPacketID(), buf); + writeVarInt(player.getEntityId(), buf); + buf.writeInt(1); // only 1 property + writeString("generic.armor", buf); + buf.writeDouble(0); //default 0 armor + writeVarInt(1, buf); // 1 modifier + writeUUID(armorAttribute, buf); // armor modifier uuid + buf.writeDouble((double) armor); // the modifier value + buf.writeByte(0); // the modifier operation, 0 is add number + + ViaVersion.getInstance().sendRawPacket(player, buf); + } +} \ No newline at end of file diff --git a/src/main/java/us/myles/ViaVersion/armor/ArmorType.java b/src/main/java/us/myles/ViaVersion/armor/ArmorType.java new file mode 100644 index 000000000..23f0bda44 --- /dev/null +++ b/src/main/java/us/myles/ViaVersion/armor/ArmorType.java @@ -0,0 +1,91 @@ +package us.myles.ViaVersion.armor; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +public enum ArmorType { + + LEATHER_HELMET(1, 298, Material.LEATHER_HELMET), + LEATHER_CHESTPLATE(3, 299, Material.LEATHER_CHESTPLATE), + LEATHER_LEGGINGS(2, 300, Material.LEATHER_LEGGINGS), + LEATHER_BOOTS(1, 301, Material.LEATHER_BOOTS), + CHAINMAIL_HELMET(2, 302, Material.CHAINMAIL_HELMET), + CHAINMAIL_CHESTPLATE(5, 303, Material.CHAINMAIL_CHESTPLATE), + CHAINMAIL_LEGGINGS(4, 304, Material.CHAINMAIL_LEGGINGS), + CHAINMAIL_BOOTS(1, 305, Material.CHAINMAIL_BOOTS), + IRON_HELMET(2, 306, Material.IRON_HELMET), + IRON_CHESTPLATE(6, 307, Material.IRON_CHESTPLATE), + IRON_LEGGINGS(5, 308, Material.IRON_LEGGINGS), + IRON_BOOTS(2, 309, Material.IRON_BOOTS), + DIAMOND_HELMET(3, 310, Material.DIAMOND_HELMET), + DIAMOND_CHESTPLATE(8, 311, Material.DIAMOND_CHESTPLATE), + DIAMOND_LEGGINGS(6, 312, Material.DIAMOND_LEGGINGS), + DIAMOND_BOOTS(3, 313, Material.DIAMOND_BOOTS), + GOLD_HELMET(2, 314, Material.GOLD_HELMET), + GOLD_CHESTPLATE(5, 315, Material.GOLD_CHESTPLATE), + GOLD_LEGGINGS(3, 316, Material.GOLD_LEGGINGS), + GOLD_BOOTS(1, 317, Material.GOLD_BOOTS), + NONE(0, 0, Material.AIR); + + private int armorpoints; + private int id; + private Material type; + + ArmorType(int armor, int id, Material type) { + this.armorpoints = armor; + this.id = id; + this.type = type; + } + + public int getArmorPoints() { + return this.armorpoints; + } + + public int getId() { + return this.id; + } + + public Material getType() { + return this.type; + } + + public static ArmorType findByType(Material type) { + for(ArmorType a : ArmorType.values()) + if(a.getType() == type) + return a; + return ArmorType.NONE; + } + + public static int calculateArmorPoints(ItemStack[] armor) { + int total = 0; + for(int i = 0; i < armor.length; i++) { + if(armor[i] != null) + total += findByType(armor[i].getType()).getArmorPoints(); + } + return total; + } + + public static ArmorType findById(int id) { + for(ArmorType a : ArmorType.values()) + if(a.getId() == id) + return a; + return ArmorType.NONE; + } + + public static boolean isArmor(Material material){ + for(ArmorType a : ArmorType.values()) + if(a.getType() == material) + return true; + return false; + } + + public static int calculateArmorPoints(int[] armor) { + int total = 0; + for(int i = 0; i < armor.length; i++) { + if(armor[i] != -1) + total += findById(armor[i]).getArmorPoints(); + } + return total; + } + +} \ No newline at end of file diff --git a/src/main/java/us/myles/ViaVersion/transformers/IncomingTransformer.java b/src/main/java/us/myles/ViaVersion/transformers/IncomingTransformer.java index bc4549e85..64fbcf1d3 100644 --- a/src/main/java/us/myles/ViaVersion/transformers/IncomingTransformer.java +++ b/src/main/java/us/myles/ViaVersion/transformers/IncomingTransformer.java @@ -1,26 +1,21 @@ package us.myles.ViaVersion.transformers; -import com.avaje.ebeaninternal.server.cluster.Packet; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; -import org.spacehq.opennbt.tag.builtin.ListTag; -import org.spacehq.opennbt.tag.builtin.StringTag; -import org.spacehq.opennbt.tag.builtin.Tag; import us.myles.ViaVersion.CancelException; import us.myles.ViaVersion.ConnectionInfo; import us.myles.ViaVersion.ViaVersionPlugin; -import us.myles.ViaVersion.slot.ItemSlotRewriter; import us.myles.ViaVersion.packets.PacketType; import us.myles.ViaVersion.packets.State; +import us.myles.ViaVersion.slot.ItemSlotRewriter; import us.myles.ViaVersion.util.PacketUtil; import us.myles.ViaVersion.util.ReflectionUtil; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.nio.charset.Charset; public class IncomingTransformer { private final ConnectionInfo info; @@ -108,6 +103,7 @@ public class IncomingTransformer { byte button = input.readByte(); short action = input.readShort(); byte mode = input.readByte(); + // if the action is on an elytra armour slot if (slot == 45 && windowID == 0) { try { Class setSlot = ReflectionUtil.nms("PacketPlayOutSetSlot"); diff --git a/src/main/java/us/myles/ViaVersion/transformers/OutgoingTransformer.java b/src/main/java/us/myles/ViaVersion/transformers/OutgoingTransformer.java index 9609fc1f5..46fcf0556 100644 --- a/src/main/java/us/myles/ViaVersion/transformers/OutgoingTransformer.java +++ b/src/main/java/us/myles/ViaVersion/transformers/OutgoingTransformer.java @@ -1,17 +1,12 @@ package us.myles.ViaVersion.transformers; import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import org.bukkit.Material; import org.bukkit.entity.EntityType; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; import org.json.simple.parser.ParseException; import org.spacehq.mc.protocol.data.game.chunk.Column; import org.spacehq.mc.protocol.util.NetUtil; -import org.spacehq.opennbt.tag.builtin.ListTag; -import org.spacehq.opennbt.tag.builtin.StringTag; -import org.spacehq.opennbt.tag.builtin.Tag; import us.myles.ViaVersion.CancelException; import us.myles.ViaVersion.ConnectionInfo; import us.myles.ViaVersion.ViaVersionPlugin; @@ -34,6 +29,7 @@ public class OutgoingTransformer { private final ConnectionInfo info; private final ViaVersionPlugin plugin = (ViaVersionPlugin) ViaVersion.getInstance(); private boolean cancel = false; + private Map uuidMap = new HashMap(); private Map clientEntityTypes = new HashMap(); private Map vehicleMap = new HashMap<>(); @@ -268,7 +264,7 @@ public class OutgoingTransformer { PacketUtil.writeString(uu, output); UUID uniqueId = UUID.fromString(uu); info.setUUID(uniqueId); - plugin.setPorted(uniqueId, true); + plugin.addPortedClient(info); output.writeBytes(input); return; } @@ -412,7 +408,6 @@ public class OutgoingTransformer { short slot = input.readShort(); output.writeShort(slot); - ItemSlotRewriter.rewrite1_8To1_9(input, output); return; }