--- a/net/minecraft/world/entity/vehicle/Boat.java
+++ b/net/minecraft/world/entity/vehicle/Boat.java
@@ -1,6 +1,8 @@
 package net.minecraft.world.entity.vehicle;
 
 import com.google.common.collect.Lists;
+import com.google.common.collect.UnmodifiableIterator;
+import java.util.Iterator;
 import java.util.List;
 import java.util.function.IntFunction;
 import javax.annotation.Nullable;
@@ -37,6 +39,7 @@
 import net.minecraft.world.item.ItemStack;
 import net.minecraft.world.item.Items;
 import net.minecraft.world.level.GameRules;
+import net.minecraft.world.level.ItemLike;
 import net.minecraft.world.level.Level;
 import net.minecraft.world.level.block.Block;
 import net.minecraft.world.level.block.Blocks;
@@ -49,8 +52,17 @@
 import net.minecraft.world.phys.shapes.BooleanOp;
 import net.minecraft.world.phys.shapes.Shapes;
 import net.minecraft.world.phys.shapes.VoxelShape;
+// CraftBukkit start
+import org.bukkit.Location;
+import org.bukkit.entity.Vehicle;
+import org.bukkit.event.vehicle.VehicleDamageEvent;
+import org.bukkit.event.vehicle.VehicleDestroyEvent;
+import org.bukkit.event.vehicle.VehicleEntityCollisionEvent;
+import org.bukkit.event.vehicle.VehicleMoveEvent;
+// CraftBukkit end
 
 public class Boat extends Entity implements VariantHolder<Boat.Type> {
+
     private static final EntityDataAccessor<Integer> DATA_ID_HURT = SynchedEntityData.defineId(Boat.class, EntityDataSerializers.INT);
     private static final EntityDataAccessor<Integer> DATA_ID_HURTDIR = SynchedEntityData.defineId(Boat.class, EntityDataSerializers.INT);
     private static final EntityDataAccessor<Float> DATA_ID_DAMAGE = SynchedEntityData.defineId(Boat.class, EntityDataSerializers.FLOAT);
@@ -61,10 +73,10 @@
     public static final int PADDLE_LEFT = 0;
     public static final int PADDLE_RIGHT = 1;
     private static final int TIME_TO_EJECT = 60;
-    private static final float PADDLE_SPEED = ((float)Math.PI / 8F);
-    public static final double PADDLE_SOUND_TIME = (double)((float)Math.PI / 4F);
+    private static final float PADDLE_SPEED = 0.3926991F;
+    public static final double PADDLE_SOUND_TIME = 0.7853981852531433D;
     public static final int BUBBLE_TIME = 60;
-    private final float[] paddlePositions = new float[2];
+    private final float[] paddlePositions;
     private float invFriction;
     private float outOfControlTicks;
     private float deltaRotation;
@@ -89,8 +101,17 @@
     private float bubbleAngle;
     private float bubbleAngleO;
 
+    // CraftBukkit start
+    // PAIL: Some of these haven't worked since a few updates, and since 1.9 they are less and less applicable.
+    public double maxSpeed = 0.4D;
+    public double occupiedDeceleration = 0.2D;
+    public double unoccupiedDeceleration = -1;
+    public boolean landBoats = false;
+    // CraftBukkit end
+
     public Boat(EntityType<? extends Boat> type, Level world) {
         super(type, world);
+        this.paddlePositions = new float[2];
         this.blocksBuilding = true;
     }
 
@@ -114,18 +135,18 @@
 
     @Override
     protected void defineSynchedData() {
-        this.entityData.define(DATA_ID_HURT, 0);
-        this.entityData.define(DATA_ID_HURTDIR, 1);
-        this.entityData.define(DATA_ID_DAMAGE, 0.0F);
-        this.entityData.define(DATA_ID_TYPE, Boat.Type.OAK.ordinal());
-        this.entityData.define(DATA_ID_PADDLE_LEFT, false);
-        this.entityData.define(DATA_ID_PADDLE_RIGHT, false);
-        this.entityData.define(DATA_ID_BUBBLE_TIME, 0);
+        this.entityData.define(Boat.DATA_ID_HURT, 0);
+        this.entityData.define(Boat.DATA_ID_HURTDIR, 1);
+        this.entityData.define(Boat.DATA_ID_DAMAGE, 0.0F);
+        this.entityData.define(Boat.DATA_ID_TYPE, Boat.Type.OAK.ordinal());
+        this.entityData.define(Boat.DATA_ID_PADDLE_LEFT, false);
+        this.entityData.define(Boat.DATA_ID_PADDLE_RIGHT, false);
+        this.entityData.define(Boat.DATA_ID_BUBBLE_TIME, 0);
     }
 
     @Override
     public boolean canCollideWith(Entity other) {
-        return canVehicleCollide(this, other);
+        return Boat.canVehicleCollide(this, other);
     }
 
     public static boolean canVehicleCollide(Entity entity, Entity other) {
@@ -138,7 +159,7 @@
     }
 
     @Override
-    public boolean isPushable() {
+    public boolean isCollidable(boolean ignoreClimbing) { // Paper
         return true;
     }
 
@@ -157,14 +178,37 @@
         if (this.isInvulnerableTo(source)) {
             return false;
         } else if (!this.level.isClientSide && !this.isRemoved()) {
+            // CraftBukkit start
+            Vehicle vehicle = (Vehicle) this.getBukkitEntity();
+            org.bukkit.entity.Entity attacker = (source.getEntity() == null) ? null : source.getEntity().getBukkitEntity();
+
+            VehicleDamageEvent event = new VehicleDamageEvent(vehicle, attacker, (double) amount);
+            this.level.getCraftServer().getPluginManager().callEvent(event);
+
+            if (event.isCancelled()) {
+                return false;
+            }
+            // f = event.getDamage(); // TODO Why don't we do this?
+            // CraftBukkit end
+
             this.setHurtDir(-this.getHurtDir());
             this.setHurtTime(10);
             this.setDamage(this.getDamage() + amount * 10.0F);
             this.markHurt();
             this.gameEvent(GameEvent.ENTITY_DAMAGE, source.getEntity());
-            boolean bl = source.getEntity() instanceof Player && ((Player)source.getEntity()).getAbilities().instabuild;
-            if (bl || this.getDamage() > 40.0F) {
-                if (!bl && this.level.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) {
+            boolean flag = source.getEntity() instanceof Player && ((Player) source.getEntity()).getAbilities().instabuild;
+
+            if (flag || this.getDamage() > 40.0F) {
+                // CraftBukkit start
+                VehicleDestroyEvent destroyEvent = new VehicleDestroyEvent(vehicle, attacker);
+                this.level.getCraftServer().getPluginManager().callEvent(destroyEvent);
+
+                if (destroyEvent.isCancelled()) {
+                    this.setDamage(40F); // Maximize damage so this doesn't get triggered again right away
+                    return true;
+                }
+                // CraftBukkit end
+                if (!flag && this.level.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) {
                     this.destroy(source);
                 }
 
@@ -178,7 +222,7 @@
     }
 
     protected void destroy(DamageSource source) {
-        this.spawnAtLocation(this.getDropItem());
+        this.spawnAtLocation((ItemLike) this.getDropItem());
     }
 
     @Override
@@ -191,7 +235,7 @@
             }
         }
 
-        this.level.addParticle(ParticleTypes.SPLASH, this.getX() + (double)this.random.nextFloat(), this.getY() + 0.7D, this.getZ() + (double)this.random.nextFloat(), 0.0D, 0.0D, 0.0D);
+        this.level.addParticle(ParticleTypes.SPLASH, this.getX() + (double) this.random.nextFloat(), this.getY() + 0.7D, this.getZ() + (double) this.random.nextFloat(), 0.0D, 0.0D, 0.0D);
         if (this.random.nextInt(20) == 0) {
             this.level.playLocalSound(this.getX(), this.getY(), this.getZ(), this.getSwimSplashSound(), this.getSoundSource(), 1.0F, 0.8F + 0.4F * this.random.nextFloat(), false);
             this.gameEvent(GameEvent.SPLASH, this.getControllingPassenger());
@@ -201,45 +245,67 @@
 
     @Override
     public void push(Entity entity) {
+        if (!this.level.paperConfig().collisions.allowVehicleCollisions && this.level.paperConfig().collisions.onlyPlayersCollide && !(entity instanceof Player)) return; // Paper
         if (entity instanceof Boat) {
             if (entity.getBoundingBox().minY < this.getBoundingBox().maxY) {
+                // CraftBukkit start
+                if (!this.isPassengerOfSameVehicle(entity)) {
+                    VehicleEntityCollisionEvent event = new VehicleEntityCollisionEvent((Vehicle) this.getBukkitEntity(), entity.getBukkitEntity());
+                    this.level.getCraftServer().getPluginManager().callEvent(event);
+
+                    if (event.isCancelled()) {
+                        return;
+                    }
+                }
+                // CraftBukkit end
                 super.push(entity);
             }
         } else if (entity.getBoundingBox().minY <= this.getBoundingBox().minY) {
+            // CraftBukkit start
+            if (!this.isPassengerOfSameVehicle(entity)) {
+                VehicleEntityCollisionEvent event = new VehicleEntityCollisionEvent((Vehicle) this.getBukkitEntity(), entity.getBukkitEntity());
+                this.level.getCraftServer().getPluginManager().callEvent(event);
+
+                if (event.isCancelled()) {
+                    return;
+                }
+            }
+            // CraftBukkit end
             super.push(entity);
         }
 
     }
 
     public Item getDropItem() {
-        Item var10000;
+        Item item;
+
         switch (this.getVariant()) {
             case SPRUCE:
-                var10000 = Items.SPRUCE_BOAT;
+                item = Items.SPRUCE_BOAT;
                 break;
             case BIRCH:
-                var10000 = Items.BIRCH_BOAT;
+                item = Items.BIRCH_BOAT;
                 break;
             case JUNGLE:
-                var10000 = Items.JUNGLE_BOAT;
+                item = Items.JUNGLE_BOAT;
                 break;
             case ACACIA:
-                var10000 = Items.ACACIA_BOAT;
+                item = Items.ACACIA_BOAT;
                 break;
             case DARK_OAK:
-                var10000 = Items.DARK_OAK_BOAT;
+                item = Items.DARK_OAK_BOAT;
                 break;
             case MANGROVE:
-                var10000 = Items.MANGROVE_BOAT;
+                item = Items.MANGROVE_BOAT;
                 break;
             case BAMBOO:
-                var10000 = Items.BAMBOO_RAFT;
+                item = Items.BAMBOO_RAFT;
                 break;
             default:
-                var10000 = Items.OAK_BOAT;
+                item = Items.OAK_BOAT;
         }
 
-        return var10000;
+        return item;
     }
 
     @Override
@@ -259,8 +325,8 @@
         this.lerpX = x;
         this.lerpY = y;
         this.lerpZ = z;
-        this.lerpYRot = (double)yaw;
-        this.lerpXRot = (double)pitch;
+        this.lerpYRot = (double) yaw;
+        this.lerpXRot = (double) pitch;
         this.lerpSteps = 10;
     }
 
@@ -269,6 +335,7 @@
         return this.getDirection().getClockWise();
     }
 
+    private Location lastLocation; // CraftBukkit
     @Override
     public void tick() {
         this.oldStatus = this.status;
@@ -309,35 +376,55 @@
             this.setDeltaMovement(Vec3.ZERO);
         }
 
+        // CraftBukkit start
+        org.bukkit.Server server = this.level.getCraftServer();
+        org.bukkit.World bworld = this.level.getWorld();
+
+        Location to = new Location(bworld, this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
+        Vehicle vehicle = (Vehicle) this.getBukkitEntity();
+
+        server.getPluginManager().callEvent(new org.bukkit.event.vehicle.VehicleUpdateEvent(vehicle));
+
+        if (this.lastLocation != null && !this.lastLocation.equals(to)) {
+            VehicleMoveEvent event = new VehicleMoveEvent(vehicle, this.lastLocation, to);
+            server.getPluginManager().callEvent(event);
+        }
+        this.lastLocation = vehicle.getLocation();
+        // CraftBukkit end
+
         this.tickBubbleColumn();
 
-        for(int i = 0; i <= 1; ++i) {
+        for (int i = 0; i <= 1; ++i) {
             if (this.getPaddleState(i)) {
-                if (!this.isSilent() && (double)(this.paddlePositions[i] % ((float)Math.PI * 2F)) <= (double)((float)Math.PI / 4F) && (double)((this.paddlePositions[i] + ((float)Math.PI / 8F)) % ((float)Math.PI * 2F)) >= (double)((float)Math.PI / 4F)) {
-                    SoundEvent soundEvent = this.getPaddleSound();
-                    if (soundEvent != null) {
-                        Vec3 vec3 = this.getViewVector(1.0F);
-                        double d = i == 1 ? -vec3.z : vec3.z;
-                        double e = i == 1 ? vec3.x : -vec3.x;
-                        this.level.playSound((Player)null, this.getX() + d, this.getY(), this.getZ() + e, soundEvent, this.getSoundSource(), 1.0F, 0.8F + 0.4F * this.random.nextFloat());
+                if (!this.isSilent() && (double) (this.paddlePositions[i] % 6.2831855F) <= 0.7853981852531433D && (double) ((this.paddlePositions[i] + 0.3926991F) % 6.2831855F) >= 0.7853981852531433D) {
+                    SoundEvent soundeffect = this.getPaddleSound();
+
+                    if (soundeffect != null) {
+                        Vec3 vec3d = this.getViewVector(1.0F);
+                        double d0 = i == 1 ? -vec3d.z : vec3d.z;
+                        double d1 = i == 1 ? vec3d.x : -vec3d.x;
+
+                        this.level.playSound((Player) null, this.getX() + d0, this.getY(), this.getZ() + d1, soundeffect, this.getSoundSource(), 1.0F, 0.8F + 0.4F * this.random.nextFloat());
                     }
                 }
 
-                this.paddlePositions[i] += ((float)Math.PI / 8F);
+                this.paddlePositions[i] += 0.3926991F;
             } else {
                 this.paddlePositions[i] = 0.0F;
             }
         }
 
         this.checkInsideBlocks();
-        List<Entity> list = this.level.getEntities(this, this.getBoundingBox().inflate((double)0.2F, (double)-0.01F, (double)0.2F), EntitySelector.pushableBy(this));
+        List<Entity> list = this.level.getEntities((Entity) this, this.getBoundingBox().inflate(0.20000000298023224D, -0.009999999776482582D, 0.20000000298023224D), EntitySelector.pushableBy(this));
+
         if (!list.isEmpty()) {
-            boolean bl = !this.level.isClientSide && !(this.getControllingPassenger() instanceof Player);
+            boolean flag = !this.level.isClientSide && !(this.getControllingPassenger() instanceof Player);
 
-            for(int j = 0; j < list.size(); ++j) {
-                Entity entity = list.get(j);
-                if (!entity.hasPassenger(this)) {
-                    if (bl && this.getPassengers().size() < this.getMaxPassengers() && !entity.isPassenger() && entity.getBbWidth() < this.getBbWidth() && entity instanceof LivingEntity && !(entity instanceof WaterAnimal) && !(entity instanceof Player)) {
+            for (int j = 0; j < list.size(); ++j) {
+                Entity entity = (Entity) list.get(j);
+
+                if (!entity.hasPassenger((Entity) this)) {
+                    if (flag && this.getPassengers().size() < this.getMaxPassengers() && !entity.isPassenger() && entity.getBbWidth() < this.getBbWidth() && entity instanceof LivingEntity && !(entity instanceof WaterAnimal) && !(entity instanceof Player)) {
                         entity.startRiding(this);
                     } else {
                         this.push(entity);
@@ -349,8 +436,10 @@
     }
 
     private void tickBubbleColumn() {
+        int i;
+
         if (this.level.isClientSide) {
-            int i = this.getBubbleTime();
+            i = this.getBubbleTime();
             if (i > 0) {
                 this.bubbleMultiplier += 0.05F;
             } else {
@@ -359,27 +448,29 @@
 
             this.bubbleMultiplier = Mth.clamp(this.bubbleMultiplier, 0.0F, 1.0F);
             this.bubbleAngleO = this.bubbleAngle;
-            this.bubbleAngle = 10.0F * (float)Math.sin((double)(0.5F * (float)this.level.getGameTime())) * this.bubbleMultiplier;
+            this.bubbleAngle = 10.0F * (float) Math.sin((double) (0.5F * (float) this.level.getGameTime())) * this.bubbleMultiplier;
         } else {
             if (!this.isAboveBubbleColumn) {
                 this.setBubbleTime(0);
             }
 
-            int j = this.getBubbleTime();
-            if (j > 0) {
-                --j;
-                this.setBubbleTime(j);
-                int k = 60 - j - 1;
-                if (k > 0 && j == 0) {
+            i = this.getBubbleTime();
+            if (i > 0) {
+                --i;
+                this.setBubbleTime(i);
+                int j = 60 - i - 1;
+
+                if (j > 0 && i == 0) {
                     this.setBubbleTime(0);
-                    Vec3 vec3 = this.getDeltaMovement();
+                    Vec3 vec3d = this.getDeltaMovement();
+
                     if (this.bubbleColumnDirectionIsDown) {
-                        this.setDeltaMovement(vec3.add(0.0D, -0.7D, 0.0D));
+                        this.setDeltaMovement(vec3d.add(0.0D, -0.7D, 0.0D));
                         this.ejectPassengers();
                     } else {
-                        this.setDeltaMovement(vec3.x, this.hasPassenger((entity) -> {
+                        this.setDeltaMovement(vec3d.x, this.hasPassenger((entity) -> {
                             return entity instanceof Player;
-                        }) ? 2.7D : 0.6D, vec3.z);
+                        }) ? 2.7D : 0.6D, vec3d.z);
                     }
                 }
 
@@ -411,36 +502,39 @@
         }
 
         if (this.lerpSteps > 0) {
-            double d = this.getX() + (this.lerpX - this.getX()) / (double)this.lerpSteps;
-            double e = this.getY() + (this.lerpY - this.getY()) / (double)this.lerpSteps;
-            double f = this.getZ() + (this.lerpZ - this.getZ()) / (double)this.lerpSteps;
-            double g = Mth.wrapDegrees(this.lerpYRot - (double)this.getYRot());
-            this.setYRot(this.getYRot() + (float)g / (float)this.lerpSteps);
-            this.setXRot(this.getXRot() + (float)(this.lerpXRot - (double)this.getXRot()) / (float)this.lerpSteps);
+            double d0 = this.getX() + (this.lerpX - this.getX()) / (double) this.lerpSteps;
+            double d1 = this.getY() + (this.lerpY - this.getY()) / (double) this.lerpSteps;
+            double d2 = this.getZ() + (this.lerpZ - this.getZ()) / (double) this.lerpSteps;
+            double d3 = Mth.wrapDegrees(this.lerpYRot - (double) this.getYRot());
+
+            this.setYRot(this.getYRot() + (float) d3 / (float) this.lerpSteps);
+            this.setXRot(this.getXRot() + (float) (this.lerpXRot - (double) this.getXRot()) / (float) this.lerpSteps);
             --this.lerpSteps;
-            this.setPos(d, e, f);
+            this.setPos(d0, d1, d2);
             this.setRot(this.getYRot(), this.getXRot());
         }
     }
 
     public void setPaddleState(boolean leftMoving, boolean rightMoving) {
-        this.entityData.set(DATA_ID_PADDLE_LEFT, leftMoving);
-        this.entityData.set(DATA_ID_PADDLE_RIGHT, rightMoving);
+        this.entityData.set(Boat.DATA_ID_PADDLE_LEFT, leftMoving);
+        this.entityData.set(Boat.DATA_ID_PADDLE_RIGHT, rightMoving);
     }
 
     public float getRowingTime(int paddle, float tickDelta) {
-        return this.getPaddleState(paddle) ? Mth.clampedLerp(this.paddlePositions[paddle] - ((float)Math.PI / 8F), this.paddlePositions[paddle], tickDelta) : 0.0F;
+        return this.getPaddleState(paddle) ? Mth.clampedLerp(this.paddlePositions[paddle] - 0.3926991F, this.paddlePositions[paddle], tickDelta) : 0.0F;
     }
 
     private Boat.Status getStatus() {
-        Boat.Status status = this.isUnderwater();
-        if (status != null) {
+        Boat.Status entityboat_enumstatus = this.isUnderwater();
+
+        if (entityboat_enumstatus != null) {
             this.waterLevel = this.getBoundingBox().maxY;
-            return status;
+            return entityboat_enumstatus;
         } else if (this.checkInWater()) {
             return Boat.Status.IN_WATER;
         } else {
             float f = this.getGroundFriction();
+
             if (f > 0.0F) {
                 this.landFriction = f;
                 return Boat.Status.ON_LAND;
@@ -451,66 +545,83 @@
     }
 
     public float getWaterLevelAbove() {
-        AABB aABB = this.getBoundingBox();
-        int i = Mth.floor(aABB.minX);
-        int j = Mth.ceil(aABB.maxX);
-        int k = Mth.floor(aABB.maxY);
-        int l = Mth.ceil(aABB.maxY - this.lastYd);
-        int m = Mth.floor(aABB.minZ);
-        int n = Mth.ceil(aABB.maxZ);
-        BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
+        AABB axisalignedbb = this.getBoundingBox();
+        int i = Mth.floor(axisalignedbb.minX);
+        int j = Mth.ceil(axisalignedbb.maxX);
+        int k = Mth.floor(axisalignedbb.maxY);
+        int l = Mth.ceil(axisalignedbb.maxY - this.lastYd);
+        int i1 = Mth.floor(axisalignedbb.minZ);
+        int j1 = Mth.ceil(axisalignedbb.maxZ);
+        BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
+        int k1 = k;
 
-        label39:
-        for(int o = k; o < l; ++o) {
+        while (k1 < l) {
             float f = 0.0F;
+            int l1 = i;
 
-            for(int p = i; p < j; ++p) {
-                for(int q = m; q < n; ++q) {
-                    mutableBlockPos.set(p, o, q);
-                    FluidState fluidState = this.level.getFluidState(mutableBlockPos);
-                    if (fluidState.is(FluidTags.WATER)) {
-                        f = Math.max(f, fluidState.getHeight(this.level, mutableBlockPos));
-                    }
+            label35:
+            while (true) {
+                if (l1 < j) {
+                    int i2 = i1;
 
-                    if (f >= 1.0F) {
-                        continue label39;
+                    while (true) {
+                        if (i2 >= j1) {
+                            ++l1;
+                            continue label35;
+                        }
+
+                        blockposition_mutableblockposition.set(l1, k1, i2);
+                        FluidState fluid = this.level.getFluidState(blockposition_mutableblockposition);
+
+                        if (fluid.is(FluidTags.WATER)) {
+                            f = Math.max(f, fluid.getHeight(this.level, blockposition_mutableblockposition));
+                        }
+
+                        if (f >= 1.0F) {
+                            break;
+                        }
+
+                        ++i2;
                     }
+                } else if (f < 1.0F) {
+                    return (float) blockposition_mutableblockposition.getY() + f;
                 }
-            }
 
-            if (f < 1.0F) {
-                return (float)mutableBlockPos.getY() + f;
+                ++k1;
+                break;
             }
         }
 
-        return (float)(l + 1);
+        return (float) (l + 1);
     }
 
     public float getGroundFriction() {
-        AABB aABB = this.getBoundingBox();
-        AABB aABB2 = new AABB(aABB.minX, aABB.minY - 0.001D, aABB.minZ, aABB.maxX, aABB.minY, aABB.maxZ);
-        int i = Mth.floor(aABB2.minX) - 1;
-        int j = Mth.ceil(aABB2.maxX) + 1;
-        int k = Mth.floor(aABB2.minY) - 1;
-        int l = Mth.ceil(aABB2.maxY) + 1;
-        int m = Mth.floor(aABB2.minZ) - 1;
-        int n = Mth.ceil(aABB2.maxZ) + 1;
-        VoxelShape voxelShape = Shapes.create(aABB2);
+        AABB axisalignedbb = this.getBoundingBox();
+        AABB axisalignedbb1 = new AABB(axisalignedbb.minX, axisalignedbb.minY - 0.001D, axisalignedbb.minZ, axisalignedbb.maxX, axisalignedbb.minY, axisalignedbb.maxZ);
+        int i = Mth.floor(axisalignedbb1.minX) - 1;
+        int j = Mth.ceil(axisalignedbb1.maxX) + 1;
+        int k = Mth.floor(axisalignedbb1.minY) - 1;
+        int l = Mth.ceil(axisalignedbb1.maxY) + 1;
+        int i1 = Mth.floor(axisalignedbb1.minZ) - 1;
+        int j1 = Mth.ceil(axisalignedbb1.maxZ) + 1;
+        VoxelShape voxelshape = Shapes.create(axisalignedbb1);
         float f = 0.0F;
-        int o = 0;
-        BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
+        int k1 = 0;
+        BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
 
-        for(int p = i; p < j; ++p) {
-            for(int q = m; q < n; ++q) {
-                int r = (p != i && p != j - 1 ? 0 : 1) + (q != m && q != n - 1 ? 0 : 1);
-                if (r != 2) {
-                    for(int s = k; s < l; ++s) {
-                        if (r <= 0 || s != k && s != l - 1) {
-                            mutableBlockPos.set(p, s, q);
-                            BlockState blockState = this.level.getBlockState(mutableBlockPos);
-                            if (!(blockState.getBlock() instanceof WaterlilyBlock) && Shapes.joinIsNotEmpty(blockState.getCollisionShape(this.level, mutableBlockPos).move((double)p, (double)s, (double)q), voxelShape, BooleanOp.AND)) {
-                                f += blockState.getBlock().getFriction();
-                                ++o;
+        for (int l1 = i; l1 < j; ++l1) {
+            for (int i2 = i1; i2 < j1; ++i2) {
+                int j2 = (l1 != i && l1 != j - 1 ? 0 : 1) + (i2 != i1 && i2 != j1 - 1 ? 0 : 1);
+
+                if (j2 != 2) {
+                    for (int k2 = k; k2 < l; ++k2) {
+                        if (j2 <= 0 || k2 != k && k2 != l - 1) {
+                            blockposition_mutableblockposition.set(l1, k2, i2);
+                            BlockState iblockdata = this.level.getBlockState(blockposition_mutableblockposition);
+
+                            if (!(iblockdata.getBlock() instanceof WaterlilyBlock) && Shapes.joinIsNotEmpty(iblockdata.getCollisionShape(this.level, blockposition_mutableblockposition).move((double) l1, (double) k2, (double) i2), voxelshape, BooleanOp.AND)) {
+                                f += iblockdata.getBlock().getFriction();
+                                ++k1;
                             }
                         }
                     }
@@ -518,90 +629,95 @@
             }
         }
 
-        return f / (float)o;
+        return f / (float) k1;
     }
 
     private boolean checkInWater() {
-        AABB aABB = this.getBoundingBox();
-        int i = Mth.floor(aABB.minX);
-        int j = Mth.ceil(aABB.maxX);
-        int k = Mth.floor(aABB.minY);
-        int l = Mth.ceil(aABB.minY + 0.001D);
-        int m = Mth.floor(aABB.minZ);
-        int n = Mth.ceil(aABB.maxZ);
-        boolean bl = false;
-        this.waterLevel = -Double.MAX_VALUE;
-        BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
+        AABB axisalignedbb = this.getBoundingBox();
+        int i = Mth.floor(axisalignedbb.minX);
+        int j = Mth.ceil(axisalignedbb.maxX);
+        int k = Mth.floor(axisalignedbb.minY);
+        int l = Mth.ceil(axisalignedbb.minY + 0.001D);
+        int i1 = Mth.floor(axisalignedbb.minZ);
+        int j1 = Mth.ceil(axisalignedbb.maxZ);
+        boolean flag = false;
 
-        for(int o = i; o < j; ++o) {
-            for(int p = k; p < l; ++p) {
-                for(int q = m; q < n; ++q) {
-                    mutableBlockPos.set(o, p, q);
-                    FluidState fluidState = this.level.getFluidState(mutableBlockPos);
-                    if (fluidState.is(FluidTags.WATER)) {
-                        float f = (float)p + fluidState.getHeight(this.level, mutableBlockPos);
-                        this.waterLevel = Math.max((double)f, this.waterLevel);
-                        bl |= aABB.minY < (double)f;
+        this.waterLevel = -1.7976931348623157E308D;
+        BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
+
+        for (int k1 = i; k1 < j; ++k1) {
+            for (int l1 = k; l1 < l; ++l1) {
+                for (int i2 = i1; i2 < j1; ++i2) {
+                    blockposition_mutableblockposition.set(k1, l1, i2);
+                    FluidState fluid = this.level.getFluidState(blockposition_mutableblockposition);
+
+                    if (fluid.is(FluidTags.WATER)) {
+                        float f = (float) l1 + fluid.getHeight(this.level, blockposition_mutableblockposition);
+
+                        this.waterLevel = Math.max((double) f, this.waterLevel);
+                        flag |= axisalignedbb.minY < (double) f;
                     }
                 }
             }
         }
 
-        return bl;
+        return flag;
     }
 
     @Nullable
     private Boat.Status isUnderwater() {
-        AABB aABB = this.getBoundingBox();
-        double d = aABB.maxY + 0.001D;
-        int i = Mth.floor(aABB.minX);
-        int j = Mth.ceil(aABB.maxX);
-        int k = Mth.floor(aABB.maxY);
-        int l = Mth.ceil(d);
-        int m = Mth.floor(aABB.minZ);
-        int n = Mth.ceil(aABB.maxZ);
-        boolean bl = false;
-        BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
+        AABB axisalignedbb = this.getBoundingBox();
+        double d0 = axisalignedbb.maxY + 0.001D;
+        int i = Mth.floor(axisalignedbb.minX);
+        int j = Mth.ceil(axisalignedbb.maxX);
+        int k = Mth.floor(axisalignedbb.maxY);
+        int l = Mth.ceil(d0);
+        int i1 = Mth.floor(axisalignedbb.minZ);
+        int j1 = Mth.ceil(axisalignedbb.maxZ);
+        boolean flag = false;
+        BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
 
-        for(int o = i; o < j; ++o) {
-            for(int p = k; p < l; ++p) {
-                for(int q = m; q < n; ++q) {
-                    mutableBlockPos.set(o, p, q);
-                    FluidState fluidState = this.level.getFluidState(mutableBlockPos);
-                    if (fluidState.is(FluidTags.WATER) && d < (double)((float)mutableBlockPos.getY() + fluidState.getHeight(this.level, mutableBlockPos))) {
-                        if (!fluidState.isSource()) {
+        for (int k1 = i; k1 < j; ++k1) {
+            for (int l1 = k; l1 < l; ++l1) {
+                for (int i2 = i1; i2 < j1; ++i2) {
+                    blockposition_mutableblockposition.set(k1, l1, i2);
+                    FluidState fluid = this.level.getFluidState(blockposition_mutableblockposition);
+
+                    if (fluid.is(FluidTags.WATER) && d0 < (double) ((float) blockposition_mutableblockposition.getY() + fluid.getHeight(this.level, blockposition_mutableblockposition))) {
+                        if (!fluid.isSource()) {
                             return Boat.Status.UNDER_FLOWING_WATER;
                         }
 
-                        bl = true;
+                        flag = true;
                     }
                 }
             }
         }
 
-        return bl ? Boat.Status.UNDER_WATER : null;
+        return flag ? Boat.Status.UNDER_WATER : null;
     }
 
     private void floatBoat() {
-        double d = (double)-0.04F;
-        double e = this.isNoGravity() ? 0.0D : (double)-0.04F;
-        double f = 0.0D;
+        double d0 = -0.03999999910593033D;
+        double d1 = this.isNoGravity() ? 0.0D : -0.03999999910593033D;
+        double d2 = 0.0D;
+
         this.invFriction = 0.05F;
         if (this.oldStatus == Boat.Status.IN_AIR && this.status != Boat.Status.IN_AIR && this.status != Boat.Status.ON_LAND) {
             this.waterLevel = this.getY(1.0D);
-            this.setPos(this.getX(), (double)(this.getWaterLevelAbove() - this.getBbHeight()) + 0.101D, this.getZ());
-            this.setDeltaMovement(this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D));
+            this.move(MoverType.SELF, new Vec3(0.0, ((double) (this.getWaterLevelAbove() - this.getBbHeight()) + 0.101D) - this.getY(), 0.0)); // Paper
+            this.setDeltaMovement(this.getDeltaMovement().multiply(1.0D, 0.0D, 1.0D)); // Paper
             this.lastYd = 0.0D;
             this.status = Boat.Status.IN_WATER;
         } else {
             if (this.status == Boat.Status.IN_WATER) {
-                f = (this.waterLevel - this.getY()) / (double)this.getBbHeight();
+                d2 = (this.waterLevel - this.getY()) / (double) this.getBbHeight();
                 this.invFriction = 0.9F;
             } else if (this.status == Boat.Status.UNDER_FLOWING_WATER) {
-                e = -7.0E-4D;
+                d1 = -7.0E-4D;
                 this.invFriction = 0.9F;
             } else if (this.status == Boat.Status.UNDER_WATER) {
-                f = (double)0.01F;
+                d2 = 0.009999999776482582D;
                 this.invFriction = 0.45F;
             } else if (this.status == Boat.Status.IN_AIR) {
                 this.invFriction = 0.9F;
@@ -612,12 +728,14 @@
                 }
             }
 
-            Vec3 vec3 = this.getDeltaMovement();
-            this.setDeltaMovement(vec3.x * (double)this.invFriction, vec3.y + e, vec3.z * (double)this.invFriction);
+            Vec3 vec3d = this.getDeltaMovement();
+
+            this.setDeltaMovement(vec3d.x * (double) this.invFriction, vec3d.y + d1, vec3d.z * (double) this.invFriction);
             this.deltaRotation *= this.invFriction;
-            if (f > 0.0D) {
-                Vec3 vec32 = this.getDeltaMovement();
-                this.setDeltaMovement(vec32.x, (vec32.y + f * 0.06153846016296973D) * 0.75D, vec32.z);
+            if (d2 > 0.0D) {
+                Vec3 vec3d1 = this.getDeltaMovement();
+
+                this.setDeltaMovement(vec3d1.x, (vec3d1.y + d2 * 0.06153846016296973D) * 0.75D, vec3d1.z);
             }
         }
 
@@ -626,6 +744,7 @@
     private void controlBoat() {
         if (this.isVehicle()) {
             float f = 0.0F;
+
             if (this.inputLeft) {
                 --this.deltaRotation;
             }
@@ -647,7 +766,7 @@
                 f -= 0.005F;
             }
 
-            this.setDeltaMovement(this.getDeltaMovement().add((double)(Mth.sin(-this.getYRot() * ((float)Math.PI / 180F)) * f), 0.0D, (double)(Mth.cos(this.getYRot() * ((float)Math.PI / 180F)) * f)));
+            this.setDeltaMovement(this.getDeltaMovement().add((double) (Mth.sin(-this.getYRot() * 0.017453292F) * f), 0.0D, (double) (Mth.cos(this.getYRot() * 0.017453292F) * f)));
             this.setPaddleState(this.inputRight && !this.inputLeft || this.inputUp, this.inputLeft && !this.inputRight || this.inputUp);
         }
     }
@@ -660,9 +779,11 @@
     public void positionRider(Entity passenger) {
         if (this.hasPassenger(passenger)) {
             float f = this.getSinglePassengerXOffset();
-            float g = (float)((this.isRemoved() ? (double)0.01F : this.getPassengersRidingOffset()) + passenger.getMyRidingOffset());
+            float f1 = (float) ((this.isRemoved() ? 0.009999999776482582D : this.getPassengersRidingOffset()) + passenger.getMyRidingOffset());
+
             if (this.getPassengers().size() > 1) {
                 int i = this.getPassengers().indexOf(passenger);
+
                 if (i == 0) {
                     f = 0.2F;
                 } else {
@@ -674,15 +795,17 @@
                 }
             }
 
-            Vec3 vec3 = (new Vec3((double)f, 0.0D, 0.0D)).yRot(-this.getYRot() * ((float)Math.PI / 180F) - ((float)Math.PI / 2F));
-            passenger.setPos(this.getX() + vec3.x, this.getY() + (double)g, this.getZ() + vec3.z);
+            Vec3 vec3d = (new Vec3((double) f, 0.0D, 0.0D)).yRot(-this.getYRot() * 0.017453292F - 1.5707964F);
+
+            passenger.setPos(this.getX() + vec3d.x, this.getY() + (double) f1, this.getZ() + vec3d.z);
             passenger.setYRot(passenger.getYRot() + this.deltaRotation);
             passenger.setYHeadRot(passenger.getYHeadRot() + this.deltaRotation);
             this.clampRotation(passenger);
             if (passenger instanceof Animal && this.getPassengers().size() == this.getMaxPassengers()) {
                 int j = passenger.getId() % 2 == 0 ? 90 : 270;
-                passenger.setYBodyRot(((Animal)passenger).yBodyRot + (float)j);
-                passenger.setYHeadRot(passenger.getYHeadRot() + (float)j);
+
+                passenger.setYBodyRot(((Animal) passenger).yBodyRot + (float) j);
+                passenger.setYHeadRot(passenger.getYHeadRot() + (float) j);
             }
 
         }
@@ -690,28 +813,38 @@
 
     @Override
     public Vec3 getDismountLocationForPassenger(LivingEntity passenger) {
-        Vec3 vec3 = getCollisionHorizontalEscapeVector((double)(this.getBbWidth() * Mth.SQRT_OF_TWO), (double)passenger.getBbWidth(), passenger.getYRot());
-        double d = this.getX() + vec3.x;
-        double e = this.getZ() + vec3.z;
-        BlockPos blockPos = new BlockPos(d, this.getBoundingBox().maxY, e);
-        BlockPos blockPos2 = blockPos.below();
-        if (!this.level.isWaterAt(blockPos2)) {
+        Vec3 vec3d = getCollisionHorizontalEscapeVector((double) (this.getBbWidth() * Mth.SQRT_OF_TWO), (double) passenger.getBbWidth(), passenger.getYRot());
+        double d0 = this.getX() + vec3d.x;
+        double d1 = this.getZ() + vec3d.z;
+        BlockPos blockposition = new BlockPos(d0, this.getBoundingBox().maxY, d1);
+        BlockPos blockposition1 = blockposition.below();
+
+        if (!this.level.isWaterAt(blockposition1)) {
             List<Vec3> list = Lists.newArrayList();
-            double f = this.level.getBlockFloorHeight(blockPos);
-            if (DismountHelper.isBlockFloorValid(f)) {
-                list.add(new Vec3(d, (double)blockPos.getY() + f, e));
+            double d2 = this.level.getBlockFloorHeight(blockposition);
+
+            if (DismountHelper.isBlockFloorValid(d2)) {
+                list.add(new Vec3(d0, (double) blockposition.getY() + d2, d1));
             }
 
-            double g = this.level.getBlockFloorHeight(blockPos2);
-            if (DismountHelper.isBlockFloorValid(g)) {
-                list.add(new Vec3(d, (double)blockPos2.getY() + g, e));
+            double d3 = this.level.getBlockFloorHeight(blockposition1);
+
+            if (DismountHelper.isBlockFloorValid(d3)) {
+                list.add(new Vec3(d0, (double) blockposition1.getY() + d3, d1));
             }
 
-            for(Pose pose : passenger.getDismountPoses()) {
-                for(Vec3 vec32 : list) {
-                    if (DismountHelper.canDismountTo(this.level, vec32, passenger, pose)) {
-                        passenger.setPose(pose);
-                        return vec32;
+            UnmodifiableIterator unmodifiableiterator = passenger.getDismountPoses().iterator();
+
+            while (unmodifiableiterator.hasNext()) {
+                Pose entitypose = (Pose) unmodifiableiterator.next();
+                Iterator iterator = list.iterator();
+
+                while (iterator.hasNext()) {
+                    Vec3 vec3d1 = (Vec3) iterator.next();
+
+                    if (DismountHelper.canDismountTo(this.level, vec3d1, passenger, entitypose)) {
+                        passenger.setPose(entitypose);
+                        return vec3d1;
                     }
                 }
             }
@@ -723,9 +856,10 @@
     protected void clampRotation(Entity entity) {
         entity.setYBodyRot(this.getYRot());
         float f = Mth.wrapDegrees(entity.getYRot() - this.getYRot());
-        float g = Mth.clamp(f, -105.0F, 105.0F);
-        entity.yRotO += g - f;
-        entity.setYRot(entity.getYRot() + g - f);
+        float f1 = Mth.clamp(f, -105.0F, 105.0F);
+
+        entity.yRotO += f1 - f;
+        entity.setYRot(entity.getYRot() + f1 - f);
         entity.setYHeadRot(entity.getYRot());
     }
 
@@ -749,17 +883,7 @@
 
     @Override
     public InteractionResult interact(Player player, InteractionHand hand) {
-        if (player.isSecondaryUseActive()) {
-            return InteractionResult.PASS;
-        } else if (this.outOfControlTicks < 60.0F) {
-            if (!this.level.isClientSide) {
-                return player.startRiding(this) ? InteractionResult.CONSUME : InteractionResult.PASS;
-            } else {
-                return InteractionResult.SUCCESS;
-            }
-        } else {
-            return InteractionResult.PASS;
-        }
+        return player.isSecondaryUseActive() ? InteractionResult.PASS : (this.outOfControlTicks < 60.0F ? (!this.level.isClientSide ? (player.startRiding(this) ? InteractionResult.CONSUME : InteractionResult.PASS) : InteractionResult.SUCCESS) : InteractionResult.PASS);
     }
 
     @Override
@@ -775,53 +899,61 @@
 
                     this.causeFallDamage(this.fallDistance, 1.0F, DamageSource.FALL);
                     if (!this.level.isClientSide && !this.isRemoved()) {
+                    // CraftBukkit start
+                    Vehicle vehicle = (Vehicle) this.getBukkitEntity();
+                    VehicleDestroyEvent destroyEvent = new VehicleDestroyEvent(vehicle, null);
+                    this.level.getCraftServer().getPluginManager().callEvent(destroyEvent);
+                    if (!destroyEvent.isCancelled()) {
                         this.kill();
                         if (this.level.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) {
-                            for(int i = 0; i < 3; ++i) {
-                                this.spawnAtLocation(this.getVariant().getPlanks());
+                            int i;
+
+                            for (i = 0; i < 3; ++i) {
+                                this.spawnAtLocation((ItemLike) this.getVariant().getPlanks());
                             }
 
-                            for(int j = 0; j < 2; ++j) {
-                                this.spawnAtLocation(Items.STICK);
+                            for (i = 0; i < 2; ++i) {
+                                this.spawnAtLocation((ItemLike) Items.STICK);
                             }
                         }
                     }
+                    } // CraftBukkit end
                 }
 
                 this.resetFallDistance();
             } else if (!this.level.getFluidState(this.blockPosition().below()).is(FluidTags.WATER) && heightDifference < 0.0D) {
-                this.fallDistance -= (float)heightDifference;
+                this.fallDistance -= (float) heightDifference;
             }
 
         }
     }
 
     public boolean getPaddleState(int paddle) {
-        return this.entityData.<Boolean>get(paddle == 0 ? DATA_ID_PADDLE_LEFT : DATA_ID_PADDLE_RIGHT) && this.getControllingPassenger() != null;
+        return (Boolean) this.entityData.get(paddle == 0 ? Boat.DATA_ID_PADDLE_LEFT : Boat.DATA_ID_PADDLE_RIGHT) && this.getControllingPassenger() != null;
     }
 
     public void setDamage(float wobbleStrength) {
-        this.entityData.set(DATA_ID_DAMAGE, wobbleStrength);
+        this.entityData.set(Boat.DATA_ID_DAMAGE, wobbleStrength);
     }
 
     public float getDamage() {
-        return this.entityData.get(DATA_ID_DAMAGE);
+        return (Float) this.entityData.get(Boat.DATA_ID_DAMAGE);
     }
 
     public void setHurtTime(int wobbleTicks) {
-        this.entityData.set(DATA_ID_HURT, wobbleTicks);
+        this.entityData.set(Boat.DATA_ID_HURT, wobbleTicks);
     }
 
     public int getHurtTime() {
-        return this.entityData.get(DATA_ID_HURT);
+        return (Integer) this.entityData.get(Boat.DATA_ID_HURT);
     }
 
     private void setBubbleTime(int wobbleTicks) {
-        this.entityData.set(DATA_ID_BUBBLE_TIME, wobbleTicks);
+        this.entityData.set(Boat.DATA_ID_BUBBLE_TIME, wobbleTicks);
     }
 
     private int getBubbleTime() {
-        return this.entityData.get(DATA_ID_BUBBLE_TIME);
+        return (Integer) this.entityData.get(Boat.DATA_ID_BUBBLE_TIME);
     }
 
     public float getBubbleAngle(float tickDelta) {
@@ -829,21 +961,20 @@
     }
 
     public void setHurtDir(int side) {
-        this.entityData.set(DATA_ID_HURTDIR, side);
+        this.entityData.set(Boat.DATA_ID_HURTDIR, side);
     }
 
     public int getHurtDir() {
-        return this.entityData.get(DATA_ID_HURTDIR);
+        return (Integer) this.entityData.get(Boat.DATA_ID_HURTDIR);
     }
 
-    @Override
     public void setVariant(Boat.Type variant) {
-        this.entityData.set(DATA_ID_TYPE, variant.ordinal());
+        this.entityData.set(Boat.DATA_ID_TYPE, variant.ordinal());
     }
 
     @Override
     public Boat.Type getVariant() {
-        return Boat.Type.byId(this.entityData.get(DATA_ID_TYPE));
+        return Boat.Type.byId((Integer) this.entityData.get(Boat.DATA_ID_TYPE));
     }
 
     @Override
@@ -878,32 +1009,18 @@
         return new ItemStack(this.getDropItem());
     }
 
-    public static enum Status {
-        IN_WATER,
-        UNDER_WATER,
-        UNDER_FLOWING_WATER,
-        ON_LAND,
-        IN_AIR;
-    }
-
     public static enum Type implements StringRepresentable {
-        OAK(Blocks.OAK_PLANKS, "oak"),
-        SPRUCE(Blocks.SPRUCE_PLANKS, "spruce"),
-        BIRCH(Blocks.BIRCH_PLANKS, "birch"),
-        JUNGLE(Blocks.JUNGLE_PLANKS, "jungle"),
-        ACACIA(Blocks.ACACIA_PLANKS, "acacia"),
-        DARK_OAK(Blocks.DARK_OAK_PLANKS, "dark_oak"),
-        MANGROVE(Blocks.MANGROVE_PLANKS, "mangrove"),
-        BAMBOO(Blocks.BAMBOO_PLANKS, "bamboo");
+
+        OAK(Blocks.OAK_PLANKS, "oak"), SPRUCE(Blocks.SPRUCE_PLANKS, "spruce"), BIRCH(Blocks.BIRCH_PLANKS, "birch"), JUNGLE(Blocks.JUNGLE_PLANKS, "jungle"), ACACIA(Blocks.ACACIA_PLANKS, "acacia"), DARK_OAK(Blocks.DARK_OAK_PLANKS, "dark_oak"), MANGROVE(Blocks.MANGROVE_PLANKS, "mangrove"), BAMBOO(Blocks.BAMBOO_PLANKS, "bamboo");
 
         private final String name;
         private final Block planks;
         public static final StringRepresentable.EnumCodec<Boat.Type> CODEC = StringRepresentable.fromEnum(Boat.Type::values);
         private static final IntFunction<Boat.Type> BY_ID = ByIdMap.continuous(Enum::ordinal, values(), ByIdMap.OutOfBoundsStrategy.ZERO);
 
-        private Type(Block baseBlock, String name) {
-            this.name = name;
-            this.planks = baseBlock;
+        private Type(Block block, String s) {
+            this.name = s;
+            this.planks = block;
         }
 
         @Override
@@ -919,17 +1036,23 @@
             return this.planks;
         }
 
-        @Override
         public String toString() {
             return this.name;
         }
 
         public static Boat.Type byId(int type) {
-            return BY_ID.apply(type);
+            return (Boat.Type) Boat.Type.BY_ID.apply(type);
         }
 
         public static Boat.Type byName(String name) {
-            return CODEC.byName(name, OAK);
+            return (Boat.Type) Boat.Type.CODEC.byName(name, Boat.Type.OAK);
         }
     }
+
+    public static enum Status {
+
+        IN_WATER, UNDER_WATER, UNDER_FLOWING_WATER, ON_LAND, IN_AIR;
+
+        private Status() {}
+    }
 }
