/** Setup it so he can see himself when disguised */
 public static void setupFakeDisguise(final Disguise disguise) {
   Entity e = disguise.getEntity();
   // If the disguises entity is null, or the disguised entity isn't a player return
   if (e == null
       || !(e instanceof Player)
       || !getDisguises().containsKey(e.getUniqueId())
       || !getDisguises().get(e.getUniqueId()).contains(disguise)) {
     return;
   }
   Player player = (Player) e;
   // Check if he can even see this..
   if (!((TargetedDisguise) disguise).canSee(player)) {
     return;
   }
   // Remove the old disguise, else we have weird disguises around the place
   DisguiseUtilities.removeSelfDisguise(player);
   // If the disguised player can't see himself. Return
   if (!disguise.isSelfDisguiseVisible()
       || !PacketsManager.isViewDisguisesListenerEnabled()
       || player.getVehicle() != null) {
     return;
   }
   selfDisguised.add(player.getUniqueId());
   sendSelfDisguise(player, (TargetedDisguise) disguise);
   if (disguise.isHidingArmorFromSelf() || disguise.isHidingHeldItemFromSelf()) {
     if (PacketsManager.isInventoryListenerEnabled()) {
       player.updateInventory();
     }
   }
 }
 /**
  * Get all EntityPlayers who have this entity in their Entity Tracker And they are in the
  * targetted disguise.
  */
 public static ArrayList<Player> getPerverts(Disguise disguise) {
   ArrayList<Player> players = new ArrayList<Player>();
   try {
     Object entityTrackerEntry = ReflectionManager.getEntityTrackerEntry(disguise.getEntity());
     if (entityTrackerEntry != null) {
       HashSet trackedPlayers =
           (HashSet)
               ReflectionManager.getNmsField("EntityTrackerEntry", "trackedPlayers")
                   .get(entityTrackerEntry);
       for (Object p : trackedPlayers) {
         Player player = (Player) ReflectionManager.getBukkitEntity(p);
         if (((TargetedDisguise) disguise).canSee(player)) {
           players.add(player);
         }
       }
     }
   } catch (Exception ex) {
     ex.printStackTrace();
   }
   return players;
 }
 /**
  * Returns the disguise if it all parsed correctly. Returns a exception with a complete message if
  * it didn't. The commandsender is purely used for checking permissions. Would defeat the purpose
  * otherwise. To reach this point, the disguise has been feed a proper disguisetype.
  */
 protected Disguise parseDisguise(
     CommandSender sender,
     String[] args,
     HashMap<DisguiseType, HashMap<ArrayList<String>, Boolean>> map)
     throws Exception {
   if (map.isEmpty()) {
     throw new IllegalArgumentException(ChatColor.RED + "You are forbidden to use this command.");
   }
   if (args.length == 0) {
     sendCommandUsage(sender, map);
     throw new IllegalArgumentException();
   }
   // How many args to skip due to the disugise being constructed
   // Time to start constructing the disguise.
   // We will need to check between all 3 kinds of disguises
   int toSkip = 1;
   ArrayList<String> usedOptions = new ArrayList<String>();
   Disguise disguise = null;
   HashMap<ArrayList<String>, Boolean> optionPermissions;
   if (args[0].startsWith("@")) {
     if (sender.hasPermission("libsdisguises.disguise.disguiseclone")) {
       disguise = DisguiseUtilities.getClonedDisguise(args[0].toLowerCase());
       if (disguise == null) {
         throw new IllegalArgumentException(
             ChatColor.RED + "Cannot find a disguise under the reference " + args[0]);
       }
     } else {
       throw new IllegalArgumentException(
           ChatColor.RED + "You do not have perimssion to use disguise references!");
     }
     optionPermissions =
         (map.containsKey(disguise.getType())
             ? map.get(disguise.getType())
             : new HashMap<ArrayList<String>, Boolean>());
   } else {
     DisguiseType disguiseType = null;
     if (args[0].equalsIgnoreCase("p")) {
       disguiseType = DisguiseType.PLAYER;
     } else {
       for (DisguiseType type : DisguiseType.values()) {
         if (args[0].equalsIgnoreCase(type.name())
             || args[0].equalsIgnoreCase(type.name().replace("_", ""))) {
           disguiseType = type;
           break;
         }
       }
     }
     if (disguiseType == null) {
       throw new IllegalArgumentException(
           ChatColor.RED
               + "Error! The disguise "
               + ChatColor.GREEN
               + args[0]
               + ChatColor.RED
               + " doesn't exist!");
     }
     if (disguiseType.getEntityType() == null) {
       throw new IllegalArgumentException(
           ChatColor.RED + "Error! This version of minecraft does not have that disguise!");
     }
     if (!map.containsKey(disguiseType)) {
       throw new IllegalArgumentException(
           ChatColor.RED + "You are forbidden to use this disguise.");
     }
     optionPermissions = map.get(disguiseType);
     HashMap<String, Boolean> disguiseOptions = this.getDisguisePermission(sender, disguiseType);
     if (disguiseType.isPlayer()) { // If he is doing a player disguise
       if (args.length == 1) {
         // He needs to give the player name
         throw new IllegalArgumentException(
             ChatColor.RED + "Error! You need to give a player name!");
       } else {
         if (!disguiseOptions.isEmpty()
             && (!disguiseOptions.containsKey(args[1].toLowerCase())
                 || !disguiseOptions.get(args[1].toLowerCase()))) {
           throw new IllegalArgumentException(
               ChatColor.RED + "Error! You don't have permission to use that name!");
         }
         // Construct the player disguise
         disguise = new PlayerDisguise(ChatColor.translateAlternateColorCodes('&', args[1]));
         toSkip++;
       }
     } else {
       if (disguiseType.isMob()) { // Its a mob, use the mob constructor
         boolean adult = true;
         if (args.length > 1) {
           if (args[1].equalsIgnoreCase("baby") || args[1].equalsIgnoreCase("adult")) {
             usedOptions.add("setbaby");
             doCheck(optionPermissions, usedOptions);
             adult = args[1].equalsIgnoreCase("adult");
             toSkip++;
           }
         }
         disguise = new MobDisguise(disguiseType, adult);
       } else if (disguiseType.isMisc()) {
         // Its a misc, we are going to use the MiscDisguise constructor.
         int miscId = -1;
         int miscData = -1;
         String secondArg = null;
         if (args.length > 1) {
           // They have defined more arguements!
           // If the first arg is a number
           if (args[1].contains(":")) {
             String[] split = args[1].split(":");
             if (isNumeric(split[1])) {
               secondArg = split[1];
             }
             args[1] = split[0];
           }
           if (isNumeric(args[1])) {
             miscId = Integer.parseInt(args[1]);
           } else {
             if (disguiseType == DisguiseType.FALLING_BLOCK
                 || disguiseType == DisguiseType.DROPPED_ITEM) {
               for (Material mat : Material.values()) {
                 if (mat.name().replace("_", "").equalsIgnoreCase(args[1].replace("_", ""))) {
                   miscId = mat.getId();
                   break;
                 }
               }
             }
           }
           if (miscId != -1) {
             switch (disguiseType) {
               case PAINTING:
               case FALLING_BLOCK:
               case SPLASH_POTION:
               case DROPPED_ITEM:
               case FISHING_HOOK:
               case ARROW:
               case SMALL_FIREBALL:
               case FIREBALL:
               case WITHER_SKULL:
                 break;
               default:
                 throw new IllegalArgumentException(
                     ChatColor.RED
                         + "Error! "
                         + disguiseType.toReadable()
                         + " doesn't know what to do with "
                         + args[1]
                         + "!");
             }
             toSkip++;
             // If they also defined a data value
             if (args.length > 2 && secondArg == null && isNumeric(args[2])) {
               secondArg = args[2];
               toSkip++;
             }
             if (secondArg != null) {
               if (disguiseType != DisguiseType.FALLING_BLOCK
                   && disguiseType != DisguiseType.DROPPED_ITEM) {
                 throw new IllegalArgumentException(
                     ChatColor.RED
                         + "Error! Only the disguises "
                         + DisguiseType.FALLING_BLOCK.toReadable()
                         + " and "
                         + DisguiseType.DROPPED_ITEM.toReadable()
                         + " uses a second number!");
               }
               miscData = Integer.parseInt(secondArg);
             }
           }
         }
         if (!disguiseOptions.isEmpty() && miscId != -1) {
           String toCheck = "" + miscId;
           if (miscData == 0 || miscData == -1) {
             if (!disguiseOptions.containsKey(toCheck) || !disguiseOptions.get(toCheck)) {
               toCheck += ":0";
             }
           } else {
             toCheck += ":" + miscData;
           }
           if (!disguiseOptions.containsKey(toCheck) || !disguiseOptions.get(toCheck)) {
             throw new IllegalArgumentException(
                 ChatColor.RED
                     + "Error! You do not have permission to use the parameter "
                     + toCheck
                     + " on the "
                     + disguiseType.toReadable()
                     + " disguise!");
           }
         }
         if (miscId != -1) {
           if (disguiseType == DisguiseType.FALLING_BLOCK) {
             usedOptions.add("setblock");
             doCheck(optionPermissions, usedOptions);
           } else if (disguiseType == DisguiseType.PAINTING) {
             usedOptions.add("setpainting");
             doCheck(optionPermissions, usedOptions);
           } else if (disguiseType == DisguiseType.SPLASH_POTION) {
             usedOptions.add("setpotionid");
             doCheck(optionPermissions, usedOptions);
           }
         }
         // Construct the disguise
         disguise = new MiscDisguise(disguiseType, miscId, miscData);
       }
     }
   }
   // Copy strings to their new range
   String[] newArgs = new String[args.length - toSkip];
   System.arraycopy(args, toSkip, newArgs, 0, args.length - toSkip);
   args = newArgs;
   Method[] methods = this.getDisguiseWatcherMethods(disguise.getWatcher().getClass());
   for (int i = 0; i < args.length; i += 2) {
     String methodName = args[i];
     String valueString = (args.length - 1 == i ? null : args[i + 1]);
     Method methodToUse = null;
     Object value = null;
     IllegalArgumentException storedEx = null;
     for (Method method : methods) {
       if (!method.getName().startsWith("get")
           && method.getName().equalsIgnoreCase(methodName)
           && method.getAnnotation(Deprecated.class) == null
           && method.getParameterTypes().length == 1) {
         try {
           methodToUse = method;
           methodName = methodToUse.getName();
           Class<?>[] types = methodToUse.getParameterTypes();
           Class param = types[0];
           if (valueString != null) {
             if (int.class == param) {
               // Parse to integer
               if (isNumeric(valueString)) {
                 value = (int) Integer.parseInt(valueString);
               } else {
                 throw parseToException("number", valueString, methodName);
               }
             } else if (float.class == param || double.class == param) {
               // Parse to number
               if (isDouble(valueString)) {
                 float obj = Float.parseFloat(valueString);
                 if (param == float.class) {
                   value = (float) obj;
                 } else if (param == double.class) {
                   value = (double) obj;
                 }
               } else {
                 throw parseToException("number.0", valueString, methodName);
               }
             } else if (param == String.class) {
               // Parse to string
               value = ChatColor.translateAlternateColorCodes('&', valueString);
             } else if (param == AnimalColor.class) {
               // Parse to animal color
               try {
                 value = AnimalColor.valueOf(valueString.toUpperCase());
               } catch (Exception ex) {
                 throw parseToException("animal color", valueString, methodName);
               }
             } else if (param == ItemStack.class) {
               // Parse to itemstack
               try {
                 value = parseToItemstack(valueString);
               } catch (Exception ex) {
                 throw new IllegalArgumentException(String.format(ex.getMessage(), methodName));
               }
             } else if (param == ItemStack[].class) {
               // Parse to itemstack array
               ItemStack[] items = new ItemStack[4];
               String[] split = valueString.split(",");
               if (split.length == 4) {
                 for (int a = 0; a < 4; a++) {
                   try {
                     items[a] = parseToItemstack(split[a]);
                   } catch (Exception ex) {
                     throw parseToException(
                         "item ID,ID,ID,ID"
                             + ChatColor.RED
                             + " or "
                             + ChatColor.GREEN
                             + "ID:Data,ID:Data,ID:Data,ID:Data combo",
                         valueString,
                         methodName);
                   }
                 }
               } else {
                 throw parseToException(
                     "item ID,ID,ID,ID"
                         + ChatColor.RED
                         + " or "
                         + ChatColor.GREEN
                         + "ID:Data,ID:Data,ID:Data,ID:Data combo",
                     valueString,
                     methodName);
               }
               value = items;
             } else if (param.getSimpleName().equals("Color")) {
               // Parse to horse color
               value = callValueOf(param, valueString, methodName, "a horse color");
             } else if (param.getSimpleName().equals("Style")) {
               // Parse to horse style
               value = callValueOf(param, valueString, methodName, "a horse style");
             } else if (param.getSimpleName().equals("Profession")) {
               // Parse to villager profession
               value = callValueOf(param, valueString, methodName, "a villager profession");
             } else if (param.getSimpleName().equals("Art")) {
               // Parse to art type
               value = callValueOf(param, valueString, methodName, "a painting art");
             } else if (param.getSimpleName().equals("Type")) {
               // Parse to ocelot type
               value = callValueOf(param, valueString, methodName, "a ocelot type");
             } else if (param == PotionEffectType.class) {
               // Parse to potion effect
               try {
                 PotionEffectType potionType =
                     PotionEffectType.getByName(valueString.toUpperCase());
                 if (potionType == null && isNumeric(valueString)) {
                   potionType = PotionEffectType.getById(Integer.parseInt(valueString));
                 }
                 if (potionType == null) throw new IllegalArgumentException();
                 value = potionType;
               } catch (Exception ex) {
                 throw parseToException("a potioneffect type", valueString, methodName);
               }
             } else if (param == int[].class) {
               String[] split = valueString.split(",");
               int[] values = new int[split.length];
               for (int b = 0; b < values.length; b++) {
                 try {
                   values[b] = Integer.parseInt(split[b]);
                 } catch (NumberFormatException ex) {
                   throw parseToException("Number,Number,Number...", valueString, methodName);
                 }
               }
               value = values;
             } else if (param == BlockFace.class) {
               try {
                 BlockFace face = BlockFace.valueOf(valueString.toUpperCase());
                 if (face.ordinal() > 3) throw new IllegalArgumentException();
                 value = face;
               } catch (Exception ex) {
                 throw parseToException(
                     "a direction (north, east, south, west)", valueString, methodName);
               }
             }
           }
           if (value == null && boolean.class == param) {
             if (valueString == null) {
               value = true;
               i--;
             } else if (valueString.equalsIgnoreCase("true")) {
               value = true;
             } else if (valueString.equalsIgnoreCase("false")) {
               value = false;
             } else throw parseToException("true/false", valueString, methodName);
           }
           if (value != null) {
             break;
           }
         } catch (IllegalArgumentException ex) {
           storedEx = ex;
           methodToUse = null;
         } catch (Exception ex) {
           ex.printStackTrace();
           methodToUse = null;
         }
       }
     }
     if (methodToUse == null) {
       if (storedEx != null) {
         throw storedEx;
       }
       throw new IllegalArgumentException(ChatColor.RED + "Cannot find the option " + methodName);
     }
     if (value == null) {
       throw new IllegalArgumentException(
           ChatColor.RED + "No value was given for the option " + methodName);
     }
     if (!usedOptions.contains(methodName.toLowerCase())) {
       usedOptions.add(methodName.toLowerCase());
     }
     doCheck(optionPermissions, usedOptions);
     if (FlagWatcher.class.isAssignableFrom(methodToUse.getDeclaringClass()))
       methodToUse.invoke(disguise.getWatcher(), value);
     else methodToUse.invoke(disguise, value);
   }
   // Alright. We've constructed our disguise.
   return disguise;
 }
 public static boolean isDisguiseInUse(Disguise disguise) {
   return disguise.getEntity() != null
       && getDisguises().containsKey(disguise.getEntity().getUniqueId())
       && getDisguises().get(disguise.getEntity().getUniqueId()).contains(disguise);
 }
 @Override
 public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
   HashMap<DisguiseType, HashMap<ArrayList<String>, Boolean>> map = getPermissions(sender);
   if (map.isEmpty()) {
     sender.sendMessage(ChatColor.RED + "You are forbidden to use this command.");
     return true;
   }
   if (args.length == 0) {
     sendCommandUsage(sender, map);
     return true;
   }
   if (args.length == 1) {
     sender.sendMessage(ChatColor.RED + "You need to supply a disguise as well as the player");
     return true;
   }
   Player player = Bukkit.getPlayer(args[0]);
   if (player == null) {
     sender.sendMessage(ChatColor.RED + "Cannot find the player '" + args[0] + "'");
     return true;
   }
   String[] newArgs = new String[args.length - 1];
   System.arraycopy(args, 1, newArgs, 0, newArgs.length);
   Disguise disguise;
   try {
     disguise = parseDisguise(sender, newArgs, map);
   } catch (DisguiseParseException ex) {
     if (ex.getMessage() != null) {
       sender.sendMessage(ex.getMessage());
     }
     return true;
   } catch (Exception ex) {
     ex.printStackTrace(System.out);
     return true;
   }
   if (disguise.isMiscDisguise() && !DisguiseConfig.isMiscDisguisesForLivingEnabled()) {
     sender.sendMessage(
         ChatColor.RED
             + "Can't disguise a living entity as a misc disguise. This has been disabled in the config!");
     return true;
   }
   if (DisguiseConfig.isNameOfPlayerShownAboveDisguise()) {
     if (disguise.getWatcher() instanceof LivingWatcher) {
       ((LivingWatcher) disguise.getWatcher()).setCustomName(player.getDisplayName());
       if (DisguiseConfig.isNameAboveHeadAlwaysVisible()) {
         ((LivingWatcher) disguise.getWatcher()).setCustomNameVisible(true);
       }
     }
   }
   DisguiseAPI.disguiseToAll(player, disguise);
   if (disguise.isDisguiseInUse()) {
     sender.sendMessage(
         ChatColor.RED
             + "Successfully disguised "
             + player.getName()
             + " as a "
             + disguise.getType().toReadable()
             + "!");
   } else {
     sender.sendMessage(
         ChatColor.RED
             + "Failed to disguise "
             + player.getName()
             + " as a "
             + disguise.getType().toReadable()
             + "!");
   }
   return true;
 }