public static void addDisguise(UUID entityId, TargetedDisguise disguise) {
   if (!getDisguises().containsKey(entityId)) {
     getDisguises().put(entityId, new HashSet<TargetedDisguise>());
   }
   getDisguises().get(entityId).add(disguise);
   checkConflicts(disguise, null);
   if (disguise.getDisguiseTarget() == TargetType.SHOW_TO_EVERYONE_BUT_THESE_PLAYERS
       && disguise.isModifyBoundingBox()) {
     doBoundingBox(disguise);
   }
 }
 public static TargetedDisguise getMainDisguise(UUID entityId) {
   TargetedDisguise toReturn = null;
   if (getDisguises().containsKey(entityId)) {
     for (TargetedDisguise disguise : getDisguises().get(entityId)) {
       if (disguise.getDisguiseTarget() == TargetType.SHOW_TO_EVERYONE_BUT_THESE_PLAYERS) {
         return disguise;
       }
       toReturn = disguise;
     }
   }
   return toReturn;
 }
 public static boolean removeDisguise(TargetedDisguise disguise) {
   UUID entityId = disguise.getEntity().getUniqueId();
   if (getDisguises().containsKey(entityId) && getDisguises().get(entityId).remove(disguise)) {
     if (getDisguises().get(entityId).isEmpty()) {
       getDisguises().remove(entityId);
     }
     if (disguise.getDisguiseTarget() == TargetType.SHOW_TO_EVERYONE_BUT_THESE_PLAYERS
         && disguise.isModifyBoundingBox()) {
       doBoundingBox(disguise);
     }
     return true;
   }
   return false;
 }
 public static TargetedDisguise getDisguise(Player observer, Entity entity) {
   UUID entityId = entity.getUniqueId();
   if (futureDisguises.containsKey(entity.getEntityId())) {
     for (TargetedDisguise disguise : futureDisguises.remove(entity.getEntityId())) {
       addDisguise(entityId, disguise);
     }
   }
   if (getDisguises().containsKey(entityId)) {
     for (TargetedDisguise disguise : getDisguises().get(entityId)) {
       if (disguise.canSee(observer)) {
         return disguise;
       }
     }
   }
   return null;
 }
 public static void doBoundingBox(TargetedDisguise disguise) {
   // TODO Slimes
   Entity entity = disguise.getEntity();
   if (entity != null) {
     if (isDisguiseInUse(disguise)) {
       DisguiseValues disguiseValues = DisguiseValues.getDisguiseValues(disguise.getType());
       FakeBoundingBox disguiseBox = disguiseValues.getAdultBox();
       if (disguiseValues.getBabyBox() != null) {
         if ((disguise.getWatcher() instanceof AgeableWatcher
                 && ((AgeableWatcher) disguise.getWatcher()).isBaby())
             || (disguise.getWatcher() instanceof ZombieWatcher
                 && ((ZombieWatcher) disguise.getWatcher()).isBaby())) {
           disguiseBox = disguiseValues.getBabyBox();
         }
       }
       ReflectionManager.setBoundingBox(entity, disguiseBox);
     } else {
       DisguiseValues entityValues =
           DisguiseValues.getDisguiseValues(DisguiseType.getType(entity.getType()));
       FakeBoundingBox entityBox = entityValues.getAdultBox();
       if (entityValues.getBabyBox() != null) {
         if ((entity instanceof Ageable && !((Ageable) entity).isAdult())
             || (entity instanceof Zombie && ((Zombie) entity).isBaby())) {
           entityBox = entityValues.getBabyBox();
         }
       }
       ReflectionManager.setBoundingBox(entity, entityBox);
     }
   }
 }
 /** Sends entity removal packets, as this disguise was removed */
 public static void destroyEntity(TargetedDisguise disguise) {
   try {
     Object entityTrackerEntry = ReflectionManager.getEntityTrackerEntry(disguise.getEntity());
     if (entityTrackerEntry != null) {
       HashSet trackedPlayers =
           (HashSet)
               ReflectionManager.getNmsField("EntityTrackerEntry", "trackedPlayers")
                   .get(entityTrackerEntry);
       HashSet cloned = (HashSet) trackedPlayers.clone();
       PacketContainer destroyPacket = new PacketContainer(PacketType.Play.Server.ENTITY_DESTROY);
       destroyPacket.getIntegerArrays().write(0, new int[] {disguise.getEntity().getEntityId()});
       for (Object p : cloned) {
         Player player = (Player) ReflectionManager.getBukkitEntity(p);
         if (player == disguise.getEntity() || disguise.canSee(player.getName())) {
           ProtocolLibrary.getProtocolManager().sendServerPacket(player, destroyPacket);
         }
       }
     }
   } catch (Exception ex) {
     ex.printStackTrace();
   }
 }
  /** Sends the self disguise to the player */
  public static void sendSelfDisguise(final Player player, final TargetedDisguise disguise) {
    try {
      if (!disguise.isDisguiseInUse()
          || !player.isValid()
          || !player.isOnline()
          || !disguise.isSelfDisguiseVisible()
          || !disguise.canSee(player)) {
        return;
      }
      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.
        // Else its going to run in a infinite loop hue hue hue..
        // At least until this disguise is discarded
        Bukkit.getScheduler()
            .runTask(
                libsDisguises,
                new Runnable() {
                  public void run() {
                    if (DisguiseAPI.getDisguise(player, player) == disguise) {
                      sendSelfDisguise(player, disguise);
                    }
                  }
                });
        return;
      }
      // Add himself to his own entity tracker
      ((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)
              .createPacket(player));
      WrappedDataWatcher dataWatcher = WrappedDataWatcher.getEntityWatcher(player);
      sendSelfPacket(
          player,
          manager
              .createPacketConstructor(
                  PacketType.Play.Server.ENTITY_METADATA, player.getEntityId(), dataWatcher, true)
              .createPacket(player.getEntityId(), dataWatcher, true));

      boolean isMoving = false;
      try {
        Field field =
            ReflectionManager.getNmsClass("EntityTrackerEntry").getDeclaredField("isMoving");
        field.setAccessible(true);
        isMoving = field.getBoolean(entityTrackerEntry);
      } catch (Exception ex) {
        ex.printStackTrace();
      }
      // Send the velocity packets
      if (isMoving) {
        Vector velocity = player.getVelocity();
        sendSelfPacket(
            player,
            manager
                .createPacketConstructor(
                    PacketType.Play.Server.ENTITY_VELOCITY,
                    player.getEntityId(),
                    velocity.getX(),
                    velocity.getY(),
                    velocity.getZ())
                .createPacket(
                    player.getEntityId(), velocity.getX(), velocity.getY(), velocity.getZ()));
      }

      // Why the hell would he even need this. Meh.
      if (player.getVehicle() != null && player.getEntityId() > player.getVehicle().getEntityId()) {
        sendSelfPacket(
            player,
            manager
                .createPacketConstructor(
                    PacketType.Play.Server.ATTACH_ENTITY, 0, player, player.getVehicle())
                .createPacket(0, player, player.getVehicle()));
      } else if (player.getPassenger() != null
          && player.getEntityId() > player.getPassenger().getEntityId()) {
        sendSelfPacket(
            player,
            manager
                .createPacketConstructor(
                    PacketType.Play.Server.ATTACH_ENTITY, 0, player.getPassenger(), player)
                .createPacket(0, player.getPassenger(), player));
      }

      // Resend the armor
      for (int i = 0; i < 5; i++) {
        ItemStack item;
        if (i == 0) {
          item = player.getItemInHand();
        } else {
          item = player.getInventory().getArmorContents()[i - 1];
        }

        if (item != null && item.getType() != Material.AIR) {
          sendSelfPacket(
              player,
              manager
                  .createPacketConstructor(
                      PacketType.Play.Server.ENTITY_EQUIPMENT, player.getEntityId(), i, item)
                  .createPacket(player.getEntityId(), i, item));
        }
      }
      Location loc = player.getLocation();
      // If the disguised is sleeping for w/e reason
      if (player.isSleeping()) {
        sendSelfPacket(
            player,
            manager
                .createPacketConstructor(
                    PacketType.Play.Server.BED,
                    player,
                    loc.getBlockX(),
                    loc.getBlockY(),
                    loc.getBlockZ())
                .createPacket(player, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()));
      }

      // Resend any active potion effects
      for (Object potionEffect : player.getActivePotionEffects()) {
        sendSelfPacket(
            player,
            manager
                .createPacketConstructor(
                    PacketType.Play.Server.ENTITY_EFFECT, player.getEntityId(), potionEffect)
                .createPacket(player.getEntityId(), potionEffect));
      }
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }
 /** Resends the entity to all the watching players, which is where the magic begins */
 public static void refreshTrackers(final TargetedDisguise disguise) {
   if (disguise.getEntity().isValid()) {
     PacketContainer destroyPacket = getDestroyPacket(disguise.getEntity().getEntityId());
     try {
       if (selfDisguised.contains(disguise.getEntity().getUniqueId())
           && disguise.isDisguiseInUse()) {
         removeSelfDisguise((Player) disguise.getEntity());
         ProtocolLibrary.getProtocolManager()
             .sendServerPacket((Player) disguise.getEntity(), destroyPacket);
         Bukkit.getScheduler()
             .scheduleSyncDelayedTask(
                 libsDisguises,
                 new Runnable() {
                   public void run() {
                     try {
                       DisguiseUtilities.sendSelfDisguise((Player) disguise.getEntity(), disguise);
                     } catch (Exception ex) {
                       ex.printStackTrace();
                     }
                   }
                 },
                 2);
       }
       final Object entityTrackerEntry =
           ReflectionManager.getEntityTrackerEntry(disguise.getEntity());
       if (entityTrackerEntry != null) {
         HashSet trackedPlayers =
             (HashSet)
                 ReflectionManager.getNmsField("EntityTrackerEntry", "trackedPlayers")
                     .get(entityTrackerEntry);
         Method clear =
             ReflectionManager.getNmsMethod(
                 "EntityTrackerEntry", "clear", ReflectionManager.getNmsClass("EntityPlayer"));
         final Method updatePlayer =
             ReflectionManager.getNmsMethod(
                 "EntityTrackerEntry",
                 "updatePlayer",
                 ReflectionManager.getNmsClass("EntityPlayer"));
         HashSet cloned = (HashSet) trackedPlayers.clone();
         for (final Object p : cloned) {
           Player player = (Player) ReflectionManager.getBukkitEntity(p);
           if (disguise.getEntity() != player && disguise.canSee(player.getName())) {
             clear.invoke(entityTrackerEntry, p);
             ProtocolLibrary.getProtocolManager().sendServerPacket(player, destroyPacket);
             Bukkit.getScheduler()
                 .scheduleSyncDelayedTask(
                     libsDisguises,
                     new Runnable() {
                       public void run() {
                         try {
                           updatePlayer.invoke(entityTrackerEntry, p);
                         } catch (Exception ex) {
                           ex.printStackTrace();
                         }
                       }
                     },
                     2);
           }
         }
       }
     } catch (Exception ex) {
       ex.printStackTrace();
     }
   }
 }
  /**
   * If name isn't null. Make sure that the name doesn't see any other disguise. Else if name is
   * null. Make sure that the observers in the disguise don't see any other disguise.
   */
  public static void checkConflicts(TargetedDisguise disguise, String name) {
    // If the disguise is being used.. Else we may accidentally undisguise something else
    if (DisguiseAPI.isDisguiseInUse(disguise)) {
      Iterator<TargetedDisguise> disguiseItel =
          getDisguises().get(disguise.getEntity().getUniqueId()).iterator();
      // Iterate through the disguises
      while (disguiseItel.hasNext()) {
        TargetedDisguise d = disguiseItel.next();
        // Make sure the disguise isn't the same thing
        if (d != disguise) {
          // If the loop'd disguise is hiding the disguise to everyone in its list
          if (d.getDisguiseTarget() == TargetType.HIDE_DISGUISE_TO_EVERYONE_BUT_THESE_PLAYERS) {
            // If player is a observer in the loop
            if (disguise.getDisguiseTarget()
                == TargetType.HIDE_DISGUISE_TO_EVERYONE_BUT_THESE_PLAYERS) {
              // If player is a observer in the disguise
              // Remove them from the loop
              if (name != null) {
                d.removePlayer(name);
              } else {
                for (String playername : disguise.getObservers()) {
                  d.silentlyRemovePlayer(playername);
                }
              }
            } else if (disguise.getDisguiseTarget()
                == TargetType.SHOW_TO_EVERYONE_BUT_THESE_PLAYERS) {
              // If player is not a observer in the loop
              if (name != null) {
                if (!disguise.getObservers().contains(name)) {
                  d.removePlayer(name);
                }
              } else {
                for (String playername : new ArrayList<String>(d.getObservers())) {
                  if (!disguise.getObservers().contains(playername)) {
                    d.silentlyRemovePlayer(playername);
                  }
                }
              }
            }
          } else if (d.getDisguiseTarget() == TargetType.SHOW_TO_EVERYONE_BUT_THESE_PLAYERS) {
            // Here you add it to the loop if they see the disguise
            if (disguise.getDisguiseTarget()
                == TargetType.HIDE_DISGUISE_TO_EVERYONE_BUT_THESE_PLAYERS) {
              // Everyone who is in the disguise needs to be added to the loop
              if (name != null) {
                d.addPlayer(name);
              } else {
                for (String playername : disguise.getObservers()) {
                  d.silentlyAddPlayer(playername);
                }
              }
            } else if (disguise.getDisguiseTarget()
                == TargetType.SHOW_TO_EVERYONE_BUT_THESE_PLAYERS) {
              // This here is a paradox.
              // If fed a name. I can do this.
              // But the rest of the time.. Its going to conflict.
              // The below is debug output. Most people wouldn't care for it.

              // System.out.print("Cannot set more than one " +
              // TargetType.SHOW_TO_EVERYONE_BUT_THESE_PLAYERS
              // + " on a entity. Removed the old disguise.");

              disguiseItel.remove();
              d.removeDisguise();
            }
          }
        }
      }
    }
  }