package net.minecraft.world.entity.animal;

import net.minecraft.world.level.block.state.AbstractStateHolder;
import net.minecraft.core.Position;
import net.minecraft.world.entity.ai.goal.MeleeAttackGoal;
import net.minecraft.world.level.block.state.properties.IntegerProperty;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.SweetBerryBushBlock;
import net.minecraft.world.level.block.StemBlock;
import net.minecraft.world.level.block.CropBlock;
import java.util.stream.Stream;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.Comparator;
import java.util.function.Function;
import net.minecraft.world.entity.ai.village.poi.PoiRecord;
import net.minecraft.world.entity.ai.village.poi.PoiManager;
import net.minecraft.world.entity.ai.village.poi.PoiType;
import net.minecraft.server.level.ServerLevel;
import java.util.Iterator;
import java.util.Optional;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
import net.minecraft.world.level.block.DoublePlantBlock;
import net.minecraft.world.level.block.Blocks;
import java.util.function.Predicate;
import net.minecraft.world.entity.ai.control.LookControl;
import com.google.common.collect.Lists;
import net.minecraft.world.level.pathfinder.Path;
import java.util.List;
import java.util.EnumSet;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.network.syncher.EntityDataSerializers;
import java.util.Random;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.entity.MobType;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.entity.Pose;
import net.minecraft.world.entity.AgableMob;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.tags.BlockTags;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.entity.ai.navigation.FlyingPathNavigation;
import net.minecraft.world.entity.ai.navigation.PathNavigation;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.network.protocol.game.DebugPackets;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
import net.minecraft.world.entity.ai.util.RandomPos;
import net.minecraft.core.Vec3i;
import net.minecraft.world.phys.Vec3;
import net.minecraft.util.Mth;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.Difficulty;
import net.minecraft.world.entity.monster.SharedMonsterAttributes;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.nbt.Tag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.ai.goal.FloatGoal;
import net.minecraft.world.entity.ai.goal.FollowParentGoal;
import net.minecraft.world.entity.ai.goal.TemptGoal;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.tags.ItemTags;
import net.minecraft.world.entity.ai.goal.BreedGoal;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.PathfinderMob;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.pathfinder.BlockPathTypes;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.control.FlyingMoveControl;
import net.minecraft.world.level.Level;
import net.minecraft.world.entity.EntityType;
import javax.annotation.Nullable;
import net.minecraft.core.BlockPos;
import java.util.UUID;
import net.minecraft.network.syncher.EntityDataAccessor;

public class Bee extends Animal implements FlyingAnimal {
    private static final EntityDataAccessor<Byte> DATA_FLAGS_ID;
    private static final EntityDataAccessor<Integer> ANGER_TIME;
    private UUID lastHurtByUUID;
    private float rollAmount;
    private float rollAmountO;
    private int timeSinceSting;
    private int ticksWithoutNectarSinceExitingHive;
    private int stayOutOfHiveCountdown;
    private int numCropsGrownSincePollination;
    private int remainingCooldownBeforeLocatingNewHive;
    private int remainingCooldownBeforeLocatingNewFlower;
    @Nullable
    private BlockPos savedFlowerPos;
    @Nullable
    private BlockPos hivePos;
    private BeePollinateGoal beePollinateGoal;
    private BeeGoToHiveGoal goToHiveGoal;
    private BeeGoToKnownFlowerGoal goToKnownFlowerGoal;
    private int underWaterTicks;
    
    public Bee(final EntityType<? extends Bee> aku, final Level bjw) {
        super(aku, bjw);
        this.remainingCooldownBeforeLocatingNewHive = 0;
        this.remainingCooldownBeforeLocatingNewFlower = 0;
        this.savedFlowerPos = null;
        this.hivePos = null;
        this.moveControl = new FlyingMoveControl(this, 20, true);
        this.lookControl = new BeeLookControl(this);
        this.setPathfindingMalus(BlockPathTypes.WATER, -1.0f);
        this.setPathfindingMalus(BlockPathTypes.COCOA, -1.0f);
        this.setPathfindingMalus(BlockPathTypes.FENCE, -1.0f);
    }
    
    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        this.entityData.<Byte>define(Bee.DATA_FLAGS_ID, (Byte)0);
        this.entityData.<Integer>define(Bee.ANGER_TIME, 0);
    }
    
    @Override
    public float getWalkTargetValue(final BlockPos fk, final LevelReader bjz) {
        if (bjz.getBlockState(fk).isAir()) {
            return 10.0f;
        }
        return 0.0f;
    }
    
    @Override
    protected void registerGoals() {
        this.goalSelector.addGoal(0, new BeeAttackGoal(this, 1.399999976158142, true));
        this.goalSelector.addGoal(1, new BeeEnterHiveGoal());
        this.goalSelector.addGoal(2, new BreedGoal(this, 1.0));
        this.goalSelector.addGoal(3, new TemptGoal(this, 1.25, Ingredient.of(ItemTags.FLOWERS), false));
        this.beePollinateGoal = new BeePollinateGoal();
        this.goalSelector.addGoal(4, this.beePollinateGoal);
        this.goalSelector.addGoal(5, new FollowParentGoal(this, 1.25));
        this.goalSelector.addGoal(5, new BeeLocateHiveGoal());
        this.goToHiveGoal = new BeeGoToHiveGoal();
        this.goalSelector.addGoal(5, this.goToHiveGoal);
        this.goToKnownFlowerGoal = new BeeGoToKnownFlowerGoal();
        this.goalSelector.addGoal(6, this.goToKnownFlowerGoal);
        this.goalSelector.addGoal(7, new BeeGrowCropGoal());
        this.goalSelector.addGoal(8, new BeeWanderGoal());
        this.goalSelector.addGoal(9, new FloatGoal(this));
        this.targetSelector.addGoal(1, new BeeHurtByOtherGoal(this).setAlertOthers(new Class[0]));
        this.targetSelector.addGoal(2, new BeeBecomeAngryTargetGoal(this));
    }
    
    @Override
    public void addAdditionalSaveData(final CompoundTag jt) {
        super.addAdditionalSaveData(jt);
        if (this.hasHive()) {
            jt.put("HivePos", NbtUtils.writeBlockPos(this.getHivePos()));
        }
        if (this.hasSavedFlowerPos()) {
            jt.put("FlowerPos", NbtUtils.writeBlockPos(this.getSavedFlowerPos()));
        }
        jt.putBoolean("HasNectar", this.hasNectar());
        jt.putBoolean("HasStung", this.hasStung());
        jt.putInt("TicksSincePollination", this.ticksWithoutNectarSinceExitingHive);
        jt.putInt("CannotEnterHiveTicks", this.stayOutOfHiveCountdown);
        jt.putInt("CropsGrownSincePollination", this.numCropsGrownSincePollination);
        jt.putInt("Anger", this.getAngerTime());
        if (this.lastHurtByUUID != null) {
            jt.putString("HurtBy", this.lastHurtByUUID.toString());
        }
        else {
            jt.putString("HurtBy", "");
        }
    }
    
    @Override
    public void readAdditionalSaveData(final CompoundTag jt) {
        this.hivePos = null;
        if (jt.contains("HivePos")) {
            this.hivePos = NbtUtils.readBlockPos(jt.getCompound("HivePos"));
        }
        this.savedFlowerPos = null;
        if (jt.contains("FlowerPos")) {
            this.savedFlowerPos = NbtUtils.readBlockPos(jt.getCompound("FlowerPos"));
        }
        super.readAdditionalSaveData(jt);
        this.setHasNectar(jt.getBoolean("HasNectar"));
        this.setHasStung(jt.getBoolean("HasStung"));
        this.setAngerTime(jt.getInt("Anger"));
        this.ticksWithoutNectarSinceExitingHive = jt.getInt("TicksSincePollination");
        this.stayOutOfHiveCountdown = jt.getInt("CannotEnterHiveTicks");
        this.numCropsGrownSincePollination = jt.getInt("CropsGrownSincePollination");
        final String string3 = jt.getString("HurtBy");
        if (!string3.isEmpty()) {
            this.lastHurtByUUID = UUID.fromString(string3);
            final Player ayj4 = this.level.getPlayerByUUID(this.lastHurtByUUID);
            this.setLastHurtByMob(ayj4);
            if (ayj4 != null) {
                this.lastHurtByPlayer = ayj4;
                this.lastHurtByPlayerTime = this.getLastHurtByMobTimestamp();
            }
        }
    }
    
    @Override
    public boolean doHurtTarget(final Entity akq) {
        final boolean boolean3 = akq.hurt(DamageSource.sting(this), (float)(int)this.getAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).getValue());
        if (boolean3) {
            this.doEnchantDamageEffects(this, akq);
            if (akq instanceof LivingEntity) {
                ((LivingEntity)akq).setStingerCount(((LivingEntity)akq).getStingerCount() + 1);
                int integer4 = 0;
                if (this.level.getDifficulty() == Difficulty.NORMAL) {
                    integer4 = 10;
                }
                else if (this.level.getDifficulty() == Difficulty.HARD) {
                    integer4 = 18;
                }
                if (integer4 > 0) {
                    ((LivingEntity)akq).addEffect(new MobEffectInstance(MobEffects.POISON, integer4 * 20, 0));
                }
            }
            this.setHasStung(true);
            this.setTarget(null);
            this.playSound(SoundEvents.BEE_STING, 1.0f, 1.0f);
        }
        return boolean3;
    }
    
    @Override
    public void tick() {
        super.tick();
        if (this.hasNectar() && this.getCropsGrownSincePollination() < 10 && this.random.nextFloat() < 0.05f) {
            for (int integer2 = 0; integer2 < this.random.nextInt(2) + 1; ++integer2) {
                this.spawnFluidParticle(this.level, this.getX() - 0.30000001192092896, this.getX() + 0.30000001192092896, this.getZ() - 0.30000001192092896, this.getZ() + 0.30000001192092896, this.getY(0.5), ParticleTypes.FALLING_NECTAR);
            }
        }
        this.updateRollAmount();
    }
    
    private void spawnFluidParticle(final Level bjw, final double double2, final double double3, final double double4, final double double5, final double double6, final ParticleOptions gt) {
        bjw.addParticle(gt, Mth.lerp(bjw.random.nextDouble(), double2, double3), double6, Mth.lerp(bjw.random.nextDouble(), double4, double5), 0.0, 0.0, 0.0);
    }
    
    private void pathfindRandomlyTowards(final BlockPos fk) {
        final Vec3 cvl3 = new Vec3(fk);
        int integer4 = 0;
        final BlockPos fk2 = new BlockPos(this);
        final int integer5 = (int)cvl3.y - fk2.getY();
        if (integer5 > 2) {
            integer4 = 4;
        }
        else if (integer5 < -2) {
            integer4 = -4;
        }
        int integer6 = 6;
        int integer7 = 8;
        final int integer8 = fk2.distManhattan(fk);
        if (integer8 < 15) {
            integer6 = integer8 / 2;
            integer7 = integer8 / 2;
        }
        final Vec3 cvl4 = RandomPos.getAirPosTowards(this, integer6, integer7, integer4, cvl3, 0.3141592741012573);
        if (cvl4 == null) {
            return;
        }
        this.navigation.setMaxVisitedNodesMultiplier(0.5f);
        this.navigation.moveTo(cvl4.x, cvl4.y, cvl4.z, 1.0);
    }
    
    @Nullable
    public BlockPos getSavedFlowerPos() {
        return this.savedFlowerPos;
    }
    
    public boolean hasSavedFlowerPos() {
        return this.savedFlowerPos != null;
    }
    
    public void setSavedFlowerPos(final BlockPos fk) {
        this.savedFlowerPos = fk;
    }
    
    private boolean isTiredOfLookingForNectar() {
        return this.ticksWithoutNectarSinceExitingHive > 3600;
    }
    
    private boolean wantsToEnterHive() {
        if (this.stayOutOfHiveCountdown > 0 || this.beePollinateGoal.isPollinating() || this.hasStung()) {
            return false;
        }
        final boolean boolean2 = this.isTiredOfLookingForNectar() || this.level.isRaining() || this.level.isNight() || this.hasNectar();
        return boolean2 && !this.isHiveNearFire();
    }
    
    public void setStayOutOfHiveCountdown(final int integer) {
        this.stayOutOfHiveCountdown = integer;
    }
    
    public float getRollAmount(final float float1) {
        return Mth.lerp(float1, this.rollAmountO, this.rollAmount);
    }
    
    private void updateRollAmount() {
        this.rollAmountO = this.rollAmount;
        if (this.isRolling()) {
            this.rollAmount = Math.min(1.0f, this.rollAmount + 0.2f);
        }
        else {
            this.rollAmount = Math.max(0.0f, this.rollAmount - 0.24f);
        }
    }
    
    @Override
    public void setLastHurtByMob(@Nullable final LivingEntity akz) {
        super.setLastHurtByMob(akz);
        if (akz != null) {
            this.lastHurtByUUID = akz.getUUID();
        }
    }
    
    @Override
    protected void customServerAiStep() {
        final boolean boolean2 = this.hasStung();
        if (this.isInWaterOrBubble()) {
            ++this.underWaterTicks;
        }
        else {
            this.underWaterTicks = 0;
        }
        if (this.underWaterTicks > 20) {
            this.hurt(DamageSource.DROWN, 1.0f);
        }
        if (boolean2) {
            ++this.timeSinceSting;
            if (this.timeSinceSting % 5 == 0 && this.random.nextInt(Mth.clamp(1200 - this.timeSinceSting, 1, 1200)) == 0) {
                this.hurt(DamageSource.GENERIC, this.getHealth());
            }
        }
        if (this.isAngry()) {
            final int integer3 = this.getAngerTime();
            this.setAngerTime(integer3 - 1);
            final LivingEntity akz4 = this.getTarget();
            if (integer3 == 0 && akz4 != null) {
                this.makeAngry(akz4);
            }
        }
        if (!this.hasNectar()) {
            ++this.ticksWithoutNectarSinceExitingHive;
        }
    }
    
    public void resetTicksWithoutNectarSinceExitingHive() {
        this.ticksWithoutNectarSinceExitingHive = 0;
    }
    
    private boolean isHiveNearFire() {
        if (this.hivePos == null) {
            return false;
        }
        final BlockEntity bwl2 = this.level.getBlockEntity(this.hivePos);
        return bwl2 instanceof BeehiveBlockEntity && ((BeehiveBlockEntity)bwl2).isFireNearby();
    }
    
    public boolean isAngry() {
        return this.getAngerTime() > 0;
    }
    
    private int getAngerTime() {
        return this.entityData.<Integer>get(Bee.ANGER_TIME);
    }
    
    private void setAngerTime(final int integer) {
        this.entityData.<Integer>set(Bee.ANGER_TIME, integer);
    }
    
    private boolean doesHiveHaveSpace(final BlockPos fk) {
        final BlockEntity bwl3 = this.level.getBlockEntity(fk);
        return bwl3 instanceof BeehiveBlockEntity && !((BeehiveBlockEntity)bwl3).isFull();
    }
    
    public boolean hasHive() {
        return this.hivePos != null;
    }
    
    @Nullable
    public BlockPos getHivePos() {
        return this.hivePos;
    }
    
    @Override
    protected void sendDebugPackets() {
        super.sendDebugPackets();
        DebugPackets.sendBeeInfo(this);
    }
    
    private int getCropsGrownSincePollination() {
        return this.numCropsGrownSincePollination;
    }
    
    private void resetNumCropsGrownSincePollination() {
        this.numCropsGrownSincePollination = 0;
    }
    
    private void incrementNumCropsGrownSincePollination() {
        ++this.numCropsGrownSincePollination;
    }
    
    @Override
    public void aiStep() {
        super.aiStep();
        if (!this.level.isClientSide) {
            if (this.stayOutOfHiveCountdown > 0) {
                --this.stayOutOfHiveCountdown;
            }
            if (this.remainingCooldownBeforeLocatingNewHive > 0) {
                --this.remainingCooldownBeforeLocatingNewHive;
            }
            if (this.remainingCooldownBeforeLocatingNewFlower > 0) {
                --this.remainingCooldownBeforeLocatingNewFlower;
            }
            final boolean boolean2 = this.isAngry() && !this.hasStung() && this.getTarget() != null && this.getTarget().distanceToSqr(this) < 4.0;
            this.setRolling(boolean2);
            if (this.tickCount % 20 == 0 && !this.isHiveValid()) {
                this.hivePos = null;
            }
        }
    }
    
    private boolean isHiveValid() {
        if (!this.hasHive()) {
            return false;
        }
        final BlockEntity bwl2 = this.level.getBlockEntity(this.hivePos);
        return bwl2 != null && bwl2.getType() == BlockEntityType.BEEHIVE;
    }
    
    public boolean hasNectar() {
        return this.getFlag(8);
    }
    
    private void setHasNectar(final boolean boolean1) {
        if (boolean1) {
            this.resetTicksWithoutNectarSinceExitingHive();
        }
        this.setFlag(8, boolean1);
    }
    
    public boolean hasStung() {
        return this.getFlag(4);
    }
    
    private void setHasStung(final boolean boolean1) {
        this.setFlag(4, boolean1);
    }
    
    private boolean isRolling() {
        return this.getFlag(2);
    }
    
    private void setRolling(final boolean boolean1) {
        this.setFlag(2, boolean1);
    }
    
    private boolean isTooFarAway(final BlockPos fk) {
        return !this.closerThan(fk, 48);
    }
    
    private void setFlag(final int integer, final boolean boolean2) {
        if (boolean2) {
            this.entityData.<Byte>set(Bee.DATA_FLAGS_ID, (byte)(this.entityData.<Byte>get(Bee.DATA_FLAGS_ID) | integer));
        }
        else {
            this.entityData.<Byte>set(Bee.DATA_FLAGS_ID, (byte)(this.entityData.<Byte>get(Bee.DATA_FLAGS_ID) & ~integer));
        }
    }
    
    private boolean getFlag(final int integer) {
        return (this.entityData.<Byte>get(Bee.DATA_FLAGS_ID) & integer) != 0x0;
    }
    
    @Override
    protected void registerAttributes() {
        super.registerAttributes();
        this.getAttributes().registerAttribute(SharedMonsterAttributes.FLYING_SPEED);
        this.getAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(10.0);
        this.getAttribute(SharedMonsterAttributes.FLYING_SPEED).setBaseValue(0.6000000238418579);
        this.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.30000001192092896);
        this.getAttributes().registerAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(2.0);
        this.getAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(48.0);
    }
    
    @Override
    protected PathNavigation createNavigation(final Level bjw) {
        final FlyingPathNavigation arp3 = new FlyingPathNavigation(this, bjw) {
            @Override
            public boolean isStableDestination(final BlockPos fk) {
                return !this.level.getBlockState(fk.below()).isAir();
            }
            
            @Override
            public void tick() {
                if (Bee.this.beePollinateGoal.isPollinating()) {
                    return;
                }
                super.tick();
            }
        };
        arp3.setCanOpenDoors(false);
        arp3.setCanFloat(false);
        arp3.setCanPassDoors(true);
        return arp3;
    }
    
    @Override
    public boolean isFood(final ItemStack ben) {
        return ben.getItem().is(ItemTags.FLOWERS);
    }
    
    private boolean isFlowerValid(final BlockPos fk) {
        return this.level.isLoaded(fk) && this.level.getBlockState(fk).getBlock().is(BlockTags.FLOWERS);
    }
    
    @Override
    protected void playStepSound(final BlockPos fk, final BlockState byj) {
    }
    
    @Override
    protected SoundEvent getAmbientSound() {
        return null;
    }
    
    @Override
    protected SoundEvent getHurtSound(final DamageSource ajz) {
        return SoundEvents.BEE_HURT;
    }
    
    @Override
    protected SoundEvent getDeathSound() {
        return SoundEvents.BEE_DEATH;
    }
    
    @Override
    protected float getSoundVolume() {
        return 0.4f;
    }
    
    @Override
    public Bee getBreedOffspring(final AgableMob ako) {
        return EntityType.BEE.create(this.level);
    }
    
    @Override
    protected float getStandingEyeHeight(final Pose alj, final EntityDimensions akr) {
        if (this.isBaby()) {
            return akr.height * 0.5f;
        }
        return akr.height * 0.5f;
    }
    
    @Override
    public boolean causeFallDamage(final float float1, final float float2) {
        return false;
    }
    
    @Override
    protected void checkFallDamage(final double double1, final boolean boolean2, final BlockState byj, final BlockPos fk) {
    }
    
    @Override
    protected boolean makeFlySound() {
        return true;
    }
    
    public void dropOffNectar() {
        this.setHasNectar(false);
        this.resetNumCropsGrownSincePollination();
    }
    
    public boolean makeAngry(final Entity akq) {
        this.setAngerTime(400 + this.random.nextInt(400));
        if (akq instanceof LivingEntity) {
            this.setLastHurtByMob((LivingEntity)akq);
        }
        return true;
    }
    
    @Override
    public boolean hurt(final DamageSource ajz, final float float2) {
        if (this.isInvulnerableTo(ajz)) {
            return false;
        }
        final Entity akq4 = ajz.getEntity();
        if (!this.level.isClientSide && akq4 instanceof Player && !((Player)akq4).isCreative() && this.canSee(akq4) && !this.isNoAi()) {
            this.beePollinateGoal.stopPollinating();
            this.makeAngry(akq4);
        }
        return super.hurt(ajz, float2);
    }
    
    @Override
    public MobType getMobType() {
        return MobType.ARTHROPOD;
    }
    
    @Override
    protected void jumpInLiquid(final net.minecraft.tags.Tag<Fluid> aaz) {
        this.setDeltaMovement(this.getDeltaMovement().add(0.0, 0.01, 0.0));
    }
    
    private boolean closerThan(final BlockPos fk, final int integer) {
        return fk.closerThan(new BlockPos(this), integer);
    }
    
    static {
        DATA_FLAGS_ID = SynchedEntityData.<Byte>defineId(Bee.class, EntityDataSerializers.BYTE);
        ANGER_TIME = SynchedEntityData.<Integer>defineId(Bee.class, EntityDataSerializers.INT);
    }
    
    class BeeHurtByOtherGoal extends HurtByTargetGoal {
        BeeHurtByOtherGoal(final Bee atd2) {
            super(atd2, new Class[0]);
        }
        
        @Override
        protected void alertOther(final Mob ala, final LivingEntity akz) {
            if (ala instanceof Bee && this.mob.canSee(akz) && ((Bee)ala).makeAngry(akz)) {
                ala.setTarget(akz);
            }
        }
    }
    
    static class BeeBecomeAngryTargetGoal extends NearestAttackableTargetGoal<Player> {
        BeeBecomeAngryTargetGoal(final Bee atd) {
            super(atd, Player.class, true);
        }
        
        @Override
        public boolean canUse() {
            return this.beeCanTarget() && super.canUse();
        }
        
        @Override
        public boolean canContinueToUse() {
            final boolean boolean2 = this.beeCanTarget();
            if (!boolean2 || this.mob.getTarget() == null) {
                this.targetMob = null;
                return false;
            }
            return super.canContinueToUse();
        }
        
        private boolean beeCanTarget() {
            final Bee atd2 = (Bee)this.mob;
            return atd2.isAngry() && !atd2.hasStung();
        }
    }
    
    abstract class BaseBeeGoal extends Goal {
        private BaseBeeGoal() {
        }
        
        public abstract boolean canBeeUse();
        
        public abstract boolean canBeeContinueToUse();
        
        @Override
        public boolean canUse() {
            return this.canBeeUse() && !Bee.this.isAngry();
        }
        
        @Override
        public boolean canContinueToUse() {
            return this.canBeeContinueToUse() && !Bee.this.isAngry();
        }
    }
    
    class BeeWanderGoal extends Goal {
        BeeWanderGoal() {
            this.setFlags(EnumSet.<Flag>of(Flag.MOVE));
        }
        
        @Override
        public boolean canUse() {
            return Bee.this.navigation.isDone() && Bee.this.random.nextInt(10) == 0;
        }
        
        @Override
        public boolean canContinueToUse() {
            return Bee.this.navigation.isInProgress();
        }
        
        @Override
        public void start() {
            final Vec3 cvl2 = this.findPos();
            if (cvl2 != null) {
                Bee.this.navigation.moveTo(Bee.this.navigation.createPath(new BlockPos(cvl2), 1), 1.0);
            }
        }
        
        @Nullable
        private Vec3 findPos() {
            Vec3 cvl4;
            if (Bee.this.isHiveValid() && !Bee.this.closerThan(Bee.this.hivePos, 40)) {
                final Vec3 cvl3 = new Vec3(Bee.this.hivePos);
                cvl4 = cvl3.subtract(Bee.this.position()).normalize();
            }
            else {
                cvl4 = Bee.this.getViewVector(0.0f);
            }
            final int integer3 = 8;
            final Vec3 cvl5 = RandomPos.getAboveLandPos(Bee.this, 8, 7, cvl4, 1.5707964f, 2, 1);
            if (cvl5 != null) {
                return cvl5;
            }
            return RandomPos.getAirPos(Bee.this, 8, 4, -2, cvl4, 1.5707963705062866);
        }
    }
    
    public class BeeGoToHiveGoal extends BaseBeeGoal {
        private int travellingTicks;
        private List<BlockPos> blacklistedTargets;
        @Nullable
        private Path lastPath;
        
        BeeGoToHiveGoal() {
            this.travellingTicks = Bee.this.level.random.nextInt(10);
            this.blacklistedTargets = Lists.newArrayList();
            this.lastPath = null;
            this.setFlags(EnumSet.<Flag>of(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);
        }
        
        @Override
        public boolean canBeeContinueToUse() {
            return this.canBeeUse();
        }
        
        @Override
        public void start() {
            this.travellingTicks = 0;
            super.start();
        }
        
        @Override
        public void stop() {
            this.travellingTicks = 0;
            Bee.this.navigation.stop();
            Bee.this.navigation.resetMaxVisitedNodesMultiplier();
        }
        
        @Override
        public void tick() {
            if (Bee.this.hivePos == null) {
                return;
            }
            ++this.travellingTicks;
            if (this.travellingTicks > 600) {
                this.dropAndBlacklistHive();
                return;
            }
            if (Bee.this.navigation.isInProgress()) {
                return;
            }
            if (Bee.this.closerThan(Bee.this.hivePos, 16)) {
                final boolean boolean2 = this.pathfindDirectlyTowards(Bee.this.hivePos);
                if (!boolean2) {
                    this.dropAndBlacklistHive();
                }
                else if (this.lastPath != null && Bee.this.navigation.getPath().sameAs(this.lastPath)) {
                    this.dropHive();
                }
                else {
                    this.lastPath = Bee.this.navigation.getPath();
                }
                return;
            }
            if (Bee.this.isTooFarAway(Bee.this.hivePos)) {
                this.dropHive();
                return;
            }
            Bee.this.pathfindRandomlyTowards(Bee.this.hivePos);
        }
        
        private boolean pathfindDirectlyTowards(final BlockPos fk) {
            Bee.this.navigation.setMaxVisitedNodesMultiplier(10.0f);
            Bee.this.navigation.moveTo(fk.getX(), fk.getY(), fk.getZ(), 1.0);
            return Bee.this.navigation.getPath() != null && Bee.this.navigation.getPath().canReach();
        }
        
        private boolean isTargetBlacklisted(final BlockPos fk) {
            return this.blacklistedTargets.contains(fk);
        }
        
        private void blacklistTarget(final BlockPos fk) {
            this.blacklistedTargets.add(fk);
            while (this.blacklistedTargets.size() > 3) {
                this.blacklistedTargets.remove(0);
            }
        }
        
        private void clearBlacklist() {
            this.blacklistedTargets.clear();
        }
        
        private void dropAndBlacklistHive() {
            if (Bee.this.hivePos != null) {
                this.blacklistTarget(Bee.this.hivePos);
            }
            this.dropHive();
        }
        
        private void dropHive() {
            Bee.this.hivePos = null;
            Bee.this.remainingCooldownBeforeLocatingNewHive = 200;
        }
        
        private boolean hasReachedTarget(final BlockPos fk) {
            if (Bee.this.closerThan(fk, 2)) {
                return true;
            }
            final Path cqq3 = Bee.this.navigation.getPath();
            return cqq3 != null && cqq3.getTarget().equals(fk) && cqq3.canReach() && cqq3.isDone();
        }
    }
    
    public class BeeGoToKnownFlowerGoal extends BaseBeeGoal {
        private int travellingTicks;
        
        BeeGoToKnownFlowerGoal() {
            this.travellingTicks = Bee.this.level.random.nextInt(10);
            this.setFlags(EnumSet.<Flag>of(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);
        }
        
        @Override
        public boolean canBeeContinueToUse() {
            return this.canBeeUse();
        }
        
        @Override
        public void start() {
            this.travellingTicks = 0;
            super.start();
        }
        
        @Override
        public void stop() {
            this.travellingTicks = 0;
            Bee.this.navigation.stop();
            Bee.this.navigation.resetMaxVisitedNodesMultiplier();
        }
        
        @Override
        public void tick() {
            if (Bee.this.savedFlowerPos == null) {
                return;
            }
            ++this.travellingTicks;
            if (this.travellingTicks > 600) {
                Bee.this.savedFlowerPos = null;
                return;
            }
            if (Bee.this.navigation.isInProgress()) {
                return;
            }
            if (Bee.this.isTooFarAway(Bee.this.savedFlowerPos)) {
                Bee.this.savedFlowerPos = null;
                return;
            }
            Bee.this.pathfindRandomlyTowards(Bee.this.savedFlowerPos);
        }
        
        private boolean wantsToGoToKnownFlower() {
            return Bee.this.ticksWithoutNectarSinceExitingHive > 2400;
        }
    }
    
    class BeeLookControl extends LookControl {
        BeeLookControl(final Mob ala) {
            super(ala);
        }
        
        @Override
        public void tick() {
            if (Bee.this.isAngry()) {
                return;
            }
            super.tick();
        }
        
        @Override
        protected boolean resetXRotOnTick() {
            return !Bee.this.beePollinateGoal.isPollinating();
        }
    }
    
    class BeePollinateGoal extends BaseBeeGoal {
        private final Predicate<BlockState> VALID_POLLINATION_BLOCKS;
        private int successfulPollinatingTicks;
        private int lastSoundPlayedTick;
        private boolean pollinating;
        private Vec3 hoverPos;
        private int pollinatingTicks;
        
        BeePollinateGoal() {
            this.VALID_POLLINATION_BLOCKS = (byj -> {
                if (byj.is(BlockTags.TALL_FLOWERS)) {
                    if (byj.getBlock() == Blocks.SUNFLOWER) {
                        return byj.<DoubleBlockHalf>getValue(DoublePlantBlock.HALF) == DoubleBlockHalf.UPPER;
                    }
                    else {
                        return true;
                    }
                }
                else {
                    return byj.is(BlockTags.SMALL_FLOWERS);
                }
            });
            this.successfulPollinatingTicks = 0;
            this.lastSoundPlayedTick = 0;
            this.pollinatingTicks = 0;
            this.setFlags(EnumSet.<Flag>of(Flag.MOVE));
        }
        
        @Override
        public boolean canBeeUse() {
            if (Bee.this.remainingCooldownBeforeLocatingNewFlower > 0) {
                return false;
            }
            if (Bee.this.hasNectar()) {
                return false;
            }
            if (Bee.this.level.isRaining()) {
                return false;
            }
            if (Bee.this.random.nextFloat() < 0.7f) {
                return false;
            }
            final Optional<BlockPos> optional2 = this.findNearbyFlower();
            if (optional2.isPresent()) {
                Bee.this.savedFlowerPos = optional2.get();
                Bee.this.navigation.moveTo(Bee.this.savedFlowerPos.getX() + 0.5, Bee.this.savedFlowerPos.getY() + 0.5, Bee.this.savedFlowerPos.getZ() + 0.5, 1.2000000476837158);
                return true;
            }
            return false;
        }
        
        @Override
        public boolean canBeeContinueToUse() {
            if (!this.pollinating) {
                return false;
            }
            if (!Bee.this.hasSavedFlowerPos()) {
                return false;
            }
            if (Bee.this.level.isRaining()) {
                return false;
            }
            if (this.hasPollinatedLongEnough()) {
                return Bee.this.random.nextFloat() < 0.2f;
            }
            if (Bee.this.tickCount % 20 == 0 && !Bee.this.isFlowerValid(Bee.this.savedFlowerPos)) {
                Bee.this.savedFlowerPos = null;
                return false;
            }
            return true;
        }
        
        private boolean hasPollinatedLongEnough() {
            return this.successfulPollinatingTicks > 400;
        }
        
        private boolean isPollinating() {
            return this.pollinating;
        }
        
        private 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 void tick() {
            ++this.pollinatingTicks;
            if (this.pollinatingTicks > 600) {
                Bee.this.savedFlowerPos = null;
                return;
            }
            final Vec3 cvl2 = new Vec3(Bee.this.savedFlowerPos).add(0.5, 0.6000000238418579, 0.5);
            if (cvl2.distanceTo(Bee.this.position()) > 1.0) {
                this.hoverPos = cvl2;
                this.setWantedPos();
                return;
            }
            if (this.hoverPos == null) {
                this.hoverPos = cvl2;
            }
            final boolean boolean3 = Bee.this.position().distanceTo(this.hoverPos) <= 0.1;
            boolean boolean4 = true;
            if (!boolean3 && this.pollinatingTicks > 600) {
                Bee.this.savedFlowerPos = null;
                return;
            }
            if (boolean3) {
                final boolean boolean5 = Bee.this.random.nextInt(100) == 0;
                if (boolean5) {
                    this.hoverPos = new Vec3(cvl2.x() + this.getOffset(), cvl2.y(), cvl2.z() + this.getOffset());
                    Bee.this.navigation.stop();
                }
                else {
                    boolean4 = false;
                }
                Bee.this.getLookControl().setLookAt(cvl2.x(), cvl2.y(), cvl2.z());
            }
            if (boolean4) {
                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.3499999940395355);
        }
        
        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.0);
        }
        
        private Optional<BlockPos> findNearestBlock(final Predicate<BlockState> predicate, final double double2) {
            final BlockPos fk5 = new BlockPos(Bee.this);
            final BlockPos.MutableBlockPos a6 = new BlockPos.MutableBlockPos();
            for (int integer7 = 0; integer7 <= double2; integer7 = ((integer7 > 0) ? (-integer7) : (1 - integer7))) {
                for (int integer8 = 0; integer8 < double2; ++integer8) {
                    for (int integer9 = 0; integer9 <= integer8; integer9 = ((integer9 > 0) ? (-integer9) : (1 - integer9))) {
                        for (int integer10 = (integer9 < integer8 && integer9 > -integer8) ? integer8 : 0; integer10 <= integer8; integer10 = ((integer10 > 0) ? (-integer10) : (1 - integer10))) {
                            a6.set(fk5).move(integer9, integer7 - 1, integer10);
                            if (fk5.closerThan(a6, double2) && predicate.test(Bee.this.level.getBlockState(a6))) {
                                return Optional.of(a6);
                            }
                        }
                    }
                }
            }
            return Optional.<BlockPos>empty();
        }
    }
    
    class BeeLocateHiveGoal extends BaseBeeGoal {
        private BeeLocateHiveGoal() {
        }
        
        @Override
        public boolean canBeeUse() {
            return Bee.this.remainingCooldownBeforeLocatingNewHive == 0 && !Bee.this.hasHive() && Bee.this.wantsToEnterHive();
        }
        
        @Override
        public boolean canBeeContinueToUse() {
            return false;
        }
        
        @Override
        public void start() {
            Bee.this.remainingCooldownBeforeLocatingNewHive = 200;
            final List<BlockPos> list2 = this.findNearbyHivesWithSpace();
            if (list2.isEmpty()) {
                return;
            }
            for (final BlockPos fk4 : list2) {
                if (!Bee.this.goToHiveGoal.isTargetBlacklisted(fk4)) {
                    Bee.this.hivePos = fk4;
                    return;
                }
            }
            Bee.this.goToHiveGoal.clearBlacklist();
            Bee.this.hivePos = list2.get(0);
        }
        
        private List<BlockPos> findNearbyHivesWithSpace() {
            final BlockPos fk3 = new BlockPos(Bee.this);
            final PoiManager asr3 = ((ServerLevel)Bee.this.level).getPoiManager();
            final Stream<PoiRecord> stream4 = asr3.getInRange(asu -> asu == PoiType.BEEHIVE || asu == PoiType.BEE_NEST, fk3, 20, PoiManager.Occupancy.ANY);
            return stream4.map(PoiRecord::getPos).filter(fk -> Bee.this.doesHiveHaveSpace(fk)).sorted(Comparator.comparingDouble(fk2 -> fk2.distSqr(fk3))).collect(Collectors.toList());
        }
    }
    
    class BeeGrowCropGoal extends BaseBeeGoal {
        private BeeGrowCropGoal() {
        }
        
        @Override
        public boolean canBeeUse() {
            return Bee.this.getCropsGrownSincePollination() < 10 && Bee.this.random.nextFloat() >= 0.3f && Bee.this.hasNectar() && Bee.this.isHiveValid();
        }
        
        @Override
        public boolean canBeeContinueToUse() {
            return this.canBeeUse();
        }
        
        @Override
        public void tick() {
            if (Bee.this.random.nextInt(30) != 0) {
                return;
            }
            for (int integer2 = 1; integer2 <= 2; ++integer2) {
                final BlockPos fk3 = new BlockPos(Bee.this).below(integer2);
                final BlockState byj4 = Bee.this.level.getBlockState(fk3);
                final Block bph5 = byj4.getBlock();
                boolean boolean6 = false;
                IntegerProperty bzj7 = null;
                if (bph5.is(BlockTags.BEE_GROWABLES)) {
                    if (bph5 instanceof CropBlock) {
                        final CropBlock bqk8 = (CropBlock)bph5;
                        if (!bqk8.isMaxAge(byj4)) {
                            boolean6 = true;
                            bzj7 = bqk8.getAgeProperty();
                        }
                    }
                    else if (bph5 instanceof StemBlock) {
                        final int integer3 = byj4.<Integer>getValue((Property<Integer>)StemBlock.AGE);
                        if (integer3 < 7) {
                            boolean6 = true;
                            bzj7 = StemBlock.AGE;
                        }
                    }
                    else if (bph5 == Blocks.SWEET_BERRY_BUSH) {
                        final int integer3 = byj4.<Integer>getValue((Property<Integer>)SweetBerryBushBlock.AGE);
                        if (integer3 < 3) {
                            boolean6 = true;
                            bzj7 = SweetBerryBushBlock.AGE;
                        }
                    }
                    if (boolean6) {
                        Bee.this.level.levelEvent(2005, fk3, 0);
                        Bee.this.level.setBlockAndUpdate(fk3, ((AbstractStateHolder<O, BlockState>)byj4).<Comparable, Integer>setValue((Property<Comparable>)bzj7, byj4.<Integer>getValue((Property<Integer>)bzj7) + 1));
                        Bee.this.incrementNumCropsGrownSincePollination();
                    }
                }
            }
        }
    }
    
    class BeeAttackGoal extends MeleeAttackGoal {
        BeeAttackGoal(final PathfinderMob alg, final double double3, final boolean boolean4) {
            super(alg, double3, boolean4);
        }
        
        @Override
        public boolean canUse() {
            return super.canUse() && Bee.this.isAngry() && !Bee.this.hasStung();
        }
        
        @Override
        public boolean canContinueToUse() {
            return super.canContinueToUse() && Bee.this.isAngry() && !Bee.this.hasStung();
        }
    }
    
    class BeeEnterHiveGoal extends BaseBeeGoal {
        private BeeEnterHiveGoal() {
        }
        
        @Override
        public boolean canBeeUse() {
            if (Bee.this.hasHive() && Bee.this.wantsToEnterHive() && Bee.this.hivePos.closerThan(Bee.this.position(), 2.0)) {
                final BlockEntity bwl2 = Bee.this.level.getBlockEntity(Bee.this.hivePos);
                if (bwl2 instanceof BeehiveBlockEntity) {
                    final BeehiveBlockEntity bwi3 = (BeehiveBlockEntity)bwl2;
                    if (!bwi3.isFull()) {
                        return true;
                    }
                    Bee.this.hivePos = null;
                }
            }
            return false;
        }
        
        @Override
        public boolean canBeeContinueToUse() {
            return false;
        }
        
        @Override
        public void start() {
            final BlockEntity bwl2 = Bee.this.level.getBlockEntity(Bee.this.hivePos);
            if (bwl2 instanceof BeehiveBlockEntity) {
                final BeehiveBlockEntity bwi3 = (BeehiveBlockEntity)bwl2;
                bwi3.addOccupant(Bee.this, Bee.this.hasNectar());
            }
        }
    }
}
