content: package net.minecraft.server;
  
  import com.google.common.collect.Iterables;
  import com.google.common.collect.Lists;
  import com.google.common.collect.Sets;
  import java.util.Arrays;
  import java.util.Collection;
  import java.util.Collections;
  import java.util.HashSet;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Random;
  import java.util.Set;
  import java.util.UUID;
  import javax.annotation.Nullable;
  import org.apache.logging.log4j.LogManager;
  import org.apache.logging.log4j.Logger;
  
  // CraftBukkit start
  import org.bukkit.Bukkit;
  import org.bukkit.Location;
  import org.bukkit.Server;
  import org.bukkit.TravelAgent;
  import org.bukkit.block.BlockFace;
  import org.bukkit.entity.Hanging;
  import org.bukkit.entity.LivingEntity;
  import org.bukkit.entity.Vehicle;
  import co.aikar.timings.MinecraftTimings; // Paper
  import co.aikar.timings.Timing; // Paper
  import io.akarin.api.internal.Akari;
  import io.akarin.api.internal.mixin.IMixinWorldServer;
  
  import org.bukkit.event.entity.EntityCombustByEntityEvent;
  import org.bukkit.event.hanging.HangingBreakByEntityEvent;
  import org.bukkit.event.vehicle.VehicleBlockCollisionEvent;
  import org.bukkit.event.vehicle.VehicleEnterEvent;
  import org.bukkit.event.vehicle.VehicleExitEvent;
  import org.bukkit.craftbukkit.CraftWorld;
  import org.bukkit.craftbukkit.entity.CraftEntity;
  import org.bukkit.craftbukkit.entity.CraftPlayer;
  import org.bukkit.craftbukkit.event.CraftEventFactory;
  import org.bukkit.event.entity.EntityAirChangeEvent;
  import org.bukkit.event.entity.EntityCombustEvent;
  import org.bukkit.event.entity.EntityPortalEvent;
  import org.bukkit.plugin.PluginManager;
  // CraftBukkit end
  
  /**
   * Akarin Changes Note
   * 1) Random -> LightRandom (performance)
   */
  public abstract class Entity implements ICommandListener, KeyedObject { // Paper
  
      // CraftBukkit start
      private static final int CURRENT_LEVEL = 2;
      // Paper start
      public static Random SHARED_RANDOM = new java.util.Random() {
          private boolean locked = false;
          @Override
          public synchronized void setSeed(long seed) {
              if (locked) {
                  LogManager.getLogger().error("Ignoring setSeed on Entity.SHARED_RANDOM", new Throwable());
              } else {
                  super.setSeed(seed);
                  locked = true;
              }
          }
      };
      List<Entity> entitySlice = null;
      // Paper end
      static boolean isLevelAtLeast(NBTTagCompound tag, int level) {
          return tag.hasKey("Bukkit.updateLevel") && tag.getInt("Bukkit.updateLevel") >= level;
      }
  
      protected CraftEntity bukkitEntity;
  
      EntityTrackerEntry tracker; // Paper
      public CraftEntity getBukkitEntity() {
          if (bukkitEntity == null) {
              bukkitEntity = CraftEntity.getEntity(world.getServer(), this);
          }
          return bukkitEntity;
      }
      Throwable addedToWorldStack; // Paper - entity debug
      // CraftBukikt end
  
      private static final Logger a = LogManager.getLogger();
      private static final List<ItemStack> b = Collections.emptyList();
      private static final AxisAlignedBB c = new AxisAlignedBB(0.0D, 0.0D, 0.0D, 0.0D, 0.0D, 0.0D);
      private static double f = 1.0D;
      private static int entityCount = 1; // Paper - MC-111480 - ID 0 is treated as special for DataWatchers, start 1
      private int id;
      public boolean i; public boolean blocksEntitySpawning() { return i; } // Paper - OBFHELPER
      public final List<Entity> passengers;
      protected int j;
      private Entity au;public void setVehicle(Entity entity) { this.au = entity; } // Paper // OBFHELPER
      public boolean attachedToPlayer;
      public World world;
      public double lastX;
      public double lastY;
      public double lastZ;
      public double locX;
      public double locY;
      public double locZ;
      // Paper start - getters to implement HopperPusher
      public double getX() {
          return locX;
      }
  
      public double getY() {
          return locY;
      }
  
      public double getZ() {
          return locZ;
      }
      // Paper end
      public double motX;
      public double motY;
      public double motZ;
      public float yaw;
      public float pitch;
      public float lastYaw;
      public float lastPitch;
      private AxisAlignedBB boundingBox;
      public boolean onGround;
      public boolean positionChanged;
      public boolean B;
      public boolean C;
      public boolean velocityChanged;
      protected boolean E;
      private boolean aw;
      public boolean dead;
      public boolean shouldBeRemoved; // Paper
      public float width;
      public float length;
      public float I;
      public float J;
      public float K;
      public float fallDistance;
      private int ax;
      private float ay;
      public double M;
      public double N;
      public double O;
      public float P;
      public boolean noclip;
      public float R;
      protected Random random;
      public int ticksLived;
      public int fireTicks;
      public boolean inWater; // Spigot - protected -> public // PAIL
      public int noDamageTicks;
      protected boolean justCreated;
      protected boolean fireProof;
      protected DataWatcher datawatcher;
      protected static final DataWatcherObject<Byte> Z = DataWatcher.a(Entity.class, DataWatcherRegistry.a);
      private static final DataWatcherObject<Integer> aA = DataWatcher.a(Entity.class, DataWatcherRegistry.b);
      private static final DataWatcherObject<String> aB = DataWatcher.a(Entity.class, DataWatcherRegistry.d);
      private static final DataWatcherObject<Boolean> aC = DataWatcher.a(Entity.class, DataWatcherRegistry.h);
      private static final DataWatcherObject<Boolean> aD = DataWatcher.a(Entity.class, DataWatcherRegistry.h);
      private static final DataWatcherObject<Boolean> aE = DataWatcher.a(Entity.class, DataWatcherRegistry.h);
      public boolean aa; public boolean isAddedToChunk() { return aa; } // Paper - OBFHELPER
      public int ab; public int getChunkX() { return ab; } // Paper - OBFHELPER
      public int ac; public int getChunkY() { return ac; } // Paper - OBFHELPER
      public int ad; public int getChunkZ() { return ad; } // Paper - OBFHELPER
      public boolean ah;
      public boolean impulse;
      public int portalCooldown;
      protected boolean ak; public boolean inPortal() { return ak; } // Paper - OBFHELPER
      protected int al;
      public int dimension;
      protected BlockPosition an;
      protected Vec3D ao;
      protected EnumDirection ap;
      private boolean invulnerable;
      protected UUID uniqueID;
      protected String ar;
      private final CommandObjectiveExecutor aG;
      public boolean glowing;
      private final Set<String> aH;
      private boolean aI;
      private final double[] aJ;
      private long aK;
      // CraftBukkit start
      public boolean valid;
      public org.bukkit.projectiles.ProjectileSource projectileSource; // For projectiles only
      public boolean forceExplosionKnockback; // SPIGOT-949
      public Timing tickTimer = MinecraftTimings.getEntityTimings(this); // Paper
      public Location origin; // Paper
      // Spigot start
      public final byte activationType = org.spigotmc.ActivationRange.initializeEntityActivationType(this);
      public final boolean defaultActivationState;
      public long activatedTick = Integer.MIN_VALUE;
      public boolean fromMobSpawner;
      public boolean spawnedViaMobSpawner; // Paper - Yes this name is similar to above, upstream took the better one
      protected int numCollisions = 0; // Paper
      public void inactiveTick() { }
      // Spigot end
  
      public float getBukkitYaw() {
          return this.yaw;
      }
      // CraftBukkit end
  
      public Entity(World world) {
          this.id = Entity.entityCount++;
          this.passengers = Lists.newArrayList();
          this.boundingBox = Entity.c;
          this.width = 0.6F;
          this.length = 1.8F;
          this.ax = 1;
          this.ay = 1.0F;
          this.random = world == null ? SHARED_RANDOM : ((IMixinWorldServer) world).rand(); // Paper // Akarin
          this.fireTicks = -this.getMaxFireTicks();
          this.justCreated = true;
          this.uniqueID = MathHelper.a(this.random);
          this.ar = this.uniqueID.toString();
          this.aG = new CommandObjectiveExecutor();
          this.aH = Sets.newHashSet();
          this.aJ = new double[] { 0.0D, 0.0D, 0.0D};
          this.world = world;
          this.setPosition(0.0D, 0.0D, 0.0D);
          if (world != null) {
              this.dimension = world.worldProvider.getDimensionManager().getDimensionID();
              // Spigot start
              this.defaultActivationState = org.spigotmc.ActivationRange.initializeEntityActivationState(this, world.spigotConfig);
          } else {
              this.defaultActivationState = false;
          }
          // Spigot end
  
          this.datawatcher = new DataWatcher(this);
          this.datawatcher.register(Entity.Z, Byte.valueOf((byte) 0));
          this.datawatcher.register(Entity.aA, Integer.valueOf(300));
          this.datawatcher.register(Entity.aC, Boolean.valueOf(false));
          this.datawatcher.register(Entity.aB, "");
          this.datawatcher.register(Entity.aD, Boolean.valueOf(false));
          this.datawatcher.register(Entity.aE, Boolean.valueOf(false));
          this.i();
      }
  
      public int getId() {
          return this.id;
      }
  
      public void h(int i) {
          this.id = i;
      }
  
      public Set<String> getScoreboardTags() {
          return this.aH;
      }
  
      public boolean addScoreboardTag(String s) {
          if (this.aH.size() >= 1024) {
              return false;
          } else {
              this.aH.add(s);
              return true;
          }
      }
  
      public boolean removeScoreboardTag(String s) {
          return this.aH.remove(s);
      }
  
      public void killEntity() {
          this.die();
      }
  
      protected abstract void i();
  
      public DataWatcher getDataWatcher() {
          return this.datawatcher;
      }
  
      public boolean equals(Object object) {
          return object instanceof Entity ? ((Entity) object).id == this.id : false;
      }
  
      public int hashCode() {
          return this.id;
      }
  
      public void die() {
          this.dead = true;
      }
  
      public void b(boolean flag) {}
  
      public void setSize(float f, float f1) {
          if (f != this.width || f1 != this.length) {
              float f2 = this.width;
  
              this.width = f;
              this.length = f1;
              if (this.width < f2) {
                  double d0 = (double) f / 2.0D;
  
                  this.a(new AxisAlignedBB(this.locX - d0, this.locY, this.locZ - d0, this.locX + d0, this.locY + (double) this.length, this.locZ + d0));
                  return;
              }
  
              AxisAlignedBB axisalignedbb = this.getBoundingBox();
  
              this.a(new AxisAlignedBB(axisalignedbb.a, axisalignedbb.b, axisalignedbb.c, axisalignedbb.a + (double) this.width, axisalignedbb.b + (double) this.length, axisalignedbb.c + (double) this.width));
              if (this.width > f2 && !this.justCreated && !this.world.isClientSide) {
                  this.move(EnumMoveType.SELF, (double) (f2 - this.width), 0.0D, (double) (f2 - this.width));
              }
          }
  
      }
  
      protected void setYawPitch(float f, float f1) {
          // CraftBukkit start - yaw was sometimes set to NaN, so we need to set it back to 0
          if (Float.isNaN(f)) {
              f = 0;
          }
  
          if (f == Float.POSITIVE_INFINITY || f == Float.NEGATIVE_INFINITY) {
              if (this instanceof EntityPlayer) {
                  this.world.getServer().getLogger().warning(this.getName() + " was caught trying to crash the server with an invalid yaw");
                  ((CraftPlayer) this.getBukkitEntity()).kickPlayer("Infinite yaw (Hacking?)"); //Spigot "Nope" -> Descriptive reason
              }
              f = 0;
          }
  
          // pitch was sometimes set to NaN, so we need to set it back to 0
          if (Float.isNaN(f1)) {
              f1 = 0;
          }
  
          if (f1 == Float.POSITIVE_INFINITY || f1 == Float.NEGATIVE_INFINITY) {
              if (this instanceof EntityPlayer) {
                  this.world.getServer().getLogger().warning(this.getName() + " was caught trying to crash the server with an invalid pitch");
                  ((CraftPlayer) this.getBukkitEntity()).kickPlayer("Infinite pitch (Hacking?)"); //Spigot "Nope" -> Descriptive reason
              }
              f1 = 0;
          }
          // CraftBukkit end
  
          this.yaw = f % 360.0F;
          this.pitch = f1 % 360.0F;
      }
  
      public void setPosition(double d0, double d1, double d2) {
          this.locX = d0;
          this.locY = d1;
          this.locZ = d2;
          if (valid) world.entityJoinedWorld(this, false); // Paper - ensure Entity is moved to its proper chunk
          float f = this.width / 2.0F;
          float f1 = this.length;
  
          this.a(new AxisAlignedBB(d0 - (double) f, d1, d2 - (double) f, d0 + (double) f, d1 + (double) f1, d2 + (double) f));
      }
  
      public void B_() {
          if (!this.world.isClientSide) {
              this.setFlag(6, this.aW());
          }
  
          this.Y();
      }
  
      // CraftBukkit start
      public void postTick() {
          // No clean way to break out of ticking once the entity has been copied to a new world, so instead we move the portalling later in the tick cycle
          if (!this.world.isClientSide && this.world instanceof WorldServer) {
              this.world.methodProfiler.a("portal");
              if (this.ak) {
                  MinecraftServer minecraftserver = this.world.getMinecraftServer();
  
                  if (true || minecraftserver.getAllowNether()) { // CraftBukkit
                      if (!this.isPassenger()) {
                          int i = this.Z();
  
                          if (this.al++ >= i) {
                              this.al = i;
                              this.portalCooldown = this.aM();
                              byte b0;
  
                              if (this.world.worldProvider.getDimensionManager().getDimensionID() == -1) {
                                  b0 = 0;
                              } else {
                                  b0 = -1;
                              }
  
                              this.b(b0);
                          }
                      }
  
                      this.ak = false;
                  }
              } else {
                  if (this.al > 0) {
                      this.al -= 4;
                  }
  
                  if (this.al < 0) {
                      this.al = 0;
                  }
              }
  
              this.I();
              this.world.methodProfiler.b();
          }
      }
      // CraftBukkit end
  
      public void Y() {
          this.world.methodProfiler.a("entityBaseTick");
          if (this.isPassenger() && this.bJ().dead) {
              this.stopRiding();
          }
  
          if (this.j > 0) {
              --this.j;
          }
  
          this.I = this.J;
          this.lastX = this.locX;
          this.lastY = this.locY;
          this.lastZ = this.locZ;
          this.lastPitch = this.pitch;
          this.lastYaw = this.yaw;
          // Moved up to postTick
          /*
          if (!this.world.isClientSide && this.world instanceof WorldServer) {
              this.world.methodProfiler.a("portal");
              if (this.ak) {
                  MinecraftServer minecraftserver = this.world.getMinecraftServer();
  
                  if (minecraftserver.getAllowNether()) {
                      if (!this.isPassenger()) {
                          int i = this.Z();
  
                          if (this.al++ >= i) {
                              this.al = i;
                              this.portalCooldown = this.aM();
                              byte b0;
  
                              if (this.world.worldProvider.getDimensionManager().getDimensionID() == -1) {
                                  b0 = 0;
                              } else {
                                  b0 = -1;
                              }
  
                              this.b(b0);
                          }
                      }
  
                      this.ak = false;
                  }
              } else {
                  if (this.al > 0) {
                      this.al -= 4;
                  }
  
                  if (this.al < 0) {
                      this.al = 0;
                  }
              }
  
              this.I();
              this.world.methodProfiler.b();
          }
          */
  
          this.as();
          this.aq();
          if (this.world.isClientSide) {
              this.extinguish();
          } else if (this.fireTicks > 0) {
              if (this.fireProof) {
                  this.fireTicks -= 4;
                  if (this.fireTicks < 0) {
                      this.extinguish();
                  }
              } else {
                  if (this.fireTicks % 20 == 0) {
                      this.damageEntity(DamageSource.BURN, 1.0F);
                  }
  
                  --this.fireTicks;
              }
          }
  
          if (this.au()) {
              this.burnFromLava();
              this.fallDistance *= 0.5F;
          }
  
          // Paper start - Configurable nether ceiling damage
          // Extracted to own function
          /*
          if (this.locY < -64.0D) {
              this.ac();
          }
          */
          this.checkAndDoHeightDamage();
          // Paper end
  
          if (!this.world.isClientSide) {
              this.setFlag(0, this.fireTicks > 0);
          }
  
          this.justCreated = false;
          this.world.methodProfiler.b();
      }
  
      // Paper start - Configurable top of nether void damage
      private boolean paperNetherCheck() {
          return this.world.paperConfig.netherVoidTopDamage && this.world.getWorld().getEnvironment() == org.bukkit.World.Environment.NETHER && this.locY >= 128.0D;
      }
  
      protected void checkAndDoHeightDamage() {
          if (this.locY < -64.0D || paperNetherCheck()) {
              this.kill();
          }
      }
      // Paper end
  
      protected void I() {
          if (this.portalCooldown > 0) {
              --this.portalCooldown;
          }
  
      }
  
      public int Z() {
          return 1;
      }
  
      protected void burnFromLava() {
          if (!this.fireProof) {
              this.damageEntity(DamageSource.LAVA, 4.0F);
  
              // CraftBukkit start - Fallen in lava TODO: this event spams!
              if (this instanceof EntityLiving) {
                  if (fireTicks <= 0) {
                      // not on fire yet
                      // TODO: shouldn't be sending null for the block
                      org.bukkit.block.Block damager = null; // ((WorldServer) this.l).getWorld().getBlockAt(i, j, k);
                      org.bukkit.entity.Entity damagee = this.getBukkitEntity();
                      EntityCombustEvent combustEvent = new org.bukkit.event.entity.EntityCombustByBlockEvent(damager, damagee, 15);
                      this.world.getServer().getPluginManager().callEvent(combustEvent);
  
                      if (!combustEvent.isCancelled()) {
                          this.setOnFire(combustEvent.getDuration());
                      }
                  } else {
                      // This will be called every single tick the entity is in lava, so don't throw an event
                      this.setOnFire(15);
                  }
                  return;
              }
              // CraftBukkit end - we also don't throw an event unless the object in lava is living, to save on some event calls
              this.setOnFire(15);
          }
      }
  
      public void setOnFire(int i) {
          int j = i * 20;
  
          if (this instanceof EntityLiving) {
              j = EnchantmentProtection.a((EntityLiving) this, j);
          }
  
          if (this.fireTicks < j) {
              this.fireTicks = j;
          }
  
      }
  
      public void extinguish() {
          this.fireTicks = 0;
      }
  
      protected final void kill() { this.ac(); } // Paper - OBFHELPER
      protected void ac() {
          this.die();
      }
  
      public boolean c(double d0, double d1, double d2) {
          AxisAlignedBB axisalignedbb = this.getBoundingBox().d(d0, d1, d2);
  
          return this.b(axisalignedbb);
      }
  
      private boolean b(AxisAlignedBB axisalignedbb) {
          return this.world.getCubes(this, axisalignedbb).isEmpty() && !this.world.containsLiquid(axisalignedbb);
      }
  
      public void move(EnumMoveType enummovetype, double d0, double d1, double d2) {
          if (this.noclip) {
              this.a(this.getBoundingBox().d(d0, d1, d2));
              this.recalcPosition();
          } else {
              // CraftBukkit start - Don't do anything if we aren't moving
              // We need to do this regardless of whether or not we are moving thanks to portals
              try {
                  this.checkBlockCollisions();
              } catch (Throwable throwable) {
                  CrashReport crashreport = CrashReport.a(throwable, "Checking entity block collision");
                  CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Entity being checked for collision");
  
                  this.appendEntityCrashDetails(crashreportsystemdetails);
                  throw new ReportedException(crashreport);
              }
              // Check if we're moving
              if (d0 == 0 && d1 == 0 && d2 == 0 && this.isVehicle() && this.isPassenger()) {
                  return;
              }
              // CraftBukkit end
              if (enummovetype == EnumMoveType.PISTON) {
                  long i = this.world.getTime();
  
                  if (i != this.aK) {
                      Arrays.fill(this.aJ, 0.0D);
                      this.aK = i;
                  }
  
                  int j;
                  double d3;
  
                  if (d0 != 0.0D) {
                      j = EnumDirection.EnumAxis.X.ordinal();
                      d3 = MathHelper.a(d0 + this.aJ[j], -0.51D, 0.51D);
                      d0 = d3 - this.aJ[j];
                      this.aJ[j] = d3;
                      if (Math.abs(d0) <= 9.999999747378752E-6D) {
                          return;
                      }
                  } else if (d1 != 0.0D) {
                      j = EnumDirection.EnumAxis.Y.ordinal();
                      d3 = MathHelper.a(d1 + this.aJ[j], -0.51D, 0.51D);
                      d1 = d3 - this.aJ[j];
                      this.aJ[j] = d3;
                      if (Math.abs(d1) <= 9.999999747378752E-6D) {
                          return;
                      }
                  } else {
                      if (d2 == 0.0D) {
                          return;
                      }
  
                      j = EnumDirection.EnumAxis.Z.ordinal();
                      d3 = MathHelper.a(d2 + this.aJ[j], -0.51D, 0.51D);
                      d2 = d3 - this.aJ[j];
                      this.aJ[j] = d3;
                      if (Math.abs(d2) <= 9.999999747378752E-6D) {
                          return;
                      }
                  }
              }
  
              this.world.methodProfiler.a("move");
              double d4 = this.locX;
              double d5 = this.locY;
              double d6 = this.locZ;
  
              if (this.E) {
                  this.E = false;
                  d0 *= 0.25D;
                  d1 *= 0.05000000074505806D;
                  d2 *= 0.25D;
                  this.motX = 0.0D;
                  this.motY = 0.0D;
                  this.motZ = 0.0D;
              }
  
              double d7 = d0;
              double d8 = d1;
              double d9 = d2;
  
              if ((enummovetype == EnumMoveType.SELF || enummovetype == EnumMoveType.PLAYER) && this.onGround && this.isSneaking() && this instanceof EntityHuman) {
                  for (double d10 = 0.05D; d0 != 0.0D && this.world.getCubes(this, this.getBoundingBox().d(d0, (double) (-this.P), 0.0D)).isEmpty(); d7 = d0) {
                      if (d0 < 0.05D && d0 >= -0.05D) {
                          d0 = 0.0D;
                      } else if (d0 > 0.0D) {
                          d0 -= 0.05D;
                      } else {
                          d0 += 0.05D;
                      }
                  }
  
                  for (; d2 != 0.0D && this.world.getCubes(this, this.getBoundingBox().d(0.0D, (double) (-this.P), d2)).isEmpty(); d9 = d2) {
                      if (d2 < 0.05D && d2 >= -0.05D) {
                          d2 = 0.0D;
                      } else if (d2 > 0.0D) {
                          d2 -= 0.05D;
                      } else {
                          d2 += 0.05D;
                      }
                  }
  
                  for (; d0 != 0.0D && d2 != 0.0D && this.world.getCubes(this, this.getBoundingBox().d(d0, (double) (-this.P), d2)).isEmpty(); d9 = d2) {
                      if (d0 < 0.05D && d0 >= -0.05D) {
                          d0 = 0.0D;
                      } else if (d0 > 0.0D) {
                          d0 -= 0.05D;
                      } else {
                          d0 += 0.05D;
                      }
  
                      d7 = d0;
                      if (d2 < 0.05D && d2 >= -0.05D) {
                          d2 = 0.0D;
                      } else if (d2 > 0.0D) {
                          d2 -= 0.05D;
                      } else {
                          d2 += 0.05D;
                      }
                  }
              }
  
              List list = this.world.getCubes(this, this.getBoundingBox().b(d0, d1, d2));
              AxisAlignedBB axisalignedbb = this.getBoundingBox();
              int k;
              int l;
  
              if (d1 != 0.0D) {
                  k = 0;
  
                  for (l = list.size(); k < l; ++k) {
                      d1 = ((AxisAlignedBB) list.get(k)).b(this.getBoundingBox(), d1);
                  }
  
                  this.a(this.getBoundingBox().d(0.0D, d1, 0.0D));
              }
  
              if (d0 != 0.0D) {
                  k = 0;
  
                  for (l = list.size(); k < l; ++k) {
                      d0 = ((AxisAlignedBB) list.get(k)).a(this.getBoundingBox(), d0);
                  }
  
                  if (d0 != 0.0D) {
                      this.a(this.getBoundingBox().d(d0, 0.0D, 0.0D));
                  }
              }
  
              if (d2 != 0.0D) {
                  k = 0;
  
                  for (l = list.size(); k < l; ++k) {
                      d2 = ((AxisAlignedBB) list.get(k)).c(this.getBoundingBox(), d2);
                  }
  
                  if (d2 != 0.0D) {
                      this.a(this.getBoundingBox().d(0.0D, 0.0D, d2));
                  }
              }
  
              boolean flag = this.onGround || d1 != d8 && d1 < 0.0D; // CraftBukkit - decompile error
              double d11;
  
              if (this.P > 0.0F && flag && (d7 != d0 || d9 != d2)) {
                  double d12 = d0;
                  double d13 = d1;
                  double d14 = d2;
                  AxisAlignedBB axisalignedbb1 = this.getBoundingBox();
  
                  this.a(axisalignedbb);
                  d1 = (double) this.P;
                  List list1 = this.world.getCubes(this, this.getBoundingBox().b(d7, d1, d9));
                  AxisAlignedBB axisalignedbb2 = this.getBoundingBox();
                  AxisAlignedBB axisalignedbb3 = axisalignedbb2.b(d7, 0.0D, d9);
  
                  d11 = d1;
                  int i1 = 0;
  
                  for (int j1 = list1.size(); i1 < j1; ++i1) {
                      d11 = ((AxisAlignedBB) list1.get(i1)).b(axisalignedbb3, d11);
                  }
  
                  axisalignedbb2 = axisalignedbb2.d(0.0D, d11, 0.0D);
                  double d15 = d7;
                  int k1 = 0;
  
                  for (int l1 = list1.size(); k1 < l1; ++k1) {
                      d15 = ((AxisAlignedBB) list1.get(k1)).a(axisalignedbb2, d15);
                  }
  
                  axisalignedbb2 = axisalignedbb2.d(d15, 0.0D, 0.0D);
                  double d16 = d9;
                  int i2 = 0;
  
                  for (int j2 = list1.size(); i2 < j2; ++i2) {
                      d16 = ((AxisAlignedBB) list1.get(i2)).c(axisalignedbb2, d16);
                  }
  
                  axisalignedbb2 = axisalignedbb2.d(0.0D, 0.0D, d16);
                  AxisAlignedBB axisalignedbb4 = this.getBoundingBox();
                  double d17 = d1;
                  int k2 = 0;
  
                  for (int l2 = list1.size(); k2 < l2; ++k2) {
                      d17 = ((AxisAlignedBB) list1.get(k2)).b(axisalignedbb4, d17);
                  }
  
                  axisalignedbb4 = axisalignedbb4.d(0.0D, d17, 0.0D);
                  double d18 = d7;
                  int i3 = 0;
  
                  for (int j3 = list1.size(); i3 < j3; ++i3) {
                      d18 = ((AxisAlignedBB) list1.get(i3)).a(axisalignedbb4, d18);
                  }
  
                  axisalignedbb4 = axisalignedbb4.d(d18, 0.0D, 0.0D);
                  double d19 = d9;
                  int k3 = 0;
  
                  for (int l3 = list1.size(); k3 < l3; ++k3) {
                      d19 = ((AxisAlignedBB) list1.get(k3)).c(axisalignedbb4, d19);
                  }
  
                  axisalignedbb4 = axisalignedbb4.d(0.0D, 0.0D, d19);
                  double d20 = d15 * d15 + d16 * d16;
                  double d21 = d18 * d18 + d19 * d19;
  
                  if (d20 > d21) {
                      d0 = d15;
                      d2 = d16;
                      d1 = -d11;
                      this.a(axisalignedbb2);
                  } else {
                      d0 = d18;
                      d2 = d19;
                      d1 = -d17;
                      this.a(axisalignedbb4);
                  }
  
                  int i4 = 0;
  
                  for (int j4 = list1.size(); i4 < j4; ++i4) {
                      d1 = ((AxisAlignedBB) list1.get(i4)).b(this.getBoundingBox(), d1);
                  }
  
                  this.a(this.getBoundingBox().d(0.0D, d1, 0.0D));
                  if (d12 * d12 + d14 * d14 >= d0 * d0 + d2 * d2) {
                      d0 = d12;
                      d1 = d13;
                      d2 = d14;
                      this.a(axisalignedbb1);
                  }
              }
  
              this.world.methodProfiler.b();
              this.world.methodProfiler.a("rest");
              this.recalcPosition();
              this.positionChanged = d7 != d0 || d9 != d2;
              this.B = d1 != d8; // CraftBukkit - decompile error
              this.onGround = this.B && d8 < 0.0D;
              this.C = this.positionChanged || this.B;
              l = MathHelper.floor(this.locX);
              int k4 = MathHelper.floor(this.locY - 0.20000000298023224D);
              int l4 = MathHelper.floor(this.locZ);
              BlockPosition blockposition = new BlockPosition(l, k4, l4);
              IBlockData iblockdata = this.world.getType(blockposition);
  
              if (iblockdata.getMaterial() == Material.AIR) {
                  BlockPosition blockposition1 = blockposition.down();
                  IBlockData iblockdata1 = this.world.getType(blockposition1);
                  Block block = iblockdata1.getBlock();
  
                  if (block instanceof BlockFence || block instanceof BlockCobbleWall || block instanceof BlockFenceGate) {
                      iblockdata = iblockdata1;
                      blockposition = blockposition1;
                  }
              }
  
              this.a(d1, this.onGround, iblockdata, blockposition);
              if (d7 != d0) {
                  this.motX = 0.0D;
              }
  
              if (d9 != d2) {
                  this.motZ = 0.0D;
              }
  
              Block block1 = iblockdata.getBlock();
  
              if (d8 != d1) {
                  block1.a(this.world, this);
              }
  
              // CraftBukkit start
              if (positionChanged && getBukkitEntity() instanceof Vehicle) {
                  Vehicle vehicle = (Vehicle) this.getBukkitEntity();
                  org.bukkit.block.Block bl = this.world.getWorld().getBlockAt(MathHelper.floor(this.locX), MathHelper.floor(this.locY), MathHelper.floor(this.locZ));
  
                  if (d7 > d0) {
                      bl = bl.getRelative(BlockFace.EAST);
                  } else if (d7 < d0) {
                      bl = bl.getRelative(BlockFace.WEST);
                  } else if (d9 > d2) {
                      bl = bl.getRelative(BlockFace.SOUTH);
                  } else if (d9 < d2) {
                      bl = bl.getRelative(BlockFace.NORTH);
                  }
  
                  if (bl.getType() != org.bukkit.Material.AIR) {
                      VehicleBlockCollisionEvent event = new VehicleBlockCollisionEvent(vehicle, bl);
                      world.getServer().getPluginManager().callEvent(event);
                  }
              }
              // CraftBukkit end
  
              if (this.playStepSound() && (!this.onGround || !this.isSneaking() || !(this instanceof EntityHuman)) && !this.isPassenger()) {
                  double d22 = this.locX - d4;
                  double d23 = this.locY - d5;
  
                  d11 = this.locZ - d6;
                  if (block1 != Blocks.LADDER) {
                      d23 = 0.0D;
                  }
  
                  if (block1 != null && this.onGround) {
                      block1.stepOn(this.world, blockposition, this);
                  }
  
                  this.J = (float) ((double) this.J + (double) MathHelper.sqrt(d22 * d22 + d11 * d11) * 0.6D);
                  this.K = (float) ((double) this.K + (double) MathHelper.sqrt(d22 * d22 + d23 * d23 + d11 * d11) * 0.6D);
                  if (this.K > (float) this.ax && iblockdata.getMaterial() != Material.AIR) {
                      this.ax = (int) this.K + 1;
                      if (this.isInWater()) {
                          Entity entity = this.isVehicle() && this.bE() != null ? this.bE() : this;
                          float f = entity == this ? 0.35F : 0.4F;
                          float f1 = MathHelper.sqrt(entity.motX * entity.motX * 0.20000000298023224D + entity.motY * entity.motY + entity.motZ * entity.motZ * 0.20000000298023224D) * f;
  
                          if (f1 > 1.0F) {
                              f1 = 1.0F;
                          }
  
                          this.a(this.ae(), f1, 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.4F);
                      } else {
                          this.a(blockposition, block1);
                      }
                  } else if (this.K > this.ay && this.ah() && iblockdata.getMaterial() == Material.AIR) {
                      this.ay = this.d(this.K);
                  }
              }
  
              // CraftBukkit start - Move to the top of the method
              /*
              try {
                  this.checkBlockCollisions();
              } catch (Throwable throwable) {
                  CrashReport crashreport = CrashReport.a(throwable, "Checking entity block collision");
                  CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Entity being checked for collision");
  
                  this.appendEntityCrashDetails(crashreportsystemdetails);
                  throw new ReportedException(crashreport);
              }
              */
              // CraftBukkit end
  
              boolean flag1 = this.an();
  
              if (this.world.e(this.getBoundingBox().shrink(0.001D))) {
                  this.burn(1);
                  if (!flag1) {
                      ++this.fireTicks;
                      if (this.fireTicks == 0) {
                          // CraftBukkit start
                          EntityCombustEvent event = new org.bukkit.event.entity.EntityCombustByBlockEvent(null, getBukkitEntity(), 8);
                          world.getServer().getPluginManager().callEvent(event);
  
                          if (!event.isCancelled()) {
                              this.setOnFire(event.getDuration());
                          }
                          // CraftBukkit end
                      }
                  }
              } else if (this.fireTicks <= 0) {
                  this.fireTicks = -this.getMaxFireTicks();
              }
  
              if (flag1 && this.isBurning()) {
                  this.a(SoundEffects.bW, 0.7F, 1.6F + (this.random.nextFloat() - this.random.nextFloat()) * 0.4F);
                  this.fireTicks = -this.getMaxFireTicks();
              }
  
              this.world.methodProfiler.b();
          }
      }
  
      public void recalcPosition() {
          AxisAlignedBB axisalignedbb = this.getBoundingBox();
  
          this.locX = (axisalignedbb.a + axisalignedbb.d) / 2.0D;
          this.locY = axisalignedbb.b;
          this.locZ = (axisalignedbb.c + axisalignedbb.f) / 2.0D;
          if (valid) world.entityJoinedWorld(this, false); // Paper - ensure Entity is moved to its proper chunk
      }
  
      protected SoundEffect ae() {
          return SoundEffects.ca;
      }
  
      protected SoundEffect af() {
          return SoundEffects.bZ;
      }
  
      protected void checkBlockCollisions() {
          AxisAlignedBB axisalignedbb = this.getBoundingBox();
          BlockPosition.PooledBlockPosition blockposition_pooledblockposition = BlockPosition.PooledBlockPosition.d(axisalignedbb.a + 0.001D, axisalignedbb.b + 0.001D, axisalignedbb.c + 0.001D);
          BlockPosition.PooledBlockPosition blockposition_pooledblockposition1 = BlockPosition.PooledBlockPosition.d(axisalignedbb.d - 0.001D, axisalignedbb.e - 0.001D, axisalignedbb.f - 0.001D);
          BlockPosition.PooledBlockPosition blockposition_pooledblockposition2 = BlockPosition.PooledBlockPosition.s();
  
          if (this.world.areChunksLoadedBetween(blockposition_pooledblockposition, blockposition_pooledblockposition1)) {
              for (int i = blockposition_pooledblockposition.getX(); i <= blockposition_pooledblockposition1.getX(); ++i) {
                  for (int j = blockposition_pooledblockposition.getY(); j <= blockposition_pooledblockposition1.getY(); ++j) {
                      for (int k = blockposition_pooledblockposition.getZ(); k <= blockposition_pooledblockposition1.getZ(); ++k) {
                          blockposition_pooledblockposition2.f(i, j, k);
                          IBlockData iblockdata = this.world.getType(blockposition_pooledblockposition2);
  
                          try {
                              iblockdata.getBlock().a(this.world, (BlockPosition) blockposition_pooledblockposition2, iblockdata, this);
                              this.a(iblockdata);
                          } catch (Throwable throwable) {
                              CrashReport crashreport = CrashReport.a(throwable, "Colliding entity with block");
                              CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Block being collided with");
  
                              CrashReportSystemDetails.a(crashreportsystemdetails, blockposition_pooledblockposition2, iblockdata);
                              throw new ReportedException(crashreport);
                          }
                      }
                  }
              }
          }
  
          blockposition_pooledblockposition.t();
          blockposition_pooledblockposition1.t();
          blockposition_pooledblockposition2.t();
      }
  
      protected void a(IBlockData iblockdata) {}
  
      protected void a(BlockPosition blockposition, Block block) {
          SoundEffectType soundeffecttype = block.getStepSound();
  
          if (this.world.getType(blockposition.up()).getBlock() == Blocks.SNOW_LAYER) {
              soundeffecttype = Blocks.SNOW_LAYER.getStepSound();
              this.a(soundeffecttype.d(), soundeffecttype.a() * 0.15F, soundeffecttype.b());
          } else if (!block.getBlockData().getMaterial().isLiquid()) {
              this.a(soundeffecttype.d(), soundeffecttype.a() * 0.15F, soundeffecttype.b());
          }
  
      }
  
      protected float d(float f) {
          return 0.0F;
      }
  
      protected boolean ah() {
          return false;
      }
  
      public void a(SoundEffect soundeffect, float f, float f1) {
          if (!this.isSilent()) {
              this.world.a((EntityHuman) null, this.locX, this.locY, this.locZ, soundeffect, this.bK(), f, f1);
          }
  
      }
  
      public boolean isSilent() {
          return ((Boolean) this.datawatcher.get(Entity.aD)).booleanValue();
      }
  
      public void setSilent(boolean flag) {
          this.datawatcher.set(Entity.aD, Boolean.valueOf(flag));
      }
  
      public boolean isNoGravity() {
          return ((Boolean) this.datawatcher.get(Entity.aE)).booleanValue();
      }
  
      public void setNoGravity(boolean flag) {
          this.datawatcher.set(Entity.aE, Boolean.valueOf(flag));
      }
  
      protected boolean playStepSound() {
          return true;
      }
  
      protected void a(double d0, boolean flag, IBlockData iblockdata, BlockPosition blockposition) {
          if (flag) {
              if (this.fallDistance > 0.0F) {
                  iblockdata.getBlock().fallOn(this.world, blockposition, this, this.fallDistance);
              }
  
              this.fallDistance = 0.0F;
          } else if (d0 < 0.0D) {
              this.fallDistance = (float) ((double) this.fallDistance - d0);
          }
  
      }
  
      @Nullable
      public AxisAlignedBB al() {
          return null;
      }
  
      protected void burn(float i) { // CraftBukkit - int -> float
          if (!this.fireProof) {
              this.damageEntity(DamageSource.FIRE, (float) i);
          }
  
      }
  
      public final boolean isFireProof() {
          return this.fireProof;
      }
  
      public void e(float f, float f1) {
          if (this.isVehicle()) {
              Iterator iterator = this.bF().iterator();
  
              while (iterator.hasNext()) {
                  Entity entity = (Entity) iterator.next();
  
                  entity.e(f, f1);
              }
          }
  
      }
  
      public boolean an() {
          if (this.inWater) {
              return true;
          } else {
              BlockPosition.PooledBlockPosition blockposition_pooledblockposition = BlockPosition.PooledBlockPosition.d(this.locX, this.locY, this.locZ);
  
              if (!this.world.isRainingAt(blockposition_pooledblockposition) && !this.world.isRainingAt(blockposition_pooledblockposition.e(this.locX, this.locY + (double) this.length, this.locZ))) {
                  blockposition_pooledblockposition.t();
                  return false;
              } else {
                  blockposition_pooledblockposition.t();
                  return true;
              }
          }
      }
  
      public boolean isInWater() {
          return this.inWater;
      }
  
      public boolean ap() {
          return this.world.a(this.getBoundingBox().grow(0.0D, -20.0D, 0.0D).shrink(0.001D), Material.WATER, this);
      }
  
      public boolean aq() {
          return this.doWaterMovement();
      }
  
      public boolean doWaterMovement() {
          // Paper end
          if (this.bJ() instanceof EntityBoat) {
              this.inWater = false;
          } else if (this.world.a(this.getBoundingBox().grow(0.0D, -0.4000000059604645D, 0.0D).shrink(0.001D), Material.WATER, this)) {
              if (!this.inWater && !this.justCreated) {
                  this.ar();
              }
  
              this.fallDistance = 0.0F;
              this.inWater = true;
              this.extinguish();
          } else {
              this.inWater = false;
          }
  
          return this.inWater;
      }
  
      protected void ar() {
          Entity entity = this.isVehicle() && this.bE() != null ? this.bE() : this;
          float f = entity == this ? 0.2F : 0.9F;
          float f1 = MathHelper.sqrt(entity.motX * entity.motX * 0.20000000298023224D + entity.motY * entity.motY + entity.motZ * entity.motZ * 0.20000000298023224D) * f;
  
          if (f1 > 1.0F) {
              f1 = 1.0F;
          }
  
          this.a(this.af(), f1, 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.4F);
          float f2 = (float) MathHelper.floor(this.getBoundingBox().b);
  
          int i;
          float f3;
          float f4;
  
          for (i = 0; (float) i < 1.0F + this.width * 20.0F; ++i) {
              f3 = (this.random.nextFloat() * 2.0F - 1.0F) * this.width;
              f4 = (this.random.nextFloat() * 2.0F - 1.0F) * this.width;
              this.world.addParticle(EnumParticle.WATER_BUBBLE, this.locX + (double) f3, (double) (f2 + 1.0F), this.locZ + (double) f4, this.motX, this.motY - (double) (this.random.nextFloat() * 0.2F), this.motZ, new int[0]);
          }
  
          for (i = 0; (float) i < 1.0F + this.width * 20.0F; ++i) {
              f3 = (this.random.nextFloat() * 2.0F - 1.0F) * this.width;
              f4 = (this.random.nextFloat() * 2.0F - 1.0F) * this.width;
              this.world.addParticle(EnumParticle.WATER_SPLASH, this.locX + (double) f3, (double) (f2 + 1.0F), this.locZ + (double) f4, this.motX, this.motY, this.motZ, new int[0]);
          }
  
      }
  
      public void as() {
          if (this.isSprinting() && !this.isInWater()) {
              this.at();
          }
  
      }
  
      protected void at() {
          int i = MathHelper.floor(this.locX);
          int j = MathHelper.floor(this.locY - 0.20000000298023224D);
          int k = MathHelper.floor(this.locZ);
          BlockPosition blockposition = new BlockPosition(i, j, k);
          IBlockData iblockdata = this.world.getType(blockposition);
  
          if (iblockdata.i() != EnumRenderType.INVISIBLE) {
              this.world.addParticle(EnumParticle.BLOCK_CRACK, this.locX + ((double) this.random.nextFloat() - 0.5D) * (double) this.width, this.getBoundingBox().b + 0.1D, this.locZ + ((double) this.random.nextFloat() - 0.5D) * (double) this.width, -this.motX * 4.0D, 1.5D, -this.motZ * 4.0D, new int[] { Block.getCombinedId(iblockdata)});
          }
  
      }
  
      public boolean a(Material material) {
          if (this.bJ() instanceof EntityBoat) {
              return false;
          } else {
              double d0 = this.locY + (double) this.getHeadHeight();
              BlockPosition blockposition = new BlockPosition(this.locX, d0, this.locZ);
              IBlockData iblockdata = this.world.getType(blockposition);
  
              if (iblockdata.getMaterial() == material) {
                  float f = BlockFluids.b(iblockdata.getBlock().toLegacyData(iblockdata)) - 0.11111111F;
                  float f1 = (float) (blockposition.getY() + 1) - f;
                  boolean flag = d0 < (double) f1;
  
                  return !flag && this instanceof EntityHuman ? false : flag;
              } else {
                  return false;
              }
          }
      }
  
      public boolean au() {
          return this.world.a(this.getBoundingBox().grow(-0.10000000149011612D, -0.4000000059604645D, -0.10000000149011612D), Material.LAVA);
      }
  
      public void b(float f, float f1, float f2, float f3) {
          float f4 = f * f + f1 * f1 + f2 * f2;
  
          if (f4 >= 1.0E-4F) {
              f4 = MathHelper.c(f4);
              if (f4 < 1.0F) {
                  f4 = 1.0F;
              }
  
              f4 = f3 / f4;
              f *= f4;
              f1 *= f4;
              f2 *= f4;
              float f5 = MathHelper.sin(this.yaw * 0.017453292F);
              float f6 = MathHelper.cos(this.yaw * 0.017453292F);
  
              this.motX += (double) (f * f6 - f2 * f5);
              this.motY += (double) f1;
              this.motZ += (double) (f2 * f6 + f * f5);
          }
      }
  
      public float aw() {
          BlockPosition.MutableBlockPosition blockposition_mutableblockposition = new BlockPosition.MutableBlockPosition(MathHelper.floor(this.locX), 0, MathHelper.floor(this.locZ));
  
          if (this.world.isLoaded(blockposition_mutableblockposition)) {
              blockposition_mutableblockposition.p(MathHelper.floor(this.locY + (double) this.getHeadHeight()));
              return this.world.n(blockposition_mutableblockposition);
          } else {
              return 0.0F;
          }
      }
  
      public void spawnIn(World world) {
          // CraftBukkit start
          if (world == null) {
              die();
              this.world = ((CraftWorld) Bukkit.getServer().getWorlds().get(0)).getHandle();
              return;
          }
          // CraftBukkit end
          this.world = world;
      }
  
      public void setLocation(double d0, double d1, double d2, float f, float f1) {
          this.locX = MathHelper.a(d0, -3.0E7D, 3.0E7D);
          this.locY = d1;
          this.locZ = MathHelper.a(d2, -3.0E7D, 3.0E7D);
          this.lastX = this.locX;
          this.lastY = this.locY;
          this.lastZ = this.locZ;
          f1 = MathHelper.a(f1, -90.0F, 90.0F);
          this.yaw = f;
          this.pitch = f1;
          this.lastYaw = this.yaw;
          this.lastPitch = this.pitch;
          double d3 = (double) (this.lastYaw - f);
  
          if (d3 < -180.0D) {
              this.lastYaw += 360.0F;
          }
  
          if (d3 >= 180.0D) {
              this.lastYaw -= 360.0F;
          }
  
          world.getChunkAt((int) Math.floor(this.locX) >> 4, (int) Math.floor(this.locZ) >> 4); // Paper - ensure chunk is always loaded
          this.setPosition(this.locX, this.locY, this.locZ);
          this.setYawPitch(f, f1);
      }
  
      public void setPositionRotation(BlockPosition blockposition, float f, float f1) {
          this.setPositionRotation((double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D, f, f1);
      }
  
      public void setPositionRotation(double d0, double d1, double d2, float f, float f1) {
          this.locX = d0;
          this.locY = d1;
          this.locZ = d2;
          this.lastX = this.locX;
          this.lastY = this.locY;
          this.lastZ = this.locZ;
          this.M = this.locX;
          this.N = this.locY;
          this.O = this.locZ;
          this.yaw = f;
          this.pitch = f1;
          this.setPosition(this.locX, this.locY, this.locZ);
      }
  
      public float g(Entity entity) {
          float f = (float) (this.locX - entity.locX);
          float f1 = (float) (this.locY - entity.locY);
          float f2 = (float) (this.locZ - entity.locZ);
  
          return MathHelper.c(f * f + f1 * f1 + f2 * f2);
      }
  
      public double d(double d0, double d1, double d2) {
          double d3 = this.locX - d0;
          double d4 = this.locY - d1;
          double d5 = this.locZ - d2;
  
          return d3 * d3 + d4 * d4 + d5 * d5;
      }
  
      public double c(BlockPosition blockposition) {
          return blockposition.distanceSquared(this.locX, this.locY, this.locZ);
      }
  
      public double d(BlockPosition blockposition) {
          return blockposition.g(this.locX, this.locY, this.locZ);
      }
  
      public double e(double d0, double d1, double d2) {
          double d3 = this.locX - d0;
          double d4 = this.locY - d1;
          double d5 = this.locZ - d2;
  
          return (double) MathHelper.sqrt(d3 * d3 + d4 * d4 + d5 * d5);
      }
  
      public double h(Entity entity) {
          double d0 = this.locX - entity.locX;
          double d1 = this.locY - entity.locY;
          double d2 = this.locZ - entity.locZ;
  
          return d0 * d0 + d1 * d1 + d2 * d2;
      }
  
      public void d(EntityHuman entityhuman) {}
  
      public void collide(Entity entity) {
          if (!this.x(entity)) {
              if (!entity.noclip && !this.noclip) {
                  double d0 = entity.locX - this.locX;
                  double d1 = entity.locZ - this.locZ;
                  double d2 = MathHelper.a(d0, d1);
  
                  if (d2 >= 0.009999999776482582D) {
                      d2 = (double) MathHelper.sqrt(d2);
                      d0 /= d2;
                      d1 /= d2;
                      double d3 = 1.0D / d2;
  
                      if (d3 > 1.0D) {
                          d3 = 1.0D;
                      }
  
                      d0 *= d3;
                      d1 *= d3;
                      d0 *= 0.05000000074505806D;
                      d1 *= 0.05000000074505806D;
                      d0 *= (double) (1.0F - this.R);
                      d1 *= (double) (1.0F - this.R);
                      if (!this.isVehicle()) {
                          this.f(-d0, 0.0D, -d1);
                      }
  
                      if (!entity.isVehicle()) {
                          entity.f(d0, 0.0D, d1);
                      }
                  }
  
              }
          }
      }
  
      public void f(double d0, double d1, double d2) {
          this.motX += d0;
          this.motY += d1;
          this.motZ += d2;
          this.impulse = true;
      }
  
      protected void ax() {
          this.velocityChanged = true;
      }
  
      public boolean damageEntity(DamageSource damagesource, float f) {
          if (this.isInvulnerable(damagesource)) {
              return false;
          } else {
              this.ax();
              return false;
          }
      }
  
      public Vec3D e(float f) {
          if (f == 1.0F) {
              return this.f(this.pitch, this.yaw);
          } else {
              float f1 = this.lastPitch + (this.pitch - this.lastPitch) * f;
              float f2 = this.lastYaw + (this.yaw - this.lastYaw) * f;
  
              return this.f(f1, f2);
          }
      }
  
      protected final Vec3D f(float f, float f1) {
          float f2 = MathHelper.cos(-f1 * 0.017453292F - 3.1415927F);
          float f3 = MathHelper.sin(-f1 * 0.017453292F - 3.1415927F);
          float f4 = -MathHelper.cos(-f * 0.017453292F);
          float f5 = MathHelper.sin(-f * 0.017453292F);
  
          return new Vec3D((double) (f3 * f4), (double) f5, (double) (f2 * f4));
      }
  
      public Vec3D f(float f) {
          if (f == 1.0F) {
              return new Vec3D(this.locX, this.locY + (double) this.getHeadHeight(), this.locZ);
          } else {
              double d0 = this.lastX + (this.locX - this.lastX) * (double) f;
              double d1 = this.lastY + (this.locY - this.lastY) * (double) f + (double) this.getHeadHeight();
              double d2 = this.lastZ + (this.locZ - this.lastZ) * (double) f;
  
              return new Vec3D(d0, d1, d2);
          }
      }
  
      public boolean isInteractable() {
          return false;
      }
  
      public boolean isCollidable() {
          return false;
      }
  
      public void runKillTrigger(Entity entity, int kills, DamageSource damageSource) { this.a(entity, kills, damageSource); } // Paper - OBFHELPER
      public void a(Entity entity, int i, DamageSource damagesource) {
          if (entity instanceof EntityPlayer) {
              CriterionTriggers.c.a((EntityPlayer) entity, this, damagesource);
          }
  
      }
  
      public boolean c(NBTTagCompound nbttagcompound) {
          String s = this.getSaveID();
  
          if (!this.dead && s != null) {
              nbttagcompound.setString("id", s);
              this.save(nbttagcompound);
              return true;
          } else {
              return false;
          }
      }
  
      public boolean d(NBTTagCompound nbttagcompound) {
          String s = this.getSaveID();
  
          if (!this.dead && s != null && !this.isPassenger()) {
              nbttagcompound.setString("id", s);
              this.save(nbttagcompound);
              return true;
          } else {
              return false;
          }
      }
  
      public static void b(DataConverterManager dataconvertermanager) {
          dataconvertermanager.a(DataConverterTypes.ENTITY, new DataInspector() {
              public NBTTagCompound a(DataConverter dataconverter, NBTTagCompound nbttagcompound, int i) {
                  if (nbttagcompound.hasKeyOfType("Passengers", 9)) {
                      NBTTagList nbttaglist = nbttagcompound.getList("Passengers", 10);
  
                      for (int j = 0; j < nbttaglist.size(); ++j) {
                          nbttaglist.a(j, dataconverter.a(DataConverterTypes.ENTITY, nbttaglist.get(j), i));
                      }
                  }
  
                  return nbttagcompound;
              }
          });
      }
  
      public NBTTagCompound save(NBTTagCompound nbttagcompound) {
          try {
              nbttagcompound.set("Pos", this.a(new double[] { this.locX, this.locY, this.locZ}));
              nbttagcompound.set("Motion", this.a(new double[] { this.motX, this.motY, this.motZ}));
  
              // CraftBukkit start - Checking for NaN pitch/yaw and resetting to zero
              // TODO: make sure this is the best way to address this.
              if (Float.isNaN(this.yaw)) {
                  this.yaw = 0;
              }
  
              if (Float.isNaN(this.pitch)) {
                  this.pitch = 0;
              }
              // CraftBukkit end
  
              nbttagcompound.set("Rotation", this.a(new float[] { this.yaw, this.pitch}));
              nbttagcompound.setFloat("FallDistance", this.fallDistance);
              nbttagcompound.setShort("Fire", (short) this.fireTicks);
              nbttagcompound.setShort("Air", (short) this.getAirTicks());
              nbttagcompound.setBoolean("OnGround", this.onGround);
              nbttagcompound.setInt("Dimension", this.dimension);
              nbttagcompound.setBoolean("Invulnerable", this.invulnerable);
              nbttagcompound.setInt("PortalCooldown", this.portalCooldown);
              nbttagcompound.a("UUID", this.getUniqueID());
              // CraftBukkit start
              // PAIL: Check above UUID reads 1.8 properly, ie: UUIDMost / UUIDLeast
              nbttagcompound.setLong("WorldUUIDLeast", this.world.getDataManager().getUUID().getLeastSignificantBits());
              nbttagcompound.setLong("WorldUUIDMost", this.world.getDataManager().getUUID().getMostSignificantBits());
              nbttagcompound.setInt("Bukkit.updateLevel", CURRENT_LEVEL);
              nbttagcompound.setInt("Spigot.ticksLived", this.ticksLived);
              // CraftBukkit end
              if (this.hasCustomName()) {
                  nbttagcompound.setString("CustomName", this.getCustomName());
              }
  
              if (this.getCustomNameVisible()) {
                  nbttagcompound.setBoolean("CustomNameVisible", this.getCustomNameVisible());
              }
  
              this.aG.b(nbttagcompound);
              if (this.isSilent()) {
                  nbttagcompound.setBoolean("Silent", this.isSilent());
              }
  
              if (this.isNoGravity()) {
                  nbttagcompound.setBoolean("NoGravity", this.isNoGravity());
              }
  
              if (this.glowing) {
                  nbttagcompound.setBoolean("Glowing", this.glowing);
              }
  
              NBTTagList nbttaglist;
              Iterator iterator;
  
              if (!this.aH.isEmpty()) {
                  nbttaglist = new NBTTagList();
                  iterator = this.aH.iterator();
  
                  while (iterator.hasNext()) {
                      String s = (String) iterator.next();
  
                      nbttaglist.add(new NBTTagString(s));
                  }
  
                  nbttagcompound.set("Tags", nbttaglist);
              }
  
              this.b(nbttagcompound);
              if (this.isVehicle()) {
                  nbttaglist = new NBTTagList();
                  iterator = this.bF().iterator();
  
                  while (iterator.hasNext()) {
                      Entity entity = (Entity) iterator.next();
                      NBTTagCompound nbttagcompound1 = new NBTTagCompound();
  
                      if (entity.c(nbttagcompound1)) {
                          nbttaglist.add(nbttagcompound1);
                      }
                  }
  
                  if (!nbttaglist.isEmpty()) {
                      nbttagcompound.set("Passengers", nbttaglist);
                  }
              }
  
              // Paper start - Save the entity's origin location
              if (origin != null) {
                  nbttagcompound.set("Paper.Origin", this.createList(origin.getX(), origin.getY(), origin.getZ()));
              }
              // Save entity's from mob spawner status
              if (spawnedViaMobSpawner) {
                  nbttagcompound.setBoolean("Paper.FromMobSpawner", true);
              }
              // Paper end
              return nbttagcompound;
          } catch (Throwable throwable) {
              CrashReport crashreport = CrashReport.a(throwable, "Saving entity NBT");
              CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Entity being saved");
  
              this.appendEntityCrashDetails(crashreportsystemdetails);
              throw new ReportedException(crashreport);
          }
      }
  
      public void f(NBTTagCompound nbttagcompound) {
          try {
              NBTTagList nbttaglist = nbttagcompound.getList("Pos", 6);
              NBTTagList nbttaglist1 = nbttagcompound.getList("Motion", 6);
              NBTTagList nbttaglist2 = nbttagcompound.getList("Rotation", 5);
  
              this.motX = nbttaglist1.f(0);
              this.motY = nbttaglist1.f(1);
              this.motZ = nbttaglist1.f(2);
  
              /* CraftBukkit start - Moved section down
              if (Math.abs(this.motX) > 10.0D) {
                  this.motX = 0.0D;
              }
  
              if (Math.abs(this.motY) > 10.0D) {
                  this.motY = 0.0D;
              }
  
              if (Math.abs(this.motZ) > 10.0D) {
                  this.motZ = 0.0D;
              }
              // CraftBukkit end */
  
              this.locX = nbttaglist.f(0);
              this.locY = nbttaglist.f(1);
              this.locZ = nbttaglist.f(2);
              this.M = this.locX;
              this.N = this.locY;
              this.O = this.locZ;
              this.lastX = this.locX;
              this.lastY = this.locY;
              this.lastZ = this.locZ;
              this.yaw = nbttaglist2.g(0);
              this.pitch = nbttaglist2.g(1);
              this.lastYaw = this.yaw;
              this.lastPitch = this.pitch;
              this.setHeadRotation(this.yaw);
              this.h(this.yaw);
              this.fallDistance = nbttagcompound.getFloat("FallDistance");
              this.fireTicks = nbttagcompound.getShort("Fire");
              this.setAirTicks(nbttagcompound.getShort("Air"));
              this.onGround = nbttagcompound.getBoolean("OnGround");
              if (nbttagcompound.hasKey("Dimension")) {
                  this.dimension = nbttagcompound.getInt("Dimension");
              }
  
              this.invulnerable = nbttagcompound.getBoolean("Invulnerable");
              this.portalCooldown = nbttagcompound.getInt("PortalCooldown");
              if (nbttagcompound.b("UUID")) {
                  this.uniqueID = nbttagcompound.a("UUID");
                  this.ar = this.uniqueID.toString();
              }
  
              this.setPosition(this.locX, this.locY, this.locZ);
              this.setYawPitch(this.yaw, this.pitch);
              if (nbttagcompound.hasKeyOfType("CustomName", 8)) {
                  this.setCustomName(nbttagcompound.getString("CustomName"));
              }
  
              this.setCustomNameVisible(nbttagcompound.getBoolean("CustomNameVisible"));
              this.aG.a(nbttagcompound);
              this.setSilent(nbttagcompound.getBoolean("Silent"));
              this.setNoGravity(nbttagcompound.getBoolean("NoGravity"));
              this.g(nbttagcompound.getBoolean("Glowing"));
              if (nbttagcompound.hasKeyOfType("Tags", 9)) {
                  this.aH.clear();
                  NBTTagList nbttaglist3 = nbttagcompound.getList("Tags", 8);
                  int i = Math.min(nbttaglist3.size(), 1024);
  
                  for (int j = 0; j < i; ++j) {
                      this.aH.add(nbttaglist3.getString(j));
                  }
              }
  
              this.a(nbttagcompound);
              if (this.aA()) {
                  this.setPosition(this.locX, this.locY, this.locZ);
              }
  
              // CraftBukkit start
              if (this instanceof EntityLiving) {
                  EntityLiving entity = (EntityLiving) this;
  
                  this.ticksLived = nbttagcompound.getInt("Spigot.ticksLived");
  
                  // Reset the persistence for tamed animals
                  if (entity instanceof EntityTameableAnimal && !isLevelAtLeast(nbttagcompound, 2) && !nbttagcompound.getBoolean("PersistenceRequired")) {
                      EntityInsentient entityinsentient = (EntityInsentient) entity;
                      entityinsentient.persistent = !entityinsentient.isTypeNotPersistent();
                  }
              }
              // CraftBukkit end
  
              // CraftBukkit start
              double limit = getBukkitEntity() instanceof Vehicle ? 100.0D : 10.0D;
              if (Math.abs(this.motX) > limit) {
                  this.motX = 0.0D;
              }
  
              if (Math.abs(this.motY) > limit) {
                  this.motY = 0.0D;
              }
  
              if (Math.abs(this.motZ) > limit) {
                  this.motZ = 0.0D;
              }
              // CraftBukkit end
  
              // CraftBukkit start - Reset world
              if (this instanceof EntityPlayer) {
                  Server server = Bukkit.getServer();
                  org.bukkit.World bworld = null;
  
                  // TODO: Remove World related checks, replaced with WorldUID
                  String worldName = nbttagcompound.getString("world");
  
                  if (nbttagcompound.hasKey("WorldUUIDMost") && nbttagcompound.hasKey("WorldUUIDLeast")) {
                      UUID uid = new UUID(nbttagcompound.getLong("WorldUUIDMost"), nbttagcompound.getLong("WorldUUIDLeast"));
                      bworld = server.getWorld(uid);
                  } else {
                      bworld = server.getWorld(worldName);
                  }
  
                  if (bworld == null) {
                      EntityPlayer entityPlayer = (EntityPlayer) this;
                      bworld = ((org.bukkit.craftbukkit.CraftServer) server).getServer().getWorldServer(entityPlayer.dimension).getWorld();
                  }
  
                  spawnIn(bworld == null? null : ((CraftWorld) bworld).getHandle());
              }
              // CraftBukkit end
  
              // Paper start - Restore the entity's origin location
              NBTTagList originTag = nbttagcompound.getList("Paper.Origin", 6);
              if (!originTag.isEmpty()) {
                  origin = new Location(world.getWorld(), originTag.getDoubleAt(0), originTag.getDoubleAt(1), originTag.getDoubleAt(2));
              }
  
              spawnedViaMobSpawner = nbttagcompound.getBoolean("Paper.FromMobSpawner"); // Restore entity's from mob spawner status
              // Paper end
  
          } catch (Throwable throwable) {
              CrashReport crashreport = CrashReport.a(throwable, "Loading entity NBT");
              CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Entity being loaded");
  
              this.appendEntityCrashDetails(crashreportsystemdetails);
              throw new ReportedException(crashreport);
          }
      }
  
      protected boolean aA() {
          return true;
      }
  
      // Paper start
      private java.lang.ref.WeakReference<Chunk> currentChunk = null;
  
      public void setCurrentChunk(Chunk chunk) {
          this.currentChunk = chunk != null ? new java.lang.ref.WeakReference<>(chunk) : null;
      }
      /**
       * Returns the entities current registered chunk. If the entity is not added to a chunk yet, it will return null
       */
      public Chunk getCurrentChunk() {
          final Chunk chunk = currentChunk != null ? currentChunk.get() : null;
          return chunk != null && chunk.isLoaded() ? chunk : (isAddedToChunk() ? world.getChunkIfLoaded(getChunkX(), getChunkZ()) : null);
      }
      /**
       * Returns the chunk at the location, using the entities local cache if avail
       * Will only return null if the location specified is not loaded
       */
      public Chunk getCurrentChunkAt(int x, int z) {
          if (getChunkX() == x && getChunkZ() == z) {
              Chunk chunk = getCurrentChunk();
              if (chunk != null) {
                  return chunk;
              }
          }
          return world.getChunkIfLoaded(x, z);
      }
      /**
       * Returns the chunk at the entities current location, using the entities local cache if avail
       * Will only return null if the location specified is not loaded
       */
      public Chunk getChunkAtLocation() {
          return getCurrentChunkAt((int)Math.floor(locX) >> 4, (int)Math.floor(locZ) >> 4);
      }
      private String entityKeyString = null;
      private MinecraftKey entityKey = getMinecraftKey();
  
      @Override
      public MinecraftKey getMinecraftKey() {
          if (entityKey == null) {
              entityKey = EntityTypes.getKey(this);
              entityKeyString = entityKey != null ? entityKey.toString() : null;
          }
          return entityKey;
      }
  
      @Override
      public String getMinecraftKeyString() {
          getMinecraftKey(); // Try to load if it doesn't exists. see: https://github.com/PaperMC/Paper/issues/1280
          return entityKeyString;
      }
      @Nullable
      public final String getSaveID() {
          return getMinecraftKeyString();
          // Paper end
      }
  
      protected abstract void a(NBTTagCompound nbttagcompound);
  
      protected abstract void b(NBTTagCompound nbttagcompound);
  
      protected NBTTagList createList(double... adouble) { return a(adouble); } // Paper - OBFHELPER
      protected NBTTagList a(double... adouble) {
          NBTTagList nbttaglist = new NBTTagList();
          double[] adouble1 = adouble;
          int i = adouble.length;
  
          for (int j = 0; j < i; ++j) {
              double d0 = adouble1[j];
  
              nbttaglist.add(new NBTTagDouble(d0));
          }
  
          return nbttaglist;
      }
  
      protected NBTTagList a(float... afloat) {
          NBTTagList nbttaglist = new NBTTagList();
          float[] afloat1 = afloat;
          int i = afloat.length;
  
          for (int j = 0; j < i; ++j) {
              float f = afloat1[j];
  
              nbttaglist.add(new NBTTagFloat(f));
          }
  
          return nbttaglist;
      }
  
      @Nullable
      public EntityItem a(Item item, int i) {
          return this.a(item, i, 0.0F);
      }
  
      @Nullable
      public EntityItem a(Item item, int i, float f) {
          return this.a(new ItemStack(item, i, 0), f);
      }
  
      @Nullable public final EntityItem dropItem(ItemStack itemstack, float offset) { return this.a(itemstack, offset); } // Paper - OBFHELPER
      @Nullable
      public EntityItem a(ItemStack itemstack, float f) {
          if (itemstack.isEmpty()) {
              return null;
          } else {
              // CraftBukkit start - Capture drops for death event
              if (this instanceof EntityLiving && !((EntityLiving) this).forceDrops) {
                  ((EntityLiving) this).drops.add(org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack));
                  return null;
              }
              // CraftBukkit end
              EntityItem entityitem = new EntityItem(this.world, this.locX, this.locY + (double) f, this.locZ, itemstack);
  
              entityitem.q();
              this.world.addEntity(entityitem);
              return entityitem;
          }
      }
  
      public boolean isAlive() {
          return !this.dead;
      }
  
      public boolean inBlock() {
          if (this.noclip) {
              return false;
          } else {
              BlockPosition.PooledBlockPosition blockposition_pooledblockposition = BlockPosition.PooledBlockPosition.s();
  
              for (int i = 0; i < 8; ++i) {
                  int j = MathHelper.floor(this.locY + (double) (((float) ((i >> 0) % 2) - 0.5F) * 0.1F) + (double) this.getHeadHeight());
                  int k = MathHelper.floor(this.locX + (double) (((float) ((i >> 1) % 2) - 0.5F) * this.width * 0.8F));
                  int l = MathHelper.floor(this.locZ + (double) (((float) ((i >> 2) % 2) - 0.5F) * this.width * 0.8F));
  
                  if (blockposition_pooledblockposition.getX() != k || blockposition_pooledblockposition.getY() != j || blockposition_pooledblockposition.getZ() != l) {
                      blockposition_pooledblockposition.f(k, j, l);
                      if (this.world.getType(blockposition_pooledblockposition).r()) {
                          blockposition_pooledblockposition.t();
                          return true;
                      }
                  }
              }
  
              blockposition_pooledblockposition.t();
              return false;
          }
      }
  
      public boolean b(EntityHuman entityhuman, EnumHand enumhand) {
          return false;
      }
  
      @Nullable
      public AxisAlignedBB j(Entity entity) {
          return null;
      }
  
      public void aE() {
          Entity entity = this.bJ();
  
          if (this.isPassenger() && entity.dead) {
              this.stopRiding();
          } else {
              this.motX = 0.0D;
              this.motY = 0.0D;
              this.motZ = 0.0D;
              this.B_();
              if (this.isPassenger()) {
                  entity.k(this);
              }
          }
      }
  
      public void k(Entity entity) {
          if (this.w(entity)) {
              entity.setPosition(this.locX, this.locY + this.aG() + entity.aF(), this.locZ);
          }
      }
  
      public double aF() {
          return 0.0D;
      }
  
      public double aG() {
          return (double) this.length * 0.75D;
      }
  
      public boolean startRiding(Entity entity) {
          return this.a(entity, false);
      }
  
      public boolean a(Entity entity, boolean flag) {
          for (Entity entity1 = entity; entity1.au != null; entity1 = entity1.au) {
              if (entity1.au == this) {
                  return false;
              }
          }
  
          if (!flag && (!this.n(entity) || !entity.q(this))) {
              return false;
          } else {
              if (this.isPassenger()) {
                  this.stopRiding();
              }
  
              this.au = entity;
              this.au.o(this);
              return true;
          }
      }
  
      protected boolean n(Entity entity) {
          return this.j <= 0;
      }
  
      public void ejectPassengers() {
          for (int i = this.passengers.size() - 1; i >= 0; --i) {
              ((Entity) this.passengers.get(i)).stopRiding();
          }
  
      }
  
      public void stopRiding() {
          if (this.au != null) {
              Entity entity = this.au;
  
              this.au = null;
              entity.p(this);
          }
  
      }
  
      protected void o(Entity entity) {
          if (entity == this) throw new IllegalArgumentException("Entities cannot become a passenger of themselves"); // Paper - issue 572
          if (entity.bJ() != this) {
              throw new IllegalStateException("Use x.startRiding(y), not y.addPassenger(x)");
          } else {
              // CraftBukkit start
              com.google.common.base.Preconditions.checkState(!entity.passengers.contains(this), "Circular entity riding! %s %s", this, entity);
  
              CraftEntity craft = (CraftEntity) entity.getBukkitEntity().getVehicle();
              Entity orig = craft == null ? null : craft.getHandle();
              if (getBukkitEntity() instanceof Vehicle && entity.getBukkitEntity() instanceof LivingEntity && entity.world.isChunkLoaded((int) entity.locX >> 4, (int) entity.locZ >> 4, false)) { // Boolean not used
                  VehicleEnterEvent event = new VehicleEnterEvent(
                          (Vehicle) getBukkitEntity(),
                           entity.getBukkitEntity()
                  );
                  Bukkit.getPluginManager().callEvent(event);
                  CraftEntity craftn = (CraftEntity) entity.getBukkitEntity().getVehicle();
                  Entity n = craftn == null ? null : craftn.getHandle();
                  if (event.isCancelled() || n != orig) {
                      return;
                  }
              }
              // CraftBukkit end
              // Spigot start
              org.spigotmc.event.entity.EntityMountEvent event = new org.spigotmc.event.entity.EntityMountEvent(entity.getBukkitEntity(), this.getBukkitEntity());
              Bukkit.getPluginManager().callEvent(event);
              if (event.isCancelled()) {
                  return;
              }
              // Spigot end
              if (!this.world.isClientSide && entity instanceof EntityHuman && !(this.bE() instanceof EntityHuman)) {
                  this.passengers.add(0, entity);
              } else {
                  this.passengers.add(entity);
              }
  
          }
      }
  
      protected void p(Entity entity) {
          if (entity.bJ() == this) {
              throw new IllegalStateException("Use x.stopRiding(y), not y.removePassenger(x)");
          } else {
              // CraftBukkit start
              entity.setVehicle(this); // Paper - Set the vehicle back for the event
              CraftEntity craft = (CraftEntity) entity.getBukkitEntity().getVehicle();
              Entity orig = craft == null ? null : craft.getHandle();
              if (getBukkitEntity() instanceof Vehicle && entity.getBukkitEntity() instanceof LivingEntity) {
                  VehicleExitEvent event = new VehicleExitEvent(
                          (Vehicle) getBukkitEntity(),
                          (LivingEntity) entity.getBukkitEntity()
                  );
                  Bukkit.getPluginManager().callEvent(event);
                  CraftEntity craftn = (CraftEntity) entity.getBukkitEntity().getVehicle();
                  Entity n = craftn == null ? null : craftn.getHandle();
                  if (event.isCancelled() || n != orig) {
                      return;
                  }
              }
              // CraftBukkit end
              // Paper start - make EntityDismountEvent cancellable
              if (!new org.spigotmc.event.entity.EntityDismountEvent(entity.getBukkitEntity(), this.getBukkitEntity()).callEvent()) {
                  return;
              }
              entity.setVehicle(null);
              // Paper end
  
              this.passengers.remove(entity);
              entity.j = 60;
          }
      }
  
      protected boolean q(Entity entity) {
          return this.bF().size() < 1;
      }
  
      public float aI() {
          return 0.0F;
      }
  
      public Vec3D aJ() {
          return this.f(this.pitch, this.yaw);
      }
  
      public void e(BlockPosition blockposition) {
          if (this.portalCooldown > 0) {
              this.portalCooldown = this.aM();
          } else {
              if (!this.world.isClientSide && !blockposition.equals(this.an)) {
                  this.an = new BlockPosition(blockposition);
                  ShapeDetector.ShapeDetectorCollection shapedetector_shapedetectorcollection = Blocks.PORTAL.c(this.world, this.an);
                  double d0 = shapedetector_shapedetectorcollection.getFacing().k() == EnumDirection.EnumAxis.X ? (double) shapedetector_shapedetectorcollection.a().getZ() : (double) shapedetector_shapedetectorcollection.a().getX();
                  double d1 = shapedetector_shapedetectorcollection.getFacing().k() == EnumDirection.EnumAxis.X ? this.locZ : this.locX;
  
                  d1 = Math.abs(MathHelper.c(d1 - (double) (shapedetector_shapedetectorcollection.getFacing().e().c() == EnumDirection.EnumAxisDirection.NEGATIVE ? 1 : 0), d0, d0 - (double) shapedetector_shapedetectorcollection.d()));
                  double d2 = MathHelper.c(this.locY - 1.0D, (double) shapedetector_shapedetectorcollection.a().getY(), (double) (shapedetector_shapedetectorcollection.a().getY() - shapedetector_shapedetectorcollection.e()));
  
                  this.ao = new Vec3D(d1, d2, 0.0D);
                  this.ap = shapedetector_shapedetectorcollection.getFacing();
              }
  
              this.ak = true;
          }
      }
  
      public int aM() {
          return 300;
      }
  
      public Iterable<ItemStack> aO() {
          return Entity.b;
      }
  
      public Iterable<ItemStack> getArmorItems() {
          return Entity.b;
      }
  
      public Iterable<ItemStack> aQ() {
          return Iterables.concat(this.aO(), this.getArmorItems());
      }
  
      public void setEquipment(EnumItemSlot enumitemslot, ItemStack itemstack) {}
  
      public boolean isBurning() {
          boolean flag = this.world != null && this.world.isClientSide;
  
          return !this.fireProof && (this.fireTicks > 0 || flag && this.getFlag(0));
      }
  
      public boolean isPassenger() {
          return this.bJ() != null;
      }
  
      public boolean isVehicle() {
          return !this.bF().isEmpty();
      }
  
      public boolean isSneaking() {
          return this.getFlag(1);
      }
  
      public void setSneaking(boolean flag) {
          this.setFlag(1, flag);
      }
  
      public boolean isSprinting() {
          return this.getFlag(3);
      }
  
      public void setSprinting(boolean flag) {
          this.setFlag(3, flag);
      }
  
      public boolean aW() {
          return this.glowing || this.world.isClientSide && this.getFlag(6);
      }
  
      public void g(boolean flag) {
          this.glowing = flag;
          if (!this.world.isClientSide) {
              this.setFlag(6, this.glowing);
          }
  
      }
  
      public boolean isInvisible() {
          return this.getFlag(5);
      }
  
      @Nullable public ScoreboardTeamBase getTeam() { return this.aY(); } // Paper - OBFHELPER
      @Nullable
      public ScoreboardTeamBase aY() {
          if (!this.world.paperConfig.nonPlayerEntitiesOnScoreboards && !(this instanceof EntityHuman)) { return null; } // Paper
          return this.world.getScoreboard().getPlayerTeam(this.bn());
      }
  
      public boolean r(Entity entity) {
          return this.a(entity.aY());
      }
  
      public boolean a(ScoreboardTeamBase scoreboardteambase) {
          return this.aY() != null ? this.aY().isAlly(scoreboardteambase) : false;
      }
  
      public void setInvisible(boolean flag) {
          this.setFlag(5, flag);
      }
  
      public boolean getFlag(int i) {
          return (((Byte) this.datawatcher.get(Entity.Z)).byteValue() & 1 << i) != 0;
      }
  
      public void setFlag(int i, boolean flag) {
          byte b0 = ((Byte) this.datawatcher.get(Entity.Z)).byteValue();
  
          if (flag) {
              this.datawatcher.set(Entity.Z, Byte.valueOf((byte) (b0 | 1 << i)));
          } else {
              this.datawatcher.set(Entity.Z, Byte.valueOf((byte) (b0 & ~(1 << i))));
          }
  
      }
  
      public int getAirTicks() {
          return ((Integer) this.datawatcher.get(Entity.aA)).intValue();
      }
  
      public void setAirTicks(int i) {
          // CraftBukkit start
          EntityAirChangeEvent event = new EntityAirChangeEvent(this.getBukkitEntity(), i);
          event.getEntity().getServer().getPluginManager().callEvent(event);
          if (event.isCancelled()) {
              return;
          }
          this.datawatcher.set(Entity.aA, Integer.valueOf(event.getAmount()));
          // CraftBukkit end
      }
  
      public void onLightningStrike(EntityLightning entitylightning) {
          // CraftBukkit start
          final org.bukkit.entity.Entity thisBukkitEntity = this.getBukkitEntity();
          final org.bukkit.entity.Entity stormBukkitEntity = entitylightning.getBukkitEntity();
          final PluginManager pluginManager = Bukkit.getPluginManager();
  
          if (thisBukkitEntity instanceof Hanging) {
              HangingBreakByEntityEvent hangingEvent = new HangingBreakByEntityEvent((Hanging) thisBukkitEntity, stormBukkitEntity);
              pluginManager.callEvent(hangingEvent);
  
              if (hangingEvent.isCancelled()) {
                  return;
              }
          }
  
          if (this.fireProof) {
              return;
          }
          CraftEventFactory.entityDamage = entitylightning;
          if (!this.damageEntity(DamageSource.LIGHTNING, 5.0F)) {
              CraftEventFactory.entityDamage = null;
              return;
          }
          // CraftBukkit end
          ++this.fireTicks;
          if (this.fireTicks == 0) {
              // CraftBukkit start - Call a combust event when lightning strikes
              EntityCombustByEntityEvent entityCombustEvent = new EntityCombustByEntityEvent(stormBukkitEntity, thisBukkitEntity, 8);
              pluginManager.callEvent(entityCombustEvent);
              if (!entityCombustEvent.isCancelled()) {
                  this.setOnFire(entityCombustEvent.getDuration());
              }
              // CraftBukkit end
          }
  
      }
  
      public void onKill(EntityLiving entityLiving) { this.b(entityLiving); } // Paper - OBFHELPER
      public void b(EntityLiving entityliving) {}
  
      protected boolean i(double d0, double d1, double d2) {
          BlockPosition blockposition = new BlockPosition(d0, d1, d2);
          double d3 = d0 - (double) blockposition.getX();
          double d4 = d1 - (double) blockposition.getY();
          double d5 = d2 - (double) blockposition.getZ();
  
          if (!this.world.a(this.getBoundingBox())) {
              return false;
          } else {
              EnumDirection enumdirection = EnumDirection.UP;
              double d6 = Double.MAX_VALUE;
  
              if (!this.world.t(blockposition.west()) && d3 < d6) {
                  d6 = d3;
                  enumdirection = EnumDirection.WEST;
              }
  
              if (!this.world.t(blockposition.east()) && 1.0D - d3 < d6) {
                  d6 = 1.0D - d3;
                  enumdirection = EnumDirection.EAST;
              }
  
              if (!this.world.t(blockposition.north()) && d5 < d6) {
                  d6 = d5;
                  enumdirection = EnumDirection.NORTH;
              }
  
              if (!this.world.t(blockposition.south()) && 1.0D - d5 < d6) {
                  d6 = 1.0D - d5;
                  enumdirection = EnumDirection.SOUTH;
              }
  
              if (!this.world.t(blockposition.up()) && 1.0D - d4 < d6) {
                  d6 = 1.0D - d4;
                  enumdirection = EnumDirection.UP;
              }
  
              float f = this.random.nextFloat() * 0.2F + 0.1F;
              float f1 = (float) enumdirection.c().a();
  
              if (enumdirection.k() == EnumDirection.EnumAxis.X) {
                  this.motX = (double) (f1 * f);
                  this.motY *= 0.75D;
                  this.motZ *= 0.75D;
              } else if (enumdirection.k() == EnumDirection.EnumAxis.Y) {
                  this.motX *= 0.75D;
                  this.motY = (double) (f1 * f);
                  this.motZ *= 0.75D;
              } else if (enumdirection.k() == EnumDirection.EnumAxis.Z) {
                  this.motX *= 0.75D;
                  this.motY *= 0.75D;
                  this.motZ = (double) (f1 * f);
              }
  
              return true;
          }
      }
  
      public void ba() {
          this.E = true;
          this.fallDistance = 0.0F;
      }
  
      public String getName() {
          if (this.hasCustomName()) {
              return this.getCustomName();
          } else {
              String s = EntityTypes.b(this);
  
              if (s == null) {
                  s = "generic";
              }
  
              return LocaleI18n.get("entity." + s + ".name");
          }
      }
  
      @Nullable
      public Entity[] bb() {
          return null;
      }
  
      public boolean s(Entity entity) {
          return this == entity;
      }
  
      public float getHeadRotation() {
          return 0.0F;
      }
  
      public void setHeadRotation(float f) {}
  
      public void h(float f) {}
  
      public boolean bd() {
          return true;
      }
  
      public boolean t(Entity entity) {
          return false;
      }
  
      public String toString() {
          return String.format("%s[\'%s\'/%d, uuid=\'%s\', l=\'%s\', x=%.2f, y=%.2f, z=%.2f, cx=%d, cd=%d, tl=%d, v=%b, d=%b]", new Object[] { this.getClass().getSimpleName(), this.getName(), Integer.valueOf(this.id), this.uniqueID.toString(), this.world == null ? "~NULL~" : this.world.getWorldData().getName(), Double.valueOf(this.locX), Double.valueOf(this.locY), Double.valueOf(this.locZ), getChunkX(), getChunkZ(), this.ticksLived, this.valid, this.dead}); // Paper - add more information
      }
  
      public boolean isInvulnerable(DamageSource damagesource) {
          return this.invulnerable && damagesource != DamageSource.OUT_OF_WORLD && !damagesource.u();
      }
  
      public boolean be() {
          return this.invulnerable;
      }
  
      public void setInvulnerable(boolean flag) {
          this.invulnerable = flag;
      }
  
      public void u(Entity entity) {
          this.setPositionRotation(entity.locX, entity.locY, entity.locZ, entity.yaw, entity.pitch);
      }
  
      private void a(Entity entity) {
          NBTTagCompound nbttagcompound = entity.save(new NBTTagCompound());
  
          nbttagcompound.remove("Dimension");
          this.f(nbttagcompound);
          this.portalCooldown = entity.portalCooldown;
          this.an = entity.an;
          this.ao = entity.ao;
          this.ap = entity.ap;
      }
  
      @Nullable
      public Entity b(int i) {
          if (!this.world.isClientSide && !this.dead) {
              this.world.methodProfiler.a("changeDimension");
              MinecraftServer minecraftserver = this.C_();
              // CraftBukkit start - Move logic into new function "teleportTo(Location,boolean)"
              // int j = this.dimension;
              // WorldServer worldserver = minecraftserver.getWorldServer(j);
              // WorldServer worldserver1 = minecraftserver.getWorldServer(i);
              WorldServer exitWorld = null;
              if (this.dimension < CraftWorld.CUSTOM_DIMENSION_OFFSET) { // Plugins must specify exit from custom Bukkit worlds
                  // Only target existing worlds (compensate for allow-nether/allow-end as false)
                  for (WorldServer world : minecraftserver.worlds) {
                      if (world.dimension == i) {
                          exitWorld = world;
                      }
                  }
              }
  
              BlockPosition blockposition = null; // PAIL: CHECK
              Location enter = this.getBukkitEntity().getLocation();
              Location exit;
              if (exitWorld != null) {
                  if (blockposition != null) {
                      exit = new Location(exitWorld.getWorld(), blockposition.getX(), blockposition.getY(), blockposition.getZ());
                  } else {
                      exit = minecraftserver.getPlayerList().calculateTarget(enter, minecraftserver.getWorldServer(i));
                  }
              }
              else {
                  exit = null;
              }
              boolean useTravelAgent = exitWorld != null && !(this.dimension == 1 && exitWorld.dimension == 1); // don't use agent for custom worlds or return from THE_END
  
              TravelAgent agent = exit != null ? (TravelAgent) ((CraftWorld) exit.getWorld()).getHandle().getTravelAgent() : org.bukkit.craftbukkit.CraftTravelAgent.DEFAULT; // return arbitrary TA to compensate for implementation dependent plugins
              boolean oldCanCreate = agent.getCanCreatePortal();
              agent.setCanCreatePortal(false); // General entities cannot create portals
  
              EntityPortalEvent event = new EntityPortalEvent(this.getBukkitEntity(), enter, exit, agent);
              event.useTravelAgent(useTravelAgent);
              event.getEntity().getServer().getPluginManager().callEvent(event);
              if (event.isCancelled() || event.getTo() == null || event.getTo().getWorld() == null || !this.isAlive()) {
                  agent.setCanCreatePortal(oldCanCreate);
                  return null;
              }
              exit = event.useTravelAgent() ? event.getPortalTravelAgent().findOrCreate(event.getTo()) : event.getTo();
              agent.setCanCreatePortal(oldCanCreate);
  
              // Need to make sure the profiler state is reset afterwards (but we still want to time the call)
              Entity entity = this.teleportTo(exit, true);
              this.world.methodProfiler.b();
              return entity;
          }
          return null;
      }
  
      public Entity teleportTo(Location exit, boolean portal) {
          if (!this.dead) { // Paper
              WorldServer worldserver = ((CraftWorld) getBukkitEntity().getLocation().getWorld()).getHandle();
              WorldServer worldserver1 = ((CraftWorld) exit.getWorld()).getHandle();
              int i = worldserver1.dimension;
              // CraftBukkit end
  
              this.dimension = i;
              /* CraftBukkit start - TODO: Check if we need this
              if (j == 1 && i == 1) {
                  worldserver1 = minecraftserver.getWorldServer(0);
                  this.dimension = 0;
              }
              // CraftBukkit end */
  
              this.world.removeEntity(this); // Paper - Fully remove entity, can't have dupes in the UUID map
              this.dead = false;
              this.world.methodProfiler.a("reposition");
              /* CraftBukkit start - Handled in calculateTarget
              BlockPosition blockposition;
  
              if (i == 1) {
                  blockposition = worldserver1.getDimensionSpawn();
              } else {
                  double d0 = this.locX;
                  double d1 = this.locZ;
                  double d2 = 8.0D;
  
                  if (i == -1) {
                      d0 = MathHelper.a(d0 / 8.0D, worldserver1.getWorldBorder().b() + 16.0D, worldserver1.getWorldBorder().d() - 16.0D);
                      d1 = MathHelper.a(d1 / 8.0D, worldserver1.getWorldBorder().c() + 16.0D, worldserver1.getWorldBorder().e() - 16.0D);
                  } else if (i == 0) {
                      d0 = MathHelper.a(d0 * 8.0D, worldserver1.getWorldBorder().b() + 16.0D, worldserver1.getWorldBorder().d() - 16.0D);
                      d1 = MathHelper.a(d1 * 8.0D, worldserver1.getWorldBorder().c() + 16.0D, worldserver1.getWorldBorder().e() - 16.0D);
                  }
  
                  d0 = (double) MathHelper.clamp((int) d0, -29999872, 29999872);
                  d1 = (double) MathHelper.clamp((int) d1, -29999872, 29999872);
                  float f = this.yaw;
  
                  this.setPositionRotation(d0, this.locY, d1, 90.0F, 0.0F);
                  PortalTravelAgent portaltravelagent = worldserver1.getTravelAgent();
  
                  portaltravelagent.b(this, f);
                  blockposition = new BlockPosition(this);
              }
  
              // CraftBukkit end */
              // CraftBukkit start - Ensure chunks are loaded in case TravelAgent is not used which would initially cause chunks to load during find/create
              // minecraftserver.getPlayerList().changeWorld(this, j, worldserver, worldserver1);
              worldserver1.getMinecraftServer().getPlayerList().repositionEntity(this, exit, portal);
              // worldserver.entityJoinedWorld(this, false); // Handled in repositionEntity
              // CraftBukkit end
              this.world.methodProfiler.c("reloading");
              Entity entity = EntityTypes.a(this.getClass(), (World) worldserver1);
  
              if (entity != null) {
                  entity.a(this);
                  /* CraftBukkit start - We need to do this...
                  if (j == 1 && i == 1) {
                      BlockPosition blockposition1 = worldserver1.q(worldserver1.getSpawn());
  
                      entity.setPositionRotation(blockposition1, entity.yaw, entity.pitch);
                  } else {
                      entity.setPositionRotation(blockposition, entity.yaw, entity.pitch);
                  }
                  // CraftBukkit end */
  
                  boolean flag = entity.attachedToPlayer;
  
                  entity.attachedToPlayer = true;
                  worldserver1.addEntity(entity);
                  entity.attachedToPlayer = flag;
                  worldserver1.entityJoinedWorld(entity, false);
                  // CraftBukkit start - Forward the CraftEntity to the new entity
                  this.getBukkitEntity().setHandle(entity);
                  entity.bukkitEntity = this.getBukkitEntity();
  
                  if (this instanceof EntityInsentient) {
                      ((EntityInsentient)this).unleash(true, false); // Unleash to prevent duping of leads.
                  }
                  // CraftBukkit end
              }
  
              this.dead = true;
              this.world.methodProfiler.b();
              worldserver.m();
              worldserver1.m();
              // this.world.methodProfiler.b(); // CraftBukkit: Moved up to keep balanced
              return entity;
          } else {
              return null;
          }
      }
  
      public boolean bf() {
          return true;
      }
  
      public float a(Explosion explosion, World world, BlockPosition blockposition, IBlockData iblockdata) {
          return iblockdata.getBlock().a(this);
      }
  
      public boolean a(Explosion explosion, World world, BlockPosition blockposition, IBlockData iblockdata, float f) {
          return true;
      }
  
      public int bg() {
          return 3;
      }
  
      public Vec3D getPortalOffset() {
          return this.ao;
      }
  
      public EnumDirection getPortalDirection() {
          return this.ap;
      }
  
      public boolean isIgnoreBlockTrigger() {
          return false;
      }
  
      public void appendEntityCrashDetails(CrashReportSystemDetails crashreportsystemdetails) {
          crashreportsystemdetails.a("Entity Type", new CrashReportCallable() {
              public String a() throws Exception {
                  return EntityTypes.a(Entity.this) + " (" + Entity.this.getClass().getCanonicalName() + ")";
              }
  
              public Object call() throws Exception {
                  return this.a();
              }
          });
          crashreportsystemdetails.a("Entity ID", (Object) Integer.valueOf(this.id));
          crashreportsystemdetails.a("Entity Name", new CrashReportCallable() {
              public String a() throws Exception {
                  return Entity.this.getName();
              }
  
              public Object call() throws Exception {
                  return this.a();
              }
          });
          crashreportsystemdetails.a("Entity\'s Exact location", (Object) String.format("%.2f, %.2f, %.2f", new Object[] { Double.valueOf(this.locX), Double.valueOf(this.locY), Double.valueOf(this.locZ)}));
          crashreportsystemdetails.a("Entity\'s Block location", (Object) CrashReportSystemDetails.a(MathHelper.floor(this.locX), MathHelper.floor(this.locY), MathHelper.floor(this.locZ)));
          crashreportsystemdetails.a("Entity\'s Momentum", (Object) String.format("%.2f, %.2f, %.2f", new Object[] { Double.valueOf(this.motX), Double.valueOf(this.motY), Double.valueOf(this.motZ)}));
          crashreportsystemdetails.a("Entity\'s Passengers", new CrashReportCallable() {
              public String a() throws Exception {
                  return Entity.this.bF().toString();
              }
  
              public Object call() throws Exception {
                  return this.a();
              }
          });
          crashreportsystemdetails.a("Entity\'s Vehicle", new CrashReportCallable() {
              public String a() throws Exception {
                  return Entity.this.bJ().toString();
              }
  
              public Object call() throws Exception {
                  return this.a();
              }
          });
      }
  
      public void setUUID(UUID uuid) { a(uuid); } // Paper - OBFHELPER
      public void a(UUID uuid) {
          this.uniqueID = uuid;
          this.ar = this.uniqueID.toString();
      }
  
      public UUID getUniqueID() {
          return this.uniqueID;
      }
  
      public String bn() {
          return this.ar;
      }
  
      public boolean bo() {
          return this.pushedByWater();
      }
  
      public boolean pushedByWater() {
          // Paper end
          return true;
      }
  
      public IChatBaseComponent getScoreboardDisplayName() {
          ChatComponentText chatcomponenttext = new ChatComponentText(ScoreboardTeam.getPlayerDisplayName(this.aY(), this.getName()));
  
          chatcomponenttext.getChatModifier().setChatHoverable(this.bv());
          chatcomponenttext.getChatModifier().setInsertion(this.bn());
          return chatcomponenttext;
      }
  
      public void setCustomName(String s) {
          // CraftBukkit start - Add a sane limit for name length
          if (s.length() > 256) {
              s = s.substring(0, 256);
          }
          // CraftBukkit end
          this.datawatcher.set(Entity.aB, s);
      }
  
      public String getCustomName() {
          return (String) this.datawatcher.get(Entity.aB);
      }
  
      public boolean hasCustomName() {
          return !((String) this.datawatcher.get(Entity.aB)).isEmpty();
      }
  
      public void setCustomNameVisible(boolean flag) {
          this.datawatcher.set(Entity.aC, Boolean.valueOf(flag));
      }
  
      public boolean getCustomNameVisible() {
          return ((Boolean) this.datawatcher.get(Entity.aC)).booleanValue();
      }
  
      public void enderTeleportTo(double d0, double d1, double d2) {
          this.aI = true;
          this.setPositionRotation(d0, d1, d2, this.yaw, this.pitch);
          this.world.entityJoinedWorld(this, false);
      }
  
      public void a(DataWatcherObject<?> datawatcherobject) {}
  
      public EnumDirection getDirection() {
          return EnumDirection.fromType2(MathHelper.floor((double) (this.yaw * 4.0F / 360.0F) + 0.5D) & 3);
      }
  
      public EnumDirection bu() {
          return this.getDirection();
      }
  
      protected ChatHoverable bv() {
          NBTTagCompound nbttagcompound = new NBTTagCompound();
          MinecraftKey minecraftkey = EntityTypes.a(this);
  
          nbttagcompound.setString("id", this.bn());
          if (minecraftkey != null) {
              nbttagcompound.setString("type", minecraftkey.toString());
          }
  
          nbttagcompound.setString("name", this.getName());
          return new ChatHoverable(ChatHoverable.EnumHoverAction.SHOW_ENTITY, new ChatComponentText(nbttagcompound.toString()));
      }
  
      public boolean a(EntityPlayer entityplayer) {
          return true;
      }
  
      public AxisAlignedBB getBoundingBox() {
          return this.boundingBox;
      }
  
      public void a(AxisAlignedBB axisalignedbb) {
          // CraftBukkit start - block invalid bounding boxes
          double a = axisalignedbb.a,
                  b = axisalignedbb.b,
                  c = axisalignedbb.c,
                  d = axisalignedbb.d,
                  e = axisalignedbb.e,
                  f = axisalignedbb.f;
          double len = axisalignedbb.d - axisalignedbb.a;
          if (len < 0) d = a;
          if (len > 64) d = a + 64.0;
  
          len = axisalignedbb.e - axisalignedbb.b;
          if (len < 0) e = b;
          if (len > 64) e = b + 64.0;
  
          len = axisalignedbb.f - axisalignedbb.c;
          if (len < 0) f = c;
          if (len > 64) f = c + 64.0;
          this.boundingBox = new AxisAlignedBB(a, b, c, d, e, f);
          // CraftBukkit end
      }
  
      public float getHeadHeight() {
          return this.length * 0.85F;
      }
  
      public boolean bz() {
          return this.aw;
      }
  
      public void k(boolean flag) {
          this.aw = flag;
      }
  
      public boolean c(int i, ItemStack itemstack) {
          return false;
      }
  
      public void sendMessage(IChatBaseComponent ichatbasecomponent) {}
  
      public boolean a(int i, String s) {
          return true;
      }
  
      public BlockPosition getChunkCoordinates() {
          return new BlockPosition(this.locX, this.locY + 0.5D, this.locZ);
      }
  
      public Vec3D d() {
          return new Vec3D(this.locX, this.locY, this.locZ);
      }
  
      public World getWorld() {
          return this.world;
      }
  
      public Entity f() {
          return this;
      }
  
      public boolean getSendCommandFeedback() {
          return false;
      }
  
      public void a(CommandObjectiveExecutor.EnumCommandResult commandobjectiveexecutor_enumcommandresult, int i) {
          if (this.world != null && !this.world.isClientSide) {
              this.aG.a(this.world.getMinecraftServer(), this, commandobjectiveexecutor_enumcommandresult, i);
          }
  
      }
  
      @Nullable
      public MinecraftServer C_() {
          return this.world.getMinecraftServer();
      }
  
      public CommandObjectiveExecutor bA() {
          return this.aG;
      }
  
      public void v(Entity entity) {
          this.aG.a(entity.bA());
      }
  
      public EnumInteractionResult a(EntityHuman entityhuman, Vec3D vec3d, EnumHand enumhand) {
          return EnumInteractionResult.PASS;
      }
  
      public boolean bB() {
          return false;
      }
  
      protected void a(EntityLiving entityliving, Entity entity) {
          if (entity instanceof EntityLiving) {
              EnchantmentManager.a((EntityLiving) entity, (Entity) entityliving);
          }
  
          EnchantmentManager.b(entityliving, entity);
      }
  
      public void b(EntityPlayer entityplayer) {}
  
      public void c(EntityPlayer entityplayer) {}
  
      public float a(EnumBlockRotation enumblockrotation) {
          float f = MathHelper.g(this.yaw);
  
          switch (enumblockrotation) {
          case CLOCKWISE_180:
              return f + 180.0F;
  
          case COUNTERCLOCKWISE_90:
              return f + 270.0F;
  
          case CLOCKWISE_90:
              return f + 90.0F;
  
          default:
              return f;
          }
      }
  
      public float a(EnumBlockMirror enumblockmirror) {
          float f = MathHelper.g(this.yaw);
  
          switch (enumblockmirror) {
          case LEFT_RIGHT:
              return -f;
  
          case FRONT_BACK:
              return 180.0F - f;
  
          default:
              return f;
          }
      }
  
      public boolean bC() {
          return false;
      }
  
      public boolean bD() {
          boolean flag = this.aI;
  
          this.aI = false;
          return flag;
      }
  
      @Nullable
      public Entity bE() {
          return null;
      }
  
      public List<Entity> bF() {
          return (List) (this.passengers.isEmpty() ? Collections.emptyList() : Lists.newArrayList(this.passengers));
      }
  
      public boolean w(Entity entity) {
          Iterator iterator = this.bF().iterator();
  
          Entity entity1;
  
          do {
              if (!iterator.hasNext()) {
                  return false;
              }
  
              entity1 = (Entity) iterator.next();
          } while (!entity1.equals(entity));
  
          return true;
      }
  
      public Collection<Entity> bG() {
          HashSet hashset = Sets.newHashSet();
  
          this.a(Entity.class, (Set) hashset);
          return hashset;
      }
  
      public <T extends Entity> Collection<T> b(Class<T> oclass) {
          HashSet hashset = Sets.newHashSet();
  
          this.a(oclass, (Set) hashset);
          return hashset;
      }
  
      private <T extends Entity> void a(Class<T> oclass, Set<T> set) {
          Entity entity;
  
          for (Iterator iterator = this.bF().iterator(); iterator.hasNext(); entity.a(oclass, set)) {
              entity = (Entity) iterator.next();
              if (oclass.isAssignableFrom(entity.getClass())) {
                  set.add((T) entity); // CraftBukkit - decompile error
              }
          }
  
      }
  
      public Entity getVehicle() {
          Entity entity;
  
          for (entity = this; entity.isPassenger(); entity = entity.bJ()) {
              ;
          }
  
          return entity;
      }
  
      public boolean x(Entity entity) {
          return this.getVehicle() == entity.getVehicle();
      }
  
      public boolean y(Entity entity) {
          Iterator iterator = this.bF().iterator();
  
          Entity entity1;
  
          do {
              if (!iterator.hasNext()) {
                  return false;
              }
  
              entity1 = (Entity) iterator.next();
              if (entity1.equals(entity)) {
                  return true;
              }
          } while (!entity1.y(entity));
  
          return true;
      }
  
      public boolean bI() {
          Entity entity = this.bE();
  
          return entity instanceof EntityHuman ? ((EntityHuman) entity).cZ() : !this.world.isClientSide;
      }
  
      @Nullable Entity getVehicleDirect() { return this.bJ(); } // Paper - OBFHELPER
      public Entity bJ() {
          return this.au;
      }
  
      public EnumPistonReaction getPushReaction() {
          return EnumPistonReaction.NORMAL;
      }
  
      public SoundCategory getDeathSoundCategory() { return bK();} // Paper - OBFHELPER
      public SoundCategory bK() {
          return SoundCategory.NEUTRAL;
      }
  
      public int getMaxFireTicks() {
          return 1;
      }
  }
  