| @@ -103,7 +103,7 @@ PacketsEnabled: | ||||
|   Collect: true | ||||
|   # This disables a fix for when a disguised entity wearing armor dies, if the disguise can wear armor. It drops unpickupable items to anyone watching. | ||||
|   EntityStatus: true | ||||
|   # Entity enquipment is the packets that are sent to ensure that a disguise has or doesn't have armor, and their held item. | ||||
|   # Entity equipment is the packets that are sent to ensure that a disguise has or doesn't have armor, and their held item. | ||||
|   # Disabling this means that any disguises which can wear armor or hold items will show the armor/held item that the disguised is wearing. | ||||
|   Enquipment: true | ||||
|   # This doesn't actually disable the packet. It would introduce problems. Instead it does the next best thing and caches the data. | ||||
|   | ||||
							
								
								
									
										7
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								pom.xml
									
									
									
									
									
								
							| @@ -7,6 +7,7 @@ | ||||
|  | ||||
| 	<build> | ||||
| 		<sourceDirectory>src</sourceDirectory> | ||||
| 		<testSourceDirectory>test</testSourceDirectory> | ||||
| 		<defaultGoal>clean package</defaultGoal> | ||||
| 		<directory>target</directory> | ||||
| 		<finalName>LibsDisguises</finalName> | ||||
| @@ -90,6 +91,12 @@ | ||||
| 			<artifactId>spigot</artifactId> | ||||
| 			<version>1.7.8-R0.1-SNAPSHOT</version> | ||||
| 		</dependency> | ||||
| 		<dependency> | ||||
| 			<groupId>junit</groupId> | ||||
| 			<artifactId>junit</artifactId> | ||||
| 			<version>4.11</version> | ||||
| 			<scope>test</scope> | ||||
| 		</dependency> | ||||
| 	</dependencies> | ||||
|  | ||||
| 	<distributionManagement> | ||||
|   | ||||
| @@ -24,9 +24,12 @@ import me.libraryaddict.disguise.utilities.ReflectionManager; | ||||
| import org.bukkit.DyeColor; | ||||
| import org.bukkit.Material; | ||||
| import org.bukkit.entity.Entity; | ||||
| import org.bukkit.entity.EntityType; | ||||
| import org.bukkit.entity.Horse; | ||||
| import org.bukkit.entity.LivingEntity; | ||||
| import org.bukkit.entity.Player; | ||||
| import org.bukkit.inventory.EntityEquipment; | ||||
| import org.bukkit.inventory.HorseInventory; | ||||
| import org.bukkit.inventory.ItemStack; | ||||
| import org.bukkit.potion.PotionEffect; | ||||
|  | ||||
| @@ -36,7 +39,7 @@ public class DisguiseAPI { | ||||
|         return constructDisguise(entity, true, true, true); | ||||
|     } | ||||
|  | ||||
|     public static Disguise constructDisguise(Entity entity, boolean doEnquipment, boolean doSneak, boolean doSprint) { | ||||
|     public static Disguise constructDisguise(Entity entity, boolean doEquipment, boolean doSneak, boolean doSprint) { | ||||
|         DisguiseType disguiseType = DisguiseType.getType(entity); | ||||
|         Disguise disguise; | ||||
|         if (disguiseType.isMisc()) { | ||||
| @@ -58,22 +61,18 @@ public class DisguiseAPI { | ||||
|         if (entity.getFireTicks() > 0) { | ||||
|             watcher.setBurning(true); | ||||
|         } | ||||
|         if (doEnquipment && entity instanceof LivingEntity) { | ||||
|             EntityEquipment enquip = ((LivingEntity) entity).getEquipment(); | ||||
|             watcher.setArmor(enquip.getArmorContents()); | ||||
|             watcher.setItemInHand(enquip.getItemInHand()); | ||||
|             if (disguiseType.getEntityType().name().equals("HORSE")) { | ||||
|                 try { | ||||
|                     Object horseInv = entity.getClass().getMethod("getInventory").invoke(entity); | ||||
|                     Object item = horseInv.getClass().getMethod("getSaddle").invoke(horseInv); | ||||
|                     if (item != null && ((ItemStack) item).getType() == Material.SADDLE) { | ||||
|                         ((HorseWatcher) watcher).setSaddled(true); | ||||
|                     } | ||||
|                     ((HorseWatcher) watcher) | ||||
|                             .setHorseArmor((ItemStack) horseInv.getClass().getMethod("getArmor").invoke(horseInv)); | ||||
|                 } catch (Exception ex) { | ||||
|                     ex.printStackTrace(); | ||||
|         if (doEquipment && entity instanceof LivingEntity) { | ||||
|             EntityEquipment equip = ((LivingEntity) entity).getEquipment(); | ||||
|             watcher.setArmor(equip.getArmorContents()); | ||||
|             watcher.setItemInHand(equip.getItemInHand()); | ||||
|             if (disguiseType.getEntityType() == EntityType.HORSE) { | ||||
|                 Horse horse = (Horse) entity; | ||||
|                 HorseInventory horseInventory = horse.getInventory(); | ||||
|                 ItemStack saddle = horseInventory.getSaddle(); | ||||
|                 if (saddle != null && saddle.getType() == Material.SADDLE) { | ||||
|                     ((HorseWatcher) watcher).setSaddled(true); | ||||
|                 } | ||||
|                 ((HorseWatcher) watcher).setHorseArmor(horseInventory.getArmor()); | ||||
|             } | ||||
|         } | ||||
|         for (Method method : entity.getClass().getMethods()) { | ||||
|   | ||||
| @@ -14,7 +14,7 @@ public class DisguiseConfig { | ||||
|     private static String disguiseBlownMessage; | ||||
|     private static int disguiseCloneExpire; | ||||
|     private static int disguiseEntityExpire; | ||||
|     private static boolean enquipmentEnabled; | ||||
|     private static boolean equipmentEnabled; | ||||
|     private static boolean entityAnimationsAdded; | ||||
|     private static boolean entityStatusEnabled; | ||||
|     private static boolean hearSelfDisguise; | ||||
| @@ -105,9 +105,13 @@ public class DisguiseConfig { | ||||
|         return blowDisguisesOnAttack; | ||||
|     } | ||||
|  | ||||
|     public static boolean isEnquipmentPacketsEnabled() { | ||||
|         return enquipmentEnabled; | ||||
|     public static boolean isEquipmentPacketsEnabled() { | ||||
|         return equipmentEnabled; | ||||
|     } | ||||
|     /** | ||||
|      * @deprecated Spelling mistake. | ||||
|      */ | ||||
|     @Deprecated public static boolean isEnquipmentPacketsEnabled() { return equipmentEnabled; } | ||||
|  | ||||
|     public static boolean isEntityAnimationsAdded() { | ||||
|         return entityAnimationsAdded; | ||||
| @@ -262,8 +266,8 @@ public class DisguiseConfig { | ||||
|     } | ||||
|  | ||||
|     public static void setEnquipmentPacketsEnabled(boolean enabled) { | ||||
|         if (enabled != isEnquipmentPacketsEnabled()) { | ||||
|             enquipmentEnabled = enabled; | ||||
|         if (enabled != isEquipmentPacketsEnabled()) { | ||||
|             equipmentEnabled = enabled; | ||||
|             PacketsManager.setupMainPacketsListener(); | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -27,8 +27,7 @@ public class LivingWatcher extends FlagWatcher { | ||||
|     static Method potionNo; | ||||
|     static { | ||||
|         try { | ||||
|             Class mobEffectList = ReflectionManager.getNmsClass("MobEffectList"); | ||||
|             list = (Object[]) mobEffectList.getField("byId").get(null); | ||||
|             list = (Object[]) ReflectionManager.getNmsField("MobEffectList", "byId").get(null); | ||||
|             for (Object obj : list) { | ||||
|                 if (obj != null) { | ||||
|                     for (Method field : obj.getClass().getMethods()) { | ||||
|   | ||||
| @@ -202,13 +202,9 @@ public class DisguiseUtilities { | ||||
|      */ | ||||
|     public static void destroyEntity(TargetedDisguise disguise) { | ||||
|         try { | ||||
|             Object world = ReflectionManager.getWorld(disguise.getEntity().getWorld()); | ||||
|             Object tracker = world.getClass().getField("tracker").get(world); | ||||
|             Object trackedEntities = tracker.getClass().getField("trackedEntities").get(tracker); | ||||
|             Object entityTrackerEntry = trackedEntities.getClass().getMethod("get", int.class) | ||||
|                     .invoke(trackedEntities, disguise.getEntity().getEntityId()); | ||||
|             Object entityTrackerEntry = ReflectionManager.getEntityTrackerEntry(disguise.getEntity()); | ||||
|             if (entityTrackerEntry != null) { | ||||
|                 HashSet trackedPlayers = (HashSet) entityTrackerEntry.getClass().getField("trackedPlayers") | ||||
|                 HashSet trackedPlayers = (HashSet) ReflectionManager.getNmsField("EntityTrackerEntry", "trackedPlayers") | ||||
|                         .get(entityTrackerEntry); | ||||
|                 HashSet cloned = (HashSet) trackedPlayers.clone(); | ||||
|                 PacketContainer destroyPacket = new PacketContainer(PacketType.Play.Server.ENTITY_DESTROY); | ||||
| @@ -325,13 +321,9 @@ public class DisguiseUtilities { | ||||
|     public static ArrayList<Player> getPerverts(Disguise disguise) { | ||||
|         ArrayList<Player> players = new ArrayList<Player>(); | ||||
|         try { | ||||
|             Object world = ReflectionManager.getWorld(disguise.getEntity().getWorld()); | ||||
|             Object tracker = world.getClass().getField("tracker").get(world); | ||||
|             Object trackedEntities = tracker.getClass().getField("trackedEntities").get(tracker); | ||||
|             Object entityTrackerEntry = trackedEntities.getClass().getMethod("get", int.class) | ||||
|                     .invoke(trackedEntities, disguise.getEntity().getEntityId()); | ||||
|             Object entityTrackerEntry = ReflectionManager.getEntityTrackerEntry(disguise.getEntity()); | ||||
|             if (entityTrackerEntry != null) { | ||||
|                 HashSet trackedPlayers = (HashSet) entityTrackerEntry.getClass().getField("trackedPlayers") | ||||
|                 HashSet trackedPlayers = (HashSet) ReflectionManager.getNmsField("EntityTrackerEntry", "trackedPlayers") | ||||
|                         .get(entityTrackerEntry); | ||||
|                 for (Object p : trackedPlayers) { | ||||
|                     Player player = (Player) ReflectionManager.getBukkitEntity(p); | ||||
| @@ -466,17 +458,13 @@ public class DisguiseUtilities { | ||||
|     public static void refreshTracker(TargetedDisguise disguise, String player) { | ||||
|         if (disguise.getEntity() != null && disguise.getEntity().isValid()) { | ||||
|             try { | ||||
|                 Object world = ReflectionManager.getWorld(disguise.getEntity().getWorld()); | ||||
|                 Object tracker = world.getClass().getField("tracker").get(world); | ||||
|                 Object trackedEntities = tracker.getClass().getField("trackedEntities").get(tracker); | ||||
|                 Object entityTrackerEntry = trackedEntities.getClass().getMethod("get", int.class) | ||||
|                         .invoke(trackedEntities, disguise.getEntity().getEntityId()); | ||||
|                 Object entityTrackerEntry = ReflectionManager.getEntityTrackerEntry(disguise.getEntity()); | ||||
|                 if (entityTrackerEntry != null) { | ||||
|                     HashSet trackedPlayers = (HashSet) entityTrackerEntry.getClass().getField("trackedPlayers") | ||||
|                     HashSet trackedPlayers = (HashSet) ReflectionManager.getNmsField("EntityTrackerEntry", "trackedPlayers") | ||||
|                             .get(entityTrackerEntry); | ||||
|                     Method clear = entityTrackerEntry.getClass() | ||||
|                             .getMethod("clear", ReflectionManager.getNmsClass("EntityPlayer")); | ||||
|                     Method updatePlayer = entityTrackerEntry.getClass().getMethod("updatePlayer", | ||||
|                     Method clear = ReflectionManager.getNmsMethod("EntityTrackerEntry", "clear", | ||||
|                             ReflectionManager.getNmsClass("EntityPlayer")); | ||||
|                     Method updatePlayer = ReflectionManager.getNmsMethod("EntityTrackerEntry", "updatePlayer", | ||||
|                             ReflectionManager.getNmsClass("EntityPlayer")); | ||||
|                     HashSet cloned = (HashSet) trackedPlayers.clone(); | ||||
|                     for (Object p : cloned) { | ||||
| @@ -499,17 +487,13 @@ public class DisguiseUtilities { | ||||
|     public static void refreshTrackers(Entity entity) { | ||||
|         if (entity.isValid()) { | ||||
|             try { | ||||
|                 Object world = ReflectionManager.getWorld(entity.getWorld()); | ||||
|                 Object tracker = world.getClass().getField("tracker").get(world); | ||||
|                 Object trackedEntities = tracker.getClass().getField("trackedEntities").get(tracker); | ||||
|                 Object entityTrackerEntry = trackedEntities.getClass().getMethod("get", int.class) | ||||
|                         .invoke(trackedEntities, entity.getEntityId()); | ||||
|                 Object entityTrackerEntry = ReflectionManager.getEntityTrackerEntry(entity); | ||||
|                 if (entityTrackerEntry != null) { | ||||
|                     HashSet trackedPlayers = (HashSet) entityTrackerEntry.getClass().getField("trackedPlayers") | ||||
|                     HashSet trackedPlayers = (HashSet) ReflectionManager.getNmsField("EntityTrackerEntry", "trackedPlayers") | ||||
|                             .get(entityTrackerEntry); | ||||
|                     Method clear = entityTrackerEntry.getClass() | ||||
|                             .getMethod("clear", ReflectionManager.getNmsClass("EntityPlayer")); | ||||
|                     Method updatePlayer = entityTrackerEntry.getClass().getMethod("updatePlayer", | ||||
|                     Method clear = ReflectionManager.getNmsMethod("EntityTrackerEntry", "clear", | ||||
|                             ReflectionManager.getNmsClass("EntityPlayer")); | ||||
|                     Method updatePlayer = ReflectionManager.getNmsMethod("EntityTrackerEntry", "updatePlayer", | ||||
|                             ReflectionManager.getNmsClass("EntityPlayer")); | ||||
|                     HashSet cloned = (HashSet) trackedPlayers.clone(); | ||||
|                     for (Object p : cloned) { | ||||
| @@ -534,16 +518,13 @@ public class DisguiseUtilities { | ||||
|      */ | ||||
|     public static void refreshTrackers(TargetedDisguise disguise) { | ||||
|         try { | ||||
|             Object world = ReflectionManager.getWorld(disguise.getEntity().getWorld()); | ||||
|             Object tracker = world.getClass().getField("tracker").get(world); | ||||
|             Object trackedEntities = tracker.getClass().getField("trackedEntities").get(tracker); | ||||
|             Object entityTrackerEntry = trackedEntities.getClass().getMethod("get", int.class) | ||||
|                     .invoke(trackedEntities, disguise.getEntity().getEntityId()); | ||||
|             Object entityTrackerEntry = ReflectionManager.getEntityTrackerEntry(disguise.getEntity()); | ||||
|             if (entityTrackerEntry != null) { | ||||
|                 HashSet trackedPlayers = (HashSet) entityTrackerEntry.getClass().getField("trackedPlayers") | ||||
|                 HashSet trackedPlayers = (HashSet) ReflectionManager.getNmsField("EntityTrackerEntry", "trackedPlayers") | ||||
|                         .get(entityTrackerEntry); | ||||
|                 Method clear = entityTrackerEntry.getClass().getMethod("clear", ReflectionManager.getNmsClass("EntityPlayer")); | ||||
|                 Method updatePlayer = entityTrackerEntry.getClass().getMethod("updatePlayer", | ||||
|                 Method clear = ReflectionManager.getNmsMethod("EntityTrackerEntry", "clear", | ||||
|                         ReflectionManager.getNmsClass("EntityPlayer")); | ||||
|                 Method updatePlayer = ReflectionManager.getNmsMethod("EntityTrackerEntry", "updatePlayer", | ||||
|                         ReflectionManager.getNmsClass("EntityPlayer")); | ||||
|                 HashSet cloned = (HashSet) trackedPlayers.clone(); | ||||
|                 for (Object p : cloned) { | ||||
| @@ -599,13 +580,9 @@ public class DisguiseUtilities { | ||||
|             selfDisguisesIds.remove(player.getUniqueId()); | ||||
|             // Get the entity tracker | ||||
|             try { | ||||
|                 Object world = ReflectionManager.getWorld(player.getWorld()); | ||||
|                 Object tracker = world.getClass().getField("tracker").get(world); | ||||
|                 Object trackedEntities = tracker.getClass().getField("trackedEntities").get(tracker); | ||||
|                 Object entityTrackerEntry = trackedEntities.getClass().getMethod("get", int.class) | ||||
|                         .invoke(trackedEntities, player.getEntityId()); | ||||
|                 Object entityTrackerEntry = ReflectionManager.getEntityTrackerEntry(player); | ||||
|                 if (entityTrackerEntry != null) { | ||||
|                     HashSet trackedPlayers = (HashSet) entityTrackerEntry.getClass().getField("trackedPlayers") | ||||
|                     HashSet trackedPlayers = (HashSet) ReflectionManager.getNmsField("EntityTrackerEntry", "trackedPlayers") | ||||
|                             .get(entityTrackerEntry); | ||||
|                     // If the tracker exists. Remove himself from his tracker | ||||
|                     trackedPlayers.remove(ReflectionManager.getNmsEntity(player)); | ||||
| @@ -637,11 +614,7 @@ public class DisguiseUtilities { | ||||
|             if (!player.isValid() || !player.isOnline() || !disguise.isSelfDisguiseVisible()) { | ||||
|                 return; | ||||
|             } | ||||
|             Object world = ReflectionManager.getWorld(player.getWorld()); | ||||
|             Object tracker = world.getClass().getField("tracker").get(world); | ||||
|             Object trackedEntities = tracker.getClass().getField("trackedEntities").get(tracker); | ||||
|             Object entityTrackerEntry = trackedEntities.getClass().getMethod("get", int.class) | ||||
|                     .invoke(trackedEntities, player.getEntityId()); | ||||
|             Object entityTrackerEntry = ReflectionManager.getEntityTrackerEntry(player); | ||||
|             if (entityTrackerEntry == null) { | ||||
|                 // A check incase the tracker is null. | ||||
|                 // If it is, then this method will be run again in one tick. Which is when it should be constructed. | ||||
| @@ -658,8 +631,7 @@ public class DisguiseUtilities { | ||||
|             } | ||||
|             int fakeId = selfDisguisesIds.get(player.getUniqueId()); | ||||
|             // Add himself to his own entity tracker | ||||
|             ((HashSet) entityTrackerEntry.getClass().getField("trackedPlayers").get(entityTrackerEntry)).add(ReflectionManager | ||||
|                     .getNmsEntity(player)); | ||||
|             ((HashSet<Object>) ReflectionManager.getNmsField("EntityTrackerEntry", "trackedPlayers").get(entityTrackerEntry)).add(ReflectionManager.getNmsEntity(player)); | ||||
|             ProtocolManager manager = ProtocolLibrary.getProtocolManager(); | ||||
|             // Send the player a packet with himself being spawned | ||||
|             manager.sendServerPacket(player, manager.createPacketConstructor(PacketType.Play.Server.NAMED_ENTITY_SPAWN, player) | ||||
|   | ||||
| @@ -120,7 +120,7 @@ public class PacketsManager { | ||||
|         ArrayList<PacketContainer> packets = new ArrayList<PacketContainer>(); | ||||
|         // 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.isEnquipmentPacketsEnabled()) { | ||||
|         if (DisguiseConfig.isEquipmentPacketsEnabled()) { | ||||
|             for (int nmsSlot = 0; nmsSlot < 5; nmsSlot++) { | ||||
|                 int armorSlot = nmsSlot - 1; | ||||
|                 if (armorSlot < 0) | ||||
| @@ -530,6 +530,7 @@ public class PacketsManager { | ||||
|                                     Object obj = null; | ||||
|                                     if (entity instanceof LivingEntity) { | ||||
|                                         try { | ||||
|                                             // Use reflection so that this works for either int or double methods | ||||
|                                             obj = LivingEntity.class.getMethod("getHealth").invoke(entity); | ||||
|                                             if (obj instanceof Double ? (Double) obj == 0 : (Integer) obj == 0) { | ||||
|                                                 soundType = SoundType.DEATH; | ||||
| @@ -544,13 +545,11 @@ public class PacketsManager { | ||||
|                                         boolean hasInvun = false; | ||||
|                                         Object nmsEntity = ReflectionManager.getNmsEntity(entity); | ||||
|                                         try { | ||||
|                                             Class entityClass = ReflectionManager.getNmsClass("Entity"); | ||||
|                                             if (entity instanceof LivingEntity) { | ||||
|                                                 hasInvun = entityClass.getField("noDamageTicks").getInt(nmsEntity) == ReflectionManager | ||||
|                                                         .getNmsClass("EntityLiving").getField("maxNoDamageTicks") | ||||
|                                                         .getInt(nmsEntity); | ||||
|                                                 hasInvun = ReflectionManager.getNmsField("Entity", "noDamageTicks").getInt(nmsEntity) == | ||||
|                                                         ReflectionManager.getNmsField("EntityLiving", "maxNoDamageTicks").getInt(nmsEntity); | ||||
|                                             } else { | ||||
|                                                 hasInvun = (Boolean) entityClass.getMethod("isInvulnerable").invoke(nmsEntity); | ||||
|                                                 hasInvun = (Boolean) ReflectionManager.getNmsMethod("Entity", "isInvulnerable").invoke(nmsEntity); | ||||
|                                             } | ||||
|                                         } catch (Exception ex) { | ||||
|                                             ex.printStackTrace(); | ||||
| @@ -581,18 +580,16 @@ public class PacketsManager { | ||||
|                                         try { | ||||
|                                             int typeId = soundLoc.getWorld().getBlockTypeIdAt(soundLoc.getBlockX(), | ||||
|                                                     soundLoc.getBlockY() - 1, soundLoc.getBlockZ()); | ||||
|                                             Class blockClass = ReflectionManager.getNmsClass("Block"); | ||||
|                                             Object block; | ||||
|                                             if (LibVersion.is1_7()) { | ||||
|                                                 block = ReflectionManager.getNmsClass("RegistryMaterials") | ||||
|                                                         .getMethod("a", int.class) | ||||
|                                                         .invoke(blockClass.getField("REGISTRY").get(null), typeId); | ||||
|                                                 block = ReflectionManager.getNmsMethod("RegistryMaterials", "a", int.class) | ||||
|                                                         .invoke(ReflectionManager.getNmsField("Block", "REGISTRY").get(null), typeId); | ||||
|                                             } else { | ||||
|                                                 block = ((Object[]) blockClass.getField("byId").get(null))[typeId]; | ||||
|                                                 block = ((Object[]) ReflectionManager.getNmsField("Block", "byId").get(null))[typeId]; | ||||
|                                             } | ||||
|                                             if (block != null) { | ||||
|                                                 Object step = blockClass.getField("stepSound").get(block); | ||||
|                                                 mods.write(0, step.getClass().getMethod("getStepSound").invoke(step)); | ||||
|                                                 Object step = ReflectionManager.getNmsField("Block", "stepSound").get(block); | ||||
|                                                 mods.write(0, ReflectionManager.getNmsMethod(step.getClass(), "getStepSound").invoke(step)); | ||||
|                                             } | ||||
|                                         } catch (Exception ex) { | ||||
|                                             ex.printStackTrace(); | ||||
| @@ -1130,8 +1127,8 @@ public class PacketsManager { | ||||
|                 packetsToListen.add(PacketType.Play.Server.ENTITY_HEAD_ROTATION); | ||||
|                 packetsToListen.add(PacketType.Play.Server.ENTITY_TELEPORT); | ||||
|             } | ||||
|             // Add enquipment packet | ||||
|             if (DisguiseConfig.isEnquipmentPacketsEnabled()) { | ||||
|             // Add equipment packet | ||||
|             if (DisguiseConfig.isEquipmentPacketsEnabled()) { | ||||
|                 packetsToListen.add(PacketType.Play.Server.ENTITY_EQUIPMENT); | ||||
|             } | ||||
|             // Add the packet that ensures if they are sleeping or not | ||||
|   | ||||
| @@ -1,10 +1,20 @@ | ||||
| package me.libraryaddict.disguise.utilities; | ||||
|  | ||||
| import java.io.BufferedReader; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | ||||
| import java.lang.reflect.Field; | ||||
| import java.lang.reflect.Method; | ||||
| import java.lang.reflect.Modifier; | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| import java.util.UUID; | ||||
| import java.util.regex.Matcher; | ||||
| import java.util.regex.Pattern; | ||||
|  | ||||
| import com.google.common.collect.ImmutableMap; | ||||
| import me.libraryaddict.disguise.disguisetypes.DisguiseType; | ||||
| import org.bukkit.Art; | ||||
| import org.bukkit.Bukkit; | ||||
| import org.bukkit.Location; | ||||
| @@ -17,6 +27,7 @@ import org.bukkit.inventory.ItemStack; | ||||
| import com.comphenix.protocol.wrappers.WrappedGameProfile; | ||||
|  | ||||
| public class ReflectionManager { | ||||
|  | ||||
|     public enum LibVersion { | ||||
|         V1_6, V1_7; | ||||
|         private static LibVersion currentVersion = LibVersion.V1_7; | ||||
| @@ -52,10 +63,126 @@ public class ReflectionManager { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static String bukkitVersion = Bukkit.getServer().getClass().getName().split("\\.")[3]; | ||||
|     private static final String bukkitVersion = Bukkit.getServer().getClass().getName().split("\\.")[3]; | ||||
|     private static final boolean isForge = Bukkit.getServer().getName().equalsIgnoreCase("Cauldron"); | ||||
|  | ||||
|     /** | ||||
|      * Map of mc-dev simple class name to fully qualified Forge class name. | ||||
|      */ | ||||
|     private static Map<String, String> ForgeClassMappings; | ||||
|     /** | ||||
|      * Map of Forge fully qualified class names to a map from mc-dev field names to Forge field names. | ||||
|      */ | ||||
|     private static Map<String, Map<String, String>> ForgeFieldMappings; | ||||
|     /** | ||||
|      * Map of Forge fully qualified class names to a map from mc-dev method names to a map from method signatures to Forge method names. | ||||
|      */ | ||||
|     private static Map<String, Map<String, Map<String, String>>> ForgeMethodMappings; | ||||
|     private static Map<Class<?>, String> primitiveTypes; | ||||
|  | ||||
|     static { | ||||
|         final String nameseg_class = "a-zA-Z0-9$_"; | ||||
|         final String fqn_class = nameseg_class + "/"; | ||||
|  | ||||
|         primitiveTypes = ImmutableMap.<Class<?>, String>builder() | ||||
|                 .put(boolean.class,"Z") | ||||
|                 .put(byte.class,   "B") | ||||
|                 .put(char.class,   "C") | ||||
|                 .put(short.class,  "S") | ||||
|                 .put(int.class,    "I") | ||||
|                 .put(long.class,   "J") | ||||
|                 .put(float.class,  "F") | ||||
|                 .put(double.class, "D") | ||||
|                 .put(void.class,   "V").build(); | ||||
|  | ||||
|         if (isForge) { | ||||
|             // Initialize the maps by reading the srg file | ||||
|             ForgeClassMappings = new HashMap<String, String>(); | ||||
|             ForgeFieldMappings = new HashMap<String, Map<String, String>>(); | ||||
|             ForgeMethodMappings = new HashMap<String, Map<String, Map<String, String>>>(); | ||||
|             try { | ||||
|                 InputStream stream = Class.forName("net.minecraftforge.common.MinecraftForge").getClassLoader() | ||||
|                         .getResourceAsStream("mappings/" + getBukkitVersion() + "/cb2numpkg.srg"); | ||||
|                 BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); | ||||
|  | ||||
|                 // 1: cb-simpleName | ||||
|                 // 2: forge-fullName (Needs dir2fqn()) | ||||
|                 Pattern classPattern = Pattern.compile("^CL: net/minecraft/server/([" + nameseg_class + "]+) ([" + fqn_class + "]+)$"); | ||||
|                 // 1: cb-simpleName | ||||
|                 // 2: cb-fieldName | ||||
|                 // 3: forge-fullName (Needs dir2fqn()) | ||||
|                 // 4: forge-fieldName | ||||
|                 Pattern fieldPattern = Pattern.compile("^FD: net/minecraft/server/([" + nameseg_class + "]+)/([" + nameseg_class + "]+) ([" + fqn_class + "]+)/([" + nameseg_class + "]+)$"); | ||||
|                 // 1: cb-simpleName | ||||
|                 // 2: cb-methodName | ||||
|                 // 3: cb-signature-args | ||||
|                 // 4: cb-signature-ret | ||||
|                 // 5: forge-fullName (Needs dir2fqn()) | ||||
|                 // 6: forge-methodName | ||||
|                 // 7: forge-signature-args | ||||
|                 // 8: forge-signature-ret | ||||
|                 Pattern methodPattern = Pattern.compile("^MD: net/minecraft/server/([" + fqn_class + "]+)/([" + nameseg_class + "]+) \\(([;\\[" + fqn_class + "]*)\\)([;\\[" + fqn_class + "]+) " + | ||||
|                         "([" + fqn_class + "]+)/([" + nameseg_class + "]+) \\(([;\\[" + fqn_class + "]*)\\)([;\\[" + fqn_class + "]+)$"); | ||||
|  | ||||
|                 String line; | ||||
|                 while ((line = reader.readLine()) != null) { | ||||
|                     Matcher classMatcher = classPattern.matcher(line); | ||||
|                     if (classMatcher.matches()) { | ||||
|                         // by CB class name | ||||
|                         ForgeClassMappings.put(classMatcher.group(1), dir2fqn(classMatcher.group(2))); | ||||
|                         continue; | ||||
|                     } | ||||
|                     Matcher fieldMatcher = fieldPattern.matcher(line); | ||||
|                     if (fieldMatcher.matches()) { | ||||
|                         // by CB class name | ||||
|                         Map<String, String> innerMap = ForgeFieldMappings.get(dir2fqn(fieldMatcher.group(3))); | ||||
|                         if (innerMap == null) { | ||||
|                             innerMap = new HashMap<String, String>(); | ||||
|                             ForgeFieldMappings.put(dir2fqn(fieldMatcher.group(3)), innerMap); | ||||
|                         } | ||||
|                         // by CB field name to Forge field name | ||||
|                         innerMap.put(fieldMatcher.group(2), fieldMatcher.group(4)); | ||||
|                         continue; | ||||
|                     } | ||||
|                     Matcher methodMatcher = methodPattern.matcher(line); | ||||
|                     if (methodMatcher.matches()) { | ||||
|                         // get by CB class name | ||||
|                         Map<String, Map<String, String>> middleMap = ForgeMethodMappings.get(dir2fqn(methodMatcher.group(5))); | ||||
|                         if (middleMap == null) { | ||||
|                             middleMap = new HashMap<String, Map<String, String>>(); | ||||
|                             ForgeMethodMappings.put(dir2fqn(methodMatcher.group(5)), middleMap); | ||||
|                         } | ||||
|                         // get by CB method name | ||||
|                         Map<String, String> innerMap = middleMap.get(methodMatcher.group(2)); | ||||
|                         if (innerMap == null) { | ||||
|                             innerMap = new HashMap<String, String>(); | ||||
|                             middleMap.put(methodMatcher.group(2), innerMap); | ||||
|                         } | ||||
|                         // store the parameter strings | ||||
|                         innerMap.put(methodMatcher.group(3), methodMatcher.group(6)); | ||||
|                         innerMap.put(methodMatcher.group(7), methodMatcher.group(6)); | ||||
|                     } | ||||
|                 } | ||||
|                 System.out.println("[LibsDisguises] Loaded in Cauldron/Forge mode"); | ||||
|                 System.out.println("[LibsDisguises] Loaded " + ForgeClassMappings.size() + " Cauldron class mappings"); | ||||
|                 System.out.println("[LibsDisguises] Loaded " + ForgeFieldMappings.size() + " Cauldron field mappings"); | ||||
|                 System.out.println("[LibsDisguises] Loaded " + ForgeMethodMappings.size() + " Cauldron method mappings"); | ||||
|             } catch (ClassNotFoundException e) { | ||||
|                 e.printStackTrace(); | ||||
|                 System.err.println("Warning: Running on Cauldron server, but couldn't load mappings file. LibsDisguises will likely crash!"); | ||||
|             } catch (IOException e) { | ||||
|                 e.printStackTrace(); | ||||
|                 System.err.println("Warning: Running on Cauldron server, but couldn't load mappings file. LibsDisguises will likely crash!"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static final Class<?> craftItemClass; | ||||
|     private static final Field pingField; | ||||
|     private static final Field trackerField; | ||||
|     private static final Field entitiesField; | ||||
|     private static final Method ihmGet; | ||||
|     private static Method damageAndIdleSoundMethod; | ||||
|     private static Class itemClass; | ||||
|     private static Field pingField; | ||||
|  | ||||
|     static { | ||||
|         for (Method method : getNmsClass("EntityLiving").getDeclaredMethods()) { | ||||
| @@ -74,21 +201,31 @@ public class ReflectionManager { | ||||
|                 ex.printStackTrace(); | ||||
|             } | ||||
|         } | ||||
|         try { | ||||
|             itemClass = getCraftClass("inventory.CraftItemStack"); | ||||
|             pingField = getNmsClass("EntityPlayer").getField("ping"); | ||||
|         } catch (Exception e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|         craftItemClass = getCraftClass("inventory.CraftItemStack"); | ||||
|         pingField = getNmsField("EntityPlayer", "ping"); | ||||
|         trackerField = getNmsField("WorldServer", "tracker"); | ||||
|         entitiesField = getNmsField("EntityTracker", "trackedEntities"); | ||||
|         ihmGet = getNmsMethod("IntHashMap", "get", int.class); | ||||
|  | ||||
|         Method m = getNmsMethod("Item", "getItemOf", getNmsClass("Block")); | ||||
|         System.out.println(m); | ||||
|  | ||||
|         DisguiseType.ARROW.isMisc(); | ||||
|     } | ||||
|  | ||||
|     private static String dir2fqn(String s) { | ||||
|         return s.replaceAll("/", "."); | ||||
|     } | ||||
|  | ||||
|     // === | ||||
|  | ||||
|     public static Object createEntityInstance(String entityName) { | ||||
|         try { | ||||
|             Class entityClass = getNmsClass("Entity" + entityName); | ||||
|             Class<?> entityClass = getNmsClass("Entity" + entityName); | ||||
|             Object entityObject; | ||||
|             Object world = getWorld(Bukkit.getWorlds().get(0)); | ||||
|             if (entityName.equals("Player")) { | ||||
|                 Object minecraftServer = getNmsClass("MinecraftServer").getMethod("getServer").invoke(null); | ||||
|                 Object minecraftServer = getNmsMethod("MinecraftServer", "getServer").invoke(null); | ||||
|                 Object playerinteractmanager = getNmsClass("PlayerInteractManager").getConstructor(getNmsClass("World")) | ||||
|                         .newInstance(world); | ||||
|                 if (LibVersion.is1_7()) { | ||||
| @@ -113,7 +250,7 @@ public class ReflectionManager { | ||||
|  | ||||
|     public static FakeBoundingBox getBoundingBox(Entity entity) { | ||||
|         try { | ||||
|             Object boundingBox = getNmsClass("Entity").getField("boundingBox").get(getNmsEntity(entity)); | ||||
|             Object boundingBox = getNmsField("Entity", "boundingBox").get(getNmsEntity(entity)); | ||||
|             double x = 0, y = 0, z = 0; | ||||
|             int stage = 0; | ||||
|             for (Field field : boundingBox.getClass().getFields()) { | ||||
| @@ -153,7 +290,7 @@ public class ReflectionManager { | ||||
|  | ||||
|     public static Entity getBukkitEntity(Object nmsEntity) { | ||||
|         try { | ||||
|             return (Entity) ReflectionManager.getNmsClass("Entity").getMethod("getBukkitEntity").invoke(nmsEntity); | ||||
|             return (Entity) getNmsMethod("Entity", "getBukkitEntity").invoke(nmsEntity); | ||||
|         } catch (Exception ex) { | ||||
|             ex.printStackTrace(); | ||||
|         } | ||||
| @@ -162,7 +299,7 @@ public class ReflectionManager { | ||||
|  | ||||
|     public static ItemStack getBukkitItem(Object nmsItem) { | ||||
|         try { | ||||
|             return (ItemStack) itemClass.getMethod("asBukkitCopy", getNmsClass("ItemStack")).invoke(null, nmsItem); | ||||
|             return (ItemStack) craftItemClass.getMethod("asBukkitCopy", getNmsClass("ItemStack")).invoke(null, nmsItem); | ||||
|         } catch (Exception e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
| @@ -173,7 +310,7 @@ public class ReflectionManager { | ||||
|         return bukkitVersion; | ||||
|     } | ||||
|  | ||||
|     public static Class getCraftClass(String className) { | ||||
|     public static Class<?> getCraftClass(String className) { | ||||
|         try { | ||||
|             return Class.forName("org.bukkit.craftbukkit." + getBukkitVersion() + "." + className); | ||||
|         } catch (Exception e) { | ||||
| @@ -184,8 +321,7 @@ public class ReflectionManager { | ||||
|  | ||||
|     public static String getCraftSound(Sound sound) { | ||||
|         try { | ||||
|             Class c = getCraftClass("CraftSound"); | ||||
|             return (String) c.getMethod("getSound", Sound.class).invoke(null, sound); | ||||
|             return (String) getCraftClass("CraftSound").getMethod("getSound", Sound.class).invoke(null, sound); | ||||
|         } catch (Exception ex) { | ||||
|             ex.printStackTrace(); | ||||
|         } | ||||
| @@ -194,8 +330,7 @@ public class ReflectionManager { | ||||
|  | ||||
|     public static String getEnumArt(Art art) { | ||||
|         try { | ||||
|             Class craftArt = Class.forName("org.bukkit.craftbukkit." + getBukkitVersion() + ".CraftArt"); | ||||
|             Object enumArt = craftArt.getMethod("BukkitToNotch", Art.class).invoke(null, art); | ||||
|             Object enumArt = getCraftClass("CraftArt").getMethod("BukkitToNotch", Art.class).invoke(null, art); | ||||
|             for (Field field : enumArt.getClass().getFields()) { | ||||
|                 if (field.getType() == String.class) { | ||||
|                     return (String) field.get(enumArt); | ||||
| @@ -207,6 +342,13 @@ public class ReflectionManager { | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     static Object getEntityTrackerEntry(Entity target) throws Exception { | ||||
|         Object world = getWorld(target.getWorld()); | ||||
|         Object tracker = trackerField.get(world); | ||||
|         Object trackedEntities = entitiesField.get(tracker); | ||||
|         return ihmGet.invoke(trackedEntities, target.getEntityId()); | ||||
|     } | ||||
|  | ||||
|     public static WrappedGameProfile getGameProfile(Player player) { | ||||
|         if (LibVersion.is1_7()) { | ||||
|             return WrappedGameProfile.fromPlayer(player); | ||||
| @@ -235,10 +377,22 @@ public class ReflectionManager { | ||||
|     } | ||||
|  | ||||
|     public static Class getNmsClass(String className) { | ||||
|         if (isForge) { | ||||
|             String forgeName = ForgeClassMappings.get(className); | ||||
|             if (forgeName != null) { | ||||
|                 try { | ||||
|                     return Class.forName(forgeName); | ||||
|                 } catch (ClassNotFoundException ignored) { | ||||
|                 } | ||||
|             } else { | ||||
|                 // Throw, because the default cannot possibly work | ||||
|                 throw new RuntimeException("Missing Forge mapping for " + className); | ||||
|             } | ||||
|         } | ||||
|         try { | ||||
|             return Class.forName("net.minecraft.server." + getBukkitVersion() + "." + className); | ||||
|         } catch (Exception e) { | ||||
|             // e.printStackTrace(); | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| @@ -254,13 +408,70 @@ public class ReflectionManager { | ||||
|  | ||||
|     public static Object getNmsItem(ItemStack itemstack) { | ||||
|         try { | ||||
|             return itemClass.getMethod("asNMSCopy", ItemStack.class).invoke(null, itemstack); | ||||
|             return craftItemClass.getMethod("asNMSCopy", ItemStack.class).invoke(null, itemstack); | ||||
|         } catch (Exception e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     public static Field getNmsField(String className, String fieldName) { | ||||
|         return getNmsField(getNmsClass(className), fieldName); | ||||
|     } | ||||
|  | ||||
|     public static Field getNmsField(Class clazz, String fieldName) { | ||||
|         if (isForge) { | ||||
|             try { | ||||
|                 return clazz.getField(ForgeFieldMappings.get(clazz.getName()).get(fieldName)); | ||||
|             } catch (NoSuchFieldException ex) { | ||||
|                 ex.printStackTrace(); | ||||
|             } catch (NullPointerException ignored) { | ||||
|             } | ||||
|         } | ||||
|         try { | ||||
|             return clazz.getField(fieldName); | ||||
|         } catch (NoSuchFieldException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     public static Method getNmsMethod(String className, String methodName, Class<?>... parameters) { | ||||
|         return getNmsMethod(getNmsClass(className), methodName, parameters); | ||||
|     } | ||||
|  | ||||
|     private static String methodSignaturePart(Class<?> param) { | ||||
|         if (param.isArray()) { | ||||
|             return "[" + methodSignaturePart(param.getComponentType()); | ||||
|         } else if (param.isPrimitive()) { | ||||
|             return primitiveTypes.get(param); | ||||
|         } else { | ||||
|             return "L" + param.getName().replaceAll("\\.", "/") + ";"; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static Method getNmsMethod(Class<?> clazz, String methodName, Class<?>... parameters) { | ||||
|         if (isForge) { | ||||
|             try { | ||||
|                 Map<String, String> innerMap = ForgeMethodMappings.get(clazz.getName()).get(methodName); | ||||
|                 StringBuilder sb = new StringBuilder(); | ||||
|                 for (Class<?> cl : parameters) { | ||||
|                     sb.append(methodSignaturePart(cl)); | ||||
|                 } | ||||
|                 return clazz.getMethod(innerMap.get(sb.toString()), parameters); | ||||
|             } catch (NoSuchMethodException e) { | ||||
|                 e.printStackTrace(); | ||||
|             } catch (NullPointerException ignored) { | ||||
|             } | ||||
|         } | ||||
|         try { | ||||
|             return clazz.getMethod(methodName, parameters); | ||||
|         } catch (NoSuchMethodException e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     public static double getPing(Player player) { | ||||
|         try { | ||||
|             return (double) pingField.getInt(ReflectionManager.getNmsEntity(player)); | ||||
| @@ -272,9 +483,9 @@ public class ReflectionManager { | ||||
|  | ||||
|     public static float[] getSize(Entity entity) { | ||||
|         try { | ||||
|             float length = getNmsClass("Entity").getField("length").getFloat(getNmsEntity(entity)); | ||||
|             float width = getNmsClass("Entity").getField("width").getFloat(getNmsEntity(entity)); | ||||
|             float height = getNmsClass("Entity").getField("height").getFloat(getNmsEntity(entity)); | ||||
|             float length = getNmsField("Entity", "length").getFloat(getNmsEntity(entity)); | ||||
|             float width = getNmsField("Entity", "width").getFloat(getNmsEntity(entity)); | ||||
|             float height = getNmsField("Entity", "height").getFloat(getNmsEntity(entity)); | ||||
|             return new float[] { length, width, height }; | ||||
|         } catch (Exception ex) { | ||||
|             ex.printStackTrace(); | ||||
| @@ -284,7 +495,7 @@ public class ReflectionManager { | ||||
|  | ||||
|     public static WrappedGameProfile getSkullBlob(WrappedGameProfile gameProfile) { | ||||
|         try { | ||||
|             Object minecraftServer = getNmsClass("MinecraftServer").getMethod("getServer").invoke(null); | ||||
|             Object minecraftServer = getNmsMethod("MinecraftServer", "getServer").invoke(null); | ||||
|             for (Method method : getNmsClass("MinecraftServer").getMethods()) { | ||||
|                 if (method.getReturnType().getSimpleName().equals("MinecraftSessionService")) { | ||||
|                     Object session = method.invoke(minecraftServer); | ||||
| @@ -319,7 +530,7 @@ public class ReflectionManager { | ||||
|  | ||||
|     public static WrappedGameProfile grabProfileAddUUID(String playername) { | ||||
|         try { | ||||
|             Object minecraftServer = getNmsClass("MinecraftServer").getMethod("getServer").invoke(null); | ||||
|             Object minecraftServer = getNmsMethod("MinecraftServer", "getServer").invoke(null); | ||||
|             for (Method method : getNmsClass("MinecraftServer").getMethods()) { | ||||
|                 if (method.getReturnType().getSimpleName().equals("GameProfileRepository")) { | ||||
|                     Object profileRepo = method.invoke(minecraftServer); | ||||
| @@ -346,8 +557,8 @@ public class ReflectionManager { | ||||
|     public static void setAllowSleep(Player player) { | ||||
|         try { | ||||
|             Object nmsEntity = getNmsEntity(player); | ||||
|             Object connection = nmsEntity.getClass().getField("playerConnection").get(nmsEntity); | ||||
|             Field check = connection.getClass().getField("checkMovement"); | ||||
|             Object connection = getNmsField(nmsEntity.getClass(), "playerConnection").get(nmsEntity); | ||||
|             Field check = getNmsField(connection.getClass(), "checkMovement"); | ||||
|             check.setBoolean(connection, true); | ||||
|         } catch (Exception ex) { | ||||
|             ex.printStackTrace(); | ||||
| @@ -356,7 +567,7 @@ public class ReflectionManager { | ||||
|  | ||||
|     public static void setBoundingBox(Entity entity, FakeBoundingBox newBox) { | ||||
|         try { | ||||
|             Object boundingBox = getNmsClass("Entity").getField("boundingBox").get(getNmsEntity(entity)); | ||||
|             Object boundingBox = getNmsField("Entity", "boundingBox").get(getNmsEntity(entity)); | ||||
|             int stage = 0; | ||||
|             Location loc = entity.getLocation(); | ||||
|             for (Field field : boundingBox.getClass().getFields()) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user