From ce292302fe3b152edf13837f4522d1db5ec34ebf Mon Sep 17 00:00:00 2001 From: libraryaddict Date: Sun, 19 Jan 2020 15:48:26 +1300 Subject: [PATCH] Code cleanup --- .../libraryaddict/disguise/LibsDisguises.java | 346 +--------------- .../utilities/packets/PacketsManager.java | 16 +- .../utilities/parser/DisguiseParser.java | 7 + .../parser/params/ParamInfoManager.java | 11 + .../reflection/ReflectionManager.java | 376 +++++++++++++++++- .../disguisetypes/DisguiseCloneTest.java | 121 ++++++ 6 files changed, 519 insertions(+), 358 deletions(-) create mode 100644 src/test/java/me/libraryaddict/disguise/disguisetypes/DisguiseCloneTest.java diff --git a/src/main/java/me/libraryaddict/disguise/LibsDisguises.java b/src/main/java/me/libraryaddict/disguise/LibsDisguises.java index bee17598..510d612e 100644 --- a/src/main/java/me/libraryaddict/disguise/LibsDisguises.java +++ b/src/main/java/me/libraryaddict/disguise/LibsDisguises.java @@ -89,10 +89,10 @@ public class LibsDisguises extends JavaPlugin { ReflectionManager.init(); - PacketsManager.init(this); - DisguiseUtilities.init(this); + PacketsManager.init(); + DisguiseUtilities.init(); - registerValues(); + ReflectionManager.registerValues(); DisguiseConfig.loadConfig(); @@ -171,346 +171,6 @@ public class LibsDisguises extends JavaPlugin { DisguiseConfig.loadConfig(); } - /** - * Here we create a nms entity for each disguise. Then grab their default values in their datawatcher. Then their - * sound volume - * for mob noises. As well as setting their watcher class and entity size. - */ - private void registerValues() { - for (DisguiseType disguiseType : DisguiseType.values()) { - if (disguiseType.getEntityType() == null) { - continue; - } - - Class watcherClass; - - try { - switch (disguiseType) { - case ARROW: - watcherClass = TippedArrowWatcher.class; - break; - case COD: - case SALMON: - watcherClass = FishWatcher.class; - break; - case SPECTRAL_ARROW: - watcherClass = ArrowWatcher.class; - break; - case PRIMED_TNT: - watcherClass = TNTWatcher.class; - break; - case MINECART_CHEST: - case MINECART_HOPPER: - case MINECART_MOB_SPAWNER: - case MINECART_TNT: - watcherClass = MinecartWatcher.class; - break; - case SPIDER: - case CAVE_SPIDER: - watcherClass = SpiderWatcher.class; - break; - case PIG_ZOMBIE: - case HUSK: - case DROWNED: - watcherClass = ZombieWatcher.class; - break; - case MAGMA_CUBE: - watcherClass = SlimeWatcher.class; - break; - case ELDER_GUARDIAN: - watcherClass = GuardianWatcher.class; - break; - case WITHER_SKELETON: - case STRAY: - watcherClass = SkeletonWatcher.class; - break; - case ILLUSIONER: - case EVOKER: - watcherClass = IllagerWizardWatcher.class; - break; - case PUFFERFISH: - watcherClass = PufferFishWatcher.class; - break; - default: - watcherClass = Class.forName( - "me.libraryaddict.disguise.disguisetypes.watchers." + toReadable(disguiseType.name()) + - "Watcher"); - break; - } - } - catch (ClassNotFoundException ex) { - // There is no explicit watcher for this entity. - Class entityClass = disguiseType.getEntityType().getEntityClass(); - - if (entityClass != null) { - if (Tameable.class.isAssignableFrom(entityClass)) { - watcherClass = TameableWatcher.class; - } else if (Ageable.class.isAssignableFrom(entityClass)) { - watcherClass = AgeableWatcher.class; - } else if (Creature.class.isAssignableFrom(entityClass)) { - watcherClass = InsentientWatcher.class; - } else if (LivingEntity.class.isAssignableFrom(entityClass)) { - watcherClass = LivingWatcher.class; - } else if (Fish.class.isAssignableFrom(entityClass)) { - watcherClass = FishWatcher.class; - } else { - watcherClass = FlagWatcher.class; - } - } else { - watcherClass = FlagWatcher.class; // Disguise is unknown type - } - } - - if (watcherClass == null) { - getLogger().severe("Error loading " + disguiseType.name() + ", FlagWatcher not assigned"); - continue; - } - - // Invalidate invalid distribution - if (LibsPremium.isPremium() && - ((LibsPremium.getPaidInformation() != null && LibsPremium.getPaidInformation().isPremium() && - !LibsPremium.getPaidInformation().isLegit()) || - (LibsPremium.getPluginInformation() != null && - LibsPremium.getPluginInformation().isPremium() && - !LibsPremium.getPluginInformation().isLegit()))) { - throw new IllegalStateException( - "Error while checking pi rate on startup! Please re-download the jar from SpigotMC before " + - "reporting this error!"); - } - - disguiseType.setWatcherClass(watcherClass); - - if (DisguiseValues.getDisguiseValues(disguiseType) != null) { - continue; - } - - String nmsEntityName = toReadable(disguiseType.name()); - Class nmsClass = ReflectionManager.getNmsClassIgnoreErrors("Entity" + nmsEntityName); - - if (nmsClass == null || Modifier.isAbstract(nmsClass.getModifiers())) { - String[] split = splitReadable(disguiseType.name()); - ArrayUtils.reverse(split); - - nmsEntityName = StringUtils.join(split); - nmsClass = ReflectionManager.getNmsClassIgnoreErrors("Entity" + nmsEntityName); - - if (nmsClass == null || Modifier.isAbstract(nmsClass.getModifiers())) { - nmsEntityName = null; - } - } - - if (nmsEntityName == null) { - switch (disguiseType) { - case DONKEY: - nmsEntityName = "HorseDonkey"; - break; - case ARROW: - nmsEntityName = "TippedArrow"; - break; - case DROPPED_ITEM: - nmsEntityName = "Item"; - break; - case FIREBALL: - nmsEntityName = "LargeFireball"; - break; - case FIREWORK: - nmsEntityName = "Fireworks"; - break; - case GIANT: - nmsEntityName = "GiantZombie"; - break; - case HUSK: - nmsEntityName = "ZombieHusk"; - break; - case ILLUSIONER: - nmsEntityName = "IllagerIllusioner"; - break; - case LEASH_HITCH: - nmsEntityName = "Leash"; - break; - case MINECART: - nmsEntityName = "MinecartRideable"; - break; - case MINECART_COMMAND: - nmsEntityName = "MinecartCommandBlock"; - break; - case MINECART_TNT: - nmsEntityName = "MinecartTNT"; - break; - case MULE: - nmsEntityName = "HorseMule"; - break; - case PRIMED_TNT: - nmsEntityName = "TNTPrimed"; - break; - case PUFFERFISH: - nmsEntityName = "PufferFish"; - break; - case SPLASH_POTION: - nmsEntityName = "Potion"; - break; - case STRAY: - nmsEntityName = "SkeletonStray"; - break; - case TRIDENT: - nmsEntityName = "ThrownTrident"; - break; - case WANDERING_TRADER: - nmsEntityName = "VillagerTrader"; - break; - case TRADER_LLAMA: - nmsEntityName = "LLamaTrader"; // Interesting capitalization - break; - default: - break; - } - } - - try { - if (disguiseType == DisguiseType.UNKNOWN) { - DisguiseValues disguiseValues = new DisguiseValues(disguiseType, null, 0, 0); - - disguiseValues.setAdultBox(new FakeBoundingBox(0, 0, 0)); - - DisguiseSound sound = DisguiseSound.getType(disguiseType.name()); - - if (sound != null) { - sound.setDamageAndIdleSoundVolume(1f); - } - - continue; - } - - if (nmsEntityName == null) { - getLogger().warning("Entity name not found! (" + disguiseType.name() + ")"); - continue; - } - - Object nmsEntity = ReflectionManager.createEntityInstance(disguiseType, nmsEntityName); - - if (nmsEntity == null) { - getLogger().warning("Entity not found! (" + nmsEntityName + ")"); - continue; - } - - disguiseType.setTypeId(ReflectionManager.getEntityTypeId(disguiseType.getEntityType())); - - Entity bukkitEntity = ReflectionManager.getBukkitEntity(nmsEntity); - - int entitySize = 0; - - for (Field field : ReflectionManager.getNmsClass("Entity").getFields()) { - if (field.getType().getName().equals("EnumEntitySize")) { - Enum enumEntitySize = (Enum) field.get(nmsEntity); - - entitySize = enumEntitySize.ordinal(); - - break; - } - } - - DisguiseValues disguiseValues = new DisguiseValues(disguiseType, nmsEntity.getClass(), entitySize, - bukkitEntity instanceof Damageable ? ((Damageable) bukkitEntity).getMaxHealth() : 0); - - WrappedDataWatcher watcher = WrappedDataWatcher.getEntityWatcher(bukkitEntity); - ArrayList indexes = MetaIndex.getMetaIndexes(disguiseType.getWatcherClass()); - boolean loggedName = false; - - for (WrappedWatchableObject watch : watcher.getWatchableObjects()) { - MetaIndex flagType = MetaIndex.getMetaIndex(watcherClass, watch.getIndex()); - - if (flagType == null) { - getLogger().severe("MetaIndex not found for " + disguiseType + "! Index: " + watch.getIndex()); - getLogger().severe("Value: " + watch.getRawValue() + " (" + watch.getRawValue().getClass() + - ") (" + nmsEntity.getClass() + ") & " + watcherClass.getSimpleName()); - continue; - } - - indexes.remove(flagType); - - Object ourValue = ReflectionManager.convertInvalidMeta(flagType.getDefault()); - Object nmsValue = ReflectionManager.convertInvalidMeta(watch.getValue()); - - if (ourValue.getClass() != nmsValue.getClass()) { - if (!loggedName) { - getLogger().severe(StringUtils.repeat("=", 20)); - getLogger().severe("MetaIndex mismatch! Disguise " + disguiseType + ", Entity " + - nmsEntityName); - loggedName = true; - } - - getLogger().severe(StringUtils.repeat("-", 20)); - getLogger().severe("Index: " + watch.getIndex() + " | " + - flagType.getFlagWatcher().getSimpleName() + " | " + MetaIndex.getName(flagType)); - Object flagDefault = flagType.getDefault(); - - getLogger().severe("LibsDisguises: " + flagDefault + " (" + flagDefault.getClass() + ")"); - getLogger().severe("LibsDisguises Converted: " + ourValue + " (" + ourValue.getClass() + ")"); - getLogger().severe("Minecraft: " + watch.getRawValue() + " (" + watch.getRawValue().getClass() + - ")"); - getLogger().severe("Minecraft Converted: " + nmsValue + " (" + nmsValue.getClass() + ")"); - getLogger().severe(StringUtils.repeat("-", 20)); - } - } - - for (MetaIndex index : indexes) { - getLogger().warning( - disguiseType + " has MetaIndex remaining! " + index.getFlagWatcher().getSimpleName() + - " at index " + index.getIndex()); - } - - DisguiseSound sound = DisguiseSound.getType(disguiseType.name()); - - if (sound != null) { - Float soundStrength = ReflectionManager.getSoundModifier(nmsEntity); - - if (soundStrength != null) { - sound.setDamageAndIdleSoundVolume(soundStrength); - } - } - - // Get the bounding box - disguiseValues.setAdultBox(ReflectionManager.getBoundingBox(bukkitEntity)); - - if (bukkitEntity instanceof Ageable) { - ((Ageable) bukkitEntity).setBaby(); - - disguiseValues.setBabyBox(ReflectionManager.getBoundingBox(bukkitEntity)); - } else if (bukkitEntity instanceof Zombie) { - ((Zombie) bukkitEntity).setBaby(true); - - disguiseValues.setBabyBox(ReflectionManager.getBoundingBox(bukkitEntity)); - } - - //disguiseValues.setEntitySize(ReflectionManager.getSize(bukkitEntity)); - } - catch (SecurityException | IllegalArgumentException | IllegalAccessException | FieldAccessException ex) { - getLogger().severe("Uh oh! Trouble while making values for the disguise " + disguiseType.name() + "!"); - getLogger().severe("Before reporting this error, " + - "please make sure you are using the latest version of LibsDisguises and ProtocolLib."); - getLogger().severe("Development builds are available at (ProtocolLib) " + - "http://ci.dmulloy2.net/job/ProtocolLib/ and (LibsDisguises) https://ci.md-5" + - ".net/job/LibsDisguises/"); - - ex.printStackTrace(); - } - } - } - - private String[] splitReadable(String string) { - String[] split = string.split("_"); - - for (int i = 0; i < split.length; i++) { - split[i] = split[i].substring(0, 1) + split[i].substring(1).toLowerCase(); - } - - return split; - } - - private String toReadable(String string) { - return StringUtils.join(splitReadable(string)); - } - public DisguiseListener getListener() { return listener; } diff --git a/src/main/java/me/libraryaddict/disguise/utilities/packets/PacketsManager.java b/src/main/java/me/libraryaddict/disguise/utilities/packets/PacketsManager.java index 9b85b00a..75a6fed9 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/packets/PacketsManager.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/packets/PacketsManager.java @@ -19,7 +19,6 @@ public class PacketsManager { private static PacketListener clientInteractEntityListener; private static PacketListener inventoryListener; private static boolean inventoryModifierEnabled; - private static LibsDisguises libsDisguises; private static PacketListener mainListener; private static PacketListener soundsListener; private static boolean soundsListenerEnabled; @@ -32,8 +31,8 @@ public class PacketsManager { // You ain't supposed to be allowed to 'interact' with a item that cannot be clicked. // Because it kicks you for hacking. - clientInteractEntityListener = new PacketListenerClientInteract(libsDisguises); - PacketListener tabListListener = new PacketListenerTabList(libsDisguises); + clientInteractEntityListener = new PacketListenerClientInteract(LibsDisguises.getInstance()); + PacketListener tabListListener = new PacketListenerTabList(LibsDisguises.getInstance()); ProtocolLibrary.getProtocolManager().addPacketListener(clientInteractEntityListener); ProtocolLibrary.getProtocolManager().addPacketListener(tabListListener); @@ -45,14 +44,13 @@ public class PacketsManager { /** * Creates the packet listeners */ - public static void init(LibsDisguises plugin) { - libsDisguises = plugin; - soundsListener = new PacketListenerSounds(libsDisguises); + public static void init() { + soundsListener = new PacketListenerSounds(LibsDisguises.getInstance()); // Self disguise (/vsd) listener - viewDisguisesListener = new PacketListenerViewSelfDisguise(libsDisguises); + viewDisguisesListener = new PacketListenerViewSelfDisguise(LibsDisguises.getInstance()); - inventoryListener = new PacketListenerInventory(libsDisguises); + inventoryListener = new PacketListenerInventory(LibsDisguises.getInstance()); packetsHandler = new PacketsHandler(); } @@ -161,7 +159,7 @@ public class PacketsManager { packetsToListen.add(Server.ENTITY_STATUS); } - mainListener = new PacketListenerMain(libsDisguises, packetsToListen); + mainListener = new PacketListenerMain(LibsDisguises.getInstance(), packetsToListen); ProtocolLibrary.getProtocolManager().addPacketListener(mainListener); } diff --git a/src/main/java/me/libraryaddict/disguise/utilities/parser/DisguiseParser.java b/src/main/java/me/libraryaddict/disguise/utilities/parser/DisguiseParser.java index 15611233..6cda560a 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/parser/DisguiseParser.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/parser/DisguiseParser.java @@ -29,6 +29,9 @@ import java.util.Map.Entry; import java.util.concurrent.TimeUnit; public class DisguiseParser { + /** + * > + */ private static HashMap> defaultWatcherValues = new HashMap<>(); public static void createDefaultMethods() { @@ -115,6 +118,10 @@ public class DisguiseParser { } } + public static HashMap> getMethodDefaults() { + return defaultWatcherValues; + } + public static String parseToString(Disguise disguise) { return parseToString(disguise, true); } diff --git a/src/main/java/me/libraryaddict/disguise/utilities/parser/params/ParamInfoManager.java b/src/main/java/me/libraryaddict/disguise/utilities/parser/params/ParamInfoManager.java index 518e2bae..d6e0420f 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/parser/params/ParamInfoManager.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/parser/params/ParamInfoManager.java @@ -3,7 +3,9 @@ package me.libraryaddict.disguise.utilities.parser.params; import me.libraryaddict.disguise.disguisetypes.Disguise; import me.libraryaddict.disguise.disguisetypes.DisguiseType; import me.libraryaddict.disguise.disguisetypes.FlagWatcher; +import me.libraryaddict.disguise.disguisetypes.PlayerDisguise; import me.libraryaddict.disguise.disguisetypes.watchers.LivingWatcher; +import me.libraryaddict.disguise.disguisetypes.watchers.PlayerWatcher; import me.libraryaddict.disguise.utilities.parser.DisguisePerm; import me.libraryaddict.disguise.utilities.parser.params.ParamInfo; import me.libraryaddict.disguise.utilities.parser.params.ParamInfoTypes; @@ -130,6 +132,15 @@ public class ParamInfoManager { } } + if (watcherClass == PlayerWatcher.class) { + try { + methods.add(PlayerDisguise.class.getMethod("setNameVisible", boolean.class)); + } + catch (NoSuchMethodException e) { + e.printStackTrace(); + } + } + return methods.toArray(new Method[0]); } diff --git a/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java b/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java index 1cb88289..b3251e00 100644 --- a/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java +++ b/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java @@ -1,19 +1,22 @@ package me.libraryaddict.disguise.utilities.reflection; +import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.wrappers.*; import com.comphenix.protocol.wrappers.EnumWrappers.Direction; import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject; import com.comphenix.protocol.wrappers.nbt.NbtWrapper; import me.libraryaddict.disguise.DisguiseConfig; -import me.libraryaddict.disguise.disguisetypes.DisguiseType; -import me.libraryaddict.disguise.disguisetypes.EntityPose; -import me.libraryaddict.disguise.disguisetypes.MetaIndex; -import me.libraryaddict.disguise.disguisetypes.VillagerData; +import me.libraryaddict.disguise.LibsDisguises; +import me.libraryaddict.disguise.disguisetypes.*; +import me.libraryaddict.disguise.disguisetypes.watchers.*; +import me.libraryaddict.disguise.utilities.DisguiseSound; import me.libraryaddict.disguise.utilities.DisguiseUtilities; +import me.libraryaddict.disguise.utilities.LibsPremium; +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.lang.StringUtils; import org.bukkit.*; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.craftbukkit.libs.it.unimi.dsi.fastutil.ints.Int2ObjectMap; import org.bukkit.craftbukkit.libs.org.apache.commons.io.IOUtils; import org.bukkit.entity.*; import org.bukkit.inventory.EquipmentSlot; @@ -26,13 +29,14 @@ import java.io.IOException; import java.io.InputStream; import java.lang.reflect.*; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.Map; import java.util.Optional; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; public class ReflectionManager { - private static String bukkitVersion = Bukkit.getServer().getClass().getName().split("\\.")[3]; + private static String bukkitVersion; private static Class craftItemClass; private static Method damageAndIdleSoundMethod; private static Constructor boundingBoxConstructor; @@ -45,6 +49,8 @@ public class ReflectionManager { private static Field trackedEntitiesField; public static void init() { + bukkitVersion = Bukkit.getServer().getClass().getName().split("\\.")[3]; + try { Object entity = createEntityInstance(DisguiseType.COW, "Cow"); @@ -1176,4 +1182,362 @@ public class ReflectionManager { return null; } + + private static Class getFlagWatcher(DisguiseType disguiseType) { + Class watcherClass; + + try { + switch (disguiseType) { + case ARROW: + watcherClass = TippedArrowWatcher.class; + break; + case COD: + case SALMON: + watcherClass = FishWatcher.class; + break; + case SPECTRAL_ARROW: + watcherClass = ArrowWatcher.class; + break; + case PRIMED_TNT: + watcherClass = TNTWatcher.class; + break; + case MINECART_CHEST: + case MINECART_HOPPER: + case MINECART_MOB_SPAWNER: + case MINECART_TNT: + watcherClass = MinecartWatcher.class; + break; + case SPIDER: + case CAVE_SPIDER: + watcherClass = SpiderWatcher.class; + break; + case PIG_ZOMBIE: + case HUSK: + case DROWNED: + watcherClass = ZombieWatcher.class; + break; + case MAGMA_CUBE: + watcherClass = SlimeWatcher.class; + break; + case ELDER_GUARDIAN: + watcherClass = GuardianWatcher.class; + break; + case WITHER_SKELETON: + case STRAY: + watcherClass = SkeletonWatcher.class; + break; + case ILLUSIONER: + case EVOKER: + watcherClass = IllagerWizardWatcher.class; + break; + case PUFFERFISH: + watcherClass = PufferFishWatcher.class; + break; + default: + watcherClass = (Class) Class.forName( + "me.libraryaddict.disguise.disguisetypes.watchers." + toReadable(disguiseType.name()) + + "Watcher"); + break; + } + } + catch (ClassNotFoundException ex) { + // There is no explicit watcher for this entity. + Class entityClass = disguiseType.getEntityType().getEntityClass(); + + if (entityClass != null) { + if (Tameable.class.isAssignableFrom(entityClass)) { + watcherClass = TameableWatcher.class; + } else if (Ageable.class.isAssignableFrom(entityClass)) { + watcherClass = AgeableWatcher.class; + } else if (Creature.class.isAssignableFrom(entityClass)) { + watcherClass = InsentientWatcher.class; + } else if (LivingEntity.class.isAssignableFrom(entityClass)) { + watcherClass = LivingWatcher.class; + } else if (Fish.class.isAssignableFrom(entityClass)) { + watcherClass = FishWatcher.class; + } else { + watcherClass = FlagWatcher.class; + } + } else { + watcherClass = FlagWatcher.class; // Disguise is unknown type + } + } + + return watcherClass; + } + + /** + * Here we create a nms entity for each disguise. Then grab their default values in their datawatcher. Then their + * sound volume + * for mob noises. As well as setting their watcher class and entity size. + */ + public static void registerValues() { + for (DisguiseType disguiseType : DisguiseType.values()) { + if (disguiseType.getEntityType() == null) { + continue; + } + + Class watcherClass = getFlagWatcher(disguiseType); + + if (watcherClass == null) { + DisguiseUtilities.getLogger() + .severe("Error loading " + disguiseType.name() + ", FlagWatcher not assigned"); + continue; + } + + // Invalidate invalid distribution + if (LibsPremium.isPremium() && + ((LibsPremium.getPaidInformation() != null && LibsPremium.getPaidInformation().isPremium() && + !LibsPremium.getPaidInformation().isLegit()) || + (LibsPremium.getPluginInformation() != null && + LibsPremium.getPluginInformation().isPremium() && + !LibsPremium.getPluginInformation().isLegit()))) { + throw new IllegalStateException( + "Error while checking pi rate on startup! Please re-download the jar from SpigotMC before " + + "reporting this error!"); + } + + disguiseType.setWatcherClass(watcherClass); + + if (LibsDisguises.getInstance() == null || DisguiseValues.getDisguiseValues(disguiseType) != null) { + continue; + } + + createNMSValues(disguiseType); + } + } + + private static void createNMSValues(DisguiseType disguiseType) { + String nmsEntityName = toReadable(disguiseType.name()); + Class nmsClass = ReflectionManager.getNmsClassIgnoreErrors("Entity" + nmsEntityName); + + if (nmsClass == null || Modifier.isAbstract(nmsClass.getModifiers())) { + String[] split = splitReadable(disguiseType.name()); + ArrayUtils.reverse(split); + + nmsEntityName = StringUtils.join(split); + nmsClass = ReflectionManager.getNmsClassIgnoreErrors("Entity" + nmsEntityName); + + if (nmsClass == null || Modifier.isAbstract(nmsClass.getModifiers())) { + nmsEntityName = null; + } + } + + if (nmsEntityName == null) { + switch (disguiseType) { + case DONKEY: + nmsEntityName = "HorseDonkey"; + break; + case ARROW: + nmsEntityName = "TippedArrow"; + break; + case DROPPED_ITEM: + nmsEntityName = "Item"; + break; + case FIREBALL: + nmsEntityName = "LargeFireball"; + break; + case FIREWORK: + nmsEntityName = "Fireworks"; + break; + case GIANT: + nmsEntityName = "GiantZombie"; + break; + case HUSK: + nmsEntityName = "ZombieHusk"; + break; + case ILLUSIONER: + nmsEntityName = "IllagerIllusioner"; + break; + case LEASH_HITCH: + nmsEntityName = "Leash"; + break; + case MINECART: + nmsEntityName = "MinecartRideable"; + break; + case MINECART_COMMAND: + nmsEntityName = "MinecartCommandBlock"; + break; + case MINECART_TNT: + nmsEntityName = "MinecartTNT"; + break; + case MULE: + nmsEntityName = "HorseMule"; + break; + case PRIMED_TNT: + nmsEntityName = "TNTPrimed"; + break; + case PUFFERFISH: + nmsEntityName = "PufferFish"; + break; + case SPLASH_POTION: + nmsEntityName = "Potion"; + break; + case STRAY: + nmsEntityName = "SkeletonStray"; + break; + case TRIDENT: + nmsEntityName = "ThrownTrident"; + break; + case WANDERING_TRADER: + nmsEntityName = "VillagerTrader"; + break; + case TRADER_LLAMA: + nmsEntityName = "LLamaTrader"; // Interesting capitalization + break; + default: + break; + } + } + + try { + if (disguiseType == DisguiseType.UNKNOWN) { + DisguiseValues disguiseValues = new DisguiseValues(disguiseType, null, 0, 0); + + disguiseValues.setAdultBox(new FakeBoundingBox(0, 0, 0)); + + DisguiseSound sound = DisguiseSound.getType(disguiseType.name()); + + if (sound != null) { + sound.setDamageAndIdleSoundVolume(1f); + } + + return; + } + + if (nmsEntityName == null) { + DisguiseUtilities.getLogger().warning("Entity name not found! (" + disguiseType.name() + ")"); + return; + } + + Object nmsEntity = ReflectionManager.createEntityInstance(disguiseType, nmsEntityName); + + if (nmsEntity == null) { + DisguiseUtilities.getLogger().warning("Entity not found! (" + nmsEntityName + ")"); + return; + } + + disguiseType.setTypeId(ReflectionManager.getEntityTypeId(disguiseType.getEntityType())); + + Entity bukkitEntity = ReflectionManager.getBukkitEntity(nmsEntity); + + int entitySize = 0; + + for (Field field : ReflectionManager.getNmsClass("Entity").getFields()) { + if (field.getType().getName().equals("EnumEntitySize")) { + Enum enumEntitySize = (Enum) field.get(nmsEntity); + + entitySize = enumEntitySize.ordinal(); + + break; + } + } + + DisguiseValues disguiseValues = new DisguiseValues(disguiseType, nmsEntity.getClass(), entitySize, + bukkitEntity instanceof Damageable ? ((Damageable) bukkitEntity).getMaxHealth() : 0); + + WrappedDataWatcher watcher = WrappedDataWatcher.getEntityWatcher(bukkitEntity); + ArrayList indexes = MetaIndex.getMetaIndexes(disguiseType.getWatcherClass()); + boolean loggedName = false; + + for (WrappedWatchableObject watch : watcher.getWatchableObjects()) { + MetaIndex flagType = MetaIndex.getMetaIndex(disguiseType.getWatcherClass(), watch.getIndex()); + + if (flagType == null) { + DisguiseUtilities.getLogger() + .severe("MetaIndex not found for " + disguiseType + "! Index: " + watch.getIndex()); + DisguiseUtilities.getLogger() + .severe("Value: " + watch.getRawValue() + " (" + watch.getRawValue().getClass() + ") (" + + nmsEntity.getClass() + ") & " + disguiseType.getWatcherClass().getSimpleName()); + continue; + } + + indexes.remove(flagType); + + Object ourValue = ReflectionManager.convertInvalidMeta(flagType.getDefault()); + Object nmsValue = ReflectionManager.convertInvalidMeta(watch.getValue()); + + if (ourValue.getClass() != nmsValue.getClass()) { + if (!loggedName) { + DisguiseUtilities.getLogger().severe(StringUtils.repeat("=", 20)); + DisguiseUtilities.getLogger() + .severe("MetaIndex mismatch! Disguise " + disguiseType + ", Entity " + nmsEntityName); + loggedName = true; + } + + DisguiseUtilities.getLogger().severe(StringUtils.repeat("-", 20)); + DisguiseUtilities.getLogger() + .severe("Index: " + watch.getIndex() + " | " + flagType.getFlagWatcher().getSimpleName() + + " | " + MetaIndex.getName(flagType)); + Object flagDefault = flagType.getDefault(); + + DisguiseUtilities.getLogger() + .severe("LibsDisguises: " + flagDefault + " (" + flagDefault.getClass() + ")"); + DisguiseUtilities.getLogger() + .severe("LibsDisguises Converted: " + ourValue + " (" + ourValue.getClass() + ")"); + DisguiseUtilities.getLogger() + .severe("Minecraft: " + watch.getRawValue() + " (" + watch.getRawValue().getClass() + ")"); + DisguiseUtilities.getLogger() + .severe("Minecraft Converted: " + nmsValue + " (" + nmsValue.getClass() + ")"); + DisguiseUtilities.getLogger().severe(StringUtils.repeat("-", 20)); + } + } + + for (MetaIndex index : indexes) { + DisguiseUtilities.getLogger().warning( + disguiseType + " has MetaIndex remaining! " + index.getFlagWatcher().getSimpleName() + + " at index " + index.getIndex()); + } + + DisguiseSound sound = DisguiseSound.getType(disguiseType.name()); + + if (sound != null) { + Float soundStrength = ReflectionManager.getSoundModifier(nmsEntity); + + if (soundStrength != null) { + sound.setDamageAndIdleSoundVolume(soundStrength); + } + } + + // Get the bounding box + disguiseValues.setAdultBox(ReflectionManager.getBoundingBox(bukkitEntity)); + + if (bukkitEntity instanceof Ageable) { + ((Ageable) bukkitEntity).setBaby(); + + disguiseValues.setBabyBox(ReflectionManager.getBoundingBox(bukkitEntity)); + } else if (bukkitEntity instanceof Zombie) { + ((Zombie) bukkitEntity).setBaby(true); + + disguiseValues.setBabyBox(ReflectionManager.getBoundingBox(bukkitEntity)); + } + + //disguiseValues.setEntitySize(ReflectionManager.getSize(bukkitEntity)); + } + catch (SecurityException | IllegalArgumentException | IllegalAccessException | FieldAccessException ex) { + DisguiseUtilities.getLogger() + .severe("Uh oh! Trouble while making values for the disguise " + disguiseType.name() + "!"); + DisguiseUtilities.getLogger().severe("Before reporting this error, " + + "please make sure you are using the latest version of LibsDisguises and ProtocolLib."); + DisguiseUtilities.getLogger().severe("Development builds are available at (ProtocolLib) " + + "http://ci.dmulloy2.net/job/ProtocolLib/ and (LibsDisguises) https://ci.md-5" + + ".net/job/LibsDisguises/"); + + ex.printStackTrace(); + } + } + + private static String[] splitReadable(String string) { + String[] split = string.split("_"); + + for (int i = 0; i < split.length; i++) { + split[i] = split[i].substring(0, 1) + split[i].substring(1).toLowerCase(); + } + + return split; + } + + private static String toReadable(String string) { + return StringUtils.join(splitReadable(string)); + } } diff --git a/src/test/java/me/libraryaddict/disguise/disguisetypes/DisguiseCloneTest.java b/src/test/java/me/libraryaddict/disguise/disguisetypes/DisguiseCloneTest.java new file mode 100644 index 00000000..eaa5a1b2 --- /dev/null +++ b/src/test/java/me/libraryaddict/disguise/disguisetypes/DisguiseCloneTest.java @@ -0,0 +1,121 @@ +package me.libraryaddict.disguise.disguisetypes; + +import me.libraryaddict.disguise.LibsDisguises; +import me.libraryaddict.disguise.utilities.DisguiseUtilities; +import me.libraryaddict.disguise.utilities.parser.DisguiseParser; +import me.libraryaddict.disguise.utilities.reflection.ReflectionManager; +import org.bukkit.Material; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.ItemStack; +import org.junit.Assert; +import org.junit.Test; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Enumeration; +import java.util.Map; + +/** + * Created by libraryaddict on 19/01/2020. + */ +public class DisguiseCloneTest { + + /** + * MetaIndex needs ProtocolLib to have initialized so. + */ + // @Test + public void testCloneDisguise() { + try { + ReflectionManager.registerValues(); + DisguiseParser.createDefaultMethods(); + DisguiseUtilities.init(); + + for (DisguiseType type : DisguiseType.values()) { + Disguise disguise; + + if (type.isPlayer()) { + disguise = new PlayerDisguise("libraryaddict"); + } else if (type.isMob()) { + disguise = new MobDisguise(type); + } else { + disguise = new MiscDisguise(type); + } + + for (Map.Entry> entry : DisguiseParser.getMethodDefaults() + .entrySet()) { + Object dValue = entry.getValue().getValue(); + + if (dValue instanceof String) { + dValue = "NewString"; + } else if (dValue instanceof Float) { + dValue = ((float) dValue) + 1; + } else if (dValue instanceof Double) { + dValue = ((double) dValue) + 1; + } else if (dValue instanceof Long) { + dValue = ((long) dValue) + 1; + } else if (dValue instanceof Integer) { + dValue = ((int) dValue) + 1; + } else if (dValue instanceof Byte) { + dValue = ((byte) dValue) + 1; + } else if (dValue instanceof Short) { + dValue = ((short) dValue) + 1; + } else if (dValue instanceof ItemStack) { + dValue = new ItemStack(Material.DIAMOND_BLOCK); + } else if (dValue instanceof Boolean) { + dValue = !((Boolean) dValue); + } else if (dValue instanceof Enum) { + Object[] vals = dValue.getClass().getEnumConstants(); + + for (int i = 0; i < vals.length; i++) { + if (vals[i] == dValue) { + continue; + } + + dValue = vals[i]; + break; + } + } else { + continue; + } + + Method m = entry.getKey(); + + Object invokeWith = disguise; + + if (FlagWatcher.class.isAssignableFrom(entry.getKey().getDeclaringClass())) { + invokeWith = disguise.getWatcher(); + } + + try { + entry.getKey().invoke(invokeWith, dValue); + } + catch (IllegalAccessException e) { + e.printStackTrace(); + } + catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + + Disguise cloned = disguise.clone(); + String dString = DisguiseUtilities.getGson().toJson(disguise); + String cString = DisguiseUtilities.getGson().toJson(cloned); + + if (!dString.equals(cString)) { + System.err.println(dString); + System.err.println(cString); + Assert.fail("Cloned disguise is not the same!"); + } + } + } + catch (Exception ex) { + ex.printStackTrace(); + + if (ex.getCause() != null) { + ex.getCause().printStackTrace(); + } + + throw ex; + } + } +}