@Override
  public void setDistance(Hologram hologram, double distance) {

    List<EntityArmorStand> armorStands = new ArrayList<EntityArmorStand>();
    Location loc = hologram.getLocation();

    for (Object as : hologram.getArmorStands()) armorStands.add((EntityArmorStand) as);

    for (Player p : hologram.getPlayers()) {

      for (int i = 1; i < armorStands.size(); ++i) {

        EntityArmorStand beforeAs = armorStands.get(i - 1);
        EntityArmorStand as = armorStands.get(i);

        int newX = MathHelper.floor(loc.getX() * 32.0D);
        int newY = MathHelper.floor((beforeAs.locY - distance) * 32.0D);
        int newZ = MathHelper.floor(loc.getZ() * 32.0D);

        PacketPlayOutEntityTeleport packet =
            new PacketPlayOutEntityTeleport(
                as.getId(), newX, newY, newZ, (byte) as.yaw, (byte) as.pitch, false);
        ((CraftPlayer) p).getHandle().playerConnection.sendPacket(packet);

        as.setLocation(as.locX, beforeAs.locY - distance, as.locZ, as.yaw, as.pitch);
      }
    }
  }
  @Override
  public void removeMessage(Hologram hologram, int index) {

    EntityArmorStand removeArmorStand = (EntityArmorStand) hologram.getArmorStands().get(index);
    List<Double> pos = new ArrayList<Double>();

    for (Player p : hologram.getPlayers()) {
      PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(removeArmorStand.getId());
      ((CraftPlayer) p).getHandle().playerConnection.sendPacket(packet);
    }

    for (int i = index + 1; i < hologram.getArmorStands().size(); ++i) {
      EntityArmorStand as = (EntityArmorStand) hologram.getArmorStands().get(i);
      EntityArmorStand oldAs = (EntityArmorStand) hologram.getArmorStands().get(i - 1);
      int dy = MathHelper.floor(oldAs.locY * 32.0D) - MathHelper.floor(as.locY * 32.0D);

      for (Player p : hologram.getPlayers()) {

        if (dy >= -128 && dy < 128) {

          PacketPlayOutRelEntityMove packet =
              new PacketPlayOutRelEntityMove(as.getId(), (byte) 0, (byte) dy, (byte) 0, false);
          ((CraftPlayer) p).getHandle().playerConnection.sendPacket(packet);

        } else {

          PacketPlayOutEntityTeleport packet =
              new PacketPlayOutEntityTeleport(
                  as.getId(),
                  MathHelper.floor(oldAs.locX * 32.0D),
                  MathHelper.floor(oldAs.locY * 32.0D),
                  MathHelper.floor(oldAs.locZ * 32.0D),
                  (byte) as.yaw,
                  (byte) as.pitch,
                  false);

          ((CraftPlayer) p).getHandle().playerConnection.sendPacket(packet);
        }
      }
      pos.add(oldAs.locY);
    }

    // Restore the correct positions
    int j = 0;
    for (int i = index + 1; i < hologram.getArmorStands().size(); ++i) {
      EntityArmorStand as = (EntityArmorStand) hologram.getArmorStands().get(i);
      as.setLocation(as.locX, pos.get(j), as.locZ, as.yaw, as.pitch);
      ++j;
    }
  }
  @Override
  public void shoot(double d0, double d1, double d2, float f, float f1) {
    float f2 = MathHelper.sqrt(d0 * d0 + d1 * d1 + d2 * d2);

    d0 /= f2;
    d1 /= f2;
    d2 /= f2;
    d0 += random.nextGaussian() * 0.007499999832361937D * f1;
    d1 += random.nextGaussian() * 0.007499999832361937D * f1;
    d2 += random.nextGaussian() * 0.007499999832361937D * f1;
    d0 *= f;
    d1 *= f;
    d2 *= f;
    motX = d0;
    motY = d1;
    motZ = d2;
    float f3 = MathHelper.sqrt(d0 * d0 + d2 * d2);

    lastYaw = yaw = (float) (Math.atan2(d0, d2) * 180.0D / 3.1415927410125732D);
    lastPitch = pitch = (float) (Math.atan2(d1, f3) * 180.0D / 3.1415927410125732D);
  }
  @Override
  public void move(Hologram hologram, Location newLocation) {

    List<EntityArmorStand> armorStands = new ArrayList<EntityArmorStand>();

    for (Object as : hologram.getArmorStands()) armorStands.add((EntityArmorStand) as);

    int newX = MathHelper.floor(newLocation.getX() * 32.0D);
    int newZ = MathHelper.floor(newLocation.getZ() * 32.0D);

    for (Player p : hologram.getPlayers()) {
      for (int i = 0; i < armorStands.size(); ++i) {

        EntityArmorStand as = armorStands.get(i);
        double distance = i * hologram.getDistance();
        int newY = MathHelper.floor((newLocation.getY() - distance) * 32.0D);

        PacketPlayOutEntityTeleport packet =
            new PacketPlayOutEntityTeleport(
                as.getId(),
                newX,
                newY,
                newZ,
                (byte) newLocation.getYaw(),
                (byte) newLocation.getPitch(),
                false);
        ((CraftPlayer) p).getHandle().playerConnection.sendPacket(packet);

        as.setLocation(
            newLocation.getX(),
            newLocation.getY() - distance,
            newLocation.getZ(),
            newLocation.getYaw(),
            newLocation.getPitch());
      }
    }
  }
 /**
  * Instantiates a new item projectile.
  *
  * @param name projectile name
  * @param loc location of projectile (sets position of projectile and shoots in pitch and yaw
  *     direction)
  * @param itemstack item stack to shoot
  * @param shooter projectile shooter
  * @param power projectile power
  */
 @SuppressWarnings("deprecation")
 public ItemProjectile(
     String name,
     Location loc,
     org.bukkit.inventory.ItemStack itemstack,
     LivingEntity shooter,
     float power) {
   super(((CraftWorld) loc.getWorld()).getHandle(), loc.getX(), loc.getY(), loc.getZ(), null);
   if (CraftItemStack.asNMSCopy(itemstack) != null)
     setItemStack(CraftItemStack.asNMSCopy(itemstack));
   else
     setItemStack(
         new net.minecraft.server.v1_8_R1.ItemStack(
             Item.getById(itemstack.getTypeId()),
             itemstack.getAmount(),
             itemstack.getData().getData()));
   if (itemstack.getTypeId() == 0) System.out.println("You cannot shoot air!");
   this.name = name;
   this.pickupDelay = Integer.MAX_VALUE;
   this.shooter = ((CraftLivingEntity) shooter).getHandle();
   this.a(0.25F, 0.25F);
   setPositionRotation(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch());
   locX -= (MathHelper.cos(yaw / 180.0F * 3.1415927F) * 0.16F);
   locY -= 0.10000000149011612D;
   locZ -= (MathHelper.sin(yaw / 180.0F * 3.1415927F) * 0.16F);
   setPosition(locX, locY, locZ);
   float f = 0.4F;
   motX =
       (-MathHelper.sin(yaw / 180.0F * 3.1415927F)
           * MathHelper.cos(pitch / 180.0F * 3.1415927F)
           * f);
   motZ =
       (MathHelper.cos(yaw / 180.0F * 3.1415927F)
           * MathHelper.cos(pitch / 180.0F * 3.1415927F)
           * f);
   motY = (-MathHelper.sin(pitch / 180.0F * 3.1415927F) * f);
   shoot(motX, motY, motZ, power * 1.5F, 1.0F);
   world.addEntity(this);
   try {
     this.f = Entity.class.getDeclaredField("invulnerable");
   } catch (NoSuchFieldException e) {
     e.printStackTrace();
   }
 }
 /**
  * Instantiates a new item projectile.
  *
  * @param name projectile name
  * @param shooter projectile shooter (it uses entity's location to set x, y, z, pitch and yaw of
  *     projectile)
  * @param item item stack to shoot
  * @param power projectile power
  */
 public ItemProjectile(
     String name, LivingEntity shooter, org.bukkit.inventory.ItemStack item, float power) {
   super(((CraftLivingEntity) shooter).getHandle().world);
   this.name = name;
   this.pickupDelay = Integer.MAX_VALUE;
   setItemStack(CraftItemStack.asNMSCopy(item));
   this.shooter = ((CraftLivingEntity) shooter).getHandle();
   this.a(0.25F, 0.25F);
   setPositionRotation(
       shooter.getLocation().getX(),
       shooter.getLocation().getY() + shooter.getEyeHeight(),
       shooter.getLocation().getZ(),
       shooter.getLocation().getYaw(),
       shooter.getLocation().getPitch());
   locX -= (MathHelper.cos(yaw / 180.0F * 3.1415927F) * 0.16F);
   locY -= 0.10000000149011612D;
   locZ -= (MathHelper.sin(yaw / 180.0F * 3.1415927F) * 0.16F);
   setPosition(locX, locY, locZ);
   float f = 0.4F;
   motX =
       (-MathHelper.sin(yaw / 180.0F * 3.1415927F)
           * MathHelper.cos(pitch / 180.0F * 3.1415927F)
           * f);
   motZ =
       (MathHelper.cos(yaw / 180.0F * 3.1415927F)
           * MathHelper.cos(pitch / 180.0F * 3.1415927F)
           * f);
   motY = (-MathHelper.sin(pitch / 180.0F * 3.1415927F) * f);
   shoot(motX, motY, motZ, power * 1.5F, 1.0F);
   world.addEntity(this);
   try {
     this.f = Entity.class.getDeclaredField("invulnerable");
   } catch (NoSuchFieldException e) {
     e.printStackTrace();
   }
 }
  @Override
  public void s_() {
    K();
    BlockPosition blockposition = new BlockPosition(locX, locY, locZ);
    IBlockData iblockdata = world.getType(blockposition);
    Block block = iblockdata.getBlock();

    if (!ignoredMaterials.contains(Material.getMaterial(Block.getId(block)))) {
      AxisAlignedBB axisalignedbb = block.a(world, blockposition, iblockdata);

      if ((axisalignedbb != null) && (axisalignedbb.a(new Vec3D(locX, locY, locZ)))) {
        float damageMultiplier = MathHelper.sqrt(motX * motX + motY * motY + motZ * motZ);
        CustomProjectileHitEvent event =
            new ItemProjectileHitEvent(
                this,
                damageMultiplier,
                world.getWorld().getBlockAt((int) locX, (int) locY, (int) locZ),
                BlockFace.UP,
                getItem());
        Bukkit.getPluginManager().callEvent(event);
        if (!event.isCancelled()) {
          die();
        }
      }
    }
    age += 1;
    Vec3D vec3d = new Vec3D(locX, locY, locZ);
    Vec3D vec3d1 = new Vec3D(locX + motX, locY + motY, locZ + motZ);
    MovingObjectPosition movingobjectposition = world.rayTrace(vec3d, vec3d1, false, true, false);

    vec3d = new Vec3D(locX, locY, locZ);
    vec3d1 = new Vec3D(locX + motX, locY + motY, locZ + motZ);
    if (movingobjectposition != null) {
      vec3d1 =
          new Vec3D(
              movingobjectposition.pos.a, movingobjectposition.pos.b, movingobjectposition.pos.c);
    }

    Entity entity = null;
    List list =
        world.getEntities(this, getBoundingBox().a(motX, motY, motZ).grow(1.0D, 1.0D, 1.0D));
    double d0 = 0.0D;

    for (Object aList : list) {
      Entity entity1 = (Entity) aList;

      if ((entity1.ad()) && ((entity1 != shooter) || (age >= 5))) {
        float f1 = 0.3F;
        AxisAlignedBB axisalignedbb1 = entity1.getBoundingBox().grow(f1, f1, f1);
        MovingObjectPosition movingobjectposition1 = axisalignedbb1.a(vec3d, vec3d1);

        if (movingobjectposition1 != null) {
          double d1 = vec3d.distanceSquared(movingobjectposition1.pos);

          if ((d1 < d0) || (d0 == 0.0D)) {
            entity = entity1;
            d0 = d1;
          }
        }
      }
    }
    if (entity != null) {
      movingobjectposition = new MovingObjectPosition(entity);
    }
    if ((movingobjectposition != null)
        && (movingobjectposition.entity != null)
        && ((movingobjectposition.entity instanceof EntityHuman))) {
      EntityHuman entityhuman = (EntityHuman) movingobjectposition.entity;
      if ((entityhuman.abilities.isInvulnerable)
          || (((shooter instanceof EntityHuman)) && (!((EntityHuman) shooter).a(entityhuman)))) {
        movingobjectposition = null;
      }
    }
    if (movingobjectposition != null) {
      if (movingobjectposition.entity != null
          && movingobjectposition.entity instanceof EntityLiving) {
        float damageMultiplier = MathHelper.sqrt(motX * motX + motY * motY + motZ * motZ);
        CustomProjectileHitEvent event =
            new ItemProjectileHitEvent(
                this,
                damageMultiplier,
                (LivingEntity) movingobjectposition.entity.getBukkitEntity(),
                getItem());
        Bukkit.getPluginManager().callEvent(event);
        if (!event.isCancelled()) {
          if (getKnockback() > 0) {
            float f4 = MathHelper.sqrt(motX * motX + motZ * motZ);
            if (f4 > 0.0F) {
              movingobjectposition.entity.g(
                  motX * getKnockback() * 0.6000000238418579D / f4,
                  0.1D,
                  motZ * getKnockback() * 0.6000000238418579D / f4);
            }
          }
          die();
        }
      } else if (movingobjectposition.a() != null) {
        if (!ignoredMaterials.contains(Material.getMaterial(Block.getId(block)))) {
          motX = ((float) (movingobjectposition.pos.a - locX));
          motY = ((float) (movingobjectposition.pos.b - locY));
          motZ = ((float) (movingobjectposition.pos.c - locZ));
          float f3 = MathHelper.sqrt(motX * motX + motY * motY + motZ * motZ);
          locX -= motX / f3 * 0.0500000007450581D;
          locY -= motY / f3 * 0.0500000007450581D;
          locZ -= motZ / f3 * 0.0500000007450581D;
          float damageMultiplier = MathHelper.sqrt(motX * motX + motY * motY + motZ * motZ);
          CustomProjectileHitEvent event =
              new ItemProjectileHitEvent(
                  this,
                  damageMultiplier,
                  world
                      .getWorld()
                      .getBlockAt(
                          (int) movingobjectposition.pos.a,
                          (int) movingobjectposition.pos.b,
                          (int) movingobjectposition.pos.c),
                  CraftBlock.notchToBlockFace(movingobjectposition.direction),
                  getItem());
          Bukkit.getPluginManager().callEvent(event);
          if (!event.isCancelled()) {
            die();
          }
        }
      }
    }

    locX += motX;
    locY += motY;
    locZ += motZ;
    float f3 = 0.99F;
    float f1 = 0.05F;
    motX *= f3;
    motY *= f3;
    motZ *= f3;
    motY -= f1;
    setPosition(locX, locY, locZ);
    checkBlockCollisions();
    if (isAlive()) {
      if (this.age >= 1000) {
        die();
      }
      for (Runnable r : runnables) {
        r.run();
      }
      for (TypedRunnable<ItemProjectile> r : typedRunnables) {
        r.run(this);
      }
    }
  }