--- a/net/minecraft/world/entity/ambient/Bat.java
+++ b/net/minecraft/world/entity/ambient/Bat.java
@@ -21,17 +21,22 @@
 import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
 import net.minecraft.world.entity.ai.attributes.Attributes;
 import net.minecraft.world.entity.ai.targeting.TargetingConditions;
+import net.minecraft.world.entity.player.Player;
 import net.minecraft.world.level.Level;
 import net.minecraft.world.level.LevelAccessor;
 import net.minecraft.world.level.block.state.BlockState;
 import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+// CraftBukkit end
 
 public class Bat extends AmbientCreature {
+
     public static final float FLAP_LENGTH_SECONDS = 0.5F;
     public static final float TICKS_PER_FLAP = 10.0F;
     private static final EntityDataAccessor<Byte> DATA_ID_FLAGS = SynchedEntityData.defineId(Bat.class, EntityDataSerializers.BYTE);
     private static final int FLAG_RESTING = 1;
-    private static final TargetingConditions BAT_RESTING_TARGETING = TargetingConditions.forNonCombat().range(4.0);
+    private static final TargetingConditions BAT_RESTING_TARGETING = TargetingConditions.forNonCombat().range(4.0D);
     public final AnimationState flyAnimationState = new AnimationState();
     public final AnimationState restAnimationState = new AnimationState();
     @Nullable
@@ -42,17 +47,18 @@
         if (!world.isClientSide) {
             this.setResting(true);
         }
+
     }
 
     @Override
     public boolean isFlapping() {
-        return !this.isResting() && (float)this.tickCount % 10.0F == 0.0F;
+        return !this.isResting() && (float) this.tickCount % 10.0F == 0.0F;
     }
 
     @Override
     protected void defineSynchedData(SynchedEntityData.Builder builder) {
         super.defineSynchedData(builder);
-        builder.define(DATA_ID_FLAGS, (byte)0);
+        builder.define(Bat.DATA_ID_FLAGS, (byte) 0);
     }
 
     @Override
@@ -82,33 +88,33 @@
     }
 
     @Override
-    public boolean isPushable() {
+    public boolean isCollidable(boolean ignoreClimbing) { // Paper - Climbing should not bypass cramming gamerule
         return false;
     }
 
     @Override
-    protected void doPush(Entity entity) {
-    }
+    protected void doPush(Entity entity) {}
 
     @Override
-    protected void pushEntities() {
-    }
+    protected void pushEntities() {}
 
     public static AttributeSupplier.Builder createAttributes() {
-        return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 6.0);
+        return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 6.0D);
     }
 
     public boolean isResting() {
-        return (this.entityData.get(DATA_ID_FLAGS) & 1) != 0;
+        return ((Byte) this.entityData.get(Bat.DATA_ID_FLAGS) & 1) != 0;
     }
 
     public void setResting(boolean roosting) {
-        byte b = this.entityData.get(DATA_ID_FLAGS);
+        byte b0 = (Byte) this.entityData.get(Bat.DATA_ID_FLAGS);
+
         if (roosting) {
-            this.entityData.set(DATA_ID_FLAGS, (byte)(b | 1));
+            this.entityData.set(Bat.DATA_ID_FLAGS, (byte) (b0 | 1));
         } else {
-            this.entityData.set(DATA_ID_FLAGS, (byte)(b & -2));
+            this.entityData.set(Bat.DATA_ID_FLAGS, (byte) (b0 & -2));
         }
+
     }
 
     @Override
@@ -116,9 +122,9 @@
         super.tick();
         if (this.isResting()) {
             this.setDeltaMovement(Vec3.ZERO);
-            this.setPosRaw(this.getX(), (double)Mth.floor(this.getY()) + 1.0 - (double)this.getBbHeight(), this.getZ());
+            this.setPosRaw(this.getX(), (double) Mth.floor(this.getY()) + 1.0D - (double) this.getBbHeight(), this.getZ());
         } else {
-            this.setDeltaMovement(this.getDeltaMovement().multiply(1.0, 0.6, 1.0));
+            this.setDeltaMovement(this.getDeltaMovement().multiply(1.0D, 0.6D, 1.0D));
         }
 
         this.setupAnimationStates();
@@ -127,55 +133,55 @@
     @Override
     protected void customServerAiStep() {
         super.customServerAiStep();
-        BlockPos blockPos = this.blockPosition();
-        BlockPos blockPos2 = blockPos.above();
+        BlockPos blockposition = this.blockPosition();
+        BlockPos blockposition1 = blockposition.above();
+
         if (this.isResting()) {
-            boolean bl = this.isSilent();
-            if (this.level().getBlockState(blockPos2).isRedstoneConductor(this.level(), blockPos)) {
+            boolean flag = this.isSilent();
+
+            if (this.level().getBlockState(blockposition1).isRedstoneConductor(this.level(), blockposition)) {
                 if (this.random.nextInt(200) == 0) {
-                    this.yHeadRot = (float)this.random.nextInt(360);
+                    this.yHeadRot = (float) this.random.nextInt(360);
                 }
 
-                if (this.level().getNearestPlayer(BAT_RESTING_TARGETING, this) != null) {
+                if (this.level().getNearestPlayer(Bat.BAT_RESTING_TARGETING, this) != null && CraftEventFactory.handleBatToggleSleepEvent(this, true)) { // CraftBukkit - Call BatToggleSleepEvent
                     this.setResting(false);
-                    if (!bl) {
-                        this.level().levelEvent(null, 1025, blockPos, 0);
+                    if (!flag) {
+                        this.level().levelEvent((Player) null, 1025, blockposition, 0);
                     }
                 }
-            } else {
+            } else if (CraftEventFactory.handleBatToggleSleepEvent(this, true)) { // CraftBukkit - Call BatToggleSleepEvent
                 this.setResting(false);
-                if (!bl) {
-                    this.level().levelEvent(null, 1025, blockPos, 0);
+                if (!flag) {
+                    this.level().levelEvent((Player) null, 1025, blockposition, 0);
                 }
             }
         } else {
-            if (this.targetPosition != null
-                && (!this.level().isEmptyBlock(this.targetPosition) || this.targetPosition.getY() <= this.level().getMinBuildHeight())) {
+            if (this.targetPosition != null && (!this.level().isEmptyBlock(this.targetPosition) || this.targetPosition.getY() <= this.level().getMinBuildHeight())) {
                 this.targetPosition = null;
             }
 
-            if (this.targetPosition == null || this.random.nextInt(30) == 0 || this.targetPosition.closerToCenterThan(this.position(), 2.0)) {
-                this.targetPosition = BlockPos.containing(
-                    this.getX() + (double)this.random.nextInt(7) - (double)this.random.nextInt(7),
-                    this.getY() + (double)this.random.nextInt(6) - 2.0,
-                    this.getZ() + (double)this.random.nextInt(7) - (double)this.random.nextInt(7)
-                );
+            if (this.targetPosition == null || this.random.nextInt(30) == 0 || this.targetPosition.closerToCenterThan(this.position(), 2.0D)) {
+                this.targetPosition = BlockPos.containing(this.getX() + (double) this.random.nextInt(7) - (double) this.random.nextInt(7), this.getY() + (double) this.random.nextInt(6) - 2.0D, this.getZ() + (double) this.random.nextInt(7) - (double) this.random.nextInt(7));
             }
 
-            double d = (double)this.targetPosition.getX() + 0.5 - this.getX();
-            double e = (double)this.targetPosition.getY() + 0.1 - this.getY();
-            double f = (double)this.targetPosition.getZ() + 0.5 - this.getZ();
-            Vec3 vec3 = this.getDeltaMovement();
-            Vec3 vec32 = vec3.add((Math.signum(d) * 0.5 - vec3.x) * 0.1F, (Math.signum(e) * 0.7F - vec3.y) * 0.1F, (Math.signum(f) * 0.5 - vec3.z) * 0.1F);
-            this.setDeltaMovement(vec32);
-            float g = (float)(Mth.atan2(vec32.z, vec32.x) * 180.0F / (float)Math.PI) - 90.0F;
-            float h = Mth.wrapDegrees(g - this.getYRot());
+            double d0 = (double) this.targetPosition.getX() + 0.5D - this.getX();
+            double d1 = (double) this.targetPosition.getY() + 0.1D - this.getY();
+            double d2 = (double) this.targetPosition.getZ() + 0.5D - this.getZ();
+            Vec3 vec3d = this.getDeltaMovement();
+            Vec3 vec3d1 = vec3d.add((Math.signum(d0) * 0.5D - vec3d.x) * 0.10000000149011612D, (Math.signum(d1) * 0.699999988079071D - vec3d.y) * 0.10000000149011612D, (Math.signum(d2) * 0.5D - vec3d.z) * 0.10000000149011612D);
+
+            this.setDeltaMovement(vec3d1);
+            float f = (float) (Mth.atan2(vec3d1.z, vec3d1.x) * 57.2957763671875D) - 90.0F;
+            float f1 = Mth.wrapDegrees(f - this.getYRot());
+
             this.zza = 0.5F;
-            this.setYRot(this.getYRot() + h);
-            if (this.random.nextInt(100) == 0 && this.level().getBlockState(blockPos2).isRedstoneConductor(this.level(), blockPos2)) {
+            this.setYRot(this.getYRot() + f1);
+            if (this.random.nextInt(100) == 0 && this.level().getBlockState(blockposition1).isRedstoneConductor(this.level(), blockposition1) && CraftEventFactory.handleBatToggleSleepEvent(this, false)) { // CraftBukkit - Call BatToggleSleepEvent
                 this.setResting(true);
             }
         }
+
     }
 
     @Override
@@ -184,8 +190,7 @@
     }
 
     @Override
-    protected void checkFallDamage(double heightDifference, boolean onGround, BlockState state, BlockPos landedPosition) {
-    }
+    protected void checkFallDamage(double heightDifference, boolean onGround, BlockState state, BlockPos landedPosition) {}
 
     @Override
     public boolean isIgnoringBlockTriggers() {
@@ -197,7 +202,7 @@
         if (this.isInvulnerableTo(source)) {
             return false;
         } else {
-            if (!this.level().isClientSide && this.isResting()) {
+            if (!this.level().isClientSide && this.isResting() && CraftEventFactory.handleBatToggleSleepEvent(this, true)) { // CraftBukkit - Call BatToggleSleepEvent
                 this.setResting(false);
             }
 
@@ -208,13 +213,13 @@
     @Override
     public void readAdditionalSaveData(CompoundTag nbt) {
         super.readAdditionalSaveData(nbt);
-        this.entityData.set(DATA_ID_FLAGS, nbt.getByte("BatFlags"));
+        this.entityData.set(Bat.DATA_ID_FLAGS, nbt.getByte("BatFlags"));
     }
 
     @Override
     public void addAdditionalSaveData(CompoundTag nbt) {
         super.addAdditionalSaveData(nbt);
-        nbt.putByte("BatFlags", this.entityData.get(DATA_ID_FLAGS));
+        nbt.putByte("BatFlags", (Byte) this.entityData.get(Bat.DATA_ID_FLAGS));
     }
 
     public static boolean checkBatSpawnRules(EntityType<Bat> type, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
@@ -222,21 +227,23 @@
             return false;
         } else {
             int i = world.getMaxLocalRawBrightness(pos);
-            int j = 4;
-            if (isHalloween()) {
-                j = 7;
+            byte b0 = 4;
+
+            if (Bat.isHalloween()) {
+                b0 = 7;
             } else if (random.nextBoolean()) {
                 return false;
             }
 
-            return i <= random.nextInt(j) && checkMobSpawnRules(type, world, spawnReason, pos, random);
+            return i > random.nextInt(b0) ? false : checkMobSpawnRules(type, world, spawnReason, pos, random);
         }
     }
 
     private static boolean isHalloween() {
-        LocalDate localDate = LocalDate.now();
-        int i = localDate.get(ChronoField.DAY_OF_MONTH);
-        int j = localDate.get(ChronoField.MONTH_OF_YEAR);
+        LocalDate localdate = LocalDate.now();
+        int i = localdate.get(ChronoField.DAY_OF_MONTH);
+        int j = localdate.get(ChronoField.MONTH_OF_YEAR);
+
         return j == 10 && i >= 20 || j == 11 && i <= 3;
     }
 
@@ -248,5 +255,6 @@
             this.restAnimationState.stop();
             this.flyAnimationState.startIfStopped(this.tickCount);
         }
+
     }
 }
