--- a/net/minecraft/world/entity/animal/Bee.java
+++ b/net/minecraft/world/entity/animal/Bee.java
@@ -3,7 +3,9 @@
 import com.google.common.collect.Lists;
 import java.util.Comparator;
 import java.util.EnumSet;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 import java.util.Optional;
 import java.util.UUID;
 import java.util.function.Predicate;
@@ -84,8 +86,14 @@
 import net.minecraft.world.level.pathfinder.Path;
 import net.minecraft.world.level.pathfinder.PathType;
 import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.event.entity.EntityPotionEffectEvent;
+import org.bukkit.event.entity.EntityTargetEvent;
+// CraftBukkit end
 
 public class Bee extends Animal implements NeutralMob, FlyingAnimal {
+
     public static final float FLAP_DEGREES_PER_TICK = 120.32113F;
     public static final int TICKS_PER_FLAP = Mth.ceil(1.4959966F);
     private static final EntityDataAccessor<Byte> DATA_FLAGS_ID = SynchedEntityData.defineId(Bee.class, EntityDataSerializers.BYTE);
@@ -123,7 +131,7 @@
     private static final int COOLDOWN_BEFORE_LOCATING_NEW_HIVE = 200;
     int remainingCooldownBeforeLocatingNewHive;
     private static final int COOLDOWN_BEFORE_LOCATING_NEW_FLOWER = 200;
-    int remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(this.random, 20, 60);
+    int remainingCooldownBeforeLocatingNewFlower;
     @Nullable
     BlockPos savedFlowerPos;
     @Nullable
@@ -135,7 +143,23 @@
 
     public Bee(EntityType<? extends Bee> type, Level world) {
         super(type, world);
-        this.moveControl = new FlyingMoveControl(this, 20, true);
+        this.remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(this.random, 20, 60);
+        // Paper start - Fix MC-167279
+        class BeeFlyingMoveControl extends FlyingMoveControl {
+            public BeeFlyingMoveControl(final Mob entity, final int maxPitchChange, final boolean noGravity) {
+                super(entity, maxPitchChange, noGravity);
+            }
+
+            @Override
+            public void tick() {
+                if (this.mob.getY() <= Bee.this.level().getMinBuildHeight()) {
+                    this.mob.setNoGravity(false);
+                }
+                super.tick();
+            }
+        }
+        this.moveControl = new BeeFlyingMoveControl(this, 20, true);
+        // Paper end - Fix MC-167279
         this.lookControl = new Bee.BeeLookControl(this);
         this.setPathfindingMalus(PathType.DANGER_FIRE, -1.0F);
         this.setPathfindingMalus(PathType.WATER, -1.0F);
@@ -147,8 +171,8 @@
     @Override
     protected void defineSynchedData(SynchedEntityData.Builder builder) {
         super.defineSynchedData(builder);
-        builder.define(DATA_FLAGS_ID, (byte)0);
-        builder.define(DATA_REMAINING_ANGER_TIME, 0);
+        builder.define(Bee.DATA_FLAGS_ID, (byte) 0);
+        builder.define(Bee.DATA_REMAINING_ANGER_TIME, 0);
     }
 
     @Override
@@ -158,13 +182,15 @@
 
     @Override
     protected void registerGoals() {
-        this.goalSelector.addGoal(0, new Bee.BeeAttackGoal(this, 1.4F, true));
+        this.goalSelector.addGoal(0, new Bee.BeeAttackGoal(this, 1.399999976158142D, true));
         this.goalSelector.addGoal(1, new Bee.BeeEnterHiveGoal());
-        this.goalSelector.addGoal(2, new BreedGoal(this, 1.0));
-        this.goalSelector.addGoal(3, new TemptGoal(this, 1.25, stack -> stack.is(ItemTags.BEE_FOOD), false));
+        this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D));
+        this.goalSelector.addGoal(3, new TemptGoal(this, 1.25D, (itemstack) -> {
+            return itemstack.is(ItemTags.BEE_FOOD);
+        }, false));
         this.beePollinateGoal = new Bee.BeePollinateGoal();
         this.goalSelector.addGoal(4, this.beePollinateGoal);
-        this.goalSelector.addGoal(5, new FollowParentGoal(this, 1.25));
+        this.goalSelector.addGoal(5, new FollowParentGoal(this, 1.25D));
         this.goalSelector.addGoal(5, new Bee.BeeLocateHiveGoal());
         this.goToHiveGoal = new Bee.BeeGoToHiveGoal();
         this.goalSelector.addGoal(5, this.goToHiveGoal);
@@ -173,34 +199,41 @@
         this.goalSelector.addGoal(7, new Bee.BeeGrowCropGoal());
         this.goalSelector.addGoal(8, new Bee.BeeWanderGoal());
         this.goalSelector.addGoal(9, new FloatGoal(this));
-        this.targetSelector.addGoal(1, new Bee.BeeHurtByOtherGoal(this).setAlertOthers(new Class[0]));
+        this.targetSelector.addGoal(1, (new Bee.BeeHurtByOtherGoal(this)).setAlertOthers(new Class[0]));
         this.targetSelector.addGoal(2, new Bee.BeeBecomeAngryTargetGoal(this));
         this.targetSelector.addGoal(3, new ResetUniversalAngerTargetGoal<>(this, true));
     }
 
     @Override
     public void addAdditionalSaveData(CompoundTag nbt) {
-        super.addAdditionalSaveData(nbt);
-        if (this.hasHive()) {
-            nbt.put("hive_pos", NbtUtils.writeBlockPos(this.getHivePos()));
+        // CraftBukkit start - selectively save data
+        this.addAdditionalSaveData(nbt, true);
+    }
+
+    @Override
+    public void addAdditionalSaveData(CompoundTag nbttagcompound, boolean includeAll) {
+        // CraftBukkit end
+        super.addAdditionalSaveData(nbttagcompound);
+        if (includeAll && this.hasHive()) { // CraftBukkit - selectively save hive
+            nbttagcompound.put("hive_pos", NbtUtils.writeBlockPos(this.getHivePos()));
         }
 
-        if (this.hasSavedFlowerPos()) {
-            nbt.put("flower_pos", NbtUtils.writeBlockPos(this.getSavedFlowerPos()));
+        if (includeAll && this.hasSavedFlowerPos()) { // CraftBukkit - selectively save flower
+            nbttagcompound.put("flower_pos", NbtUtils.writeBlockPos(this.getSavedFlowerPos()));
         }
 
-        nbt.putBoolean("HasNectar", this.hasNectar());
-        nbt.putBoolean("HasStung", this.hasStung());
-        nbt.putInt("TicksSincePollination", this.ticksWithoutNectarSinceExitingHive);
-        nbt.putInt("CannotEnterHiveTicks", this.stayOutOfHiveCountdown);
-        nbt.putInt("CropsGrownSincePollination", this.numCropsGrownSincePollination);
-        this.addPersistentAngerSaveData(nbt);
+        nbttagcompound.putBoolean("HasNectar", this.hasNectar());
+        nbttagcompound.putBoolean("HasStung", this.hasStung());
+        nbttagcompound.putInt("TicksSincePollination", this.ticksWithoutNectarSinceExitingHive);
+        nbttagcompound.putInt("CannotEnterHiveTicks", this.stayOutOfHiveCountdown);
+        nbttagcompound.putInt("CropsGrownSincePollination", this.numCropsGrownSincePollination);
+        this.addPersistentAngerSaveData(nbttagcompound);
     }
 
     @Override
     public void readAdditionalSaveData(CompoundTag nbt) {
-        this.hivePos = NbtUtils.readBlockPos(nbt, "hive_pos").orElse(null);
-        this.savedFlowerPos = NbtUtils.readBlockPos(nbt, "flower_pos").orElse(null);
+        this.hivePos = (BlockPos) NbtUtils.readBlockPos(nbt, "hive_pos").orElse(null); // CraftBukkit - decompile error
+        this.savedFlowerPos = (BlockPos) NbtUtils.readBlockPos(nbt, "flower_pos").orElse(null); // CraftBukkit - decompile error
         super.readAdditionalSaveData(nbt);
         this.setHasNectar(nbt.getBoolean("HasNectar"));
         this.setHasStung(nbt.getBoolean("HasStung"));
@@ -212,24 +245,32 @@
 
     @Override
     public boolean doHurtTarget(Entity target) {
-        DamageSource damageSource = this.damageSources().sting(this);
-        boolean bl = target.hurt(damageSource, (float)((int)this.getAttributeValue(Attributes.ATTACK_DAMAGE)));
-        if (bl) {
-            if (this.level() instanceof ServerLevel serverLevel) {
-                EnchantmentHelper.doPostAttackEffects(serverLevel, target, damageSource);
+        DamageSource damagesource = this.damageSources().sting(this);
+        boolean flag = target.hurt(damagesource, (float) ((int) this.getAttributeValue(Attributes.ATTACK_DAMAGE)));
+
+        if (flag) {
+            Level world = this.level();
+
+            if (world instanceof ServerLevel) {
+                ServerLevel worldserver = (ServerLevel) world;
+
+                EnchantmentHelper.doPostAttackEffects(worldserver, target, damagesource);
             }
 
-            if (target instanceof LivingEntity livingEntity) {
-                livingEntity.setStingerCount(livingEntity.getStingerCount() + 1);
-                int i = 0;
+            if (target instanceof LivingEntity) {
+                LivingEntity entityliving = (LivingEntity) target;
+
+                entityliving.setStingerCount(entityliving.getStingerCount() + 1);
+                byte b0 = 0;
+
                 if (this.level().getDifficulty() == Difficulty.NORMAL) {
-                    i = 10;
+                    b0 = 10;
                 } else if (this.level().getDifficulty() == Difficulty.HARD) {
-                    i = 18;
+                    b0 = 18;
                 }
 
-                if (i > 0) {
-                    livingEntity.addEffect(new MobEffectInstance(MobEffects.POISON, i * 20, 0), this);
+                if (b0 > 0) {
+                    entityliving.addEffect(new MobEffectInstance(MobEffects.POISON, b0 * 20, 0), this, EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit
                 }
             }
 
@@ -238,17 +279,15 @@
             this.playSound(SoundEvents.BEE_STING, 1.0F, 1.0F);
         }
 
-        return bl;
+        return flag;
     }
 
     @Override
     public void tick() {
         super.tick();
         if (this.hasNectar() && this.getCropsGrownSincePollination() < 10 && this.random.nextFloat() < 0.05F) {
-            for (int i = 0; i < this.random.nextInt(2) + 1; i++) {
-                this.spawnFluidParticle(
-                    this.level(), this.getX() - 0.3F, this.getX() + 0.3F, this.getZ() - 0.3F, this.getZ() + 0.3F, this.getY(0.5), ParticleTypes.FALLING_NECTAR
-                );
+            for (int i = 0; i < this.random.nextInt(2) + 1; ++i) {
+                this.spawnFluidParticle(this.level(), this.getX() - 0.30000001192092896D, this.getX() + 0.30000001192092896D, this.getZ() - 0.30000001192092896D, this.getZ() + 0.30000001192092896D, this.getY(0.5D), ParticleTypes.FALLING_NECTAR);
             }
         }
 
@@ -256,32 +295,35 @@
     }
 
     private void spawnFluidParticle(Level world, double lastX, double x, double lastZ, double z, double y, ParticleOptions effect) {
-        world.addParticle(effect, Mth.lerp(world.random.nextDouble(), lastX, x), y, Mth.lerp(world.random.nextDouble(), lastZ, z), 0.0, 0.0, 0.0);
+        world.addParticle(effect, Mth.lerp(world.random.nextDouble(), lastX, x), y, Mth.lerp(world.random.nextDouble(), lastZ, z), 0.0D, 0.0D, 0.0D);
     }
 
     void pathfindRandomlyTowards(BlockPos pos) {
-        Vec3 vec3 = Vec3.atBottomCenterOf(pos);
-        int i = 0;
-        BlockPos blockPos = this.blockPosition();
-        int j = (int)vec3.y - blockPos.getY();
-        if (j > 2) {
-            i = 4;
-        } else if (j < -2) {
-            i = -4;
+        Vec3 vec3d = Vec3.atBottomCenterOf(pos);
+        byte b0 = 0;
+        BlockPos blockposition1 = this.blockPosition();
+        int i = (int) vec3d.y - blockposition1.getY();
+
+        if (i > 2) {
+            b0 = 4;
+        } else if (i < -2) {
+            b0 = -4;
         }
 
-        int k = 6;
-        int l = 8;
-        int m = blockPos.distManhattan(pos);
-        if (m < 15) {
-            k = m / 2;
-            l = m / 2;
+        int j = 6;
+        int k = 8;
+        int l = blockposition1.distManhattan(pos);
+
+        if (l < 15) {
+            j = l / 2;
+            k = l / 2;
         }
 
-        Vec3 vec32 = AirRandomPos.getPosTowards(this, k, l, i, vec3, (float) (Math.PI / 10));
-        if (vec32 != null) {
+        Vec3 vec3d1 = AirRandomPos.getPosTowards(this, j, k, b0, vec3d, 0.3141592741012573D);
+
+        if (vec3d1 != null) {
             this.navigation.setMaxVisitedNodesMultiplier(0.5F);
-            this.navigation.moveTo(vec32.x, vec32.y, vec32.z, 1.0);
+            this.navigation.moveTo(vec3d1.x, vec3d1.y, vec3d1.z, 1.0D);
         }
     }
 
@@ -314,8 +356,9 @@
 
     boolean wantsToEnterHive() {
         if (this.stayOutOfHiveCountdown <= 0 && !this.beePollinateGoal.isPollinating() && !this.hasStung() && this.getTarget() == null) {
-            boolean bl = this.isTiredOfLookingForNectar() || this.level().isRaining() || this.level().isNight() || this.hasNectar();
-            return bl && !this.isHiveNearFire();
+            boolean flag = this.isTiredOfLookingForNectar() || this.level().isRaining() || this.level().isNight() || this.hasNectar();
+
+            return flag && !this.isHiveNearFire();
         } else {
             return false;
         }
@@ -336,13 +379,15 @@
         } else {
             this.rollAmount = Math.max(0.0F, this.rollAmount - 0.24F);
         }
+
     }
 
     @Override
     protected void customServerAiStep() {
-        boolean bl = this.hasStung();
+        boolean flag = this.hasStung();
+
         if (this.isInWaterOrBubble()) {
-            this.underWaterTicks++;
+            ++this.underWaterTicks;
         } else {
             this.underWaterTicks = 0;
         }
@@ -351,20 +396,21 @@
             this.hurt(this.damageSources().drown(), 1.0F);
         }
 
-        if (bl) {
-            this.timeSinceSting++;
+        if (flag) {
+            ++this.timeSinceSting;
             if (this.timeSinceSting % 5 == 0 && this.random.nextInt(Mth.clamp(1200 - this.timeSinceSting, 1, 1200)) == 0) {
                 this.hurt(this.damageSources().generic(), this.getHealth());
             }
         }
 
         if (!this.hasNectar()) {
-            this.ticksWithoutNectarSinceExitingHive++;
+            ++this.ticksWithoutNectarSinceExitingHive;
         }
 
         if (!this.level().isClientSide) {
-            this.updatePersistentAnger((ServerLevel)this.level(), false);
+            this.updatePersistentAnger((ServerLevel) this.level(), false);
         }
+
     }
 
     public void resetTicksWithoutNectarSinceExitingHive() {
@@ -375,19 +421,21 @@
         if (this.hivePos == null) {
             return false;
         } else {
-            BlockEntity blockEntity = this.level().getBlockEntity(this.hivePos);
-            return blockEntity instanceof BeehiveBlockEntity && ((BeehiveBlockEntity)blockEntity).isFireNearby();
+            if (!this.level().isLoadedAndInBounds(this.hivePos)) return false; // Paper - Do not allow bees to load chunks for beehives
+            BlockEntity tileentity = this.level().getBlockEntity(this.hivePos);
+
+            return tileentity instanceof BeehiveBlockEntity && ((BeehiveBlockEntity) tileentity).isFireNearby();
         }
     }
 
     @Override
     public int getRemainingPersistentAngerTime() {
-        return this.entityData.get(DATA_REMAINING_ANGER_TIME);
+        return (Integer) this.entityData.get(Bee.DATA_REMAINING_ANGER_TIME);
     }
 
     @Override
     public void setRemainingPersistentAngerTime(int angerTime) {
-        this.entityData.set(DATA_REMAINING_ANGER_TIME, angerTime);
+        this.entityData.set(Bee.DATA_REMAINING_ANGER_TIME, angerTime);
     }
 
     @Nullable
@@ -403,12 +451,14 @@
 
     @Override
     public void startPersistentAngerTimer() {
-        this.setRemainingPersistentAngerTime(PERSISTENT_ANGER_TIME.sample(this.random));
+        this.setRemainingPersistentAngerTime(Bee.PERSISTENT_ANGER_TIME.sample(this.random));
     }
 
     private boolean doesHiveHaveSpace(BlockPos pos) {
-        BlockEntity blockEntity = this.level().getBlockEntity(pos);
-        return blockEntity instanceof BeehiveBlockEntity && !((BeehiveBlockEntity)blockEntity).isFull();
+        if (!this.level().isLoadedAndInBounds(pos)) return false; // Paper - Do not allow bees to load chunks for beehives
+        BlockEntity tileentity = this.level().getBlockEntity(pos);
+
+        return tileentity instanceof BeehiveBlockEntity ? !((BeehiveBlockEntity) tileentity).isFull() : false;
     }
 
     @VisibleForDebug
@@ -442,7 +492,7 @@
     }
 
     void incrementNumCropsGrownSincePollination() {
-        this.numCropsGrownSincePollination++;
+        ++this.numCropsGrownSincePollination;
     }
 
     @Override
@@ -450,23 +500,25 @@
         super.aiStep();
         if (!this.level().isClientSide) {
             if (this.stayOutOfHiveCountdown > 0) {
-                this.stayOutOfHiveCountdown--;
+                --this.stayOutOfHiveCountdown;
             }
 
             if (this.remainingCooldownBeforeLocatingNewHive > 0) {
-                this.remainingCooldownBeforeLocatingNewHive--;
+                --this.remainingCooldownBeforeLocatingNewHive;
             }
 
             if (this.remainingCooldownBeforeLocatingNewFlower > 0) {
-                this.remainingCooldownBeforeLocatingNewFlower--;
+                --this.remainingCooldownBeforeLocatingNewFlower;
             }
 
-            boolean bl = this.isAngry() && !this.hasStung() && this.getTarget() != null && this.getTarget().distanceToSqr(this) < 4.0;
-            this.setRolling(bl);
+            boolean flag = this.isAngry() && !this.hasStung() && this.getTarget() != null && this.getTarget().distanceToSqr((Entity) this) < 4.0D;
+
+            this.setRolling(flag);
             if (this.tickCount % 20 == 0 && !this.isHiveValid()) {
                 this.hivePos = null;
             }
         }
+
     }
 
     boolean isHiveValid() {
@@ -475,8 +527,10 @@
         } else if (this.isTooFarAway(this.hivePos)) {
             return false;
         } else {
-            BlockEntity blockEntity = this.level().getBlockEntity(this.hivePos);
-            return blockEntity != null && blockEntity.getType() == BlockEntityType.BEEHIVE;
+            if (this.level().getChunkIfLoadedImmediately(this.hivePos.getX() >> 4, this.hivePos.getZ() >> 4) == null) return true; // Paper - just assume the hive is still there, no need to load the chunk(s)
+            BlockEntity tileentity = this.level().getBlockEntity(this.hivePos);
+
+            return tileentity != null && tileentity.getType() == BlockEntityType.BEEHIVE;
         }
     }
 
@@ -500,11 +554,13 @@
         this.setFlag(4, hasStung);
     }
 
+    public net.kyori.adventure.util.TriState rollingOverride = net.kyori.adventure.util.TriState.NOT_SET; // Paper - Rolling override
     public boolean isRolling() {
         return this.getFlag(2);
     }
 
     public void setRolling(boolean nearTarget) {
+        nearTarget = rollingOverride.toBooleanOrElse(nearTarget); // Paper - Rolling override
         this.setFlag(2, nearTarget);
     }
 
@@ -514,28 +570,24 @@
 
     private void setFlag(int bit, boolean value) {
         if (value) {
-            this.entityData.set(DATA_FLAGS_ID, (byte)(this.entityData.get(DATA_FLAGS_ID) | bit));
+            this.entityData.set(Bee.DATA_FLAGS_ID, (byte) ((Byte) this.entityData.get(Bee.DATA_FLAGS_ID) | bit));
         } else {
-            this.entityData.set(DATA_FLAGS_ID, (byte)(this.entityData.get(DATA_FLAGS_ID) & ~bit));
+            this.entityData.set(Bee.DATA_FLAGS_ID, (byte) ((Byte) this.entityData.get(Bee.DATA_FLAGS_ID) & ~bit));
         }
+
     }
 
     private boolean getFlag(int location) {
-        return (this.entityData.get(DATA_FLAGS_ID) & location) != 0;
+        return ((Byte) this.entityData.get(Bee.DATA_FLAGS_ID) & location) != 0;
     }
 
     public static AttributeSupplier.Builder createAttributes() {
-        return Mob.createMobAttributes()
-            .add(Attributes.MAX_HEALTH, 10.0)
-            .add(Attributes.FLYING_SPEED, 0.6F)
-            .add(Attributes.MOVEMENT_SPEED, 0.3F)
-            .add(Attributes.ATTACK_DAMAGE, 2.0)
-            .add(Attributes.FOLLOW_RANGE, 48.0);
+        return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 10.0D).add(Attributes.FLYING_SPEED, 0.6000000238418579D).add(Attributes.MOVEMENT_SPEED, 0.30000001192092896D).add(Attributes.ATTACK_DAMAGE, 2.0D).add(Attributes.FOLLOW_RANGE, 48.0D);
     }
 
     @Override
     protected PathNavigation createNavigation(Level world) {
-        FlyingPathNavigation flyingPathNavigation = new FlyingPathNavigation(this, world) {
+        FlyingPathNavigation navigationflying = new FlyingPathNavigation(this, world) {
             @Override
             public boolean isStableDestination(BlockPos pos) {
                 return !this.level.getBlockState(pos.below()).isAir();
@@ -548,10 +600,11 @@
                 }
             }
         };
-        flyingPathNavigation.setCanOpenDoors(false);
-        flyingPathNavigation.setCanFloat(false);
-        flyingPathNavigation.setCanPassDoors(true);
-        return flyingPathNavigation;
+
+        navigationflying.setCanOpenDoors(false);
+        navigationflying.setCanFloat(false);
+        navigationflying.setCanPassDoors(true);
+        return navigationflying;
     }
 
     @Override
@@ -564,8 +617,7 @@
     }
 
     @Override
-    protected void playStepSound(BlockPos pos, BlockState state) {
-    }
+    protected void playStepSound(BlockPos pos, BlockState state) {}
 
     @Override
     protected SoundEvent getAmbientSound() {
@@ -589,17 +641,16 @@
 
     @Nullable
     @Override
-    public Bee getBreedOffspring(ServerLevel serverLevel, AgeableMob ageableMob) {
-        return EntityType.BEE.create(serverLevel);
+    public Bee getBreedOffspring(ServerLevel world, AgeableMob entity) {
+        return (Bee) EntityType.BEE.create(world);
     }
 
     @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 isFlapping() {
-        return this.isFlying() && this.tickCount % TICKS_PER_FLAP == 0;
+        return this.isFlying() && this.tickCount % Bee.TICKS_PER_FLAP == 0;
     }
 
     @Override
@@ -617,49 +668,242 @@
         if (this.isInvulnerableTo(source)) {
             return false;
         } else {
-            if (!this.level().isClientSide) {
+            // CraftBukkit start - Only stop pollinating if entity was damaged
+            boolean result = super.hurt(source, amount);
+            if (result && !this.level().isClientSide) {
+            // CraftBukkit end
                 this.beePollinateGoal.stopPollinating();
             }
 
-            return super.hurt(source, amount);
+            return result; // CraftBukkit
         }
     }
 
     @Override
     protected void jumpInLiquid(TagKey<Fluid> fluid) {
-        this.setDeltaMovement(this.getDeltaMovement().add(0.0, 0.01, 0.0));
+        this.setDeltaMovement(this.getDeltaMovement().add(0.0D, 0.01D, 0.0D));
     }
 
     @Override
     public Vec3 getLeashOffset() {
-        return new Vec3(0.0, (double)(0.5F * this.getEyeHeight()), (double)(this.getBbWidth() * 0.2F));
+        return new Vec3(0.0D, (double) (0.5F * this.getEyeHeight()), (double) (this.getBbWidth() * 0.2F));
     }
 
     boolean closerThan(BlockPos pos, int distance) {
-        return pos.closerThan(this.blockPosition(), (double)distance);
+        return pos.closerThan(this.blockPosition(), (double) distance);
     }
 
     public void setHivePos(BlockPos pos) {
         this.hivePos = pos;
     }
 
-    abstract class BaseBeeGoal extends Goal {
-        public abstract boolean canBeeUse();
+    private class BeePollinateGoal extends Bee.BaseBeeGoal {
 
-        public abstract boolean canBeeContinueToUse();
+        private static final int MIN_POLLINATION_TICKS = 400;
+        private static final int MIN_FIND_FLOWER_RETRY_COOLDOWN = 20;
+        private static final int MAX_FIND_FLOWER_RETRY_COOLDOWN = 60;
+        private final Predicate<BlockState> VALID_POLLINATION_BLOCKS = (iblockdata) -> {
+            return iblockdata.hasProperty(BlockStateProperties.WATERLOGGED) && (Boolean) iblockdata.getValue(BlockStateProperties.WATERLOGGED) ? false : (iblockdata.is(BlockTags.FLOWERS) ? (iblockdata.is(Blocks.SUNFLOWER) ? iblockdata.getValue(DoublePlantBlock.HALF) == DoubleBlockHalf.UPPER : true) : false);
+        };
+        private static final double ARRIVAL_THRESHOLD = 0.1D;
+        private static final int POSITION_CHANGE_CHANCE = 25;
+        private static final float SPEED_MODIFIER = 0.35F;
+        private static final float HOVER_HEIGHT_WITHIN_FLOWER = 0.6F;
+        private static final float HOVER_POS_OFFSET = 0.33333334F;
+        private int successfulPollinatingTicks;
+        private int lastSoundPlayedTick;
+        private boolean pollinating;
+        @Nullable
+        private Vec3 hoverPos;
+        private int pollinatingTicks;
+        private static final int MAX_POLLINATING_TICKS = 600;
+
+        BeePollinateGoal() {
+            super();
+            this.setFlags(EnumSet.of(Goal.Flag.MOVE));
+        }
 
         @Override
-        public boolean canUse() {
-            return this.canBeeUse() && !Bee.this.isAngry();
+        public boolean canBeeUse() {
+            if (Bee.this.remainingCooldownBeforeLocatingNewFlower > 0) {
+                return false;
+            } else if (Bee.this.hasNectar()) {
+                return false;
+            } else if (Bee.this.level().isRaining()) {
+                return false;
+            } else {
+                Optional<BlockPos> optional = this.findNearbyFlower();
+
+                if (optional.isPresent()) {
+                    Bee.this.savedFlowerPos = (BlockPos) optional.get();
+                    Bee.this.navigation.moveTo((double) Bee.this.savedFlowerPos.getX() + 0.5D, (double) Bee.this.savedFlowerPos.getY() + 0.5D, (double) Bee.this.savedFlowerPos.getZ() + 0.5D, 1.2000000476837158D);
+                    return true;
+                } else {
+                    Bee.this.remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(Bee.this.random, 20, 60);
+                    return false;
+                }
+            }
         }
 
         @Override
-        public boolean canContinueToUse() {
-            return this.canBeeContinueToUse() && !Bee.this.isAngry();
+        public boolean canBeeContinueToUse() {
+            if (!this.pollinating) {
+                return false;
+            } else if (!Bee.this.hasSavedFlowerPos()) {
+                return false;
+            } else if (Bee.this.level().isRaining()) {
+                return false;
+            } else if (this.hasPollinatedLongEnough()) {
+                return Bee.this.random.nextFloat() < 0.2F;
+            } else if (Bee.this.tickCount % 20 == 0 && !Bee.this.isFlowerValid(Bee.this.savedFlowerPos)) {
+                Bee.this.savedFlowerPos = null;
+                return false;
+            } else {
+                return true;
+            }
+        }
+
+        private boolean hasPollinatedLongEnough() {
+            return this.successfulPollinatingTicks > 400;
+        }
+
+        boolean isPollinating() {
+            return this.pollinating;
+        }
+
+        void stopPollinating() {
+            this.pollinating = false;
+        }
+
+        @Override
+        public void start() {
+            this.successfulPollinatingTicks = 0;
+            this.pollinatingTicks = 0;
+            this.lastSoundPlayedTick = 0;
+            this.pollinating = true;
+            Bee.this.resetTicksWithoutNectarSinceExitingHive();
+        }
+
+        @Override
+        public void stop() {
+            if (this.hasPollinatedLongEnough()) {
+                Bee.this.setHasNectar(true);
+            }
+
+            this.pollinating = false;
+            Bee.this.navigation.stop();
+            Bee.this.remainingCooldownBeforeLocatingNewFlower = 200;
+        }
+
+        @Override
+        public boolean requiresUpdateEveryTick() {
+            return true;
+        }
+
+        @Override
+        public void tick() {
+            ++this.pollinatingTicks;
+            if (this.pollinatingTicks > 600) {
+                Bee.this.savedFlowerPos = null;
+            } else if (Bee.this.savedFlowerPos != null) { // Paper - add null check since API can manipulate this
+                Vec3 vec3d = Vec3.atBottomCenterOf(Bee.this.savedFlowerPos).add(0.0D, 0.6000000238418579D, 0.0D);
+
+                if (vec3d.distanceTo(Bee.this.position()) > 1.0D) {
+                    this.hoverPos = vec3d;
+                    this.setWantedPos();
+                } else {
+                    if (this.hoverPos == null) {
+                        this.hoverPos = vec3d;
+                    }
+
+                    boolean flag = Bee.this.position().distanceTo(this.hoverPos) <= 0.1D;
+                    boolean flag1 = true;
+
+                    if (!flag && this.pollinatingTicks > 600) {
+                        Bee.this.savedFlowerPos = null;
+                    } else {
+                        if (flag) {
+                            boolean flag2 = Bee.this.random.nextInt(25) == 0;
+
+                            if (flag2) {
+                                this.hoverPos = new Vec3(vec3d.x() + (double) this.getOffset(), vec3d.y(), vec3d.z() + (double) this.getOffset());
+                                Bee.this.navigation.stop();
+                            } else {
+                                flag1 = false;
+                            }
+
+                            Bee.this.getLookControl().setLookAt(vec3d.x(), vec3d.y(), vec3d.z());
+                        }
+
+                        if (flag1) {
+                            this.setWantedPos();
+                        }
+
+                        ++this.successfulPollinatingTicks;
+                        if (Bee.this.random.nextFloat() < 0.05F && this.successfulPollinatingTicks > this.lastSoundPlayedTick + 60) {
+                            this.lastSoundPlayedTick = this.successfulPollinatingTicks;
+                            Bee.this.playSound(SoundEvents.BEE_POLLINATE, 1.0F, 1.0F);
+                        }
+
+                    }
+                }
+            }
+        }
+
+        private void setWantedPos() {
+            Bee.this.getMoveControl().setWantedPosition(this.hoverPos.x(), this.hoverPos.y(), this.hoverPos.z(), 0.3499999940395355D);
+        }
+
+        private float getOffset() {
+            return (Bee.this.random.nextFloat() * 2.0F - 1.0F) * 0.33333334F;
+        }
+
+        private Optional<BlockPos> findNearbyFlower() {
+            return this.findNearestBlock(this.VALID_POLLINATION_BLOCKS, 5.0D);
+        }
+
+        private Optional<BlockPos> findNearestBlock(Predicate<BlockState> predicate, double searchDistance) {
+            BlockPos blockposition = Bee.this.blockPosition();
+            BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
+
+            for (int i = 0; (double) i <= searchDistance; i = i > 0 ? -i : 1 - i) {
+                for (int j = 0; (double) j < searchDistance; ++j) {
+                    for (int k = 0; k <= j; k = k > 0 ? -k : 1 - k) {
+                        for (int l = k < j && k > -j ? j : 0; l <= j; l = l > 0 ? -l : 1 - l) {
+                            blockposition_mutableblockposition.setWithOffset(blockposition, k, i - 1, l);
+                            if (blockposition.closerThan(blockposition_mutableblockposition, searchDistance) && predicate.test(Bee.this.level().getBlockState(blockposition_mutableblockposition))) {
+                                return Optional.of(blockposition_mutableblockposition);
+                            }
+                        }
+                    }
+                }
+            }
+
+            return Optional.empty();
         }
     }
 
-    class BeeAttackGoal extends MeleeAttackGoal {
+    private class BeeLookControl extends LookControl {
+
+        BeeLookControl(final Mob entity) {
+            super(entity);
+        }
+
+        @Override
+        public void tick() {
+            if (!Bee.this.isAngry()) {
+                super.tick();
+            }
+        }
+
+        @Override
+        protected boolean resetXRotOnTick() {
+            return !Bee.this.beePollinateGoal.isPollinating();
+        }
+    }
+
+    private class BeeAttackGoal extends MeleeAttackGoal {
+
         BeeAttackGoal(final PathfinderMob mob, final double speed, final boolean pauseWhenMobIdle) {
             super(mob, speed, pauseWhenMobIdle);
         }
@@ -675,48 +919,58 @@
         }
     }
 
-    static class BeeBecomeAngryTargetGoal extends NearestAttackableTargetGoal<Player> {
-        BeeBecomeAngryTargetGoal(Bee bee) {
-            super(bee, Player.class, 10, true, false, bee::isAngryAt);
-        }
+    private class BeeEnterHiveGoal extends Bee.BaseBeeGoal {
 
-        @Override
-        public boolean canUse() {
-            return this.beeCanTarget() && super.canUse();
+        BeeEnterHiveGoal() {
+            super();
         }
 
         @Override
-        public boolean canContinueToUse() {
-            boolean bl = this.beeCanTarget();
-            if (bl && this.mob.getTarget() != null) {
-                return super.canContinueToUse();
-            } else {
-                this.targetMob = null;
-                return false;
+        public boolean canBeeUse() {
+            if (Bee.this.hasHive() && Bee.this.wantsToEnterHive() && Bee.this.hivePos.closerToCenterThan(Bee.this.position(), 2.0D)) {
+                if (!Bee.this.level().isLoadedAndInBounds(Bee.this.hivePos)) return false; // Paper - Do not allow bees to load chunks for beehives
+                BlockEntity tileentity = Bee.this.level().getBlockEntity(Bee.this.hivePos);
+
+                if (tileentity instanceof BeehiveBlockEntity) {
+                    BeehiveBlockEntity tileentitybeehive = (BeehiveBlockEntity) tileentity;
+
+                    if (!tileentitybeehive.isFull()) {
+                        return true;
+                    }
+
+                    Bee.this.hivePos = null;
+                }
             }
+
+            return false;
         }
 
-        private boolean beeCanTarget() {
-            Bee bee = (Bee)this.mob;
-            return bee.isAngry() && !bee.hasStung();
+        @Override
+        public boolean canBeeContinueToUse() {
+            return false;
         }
-    }
 
-    class BeeEnterHiveGoal extends Bee.BaseBeeGoal {
         @Override
-        public boolean canBeeUse() {
-            if (Bee.this.hasHive()
-                && Bee.this.wantsToEnterHive()
-                && Bee.this.hivePos.closerToCenterThan(Bee.this.position(), 2.0)
-                && Bee.this.level().getBlockEntity(Bee.this.hivePos) instanceof BeehiveBlockEntity beehiveBlockEntity) {
-                if (!beehiveBlockEntity.isFull()) {
-                    return true;
-                }
+        public void start() {
+            if (!Bee.this.level().isLoadedAndInBounds(Bee.this.hivePos)) return; // Paper - Do not allow bees to load chunks for beehives
+            BlockEntity tileentity = Bee.this.level().getBlockEntity(Bee.this.hivePos);
 
-                Bee.this.hivePos = null;
+            if (tileentity instanceof BeehiveBlockEntity tileentitybeehive) {
+                tileentitybeehive.addOccupant(Bee.this);
             }
 
-            return false;
+        }
+    }
+
+    private class BeeLocateHiveGoal extends Bee.BaseBeeGoal {
+
+        BeeLocateHiveGoal() {
+            super();
+        }
+
+        @Override
+        public boolean canBeeUse() {
+            return Bee.this.remainingCooldownBeforeLocatingNewHive == 0 && !Bee.this.hasHive() && Bee.this.wantsToEnterHive();
         }
 
         @Override
@@ -726,34 +980,63 @@
 
         @Override
         public void start() {
-            if (Bee.this.level().getBlockEntity(Bee.this.hivePos) instanceof BeehiveBlockEntity beehiveBlockEntity) {
-                beehiveBlockEntity.addOccupant(Bee.this);
+            Bee.this.remainingCooldownBeforeLocatingNewHive = 200;
+            List<BlockPos> list = this.findNearbyHivesWithSpace();
+
+            if (!list.isEmpty()) {
+                Iterator iterator = list.iterator();
+
+                BlockPos blockposition;
+
+                do {
+                    if (!iterator.hasNext()) {
+                        Bee.this.goToHiveGoal.clearBlacklist();
+                        Bee.this.hivePos = (BlockPos) list.get(0);
+                        return;
+                    }
+
+                    blockposition = (BlockPos) iterator.next();
+                } while (Bee.this.goToHiveGoal.isTargetBlacklisted(blockposition));
+
+                Bee.this.hivePos = blockposition;
             }
         }
+
+        private List<BlockPos> findNearbyHivesWithSpace() {
+            BlockPos blockposition = Bee.this.blockPosition();
+            PoiManager villageplace = ((ServerLevel) Bee.this.level()).getPoiManager();
+            Stream<PoiRecord> stream = villageplace.getInRange((holder) -> {
+                return holder.is(PoiTypeTags.BEE_HOME);
+            }, blockposition, 20, PoiManager.Occupancy.ANY);
+
+            return (List) stream.map(PoiRecord::getPos).filter(Bee.this::doesHiveHaveSpace).sorted(Comparator.comparingDouble((blockposition1) -> {
+                return blockposition1.distSqr(blockposition);
+            })).collect(Collectors.toList());
+        }
     }
 
     @VisibleForDebug
     public class BeeGoToHiveGoal extends Bee.BaseBeeGoal {
+
         public static final int MAX_TRAVELLING_TICKS = 600;
-        int travellingTicks = Bee.this.level().random.nextInt(10);
+        int travellingTicks;
         private static final int MAX_BLACKLISTED_TARGETS = 3;
-        final List<BlockPos> blacklistedTargets = Lists.newArrayList();
+        final List<BlockPos> blacklistedTargets;
         @Nullable
         private Path lastPath;
         private static final int TICKS_BEFORE_HIVE_DROP = 60;
         private int ticksStuck;
 
         BeeGoToHiveGoal() {
+            super();
+            this.travellingTicks = Bee.this.random.nextInt(10); // CraftBukkit - SPIGOT-7495: Give Bees another chance and let them use their own random, avoid concurrency issues
+            this.blacklistedTargets = Lists.newArrayList();
             this.setFlags(EnumSet.of(Goal.Flag.MOVE));
         }
 
         @Override
         public boolean canBeeUse() {
-            return Bee.this.hivePos != null
-                && !Bee.this.hasRestriction()
-                && Bee.this.wantsToEnterHive()
-                && !this.hasReachedTarget(Bee.this.hivePos)
-                && Bee.this.level().getBlockState(Bee.this.hivePos).is(BlockTags.BEEHIVES);
+            return Bee.this.hivePos != null && !Bee.this.hasRestriction() && Bee.this.wantsToEnterHive() && !this.hasReachedTarget(Bee.this.hivePos) && Bee.this.level().getBlockState(Bee.this.hivePos).is(BlockTags.BEEHIVES);
         }
 
         @Override
@@ -779,7 +1062,7 @@
         @Override
         public void tick() {
             if (Bee.this.hivePos != null) {
-                this.travellingTicks++;
+                ++this.travellingTicks;
                 if (this.travellingTicks > this.adjustedTickDelay(600)) {
                     this.dropAndBlacklistHive();
                 } else if (!Bee.this.navigation.isInProgress()) {
@@ -790,11 +1073,12 @@
                             Bee.this.pathfindRandomlyTowards(Bee.this.hivePos);
                         }
                     } else {
-                        boolean bl = this.pathfindDirectlyTowards(Bee.this.hivePos);
-                        if (!bl) {
+                        boolean flag = this.pathfindDirectlyTowards(Bee.this.hivePos);
+
+                        if (!flag) {
                             this.dropAndBlacklistHive();
                         } else if (this.lastPath != null && Bee.this.navigation.getPath().sameAs(this.lastPath)) {
-                            this.ticksStuck++;
+                            ++this.ticksStuck;
                             if (this.ticksStuck > 60) {
                                 this.dropHive();
                                 this.ticksStuck = 0;
@@ -802,6 +1086,7 @@
                         } else {
                             this.lastPath = Bee.this.navigation.getPath();
                         }
+
                     }
                 }
             }
@@ -809,7 +1094,7 @@
 
         private boolean pathfindDirectlyTowards(BlockPos pos) {
             Bee.this.navigation.setMaxVisitedNodesMultiplier(10.0F);
-            Bee.this.navigation.moveTo((double)pos.getX(), (double)pos.getY(), (double)pos.getZ(), 2, 1.0);
+            Bee.this.navigation.moveTo((double) pos.getX(), (double) pos.getY(), (double) pos.getZ(), 2, 1.0D);
             return Bee.this.navigation.getPath() != null && Bee.this.navigation.getPath().canReach();
         }
 
@@ -823,6 +1108,7 @@
             while (this.blacklistedTargets.size() > 3) {
                 this.blacklistedTargets.remove(0);
             }
+
         }
 
         void clearBlacklist() {
@@ -846,27 +1132,27 @@
             if (Bee.this.closerThan(pos, 2)) {
                 return true;
             } else {
-                Path path = Bee.this.navigation.getPath();
-                return path != null && path.getTarget().equals(pos) && path.canReach() && path.isDone();
+                Path pathentity = Bee.this.navigation.getPath();
+
+                return pathentity != null && pathentity.getTarget().equals(pos) && pathentity.canReach() && pathentity.isDone();
             }
         }
     }
 
     public class BeeGoToKnownFlowerGoal extends Bee.BaseBeeGoal {
+
         private static final int MAX_TRAVELLING_TICKS = 600;
-        int travellingTicks = Bee.this.level().random.nextInt(10);
+        int travellingTicks;
 
         BeeGoToKnownFlowerGoal() {
+            super();
+            this.travellingTicks = Bee.this.random.nextInt(10); // CraftBukkit - SPIGOT-7495: Give Bees another chance and let them use their own random, avoid concurrency issues
             this.setFlags(EnumSet.of(Goal.Flag.MOVE));
         }
 
         @Override
         public boolean canBeeUse() {
-            return Bee.this.savedFlowerPos != null
-                && !Bee.this.hasRestriction()
-                && this.wantsToGoToKnownFlower()
-                && Bee.this.isFlowerValid(Bee.this.savedFlowerPos)
-                && !Bee.this.closerThan(Bee.this.savedFlowerPos, 2);
+            return Bee.this.savedFlowerPos != null && !Bee.this.hasRestriction() && this.wantsToGoToKnownFlower() && Bee.this.isFlowerValid(Bee.this.savedFlowerPos) && !Bee.this.closerThan(Bee.this.savedFlowerPos, 2);
         }
 
         @Override
@@ -890,7 +1176,7 @@
         @Override
         public void tick() {
             if (Bee.this.savedFlowerPos != null) {
-                this.travellingTicks++;
+                ++this.travellingTicks;
                 if (this.travellingTicks > this.adjustedTickDelay(600)) {
                     Bee.this.savedFlowerPos = null;
                 } else if (!Bee.this.navigation.isInProgress()) {
@@ -908,12 +1194,17 @@
         }
     }
 
-    class BeeGrowCropGoal extends Bee.BaseBeeGoal {
+    private class BeeGrowCropGoal extends Bee.BaseBeeGoal {
+
         static final int GROW_CHANCE = 30;
 
+        BeeGrowCropGoal() {
+            super();
+        }
+
         @Override
         public boolean canBeeUse() {
-            return Bee.this.getCropsGrownSincePollination() < 10 && !(Bee.this.random.nextFloat() < 0.3F) && Bee.this.hasNectar() && Bee.this.isHiveValid();
+            return Bee.this.getCropsGrownSincePollination() >= 10 ? false : (Bee.this.random.nextFloat() < 0.3F ? false : Bee.this.hasNectar() && Bee.this.isHiveValid());
         }
 
         @Override
@@ -924,342 +1215,163 @@
         @Override
         public void tick() {
             if (Bee.this.random.nextInt(this.adjustedTickDelay(30)) == 0) {
-                for (int i = 1; i <= 2; i++) {
-                    BlockPos blockPos = Bee.this.blockPosition().below(i);
-                    BlockState blockState = Bee.this.level().getBlockState(blockPos);
-                    Block block = blockState.getBlock();
-                    BlockState blockState2 = null;
-                    if (blockState.is(BlockTags.BEE_GROWABLES)) {
+                for (int i = 1; i <= 2; ++i) {
+                    BlockPos blockposition = Bee.this.blockPosition().below(i);
+                    BlockState iblockdata = Bee.this.level().getBlockState(blockposition);
+                    Block block = iblockdata.getBlock();
+                    BlockState iblockdata1 = null;
+
+                    if (iblockdata.is(BlockTags.BEE_GROWABLES)) {
                         if (block instanceof CropBlock) {
-                            CropBlock cropBlock = (CropBlock)block;
-                            if (!cropBlock.isMaxAge(blockState)) {
-                                blockState2 = cropBlock.getStateForAge(cropBlock.getAge(blockState) + 1);
-                            }
-                        } else if (block instanceof StemBlock) {
-                            int j = blockState.getValue(StemBlock.AGE);
-                            if (j < 7) {
-                                blockState2 = blockState.setValue(StemBlock.AGE, Integer.valueOf(j + 1));
+                            CropBlock blockcrops = (CropBlock) block;
+
+                            if (!blockcrops.isMaxAge(iblockdata)) {
+                                iblockdata1 = blockcrops.getStateForAge(blockcrops.getAge(iblockdata) + 1);
                             }
-                        } else if (blockState.is(Blocks.SWEET_BERRY_BUSH)) {
-                            int k = blockState.getValue(SweetBerryBushBlock.AGE);
-                            if (k < 3) {
-                                blockState2 = blockState.setValue(SweetBerryBushBlock.AGE, Integer.valueOf(k + 1));
+                        } else {
+                            int j;
+
+                            if (block instanceof StemBlock) {
+                                j = (Integer) iblockdata.getValue(StemBlock.AGE);
+                                if (j < 7) {
+                                    iblockdata1 = (BlockState) iblockdata.setValue(StemBlock.AGE, j + 1);
+                                }
+                            } else if (iblockdata.is(Blocks.SWEET_BERRY_BUSH)) {
+                                j = (Integer) iblockdata.getValue(SweetBerryBushBlock.AGE);
+                                if (j < 3) {
+                                    iblockdata1 = (BlockState) iblockdata.setValue(SweetBerryBushBlock.AGE, j + 1);
+                                }
+                            } else if (iblockdata.is(Blocks.CAVE_VINES) || iblockdata.is(Blocks.CAVE_VINES_PLANT)) {
+                                ((BonemealableBlock) iblockdata.getBlock()).performBonemeal((ServerLevel) Bee.this.level(), Bee.this.random, blockposition, iblockdata);
                             }
-                        } else if (blockState.is(Blocks.CAVE_VINES) || blockState.is(Blocks.CAVE_VINES_PLANT)) {
-                            ((BonemealableBlock)blockState.getBlock()).performBonemeal((ServerLevel)Bee.this.level(), Bee.this.random, blockPos, blockState);
                         }
 
-                        if (blockState2 != null) {
-                            Bee.this.level().levelEvent(2011, blockPos, 15);
-                            Bee.this.level().setBlockAndUpdate(blockPos, blockState2);
+                        if (iblockdata1 != null && CraftEventFactory.callEntityChangeBlockEvent(Bee.this, blockposition, iblockdata1)) { // CraftBukkit
+                            Bee.this.level().levelEvent(2011, blockposition, 15);
+                            Bee.this.level().setBlockAndUpdate(blockposition, iblockdata1);
                             Bee.this.incrementNumCropsGrownSincePollination();
                         }
                     }
                 }
+
             }
         }
     }
 
-    class BeeHurtByOtherGoal extends HurtByTargetGoal {
-        BeeHurtByOtherGoal(final Bee bee) {
-            super(bee);
-        }
+    private class BeeWanderGoal extends Goal {
 
-        @Override
-        public boolean canContinueToUse() {
-            return Bee.this.isAngry() && super.canContinueToUse();
-        }
+        private static final int WANDER_THRESHOLD = 22;
 
-        @Override
-        protected void alertOther(Mob mob, LivingEntity target) {
-            if (mob instanceof Bee && this.mob.hasLineOfSight(target)) {
-                mob.setTarget(target);
-            }
+        BeeWanderGoal() {
+            this.setFlags(EnumSet.of(Goal.Flag.MOVE));
         }
-    }
 
-    class BeeLocateHiveGoal extends Bee.BaseBeeGoal {
         @Override
-        public boolean canBeeUse() {
-            return Bee.this.remainingCooldownBeforeLocatingNewHive == 0 && !Bee.this.hasHive() && Bee.this.wantsToEnterHive();
+        public boolean canUse() {
+            return Bee.this.navigation.isDone() && Bee.this.random.nextInt(10) == 0;
         }
 
         @Override
-        public boolean canBeeContinueToUse() {
-            return false;
+        public boolean canContinueToUse() {
+            return Bee.this.navigation.isInProgress();
         }
 
         @Override
         public void start() {
-            Bee.this.remainingCooldownBeforeLocatingNewHive = 200;
-            List<BlockPos> list = this.findNearbyHivesWithSpace();
-            if (!list.isEmpty()) {
-                for (BlockPos blockPos : list) {
-                    if (!Bee.this.goToHiveGoal.isTargetBlacklisted(blockPos)) {
-                        Bee.this.hivePos = blockPos;
-                        return;
-                    }
-                }
+            Vec3 vec3d = this.findPos();
 
-                Bee.this.goToHiveGoal.clearBlacklist();
-                Bee.this.hivePos = list.get(0);
+            if (vec3d != null) {
+                Bee.this.navigation.moveTo(Bee.this.navigation.createPath(BlockPos.containing(vec3d), 1), 1.0D);
             }
-        }
 
-        private List<BlockPos> findNearbyHivesWithSpace() {
-            BlockPos blockPos = Bee.this.blockPosition();
-            PoiManager poiManager = ((ServerLevel)Bee.this.level()).getPoiManager();
-            Stream<PoiRecord> stream = poiManager.getInRange(poiType -> poiType.is(PoiTypeTags.BEE_HOME), blockPos, 20, PoiManager.Occupancy.ANY);
-            return stream.map(PoiRecord::getPos)
-                .filter(Bee.this::doesHiveHaveSpace)
-                .sorted(Comparator.comparingDouble(blockPos2 -> blockPos2.distSqr(blockPos)))
-                .collect(Collectors.toList());
         }
-    }
 
-    class BeeLookControl extends LookControl {
-        BeeLookControl(final Mob entity) {
-            super(entity);
-        }
+        @Nullable
+        private Vec3 findPos() {
+            Vec3 vec3d;
 
-        @Override
-        public void tick() {
-            if (!Bee.this.isAngry()) {
-                super.tick();
+            if (Bee.this.isHiveValid() && !Bee.this.closerThan(Bee.this.hivePos, 22)) {
+                Vec3 vec3d1 = Vec3.atCenterOf(Bee.this.hivePos);
+
+                vec3d = vec3d1.subtract(Bee.this.position()).normalize();
+            } else {
+                vec3d = Bee.this.getViewVector(0.0F);
             }
-        }
 
-        @Override
-        protected boolean resetXRotOnTick() {
-            return !Bee.this.beePollinateGoal.isPollinating();
+            boolean flag = true;
+            Vec3 vec3d2 = HoverRandomPos.getPos(Bee.this, 8, 7, vec3d.x, vec3d.z, 1.5707964F, 3, 1);
+
+            return vec3d2 != null ? vec3d2 : AirAndWaterRandomPos.getPos(Bee.this, 8, 4, -2, vec3d.x, vec3d.z, 1.5707963705062866D);
         }
     }
 
-    class BeePollinateGoal extends Bee.BaseBeeGoal {
-        private static final int MIN_POLLINATION_TICKS = 400;
-        private static final int MIN_FIND_FLOWER_RETRY_COOLDOWN = 20;
-        private static final int MAX_FIND_FLOWER_RETRY_COOLDOWN = 60;
-        private final Predicate<BlockState> VALID_POLLINATION_BLOCKS = state -> (
-                    !state.hasProperty(BlockStateProperties.WATERLOGGED) || !state.getValue(BlockStateProperties.WATERLOGGED)
-                )
-                && state.is(BlockTags.FLOWERS)
-                && (!state.is(Blocks.SUNFLOWER) || state.getValue(DoublePlantBlock.HALF) == DoubleBlockHalf.UPPER);
-        private static final double ARRIVAL_THRESHOLD = 0.1;
-        private static final int POSITION_CHANGE_CHANCE = 25;
-        private static final float SPEED_MODIFIER = 0.35F;
-        private static final float HOVER_HEIGHT_WITHIN_FLOWER = 0.6F;
-        private static final float HOVER_POS_OFFSET = 0.33333334F;
-        private int successfulPollinatingTicks;
-        private int lastSoundPlayedTick;
-        private boolean pollinating;
-        @Nullable
-        private Vec3 hoverPos;
-        private int pollinatingTicks;
-        private static final int MAX_POLLINATING_TICKS = 600;
+    private class BeeHurtByOtherGoal extends HurtByTargetGoal {
 
-        BeePollinateGoal() {
-            this.setFlags(EnumSet.of(Goal.Flag.MOVE));
+        BeeHurtByOtherGoal(final Bee entitybee) {
+            super(entitybee);
         }
 
         @Override
-        public boolean canBeeUse() {
-            if (Bee.this.remainingCooldownBeforeLocatingNewFlower > 0) {
-                return false;
-            } else if (Bee.this.hasNectar()) {
-                return false;
-            } else if (Bee.this.level().isRaining()) {
-                return false;
-            } else {
-                Optional<BlockPos> optional = this.findNearbyFlower();
-                if (optional.isPresent()) {
-                    Bee.this.savedFlowerPos = optional.get();
-                    Bee.this.navigation
-                        .moveTo(
-                            (double)Bee.this.savedFlowerPos.getX() + 0.5,
-                            (double)Bee.this.savedFlowerPos.getY() + 0.5,
-                            (double)Bee.this.savedFlowerPos.getZ() + 0.5,
-                            1.2F
-                        );
-                    return true;
-                } else {
-                    Bee.this.remainingCooldownBeforeLocatingNewFlower = Mth.nextInt(Bee.this.random, 20, 60);
-                    return false;
-                }
-            }
+        public boolean canContinueToUse() {
+            return Bee.this.isAngry() && super.canContinueToUse();
         }
 
         @Override
-        public boolean canBeeContinueToUse() {
-            if (!this.pollinating) {
-                return false;
-            } else if (!Bee.this.hasSavedFlowerPos()) {
-                return false;
-            } else if (Bee.this.level().isRaining()) {
-                return false;
-            } else if (this.hasPollinatedLongEnough()) {
-                return Bee.this.random.nextFloat() < 0.2F;
-            } else if (Bee.this.tickCount % 20 == 0 && !Bee.this.isFlowerValid(Bee.this.savedFlowerPos)) {
-                Bee.this.savedFlowerPos = null;
-                return false;
-            } else {
-                return true;
+        protected void alertOther(Mob mob, LivingEntity target) {
+            if (mob instanceof Bee && this.mob.hasLineOfSight(target)) {
+                mob.setTarget(target, EntityTargetEvent.TargetReason.TARGET_ATTACKED_ENTITY, true); // CraftBukkit - reason
             }
-        }
-
-        private boolean hasPollinatedLongEnough() {
-            return this.successfulPollinatingTicks > 400;
-        }
 
-        boolean isPollinating() {
-            return this.pollinating;
         }
+    }
 
-        void stopPollinating() {
-            this.pollinating = false;
-        }
+    private static class BeeBecomeAngryTargetGoal extends NearestAttackableTargetGoal<Player> {
 
-        @Override
-        public void start() {
-            this.successfulPollinatingTicks = 0;
-            this.pollinatingTicks = 0;
-            this.lastSoundPlayedTick = 0;
-            this.pollinating = true;
-            Bee.this.resetTicksWithoutNectarSinceExitingHive();
+        BeeBecomeAngryTargetGoal(Bee bee) {
+            // Objects.requireNonNull(entitybee); // CraftBukkit - decompile error
+            super(bee, Player.class, 10, true, false, bee::isAngryAt);
         }
 
         @Override
-        public void stop() {
-            if (this.hasPollinatedLongEnough()) {
-                Bee.this.setHasNectar(true);
-            }
-
-            this.pollinating = false;
-            Bee.this.navigation.stop();
-            Bee.this.remainingCooldownBeforeLocatingNewFlower = 200;
+        public boolean canUse() {
+            return this.beeCanTarget() && super.canUse();
         }
 
         @Override
-        public boolean requiresUpdateEveryTick() {
-            return true;
-        }
+        public boolean canContinueToUse() {
+            boolean flag = this.beeCanTarget();
 
-        @Override
-        public void tick() {
-            this.pollinatingTicks++;
-            if (this.pollinatingTicks > 600) {
-                Bee.this.savedFlowerPos = null;
+            if (flag && this.mob.getTarget() != null) {
+                return super.canContinueToUse();
             } else {
-                Vec3 vec3 = Vec3.atBottomCenterOf(Bee.this.savedFlowerPos).add(0.0, 0.6F, 0.0);
-                if (vec3.distanceTo(Bee.this.position()) > 1.0) {
-                    this.hoverPos = vec3;
-                    this.setWantedPos();
-                } else {
-                    if (this.hoverPos == null) {
-                        this.hoverPos = vec3;
-                    }
-
-                    boolean bl = Bee.this.position().distanceTo(this.hoverPos) <= 0.1;
-                    boolean bl2 = true;
-                    if (!bl && this.pollinatingTicks > 600) {
-                        Bee.this.savedFlowerPos = null;
-                    } else {
-                        if (bl) {
-                            boolean bl3 = Bee.this.random.nextInt(25) == 0;
-                            if (bl3) {
-                                this.hoverPos = new Vec3(vec3.x() + (double)this.getOffset(), vec3.y(), vec3.z() + (double)this.getOffset());
-                                Bee.this.navigation.stop();
-                            } else {
-                                bl2 = false;
-                            }
-
-                            Bee.this.getLookControl().setLookAt(vec3.x(), vec3.y(), vec3.z());
-                        }
-
-                        if (bl2) {
-                            this.setWantedPos();
-                        }
-
-                        this.successfulPollinatingTicks++;
-                        if (Bee.this.random.nextFloat() < 0.05F && this.successfulPollinatingTicks > this.lastSoundPlayedTick + 60) {
-                            this.lastSoundPlayedTick = this.successfulPollinatingTicks;
-                            Bee.this.playSound(SoundEvents.BEE_POLLINATE, 1.0F, 1.0F);
-                        }
-                    }
-                }
+                this.targetMob = null;
+                return false;
             }
         }
 
-        private void setWantedPos() {
-            Bee.this.getMoveControl().setWantedPosition(this.hoverPos.x(), this.hoverPos.y(), this.hoverPos.z(), 0.35F);
-        }
-
-        private float getOffset() {
-            return (Bee.this.random.nextFloat() * 2.0F - 1.0F) * 0.33333334F;
-        }
+        private boolean beeCanTarget() {
+            Bee entitybee = (Bee) this.mob;
 
-        private Optional<BlockPos> findNearbyFlower() {
-            return this.findNearestBlock(this.VALID_POLLINATION_BLOCKS, 5.0);
+            return entitybee.isAngry() && !entitybee.hasStung();
         }
+    }
 
-        private Optional<BlockPos> findNearestBlock(Predicate<BlockState> predicate, double searchDistance) {
-            BlockPos blockPos = Bee.this.blockPosition();
-            BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
-
-            for (int i = 0; (double)i <= searchDistance; i = i > 0 ? -i : 1 - i) {
-                for (int j = 0; (double)j < searchDistance; j++) {
-                    for (int k = 0; k <= j; k = k > 0 ? -k : 1 - k) {
-                        for (int l = k < j && k > -j ? j : 0; l <= j; l = l > 0 ? -l : 1 - l) {
-                            mutableBlockPos.setWithOffset(blockPos, k, i - 1, l);
-                            if (blockPos.closerThan(mutableBlockPos, searchDistance) && predicate.test(Bee.this.level().getBlockState(mutableBlockPos))) {
-                                return Optional.of(mutableBlockPos);
-                            }
-                        }
-                    }
-                }
-            }
+    private abstract class BaseBeeGoal extends Goal {
 
-            return Optional.empty();
-        }
-    }
+        BaseBeeGoal() {}
 
-    class BeeWanderGoal extends Goal {
-        private static final int WANDER_THRESHOLD = 22;
+        public abstract boolean canBeeUse();
 
-        BeeWanderGoal() {
-            this.setFlags(EnumSet.of(Goal.Flag.MOVE));
-        }
+        public abstract boolean canBeeContinueToUse();
 
         @Override
         public boolean canUse() {
-            return Bee.this.navigation.isDone() && Bee.this.random.nextInt(10) == 0;
+            return this.canBeeUse() && !Bee.this.isAngry();
         }
 
         @Override
         public boolean canContinueToUse() {
-            return Bee.this.navigation.isInProgress();
-        }
-
-        @Override
-        public void start() {
-            Vec3 vec3 = this.findPos();
-            if (vec3 != null) {
-                Bee.this.navigation.moveTo(Bee.this.navigation.createPath(BlockPos.containing(vec3), 1), 1.0);
-            }
-        }
-
-        @Nullable
-        private Vec3 findPos() {
-            Vec3 vec32;
-            if (Bee.this.isHiveValid() && !Bee.this.closerThan(Bee.this.hivePos, 22)) {
-                Vec3 vec3 = Vec3.atCenterOf(Bee.this.hivePos);
-                vec32 = vec3.subtract(Bee.this.position()).normalize();
-            } else {
-                vec32 = Bee.this.getViewVector(0.0F);
-            }
-
-            int i = 8;
-            Vec3 vec34 = HoverRandomPos.getPos(Bee.this, 8, 7, vec32.x, vec32.z, (float) (Math.PI / 2), 3, 1);
-            return vec34 != null ? vec34 : AirAndWaterRandomPos.getPos(Bee.this, 8, 4, -2, vec32.x, vec32.z, (float) (Math.PI / 2));
+            return this.canBeeContinueToUse() && !Bee.this.isAngry();
         }
     }
 }
