diff --git a/src/main/java/me/libraryaddict/disguise/DisguiseAPI.java b/src/main/java/me/libraryaddict/disguise/DisguiseAPI.java index 80255622..a596bbe3 100644 --- a/src/main/java/me/libraryaddict/disguise/DisguiseAPI.java +++ b/src/main/java/me/libraryaddict/disguise/DisguiseAPI.java @@ -63,7 +63,7 @@ public class DisguiseAPI { if (doEquipment && entity instanceof LivingEntity) { EntityEquipment equip = ((LivingEntity) entity).getEquipment(); watcher.setArmor(equip.getArmorContents()); - watcher.setItemInHand(equip.getItemInHand()); + watcher.setItemInMainHand(equip.getItemInMainHand()); if (disguiseType.getEntityType() == EntityType.HORSE) { Horse horse = (Horse) entity; HorseInventory horseInventory = horse.getInventory(); diff --git a/src/main/java/me/libraryaddict/disguise/LibsDisguises.java b/src/main/java/me/libraryaddict/disguise/LibsDisguises.java index d1493643..c1244d40 100644 --- a/src/main/java/me/libraryaddict/disguise/LibsDisguises.java +++ b/src/main/java/me/libraryaddict/disguise/LibsDisguises.java @@ -228,8 +228,16 @@ public class LibsDisguises extends JavaPlugin { for (WrappedWatchableObject watch : watcher.getWatchableObjects()) { disguiseValues.setMetaValue(watch.getIndex(), watch.getValue()); // Uncomment when I need to find the new datawatcher values for a class.. -// System.out.print("Disguise: " + disguiseType + ", ID: " + watch.getIndex() + ", Class: " -// + (watch.getValue() == null ? "null" : watch.getValue().getClass()) + ", Value: " + watch.getValue()); + //TODO: Recomment this section when finished + int id = watch.getIndex(); + Object val = watch.getValue(); + Class valClazz = val != null ? watch.getValue().getClass() : null; + try { + val = val.toString(); + } catch (Exception e) { + val = val != null ? val.getClass() : "null"; + } + System.out.println("Disguise: " + disguiseType + ", ID: " + id + ", Class: " + (val == null ? "null" : valClazz) + ", Value: " + val); } DisguiseSound sound = DisguiseSound.getType(disguiseType.name()); if (sound != null) { diff --git a/src/main/java/me/libraryaddict/disguise/disguisetypes/FlagWatcher.java b/src/main/java/me/libraryaddict/disguise/disguisetypes/FlagWatcher.java index 81e120d4..8920074e 100644 --- a/src/main/java/me/libraryaddict/disguise/disguisetypes/FlagWatcher.java +++ b/src/main/java/me/libraryaddict/disguise/disguisetypes/FlagWatcher.java @@ -13,6 +13,7 @@ import me.libraryaddict.disguise.utilities.ReflectionManager; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import java.lang.reflect.InvocationTargetException; @@ -23,35 +24,21 @@ import java.util.List; public class FlagWatcher { - public enum SlotType { - - BOOTS(0), CHESTPLATE(2), HELD_ITEM(4), HELMET(3), LEGGINGS(1); - // The ints is for bukkit. Not nms slots. - private int slotNo = 0; - - SlotType(int no) { - slotNo = no; - } - - public int getSlot() { - return slotNo; - } - } - private boolean addEntityAnimations = DisguiseConfig.isEntityAnimationsAdded(); /** - * This is the entity values I need to add else it could crash them.. + * These are the entity values I need to add else it could crash them.. */ private HashMap backupEntityValues = new HashMap<>(); private TargetedDisguise disguise; private HashMap entityValues = new HashMap<>(); private boolean hasDied; - private ItemStack[] items = new ItemStack[5]; + public EntityEquipment equipment; private HashSet modifiedEntityAnimations = new HashSet<>(); private List watchableObjects; public FlagWatcher(Disguise disguise) { this.disguise = (TargetedDisguise) disguise; + equipment = ReflectionManager.createEntityEquipment(disguise.getEntity()); } private byte addEntityAnimations(byte originalValue, byte entityValue) { @@ -74,7 +61,7 @@ public class FlagWatcher { cloned = new FlagWatcher(getDisguise()); } cloned.entityValues = (HashMap) entityValues.clone(); - cloned.items = items.clone(); + cloned.equipment = ReflectionManager.createEntityEquipment(cloned.getDisguise().getEntity()); cloned.modifiedEntityAnimations = (HashSet) modifiedEntityAnimations.clone(); cloned.addEntityAnimations = addEntityAnimations; return cloned; @@ -160,7 +147,7 @@ public class FlagWatcher { public ItemStack[] getArmor() { ItemStack[] armor = new ItemStack[4]; - System.arraycopy(items, 0, armor, 0, 4); + System.arraycopy(armor, 0, armor, 0, 4); return armor; } @@ -176,16 +163,18 @@ public class FlagWatcher { return ((byte) getValue(0, (byte) 0) & 1 << byteValue) != 0; } - public ItemStack getItemInHand() { - return getItemStack(SlotType.HELD_ITEM); + public ItemStack getItemInMainHand() { + if (equipment == null) return null; + return equipment.getItemInMainHand(); } - public ItemStack getItemStack(int slot) { - return items[slot]; + public ItemStack getItemInOffHand() { + if (equipment == null) return null; + return equipment.getItemInOffHand(); } - public ItemStack getItemStack(SlotType slot) { - return getItemStack(slot.getSlot()); + public EntityEquipment getEquipment() { + return equipment; } protected Object getValue(int no, Object backup) { @@ -289,9 +278,10 @@ public class FlagWatcher { } public void setArmor(ItemStack[] itemstack) { - for (int i = 0; i < itemstack.length; i++) { - setItemStack(i, itemstack[i]); - } + setItemStack(EquipmentSlot.HEAD, itemstack[0]); + setItemStack(EquipmentSlot.CHEST, itemstack[1]); + setItemStack(EquipmentSlot.LEGS, itemstack[2]); + setItemStack(EquipmentSlot.FEET, itemstack[3]); } protected void setBackupValue(int no, Object value) { @@ -331,41 +321,43 @@ public class FlagWatcher { sendData(0); } + /** + * Don't use this, use setItemInMainHand instead + * @param itemstack + */ + @Deprecated public void setItemInHand(ItemStack itemstack) { - setItemStack(SlotType.HELD_ITEM, itemstack); + setItemInMainHand(itemstack); } - public void setItemStack(int slot, ItemStack itemStack) { + public void setItemInMainHand(ItemStack itemstack) { + setItemStack(EquipmentSlot.HAND, itemstack); + } + + public void setItemInOffHand(ItemStack itemstack) { + setItemStack(EquipmentSlot.OFF_HAND, itemstack); + } + + public void setItemStack(EquipmentSlot slot, ItemStack itemStack) { + if (equipment == null) return; // Itemstack which is null means that its not replacing the disguises itemstack. if (itemStack == null) { // Find the item to replace it with if (getDisguise().getEntity() instanceof LivingEntity) { EntityEquipment equipment = ((LivingEntity) getDisguise().getEntity()).getEquipment(); - if (slot == 4) { - itemStack = equipment.getItemInHand(); - } else { - itemStack = equipment.getArmorContents()[slot]; - } - if (itemStack != null && itemStack.getTypeId() == 0) { - itemStack = null; - } + setItemStack(equipment, slot, itemStack); } } - Object itemToSend = null; if (itemStack != null && itemStack.getTypeId() != 0) { itemToSend = ReflectionManager.getNmsItem(itemStack); } - items[slot] = itemStack; + setItemStack(equipment, slot, itemStack); if (DisguiseAPI.isDisguiseInUse(getDisguise()) && getDisguise().getWatcher() == this) { - slot++; - if (slot > 4) { - slot = 0; - } PacketContainer packet = new PacketContainer(Server.ENTITY_EQUIPMENT); StructureModifier mods = packet.getModifier(); mods.write(0, getDisguise().getEntity().getEntityId()); - mods.write(1, slot); + mods.write(1, ReflectionManager.createEnumItemSlot(slot)); mods.write(2, itemToSend); for (Player player : DisguiseUtilities.getPerverts(getDisguise())) { try { @@ -377,8 +369,47 @@ public class FlagWatcher { } } - public void setItemStack(SlotType slot, ItemStack itemStack) { - setItemStack(slot.getSlot(), itemStack); + private void setItemStack(EntityEquipment equipment, EquipmentSlot slot, ItemStack itemStack) { + if (equipment == null) return; + switch (slot) { + case CHEST: + equipment.setChestplate(itemStack); + break; + case FEET: + equipment.setBoots(itemStack); + break; + case HAND: + equipment.setItemInMainHand(itemStack); + break; + case HEAD: + equipment.setHelmet(itemStack); + break; + case LEGS: + equipment.setLeggings(itemStack); + break; + case OFF_HAND: + equipment.setItemInOffHand(itemStack); + break; + } + } + + public ItemStack getItemStack(EquipmentSlot slot) { + if (equipment == null) return null; + switch (slot) { + case CHEST: + return equipment.getChestplate(); + case FEET: + return equipment.getBoots(); + case HAND: + return equipment.getItemInMainHand(); + case HEAD: + return equipment.getHelmet(); + case LEGS: + return equipment.getLeggings(); + case OFF_HAND: + return equipment.getItemInOffHand(); + } + return null; } public void setRightClicking(boolean setRightClicking) { diff --git a/src/main/java/me/libraryaddict/disguise/disguisetypes/watchers/EndermanWatcher.java b/src/main/java/me/libraryaddict/disguise/disguisetypes/watchers/EndermanWatcher.java index a08e6554..fc14ad11 100644 --- a/src/main/java/me/libraryaddict/disguise/disguisetypes/watchers/EndermanWatcher.java +++ b/src/main/java/me/libraryaddict/disguise/disguisetypes/watchers/EndermanWatcher.java @@ -10,7 +10,7 @@ public class EndermanWatcher extends LivingWatcher { } @Override - public ItemStack getItemInHand() { + public ItemStack getItemInMainHand() { return new ItemStack((byte) getValue(16, (byte) 0), 1, ((byte) getValue(17, (byte) 0))); } @@ -18,23 +18,13 @@ public class EndermanWatcher extends LivingWatcher { return (byte) getValue(18, (byte) 0) == 1; } - @Deprecated - public boolean isAgressive() { - return isAggressive(); - } - public void setAggressive(boolean isAggressive) { setValue(18, (byte) (isAggressive ? 1 : 0)); sendData(18); } - @Deprecated - public void setAgressive(boolean isAgressive) { - setAggressive(isAgressive); - } - @Override - public void setItemInHand(ItemStack itemstack) { + public void setItemInMainHand(ItemStack itemstack) { setValue(16, (short) (itemstack.getTypeId() & 255)); setValue(17, (byte) (itemstack.getDurability() & 255)); } diff --git a/src/main/java/me/libraryaddict/disguise/utilities/DisguiseUtilities.java b/src/main/java/me/libraryaddict/disguise/utilities/DisguiseUtilities.java index 6c582cb1..04b834c3 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/DisguiseUtilities.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/DisguiseUtilities.java @@ -6,6 +6,9 @@ import com.comphenix.protocol.ProtocolManager; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.wrappers.WrappedDataWatcher; +import com.comphenix.protocol.wrappers.WrappedDataWatcher.Registry; +import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer; +import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject; import com.comphenix.protocol.wrappers.WrappedGameProfile; import me.libraryaddict.disguise.DisguiseAPI; import me.libraryaddict.disguise.DisguiseConfig; @@ -25,14 +28,21 @@ import org.bukkit.World; import org.bukkit.block.BlockFace; import org.bukkit.entity.Ageable; import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.entity.Zombie; +import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scoreboard.Scoreboard; +import org.bukkit.scoreboard.Team; +import org.bukkit.scoreboard.Team.Option; +import org.bukkit.scoreboard.Team.OptionStatus; import org.bukkit.util.Vector; import java.lang.reflect.Array; +import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -265,7 +275,7 @@ public class DisguiseUtilities { } public static void doBoundingBox(TargetedDisguise disguise) { - // TODO Slimes + //TODO: Slimes Entity entity = disguise.getEntity(); if (entity != null) { if (isDisguiseInUse(disguise)) { @@ -772,6 +782,16 @@ public class DisguiseUtilities { } catch (Exception ex) { ex.printStackTrace(System.out); } + //Code to stop player pushing in 1.9 + //TODO: Check validity + Scoreboard scoreboard = player.getScoreboard(); + Team t; + if ((t = scoreboard.getTeam("LDPushing")) != null) { + t.setOption(Option.COLLISION_RULE, OptionStatus.ALWAYS); + t.removeEntry(player.getName()); + t.unregister(); + } + //Finish up // Remove the fake entity ID from the disguise bin selfDisguised.remove(player.getUniqueId()); // Get the entity tracker @@ -973,6 +993,18 @@ public class DisguiseUtilities { if (!disguise.isSelfDisguiseVisible() || !PacketsManager.isViewDisguisesListenerEnabled() || player.getVehicle() != null) { return; } + //Code to stop player pushing in 1.9 + //TODO: Check validity + Scoreboard scoreboard = player.getScoreboard(); + Team t; + if ((t = scoreboard.getTeam("LDPushing")) != null) { + t.setOption(Option.COLLISION_RULE, OptionStatus.NEVER); + } else { + t = scoreboard.registerNewTeam("LDPushing"); + t.setOption(Option.COLLISION_RULE, OptionStatus.NEVER); + t.addEntry(player.getName()); + } + //Finish up selfDisguised.add(player.getUniqueId()); sendSelfDisguise(player, (TargetedDisguise) disguise); if (disguise.isHidingArmorFromSelf() || disguise.isHidingHeldItemFromSelf()) { @@ -981,4 +1013,5 @@ public class DisguiseUtilities { } } } + } diff --git a/src/main/java/me/libraryaddict/disguise/utilities/PacketsManager.java b/src/main/java/me/libraryaddict/disguise/utilities/PacketsManager.java index 38d8a76c..87ec43fc 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/PacketsManager.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/PacketsManager.java @@ -43,6 +43,7 @@ import org.bukkit.entity.Item; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.entity.Zombie; +import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.metadata.FixedMetadataValue; import org.bukkit.util.Vector; @@ -124,25 +125,18 @@ public class PacketsManager { // This sends the armor packets so that the player isn't naked. // Please note it only sends the packets that wouldn't be sent normally if (DisguiseConfig.isEquipmentPacketsEnabled()) { - for (int nmsSlot = 0; nmsSlot < 5; nmsSlot++) { - int armorSlot = nmsSlot - 1; - if (armorSlot < 0) - armorSlot = 4; - ItemStack itemstack = disguise.getWatcher().getItemStack(armorSlot); + for (EquipmentSlot slot : EquipmentSlot.values()) { + ItemStack itemstack = disguise.getWatcher().getItemStack(slot); if (itemstack != null && itemstack.getTypeId() != 0) { ItemStack item = null; if (disguisedEntity instanceof LivingEntity) { - if (nmsSlot == 0) { - item = ((LivingEntity) disguisedEntity).getEquipment().getItemInHand(); - } else { - item = ((LivingEntity) disguisedEntity).getEquipment().getArmorContents()[armorSlot]; - } + item = ReflectionManager.getEquipment(slot, disguisedEntity); } if (item == null || item.getType() == Material.AIR) { PacketContainer packet = new PacketContainer(Server.ENTITY_EQUIPMENT); StructureModifier mods = packet.getModifier(); mods.write(0, disguisedEntity.getEntityId()); - mods.write(1, nmsSlot); + mods.write(1, ReflectionManager.createEnumItemSlot(slot)); mods.write(2, ReflectionManager.getNmsItem(itemstack)); packets.add(packet); } @@ -281,7 +275,6 @@ public class PacketsManager { delayedPackets = new PacketContainer[]{delayedPacket}; } else if (disguise.getType().isMob() || disguise.getType() == DisguiseType.ARMOR_STAND) { - DisguiseValues values = DisguiseValues.getDisguiseValues(disguise.getType()); Vector vec = disguisedEntity.getVelocity(); spawnPackets[0] = new PacketContainer(Server.SPAWN_ENTITY_LIVING); @@ -1404,16 +1397,14 @@ public class PacketsManager { } } } else if (sentPacket.getType() == Server.ENTITY_EQUIPMENT) { - int slot = (Integer) packets[0].getModifier().read(1) - 1; - if (slot < 0) - slot = 4; - org.bukkit.inventory.ItemStack itemstack = disguise.getWatcher().getItemStack(slot); - if (itemstack != null) { + EquipmentSlot slot = ReflectionManager.createEquipmentSlot(packets[0].getModifier().read(1)); + org.bukkit.inventory.ItemStack itemStack = disguise.getWatcher().getItemStack(slot); + if (itemStack != null) { packets[0] = packets[0].shallowClone(); - packets[0].getModifier().write(2, - (itemstack.getTypeId() == 0 ? null : ReflectionManager.getNmsItem(itemstack))); + packets[0].getModifier().write(2, (itemStack.getTypeId() == 0 ? null : ReflectionManager.getNmsItem(itemStack))); } - if (disguise.getWatcher().isRightClicking() && slot == 4) { + //TODO: Add left hand here + if (disguise.getWatcher().isRightClicking() && slot == EquipmentSlot.HAND) { ItemStack heldItem = packets[0].getItemModifier().read(0); if (heldItem != null && heldItem.getType() != Material.AIR) { // Convert the datawatcher diff --git a/src/main/java/me/libraryaddict/disguise/utilities/ReflectionManager.java b/src/main/java/me/libraryaddict/disguise/utilities/ReflectionManager.java index 3fc83573..c43e25f3 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/ReflectionManager.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/ReflectionManager.java @@ -11,7 +11,10 @@ import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.World; import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; +import org.bukkit.inventory.EntityEquipment; +import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; @@ -476,25 +479,6 @@ public class ReflectionManager { } } - /** - * This creates a DataWatcherItem usable with WrappedWatchableObject - * @param id - * @param value - * @return - */ - public static Object createDataWatcherItem(int id, Object value) { - if (value == null) return null; - Serializer serializer = Registry.get(value.getClass()); - WrappedDataWatcherObject watcherObject = new WrappedDataWatcherObject(id, serializer); - Constructor construct = ReflectionManager.getNmsConstructor("DataWatcher$Item", getNmsClass("DataWatcherObject"), Object.class); - try { - return construct.newInstance(watcherObject.getHandle(), value); - } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - } - return null; - } - public static void setBoundingBox(Entity entity, FakeBoundingBox newBox) { try { Location loc = entity.getLocation(); @@ -506,4 +490,112 @@ public class ReflectionManager { } } + /** + * Creates the NMS object EnumItemSlot from an EquipmentSlot. + * @param slot + * @return null if the equipment slot is null + */ + public static Enum createEnumItemSlot(EquipmentSlot slot) { + Class clazz = getNmsClass("EnumItemSlot"); + Object[] enums = clazz != null ? clazz.getEnumConstants() : null; + if (enums == null) return null; + switch (slot) { + case HAND: + return (Enum) enums[0]; + case OFF_HAND: + return (Enum) enums[1]; + case FEET: + return (Enum) enums[2]; + case LEGS: + return (Enum) enums[3]; + case CHEST: + return (Enum) enums[4]; + case HEAD: + return (Enum) enums[5]; + default: + return null; + } + } + + /** + * Creates the Bukkit object EquipmentSlot from an EnumItemSlot object. + * @return null if the object isn't an nms EnumItemSlot + */ + public static EquipmentSlot createEquipmentSlot(Object enumItemSlot) { + try { + Enum nmsSlot = (Enum) enumItemSlot; + switch (nmsSlot.name()) { + case "MAINHAND": + return EquipmentSlot.HAND; + case "OFFHAND": + return EquipmentSlot.OFF_HAND; + case "FEET": + return EquipmentSlot.FEET; + case "LEGS": + return EquipmentSlot.LEGS; + case "CHEST": + return EquipmentSlot.CHEST; + case "HEAD": + return EquipmentSlot.HAND; + } + } catch (Exception e) { + return null; + } + return null; + } + + /** + * Gets equipment from this entity based on the slot given. + * @param slot + * @return null if the disguisedEntity is not an instance of a living entity + */ + public static ItemStack getEquipment(EquipmentSlot slot, Entity disguisedEntity) { + if (!(disguisedEntity instanceof LivingEntity)) return null; + switch (slot) { + case HAND: + return ((LivingEntity) disguisedEntity).getEquipment().getItemInMainHand(); + case OFF_HAND: + return ((LivingEntity) disguisedEntity).getEquipment().getItemInOffHand(); + case FEET: + return ((LivingEntity) disguisedEntity).getEquipment().getBoots(); + case LEGS: + return ((LivingEntity) disguisedEntity).getEquipment().getLeggings(); + case CHEST: + return ((LivingEntity) disguisedEntity).getEquipment().getChestplate(); + case HEAD: + return ((LivingEntity) disguisedEntity).getEquipment().getHelmet(); + default: + return null; + } + } + + /** + * This creates a DataWatcherItem usable with WrappedWatchableObject + * @param id + * @param value + * @return + */ + public static Object createDataWatcherItem(int id, Object value) { + if (value == null) return null; + Serializer serializer = Registry.get(value.getClass()); + WrappedDataWatcherObject watcherObject = new WrappedDataWatcherObject(id, serializer); + Constructor construct = getNmsConstructor("DataWatcher$Item", getNmsClass("DataWatcherObject"), Object.class); + try { + return construct.newInstance(watcherObject.getHandle(), value); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + return null; + } + + public static EntityEquipment createEntityEquipment(Entity entity) { + if (!(entity instanceof LivingEntity)) return null; + Constructor construct = getNmsConstructor("CraftEntityEquipment", getNmsClass("CraftLivingEntity")); + try { + return (EntityEquipment) construct.newInstance((LivingEntity) entity); + } catch (InstantiationException | IllegalAccessException | InvocationTargetException | ClassCastException e) { + e.printStackTrace(); + } + return null; + } }