package net.minecraft.world.entity;

import java.util.AbstractList;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.item.AxeItem;
import net.minecraft.world.entity.decoration.LeashFenceKnotEntity;
import net.minecraft.world.entity.monster.Enemy;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.core.Vec3i;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.AbstractSkullBlock;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.DifficultyInstance;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.BlockGetter;
import java.util.Random;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.util.Mth;
import net.minecraft.network.protocol.game.DebugPackets;
import net.minecraft.world.Difficulty;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.item.ArmorItem;
import net.minecraft.world.item.BowItem;
import net.minecraft.world.item.SwordItem;
import java.util.List;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.storage.loot.LootContext;
import java.util.UUID;
import java.util.Iterator;
import net.minecraft.world.entity.decoration.HangingEntity;
import net.minecraft.nbt.FloatTag;
import net.minecraft.nbt.Tag;
import net.minecraft.nbt.ListTag;
import net.minecraft.world.entity.ai.goal.Goal;
import net.minecraft.world.entity.vehicle.Boat;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.entity.ai.navigation.GroundPathNavigation;
import net.minecraft.world.entity.monster.SharedMonsterAttributes;
import java.util.Arrays;
import com.google.common.collect.Maps;
import net.minecraft.world.level.Level;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import javax.annotation.Nullable;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.pathfinder.BlockPathTypes;
import java.util.Map;
import net.minecraft.world.item.ItemStack;
import net.minecraft.core.NonNullList;
import net.minecraft.world.entity.ai.sensing.Sensing;
import net.minecraft.world.entity.ai.goal.GoalSelector;
import net.minecraft.world.entity.ai.navigation.PathNavigation;
import net.minecraft.world.entity.ai.control.BodyRotationControl;
import net.minecraft.world.entity.ai.control.JumpControl;
import net.minecraft.world.entity.ai.control.MoveControl;
import net.minecraft.world.entity.ai.control.LookControl;
import net.minecraft.network.syncher.EntityDataAccessor;

public abstract class Mob extends LivingEntity {
    private static final EntityDataAccessor<Byte> DATA_MOB_FLAGS_ID;
    public int ambientSoundTime;
    protected int xpReward;
    protected LookControl lookControl;
    protected MoveControl moveControl;
    protected JumpControl jumpControl;
    private final BodyRotationControl bodyRotationControl;
    protected PathNavigation navigation;
    protected final GoalSelector goalSelector;
    protected final GoalSelector targetSelector;
    private LivingEntity target;
    private final Sensing sensing;
    private final NonNullList<ItemStack> handItems;
    protected final float[] handDropChances;
    private final NonNullList<ItemStack> armorItems;
    protected final float[] armorDropChances;
    private boolean canPickUpLoot;
    private boolean persistenceRequired;
    private final Map<BlockPathTypes, Float> pathfindingMalus;
    private ResourceLocation lootTable;
    private long lootTableSeed;
    @Nullable
    private Entity leashHolder;
    private int delayedLeashHolderId;
    @Nullable
    private CompoundTag leashInfoTag;
    private BlockPos restrictCenter;
    private float restrictRadius;
    
    protected Mob(final EntityType<? extends Mob> aku, final Level bjw) {
        super(aku, bjw);
        this.handItems = NonNullList.<ItemStack>withSize(2, ItemStack.EMPTY);
        this.handDropChances = new float[2];
        this.armorItems = NonNullList.<ItemStack>withSize(4, ItemStack.EMPTY);
        this.armorDropChances = new float[4];
        this.pathfindingMalus = Maps.newEnumMap(BlockPathTypes.class);
        this.restrictCenter = BlockPos.ZERO;
        this.restrictRadius = -1.0f;
        this.goalSelector = new GoalSelector((bjw == null || bjw.getProfiler() == null) ? null : bjw.getProfiler());
        this.targetSelector = new GoalSelector((bjw == null || bjw.getProfiler() == null) ? null : bjw.getProfiler());
        this.lookControl = new LookControl(this);
        this.moveControl = new MoveControl(this);
        this.jumpControl = new JumpControl(this);
        this.bodyRotationControl = this.createBodyControl();
        this.navigation = this.createNavigation(bjw);
        this.sensing = new Sensing(this);
        Arrays.fill(this.armorDropChances, 0.085f);
        Arrays.fill(this.handDropChances, 0.085f);
        if (bjw != null && !bjw.isClientSide) {
            this.registerGoals();
        }
    }
    
    protected void registerGoals() {
    }
    
    @Override
    protected void registerAttributes() {
        super.registerAttributes();
        this.getAttributes().registerAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(16.0);
        this.getAttributes().registerAttribute(SharedMonsterAttributes.ATTACK_KNOCKBACK);
    }
    
    protected PathNavigation createNavigation(final Level bjw) {
        return new GroundPathNavigation(this, bjw);
    }
    
    public float getPathfindingMalus(final BlockPathTypes cqm) {
        final Float float3 = this.pathfindingMalus.get(cqm);
        return (float3 == null) ? cqm.getMalus() : float3;
    }
    
    public void setPathfindingMalus(final BlockPathTypes cqm, final float float2) {
        this.pathfindingMalus.put(cqm, float2);
    }
    
    protected BodyRotationControl createBodyControl() {
        return new BodyRotationControl(this);
    }
    
    public LookControl getLookControl() {
        return this.lookControl;
    }
    
    public MoveControl getMoveControl() {
        if (this.isPassenger() && this.getVehicle() instanceof Mob) {
            final Mob ala2 = (Mob)this.getVehicle();
            return ala2.getMoveControl();
        }
        return this.moveControl;
    }
    
    public JumpControl getJumpControl() {
        return this.jumpControl;
    }
    
    public PathNavigation getNavigation() {
        if (this.isPassenger() && this.getVehicle() instanceof Mob) {
            final Mob ala2 = (Mob)this.getVehicle();
            return ala2.getNavigation();
        }
        return this.navigation;
    }
    
    public Sensing getSensing() {
        return this.sensing;
    }
    
    @Nullable
    public LivingEntity getTarget() {
        return this.target;
    }
    
    public void setTarget(@Nullable final LivingEntity akz) {
        this.target = akz;
    }
    
    @Override
    public boolean canAttackType(final EntityType<?> aku) {
        return aku != EntityType.GHAST;
    }
    
    public void ate() {
    }
    
    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        this.entityData.<Byte>define(Mob.DATA_MOB_FLAGS_ID, (Byte)0);
    }
    
    public int getAmbientSoundInterval() {
        return 80;
    }
    
    public void playAmbientSound() {
        final SoundEvent aah2 = this.getAmbientSound();
        if (aah2 != null) {
            this.playSound(aah2, this.getSoundVolume(), this.getVoicePitch());
        }
    }
    
    @Override
    public void baseTick() {
        super.baseTick();
        this.level.getProfiler().push("mobBaseTick");
        if (this.isAlive() && this.random.nextInt(1000) < this.ambientSoundTime++) {
            this.resetAmbientSoundTime();
            this.playAmbientSound();
        }
        this.level.getProfiler().pop();
    }
    
    @Override
    protected void playHurtSound(final DamageSource ajz) {
        this.resetAmbientSoundTime();
        super.playHurtSound(ajz);
    }
    
    private void resetAmbientSoundTime() {
        this.ambientSoundTime = -this.getAmbientSoundInterval();
    }
    
    @Override
    protected int getExperienceReward(final Player ayj) {
        if (this.xpReward > 0) {
            int integer3 = this.xpReward;
            for (int integer4 = 0; integer4 < this.armorItems.size(); ++integer4) {
                if (!this.armorItems.get(integer4).isEmpty() && this.armorDropChances[integer4] <= 1.0f) {
                    integer3 += 1 + this.random.nextInt(3);
                }
            }
            for (int integer4 = 0; integer4 < this.handItems.size(); ++integer4) {
                if (!this.handItems.get(integer4).isEmpty() && this.handDropChances[integer4] <= 1.0f) {
                    integer3 += 1 + this.random.nextInt(3);
                }
            }
            return integer3;
        }
        return this.xpReward;
    }
    
    public void spawnAnim() {
        if (this.level.isClientSide) {
            for (int integer2 = 0; integer2 < 20; ++integer2) {
                final double double3 = this.random.nextGaussian() * 0.02;
                final double double4 = this.random.nextGaussian() * 0.02;
                final double double5 = this.random.nextGaussian() * 0.02;
                final double double6 = 10.0;
                this.level.addParticle(ParticleTypes.POOF, this.getX(1.0) - double3 * 10.0, this.getRandomY() - double4 * 10.0, this.getRandomZ(1.0) - double5 * 10.0, double3, double4, double5);
            }
        }
        else {
            this.level.broadcastEntityEvent(this, (byte)20);
        }
    }
    
    @Override
    public void handleEntityEvent(final byte byte1) {
        if (byte1 == 20) {
            this.spawnAnim();
        }
        else {
            super.handleEntityEvent(byte1);
        }
    }
    
    @Override
    public void tick() {
        super.tick();
        if (!this.level.isClientSide) {
            this.tickLeash();
            if (this.tickCount % 5 == 0) {
                this.updateControlFlags();
            }
        }
    }
    
    protected void updateControlFlags() {
        final boolean boolean2 = !(this.getControllingPassenger() instanceof Mob);
        final boolean boolean3 = !(this.getVehicle() instanceof Boat);
        this.goalSelector.setControlFlag(Goal.Flag.MOVE, boolean2);
        this.goalSelector.setControlFlag(Goal.Flag.JUMP, boolean2 && boolean3);
        this.goalSelector.setControlFlag(Goal.Flag.LOOK, boolean2);
    }
    
    @Override
    protected float tickHeadTurn(final float float1, final float float2) {
        this.bodyRotationControl.clientTick();
        return float2;
    }
    
    @Nullable
    protected SoundEvent getAmbientSound() {
        return null;
    }
    
    @Override
    public void addAdditionalSaveData(final CompoundTag jt) {
        super.addAdditionalSaveData(jt);
        jt.putBoolean("CanPickUpLoot", this.canPickUpLoot());
        jt.putBoolean("PersistenceRequired", this.persistenceRequired);
        final ListTag jz3 = new ListTag();
        for (final ItemStack ben5 : this.armorItems) {
            final CompoundTag jt2 = new CompoundTag();
            if (!ben5.isEmpty()) {
                ben5.save(jt2);
            }
            ((AbstractList<CompoundTag>)jz3).add(jt2);
        }
        jt.put("ArmorItems", jz3);
        final ListTag jz4 = new ListTag();
        for (final ItemStack ben6 : this.handItems) {
            final CompoundTag jt3 = new CompoundTag();
            if (!ben6.isEmpty()) {
                ben6.save(jt3);
            }
            ((AbstractList<CompoundTag>)jz4).add(jt3);
        }
        jt.put("HandItems", jz4);
        final ListTag jz5 = new ListTag();
        for (final float float9 : this.armorDropChances) {
            ((AbstractList<FloatTag>)jz5).add(FloatTag.valueOf(float9));
        }
        jt.put("ArmorDropChances", jz5);
        final ListTag jz6 = new ListTag();
        for (final float float10 : this.handDropChances) {
            ((AbstractList<FloatTag>)jz6).add(FloatTag.valueOf(float10));
        }
        jt.put("HandDropChances", jz6);
        if (this.leashHolder != null) {
            final CompoundTag jt3 = new CompoundTag();
            if (this.leashHolder instanceof LivingEntity) {
                final UUID uUID8 = this.leashHolder.getUUID();
                jt3.putUUID("UUID", uUID8);
            }
            else if (this.leashHolder instanceof HangingEntity) {
                final BlockPos fk8 = ((HangingEntity)this.leashHolder).getPos();
                jt3.putInt("X", fk8.getX());
                jt3.putInt("Y", fk8.getY());
                jt3.putInt("Z", fk8.getZ());
            }
            jt.put("Leash", jt3);
        }
        else if (this.leashInfoTag != null) {
            jt.put("Leash", this.leashInfoTag.copy());
        }
        jt.putBoolean("LeftHanded", this.isLeftHanded());
        if (this.lootTable != null) {
            jt.putString("DeathLootTable", this.lootTable.toString());
            if (this.lootTableSeed != 0L) {
                jt.putLong("DeathLootTableSeed", this.lootTableSeed);
            }
        }
        if (this.isNoAi()) {
            jt.putBoolean("NoAI", this.isNoAi());
        }
    }
    
    @Override
    public void readAdditionalSaveData(final CompoundTag jt) {
        super.readAdditionalSaveData(jt);
        if (jt.contains("CanPickUpLoot", 1)) {
            this.setCanPickUpLoot(jt.getBoolean("CanPickUpLoot"));
        }
        this.persistenceRequired = jt.getBoolean("PersistenceRequired");
        if (jt.contains("ArmorItems", 9)) {
            final ListTag jz3 = jt.getList("ArmorItems", 10);
            for (int integer4 = 0; integer4 < this.armorItems.size(); ++integer4) {
                this.armorItems.set(integer4, ItemStack.of(jz3.getCompound(integer4)));
            }
        }
        if (jt.contains("HandItems", 9)) {
            final ListTag jz3 = jt.getList("HandItems", 10);
            for (int integer4 = 0; integer4 < this.handItems.size(); ++integer4) {
                this.handItems.set(integer4, ItemStack.of(jz3.getCompound(integer4)));
            }
        }
        if (jt.contains("ArmorDropChances", 9)) {
            final ListTag jz3 = jt.getList("ArmorDropChances", 5);
            for (int integer4 = 0; integer4 < jz3.size(); ++integer4) {
                this.armorDropChances[integer4] = jz3.getFloat(integer4);
            }
        }
        if (jt.contains("HandDropChances", 9)) {
            final ListTag jz3 = jt.getList("HandDropChances", 5);
            for (int integer4 = 0; integer4 < jz3.size(); ++integer4) {
                this.handDropChances[integer4] = jz3.getFloat(integer4);
            }
        }
        if (jt.contains("Leash", 10)) {
            this.leashInfoTag = jt.getCompound("Leash");
        }
        this.setLeftHanded(jt.getBoolean("LeftHanded"));
        if (jt.contains("DeathLootTable", 8)) {
            this.lootTable = new ResourceLocation(jt.getString("DeathLootTable"));
            this.lootTableSeed = jt.getLong("DeathLootTableSeed");
        }
        this.setNoAi(jt.getBoolean("NoAI"));
    }
    
    @Override
    protected void dropFromLootTable(final DamageSource ajz, final boolean boolean2) {
        super.dropFromLootTable(ajz, boolean2);
        this.lootTable = null;
    }
    
    @Override
    protected LootContext.Builder createLootContext(final boolean boolean1, final DamageSource ajz) {
        return super.createLootContext(boolean1, ajz).withOptionalRandomSeed(this.lootTableSeed, this.random);
    }
    
    @Override
    public final ResourceLocation getLootTable() {
        return (this.lootTable == null) ? this.getDefaultLootTable() : this.lootTable;
    }
    
    protected ResourceLocation getDefaultLootTable() {
        return super.getLootTable();
    }
    
    public void setZza(final float float1) {
        this.zza = float1;
    }
    
    public void setYya(final float float1) {
        this.yya = float1;
    }
    
    public void setXxa(final float float1) {
        this.xxa = float1;
    }
    
    @Override
    public void setSpeed(final float float1) {
        super.setSpeed(float1);
        this.setZza(float1);
    }
    
    @Override
    public void aiStep() {
        super.aiStep();
        this.level.getProfiler().push("looting");
        if (!this.level.isClientSide && this.canPickUpLoot() && this.isAlive() && !this.dead && this.level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
            final List<ItemEntity> list2 = this.level.<ItemEntity>getEntitiesOfClass(ItemEntity.class, this.getBoundingBox().inflate(1.0, 0.0, 1.0));
            for (final ItemEntity awb4 : list2) {
                if (!awb4.removed && !awb4.getItem().isEmpty()) {
                    if (awb4.hasPickUpDelay()) {
                        continue;
                    }
                    this.pickUpItem(awb4);
                }
            }
        }
        this.level.getProfiler().pop();
    }
    
    protected void pickUpItem(final ItemEntity awb) {
        final ItemStack ben3 = awb.getItem();
        final EquipmentSlot akv4 = getEquipmentSlotForItem(ben3);
        final ItemStack ben4 = this.getItemBySlot(akv4);
        final boolean boolean6 = this.canReplaceCurrentItem(ben3, ben4, akv4);
        if (boolean6 && this.canHoldItem(ben3)) {
            final double double7 = this.getEquipmentDropChance(akv4);
            if (!ben4.isEmpty() && Math.max(this.random.nextFloat() - 0.1f, 0.0f) < double7) {
                this.spawnAtLocation(ben4);
            }
            this.setItemSlot(akv4, ben3);
            switch (akv4.getType()) {
                case HAND: {
                    this.handDropChances[akv4.getIndex()] = 2.0f;
                    break;
                }
                case ARMOR: {
                    this.armorDropChances[akv4.getIndex()] = 2.0f;
                    break;
                }
            }
            this.persistenceRequired = true;
            this.take(awb, ben3.getCount());
            awb.remove();
        }
    }
    
    protected boolean canReplaceCurrentItem(final ItemStack ben1, final ItemStack ben2, final EquipmentSlot akv) {
        boolean boolean5 = true;
        if (!ben2.isEmpty()) {
            if (akv.getType() == EquipmentSlot.Type.HAND) {
                if (ben1.getItem() instanceof SwordItem && !(ben2.getItem() instanceof SwordItem)) {
                    boolean5 = true;
                }
                else if (ben1.getItem() instanceof SwordItem && ben2.getItem() instanceof SwordItem) {
                    final SwordItem bfq6 = (SwordItem)ben1.getItem();
                    final SwordItem bfq7 = (SwordItem)ben2.getItem();
                    if (bfq6.getDamage() == bfq7.getDamage()) {
                        boolean5 = (ben1.getDamageValue() < ben2.getDamageValue() || (ben1.hasTag() && !ben2.hasTag()));
                    }
                    else {
                        boolean5 = (bfq6.getDamage() > bfq7.getDamage());
                    }
                }
                else {
                    boolean5 = (ben1.getItem() instanceof BowItem && ben2.getItem() instanceof BowItem && ben1.hasTag() && !ben2.hasTag());
                }
            }
            else if (ben1.getItem() instanceof ArmorItem && !(ben2.getItem() instanceof ArmorItem)) {
                boolean5 = true;
            }
            else if (ben1.getItem() instanceof ArmorItem && ben2.getItem() instanceof ArmorItem && !EnchantmentHelper.hasBindingCurse(ben2)) {
                final ArmorItem bcg6 = (ArmorItem)ben1.getItem();
                final ArmorItem bcg7 = (ArmorItem)ben2.getItem();
                if (bcg6.getDefense() == bcg7.getDefense()) {
                    boolean5 = (ben1.getDamageValue() < ben2.getDamageValue() || (ben1.hasTag() && !ben2.hasTag()));
                }
                else {
                    boolean5 = (bcg6.getDefense() > bcg7.getDefense());
                }
            }
            else {
                boolean5 = false;
            }
        }
        return boolean5;
    }
    
    protected boolean canHoldItem(final ItemStack ben) {
        return true;
    }
    
    public boolean removeWhenFarAway(final double double1) {
        return true;
    }
    
    public boolean requiresCustomPersistence() {
        return false;
    }
    
    protected boolean shouldDespawnInPeaceful() {
        return false;
    }
    
    @Override
    public void checkDespawn() {
        if (this.level.getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) {
            this.remove();
            return;
        }
        if (this.isPersistenceRequired() || this.requiresCustomPersistence()) {
            this.noActionTime = 0;
            return;
        }
        final Entity akq2 = this.level.getNearestPlayer(this, -1.0);
        if (akq2 != null) {
            final double double3 = akq2.distanceToSqr(this);
            if (double3 > 16384.0 && this.removeWhenFarAway(double3)) {
                this.remove();
            }
            if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && double3 > 1024.0 && this.removeWhenFarAway(double3)) {
                this.remove();
            }
            else if (double3 < 1024.0) {
                this.noActionTime = 0;
            }
        }
    }
    
    @Override
    protected final void serverAiStep() {
        ++this.noActionTime;
        this.level.getProfiler().push("sensing");
        this.sensing.tick();
        this.level.getProfiler().pop();
        this.level.getProfiler().push("targetSelector");
        this.targetSelector.tick();
        this.level.getProfiler().pop();
        this.level.getProfiler().push("goalSelector");
        this.goalSelector.tick();
        this.level.getProfiler().pop();
        this.level.getProfiler().push("navigation");
        this.navigation.tick();
        this.level.getProfiler().pop();
        this.level.getProfiler().push("mob tick");
        this.customServerAiStep();
        this.level.getProfiler().pop();
        this.level.getProfiler().push("controls");
        this.level.getProfiler().push("move");
        this.moveControl.tick();
        this.level.getProfiler().popPush("look");
        this.lookControl.tick();
        this.level.getProfiler().popPush("jump");
        this.jumpControl.tick();
        this.level.getProfiler().pop();
        this.level.getProfiler().pop();
        this.sendDebugPackets();
    }
    
    protected void sendDebugPackets() {
        DebugPackets.sendGoalSelector(this.level, this, this.goalSelector);
    }
    
    protected void customServerAiStep() {
    }
    
    public int getMaxHeadXRot() {
        return 40;
    }
    
    public int getMaxHeadYRot() {
        return 75;
    }
    
    public int getHeadRotSpeed() {
        return 10;
    }
    
    public void lookAt(final Entity akq, final float float2, final float float3) {
        final double double5 = akq.getX() - this.getX();
        final double double6 = akq.getZ() - this.getZ();
        double double7;
        if (akq instanceof LivingEntity) {
            final LivingEntity akz11 = (LivingEntity)akq;
            double7 = akz11.getEyeY() - this.getEyeY();
        }
        else {
            double7 = (akq.getBoundingBox().minY + akq.getBoundingBox().maxY) / 2.0 - this.getEyeY();
        }
        final double double8 = Mth.sqrt(double5 * double5 + double6 * double6);
        final float float4 = (float)(Mth.atan2(double6, double5) * 57.2957763671875) - 90.0f;
        final float float5 = (float)(-(Mth.atan2(double7, double8) * 57.2957763671875));
        this.xRot = this.rotlerp(this.xRot, float5, float3);
        this.yRot = this.rotlerp(this.yRot, float4, float2);
    }
    
    private float rotlerp(final float float1, final float float2, final float float3) {
        float float4 = Mth.wrapDegrees(float2 - float1);
        if (float4 > float3) {
            float4 = float3;
        }
        if (float4 < -float3) {
            float4 = -float3;
        }
        return float1 + float4;
    }
    
    public static boolean checkMobSpawnRules(final EntityType<? extends Mob> aku, final LevelAccessor bjx, final MobSpawnType alc, final BlockPos fk, final Random random) {
        final BlockPos fk2 = fk.below();
        return alc == MobSpawnType.SPAWNER || bjx.getBlockState(fk2).isValidSpawn(bjx, fk2, aku);
    }
    
    public boolean checkSpawnRules(final LevelAccessor bjx, final MobSpawnType alc) {
        return true;
    }
    
    public boolean checkSpawnObstruction(final LevelReader bjz) {
        return !bjz.containsAnyLiquid(this.getBoundingBox()) && bjz.isUnobstructed(this);
    }
    
    public int getMaxSpawnClusterSize() {
        return 4;
    }
    
    public boolean isMaxGroupSizeReached(final int integer) {
        return false;
    }
    
    @Override
    public int getMaxFallDistance() {
        if (this.getTarget() == null) {
            return 3;
        }
        int integer2 = (int)(this.getHealth() - this.getMaxHealth() * 0.33f);
        integer2 -= (3 - this.level.getDifficulty().getId()) * 4;
        if (integer2 < 0) {
            integer2 = 0;
        }
        return integer2 + 3;
    }
    
    @Override
    public Iterable<ItemStack> getHandSlots() {
        return this.handItems;
    }
    
    @Override
    public Iterable<ItemStack> getArmorSlots() {
        return this.armorItems;
    }
    
    @Override
    public ItemStack getItemBySlot(final EquipmentSlot akv) {
        switch (akv.getType()) {
            case HAND: {
                return this.handItems.get(akv.getIndex());
            }
            case ARMOR: {
                return this.armorItems.get(akv.getIndex());
            }
            default: {
                return ItemStack.EMPTY;
            }
        }
    }
    
    @Override
    public void setItemSlot(final EquipmentSlot akv, final ItemStack ben) {
        switch (akv.getType()) {
            case HAND: {
                this.handItems.set(akv.getIndex(), ben);
                break;
            }
            case ARMOR: {
                this.armorItems.set(akv.getIndex(), ben);
                break;
            }
        }
    }
    
    @Override
    protected void dropCustomDeathLoot(final DamageSource ajz, final int integer, final boolean boolean3) {
        super.dropCustomDeathLoot(ajz, integer, boolean3);
        for (final EquipmentSlot akv8 : EquipmentSlot.values()) {
            final ItemStack ben9 = this.getItemBySlot(akv8);
            final float float10 = this.getEquipmentDropChance(akv8);
            final boolean boolean4 = float10 > 1.0f;
            if (!ben9.isEmpty() && !EnchantmentHelper.hasVanishingCurse(ben9) && (boolean3 || boolean4) && Math.max(this.random.nextFloat() - integer * 0.01f, 0.0f) < float10) {
                if (!boolean4 && ben9.isDamageableItem()) {
                    ben9.setDamageValue(ben9.getMaxDamage() - this.random.nextInt(1 + this.random.nextInt(Math.max(ben9.getMaxDamage() - 3, 1))));
                }
                this.spawnAtLocation(ben9);
            }
        }
    }
    
    protected float getEquipmentDropChance(final EquipmentSlot akv) {
        float float3 = 0.0f;
        switch (akv.getType()) {
            case HAND: {
                float3 = this.handDropChances[akv.getIndex()];
                break;
            }
            case ARMOR: {
                float3 = this.armorDropChances[akv.getIndex()];
                break;
            }
            default: {
                float3 = 0.0f;
                break;
            }
        }
        return float3;
    }
    
    protected void populateDefaultEquipmentSlots(final DifficultyInstance ajj) {
        if (this.random.nextFloat() < 0.15f * ajj.getSpecialMultiplier()) {
            int integer3 = this.random.nextInt(2);
            final float float4 = (this.level.getDifficulty() == Difficulty.HARD) ? 0.1f : 0.25f;
            if (this.random.nextFloat() < 0.095f) {
                ++integer3;
            }
            if (this.random.nextFloat() < 0.095f) {
                ++integer3;
            }
            if (this.random.nextFloat() < 0.095f) {
                ++integer3;
            }
            boolean boolean5 = true;
            for (final EquipmentSlot akv9 : EquipmentSlot.values()) {
                if (akv9.getType() == EquipmentSlot.Type.ARMOR) {
                    final ItemStack ben10 = this.getItemBySlot(akv9);
                    if (!boolean5 && this.random.nextFloat() < float4) {
                        break;
                    }
                    boolean5 = false;
                    if (ben10.isEmpty()) {
                        final Item bei11 = getEquipmentForSlot(akv9, integer3);
                        if (bei11 != null) {
                            this.setItemSlot(akv9, new ItemStack(bei11));
                        }
                    }
                }
            }
        }
    }
    
    public static EquipmentSlot getEquipmentSlotForItem(final ItemStack ben) {
        final Item bei2 = ben.getItem();
        if (bei2 == Blocks.CARVED_PUMPKIN.asItem() || (bei2 instanceof BlockItem && ((BlockItem)bei2).getBlock() instanceof AbstractSkullBlock)) {
            return EquipmentSlot.HEAD;
        }
        if (bei2 instanceof ArmorItem) {
            return ((ArmorItem)bei2).getSlot();
        }
        if (bei2 == Items.ELYTRA) {
            return EquipmentSlot.CHEST;
        }
        if (bei2 == Items.SHIELD) {
            return EquipmentSlot.OFFHAND;
        }
        return EquipmentSlot.MAINHAND;
    }
    
    @Nullable
    public static Item getEquipmentForSlot(final EquipmentSlot akv, final int integer) {
        switch (akv) {
            case HEAD: {
                if (integer == 0) {
                    return Items.LEATHER_HELMET;
                }
                if (integer == 1) {
                    return Items.GOLDEN_HELMET;
                }
                if (integer == 2) {
                    return Items.CHAINMAIL_HELMET;
                }
                if (integer == 3) {
                    return Items.IRON_HELMET;
                }
                if (integer == 4) {
                    return Items.DIAMOND_HELMET;
                }
            }
            case CHEST: {
                if (integer == 0) {
                    return Items.LEATHER_CHESTPLATE;
                }
                if (integer == 1) {
                    return Items.GOLDEN_CHESTPLATE;
                }
                if (integer == 2) {
                    return Items.CHAINMAIL_CHESTPLATE;
                }
                if (integer == 3) {
                    return Items.IRON_CHESTPLATE;
                }
                if (integer == 4) {
                    return Items.DIAMOND_CHESTPLATE;
                }
            }
            case LEGS: {
                if (integer == 0) {
                    return Items.LEATHER_LEGGINGS;
                }
                if (integer == 1) {
                    return Items.GOLDEN_LEGGINGS;
                }
                if (integer == 2) {
                    return Items.CHAINMAIL_LEGGINGS;
                }
                if (integer == 3) {
                    return Items.IRON_LEGGINGS;
                }
                if (integer == 4) {
                    return Items.DIAMOND_LEGGINGS;
                }
            }
            case FEET: {
                if (integer == 0) {
                    return Items.LEATHER_BOOTS;
                }
                if (integer == 1) {
                    return Items.GOLDEN_BOOTS;
                }
                if (integer == 2) {
                    return Items.CHAINMAIL_BOOTS;
                }
                if (integer == 3) {
                    return Items.IRON_BOOTS;
                }
                if (integer == 4) {
                    return Items.DIAMOND_BOOTS;
                }
                break;
            }
        }
        return null;
    }
    
    protected void populateDefaultEquipmentEnchantments(final DifficultyInstance ajj) {
        final float float3 = ajj.getSpecialMultiplier();
        if (!this.getMainHandItem().isEmpty() && this.random.nextFloat() < 0.25f * float3) {
            this.setItemSlot(EquipmentSlot.MAINHAND, EnchantmentHelper.enchantItem(this.random, this.getMainHandItem(), (int)(5.0f + float3 * this.random.nextInt(18)), false));
        }
        for (final EquipmentSlot akv7 : EquipmentSlot.values()) {
            if (akv7.getType() == EquipmentSlot.Type.ARMOR) {
                final ItemStack ben8 = this.getItemBySlot(akv7);
                if (!ben8.isEmpty() && this.random.nextFloat() < 0.5f * float3) {
                    this.setItemSlot(akv7, EnchantmentHelper.enchantItem(this.random, ben8, (int)(5.0f + float3 * this.random.nextInt(18)), false));
                }
            }
        }
    }
    
    @Nullable
    public SpawnGroupData finalizeSpawn(final LevelAccessor bjx, final DifficultyInstance ajj, final MobSpawnType alc, @Nullable final SpawnGroupData alm, @Nullable final CompoundTag jt) {
        this.getAttribute(SharedMonsterAttributes.FOLLOW_RANGE).addModifier(new AttributeModifier("Random spawn bonus", this.random.nextGaussian() * 0.05, AttributeModifier.Operation.MULTIPLY_BASE));
        if (this.random.nextFloat() < 0.05f) {
            this.setLeftHanded(true);
        }
        else {
            this.setLeftHanded(false);
        }
        return alm;
    }
    
    public boolean canBeControlledByRider() {
        return false;
    }
    
    public void setPersistenceRequired() {
        this.persistenceRequired = true;
    }
    
    public void setDropChance(final EquipmentSlot akv, final float float2) {
        switch (akv.getType()) {
            case HAND: {
                this.handDropChances[akv.getIndex()] = float2;
                break;
            }
            case ARMOR: {
                this.armorDropChances[akv.getIndex()] = float2;
                break;
            }
        }
    }
    
    public boolean canPickUpLoot() {
        return this.canPickUpLoot;
    }
    
    public void setCanPickUpLoot(final boolean boolean1) {
        this.canPickUpLoot = boolean1;
    }
    
    @Override
    public boolean canTakeItem(final ItemStack ben) {
        final EquipmentSlot akv3 = getEquipmentSlotForItem(ben);
        return this.getItemBySlot(akv3).isEmpty() && this.canPickUpLoot();
    }
    
    public boolean isPersistenceRequired() {
        return this.persistenceRequired;
    }
    
    @Override
    public final boolean interact(final Player ayj, final InteractionHand ajk) {
        if (!this.isAlive()) {
            return false;
        }
        if (this.getLeashHolder() == ayj) {
            this.dropLeash(true, !ayj.abilities.instabuild);
            return true;
        }
        final ItemStack ben4 = ayj.getItemInHand(ajk);
        if (ben4.getItem() == Items.LEAD && this.canBeLeashed(ayj)) {
            this.setLeashedTo(ayj, true);
            ben4.shrink(1);
            return true;
        }
        return this.mobInteract(ayj, ajk) || super.interact(ayj, ajk);
    }
    
    protected boolean mobInteract(final Player ayj, final InteractionHand ajk) {
        return false;
    }
    
    public boolean isWithinRestriction() {
        return this.isWithinRestriction(new BlockPos(this));
    }
    
    public boolean isWithinRestriction(final BlockPos fk) {
        return this.restrictRadius == -1.0f || this.restrictCenter.distSqr(fk) < this.restrictRadius * this.restrictRadius;
    }
    
    public void restrictTo(final BlockPos fk, final int integer) {
        this.restrictCenter = fk;
        this.restrictRadius = (float)integer;
    }
    
    public BlockPos getRestrictCenter() {
        return this.restrictCenter;
    }
    
    public float getRestrictRadius() {
        return this.restrictRadius;
    }
    
    public boolean hasRestriction() {
        return this.restrictRadius != -1.0f;
    }
    
    protected void tickLeash() {
        if (this.leashInfoTag != null) {
            this.restoreLeashFromSave();
        }
        if (this.leashHolder == null) {
            return;
        }
        if (!this.isAlive() || !this.leashHolder.isAlive()) {
            this.dropLeash(true, true);
        }
    }
    
    public void dropLeash(final boolean boolean1, final boolean boolean2) {
        if (this.leashHolder != null) {
            this.forcedLoading = false;
            if (!(this.leashHolder instanceof Player)) {
                this.leashHolder.forcedLoading = false;
            }
            this.leashHolder = null;
            if (!this.level.isClientSide && boolean2) {
                this.spawnAtLocation(Items.LEAD);
            }
            if (!this.level.isClientSide && boolean1 && this.level instanceof ServerLevel) {
                ((ServerLevel)this.level).getChunkSource().broadcast(this, new ClientboundSetEntityLinkPacket(this, null));
            }
        }
    }
    
    public boolean canBeLeashed(final Player ayj) {
        return !this.isLeashed() && !(this instanceof Enemy);
    }
    
    public boolean isLeashed() {
        return this.leashHolder != null;
    }
    
    @Nullable
    public Entity getLeashHolder() {
        if (this.leashHolder == null && this.delayedLeashHolderId != 0 && this.level.isClientSide) {
            this.leashHolder = this.level.getEntity(this.delayedLeashHolderId);
        }
        return this.leashHolder;
    }
    
    public void setLeashedTo(final Entity akq, final boolean boolean2) {
        this.leashHolder = akq;
        this.forcedLoading = true;
        if (!(this.leashHolder instanceof Player)) {
            this.leashHolder.forcedLoading = true;
        }
        if (!this.level.isClientSide && boolean2 && this.level instanceof ServerLevel) {
            ((ServerLevel)this.level).getChunkSource().broadcast(this, new ClientboundSetEntityLinkPacket(this, this.leashHolder));
        }
        if (this.isPassenger()) {
            this.stopRiding();
        }
    }
    
    public void setDelayedLeashHolderId(final int integer) {
        this.delayedLeashHolderId = integer;
        this.dropLeash(false, false);
    }
    
    @Override
    public boolean startRiding(final Entity akq, final boolean boolean2) {
        final boolean boolean3 = super.startRiding(akq, boolean2);
        if (boolean3 && this.isLeashed()) {
            this.dropLeash(true, true);
        }
        return boolean3;
    }
    
    private void restoreLeashFromSave() {
        if (this.leashInfoTag != null && this.level instanceof ServerLevel) {
            if (this.leashInfoTag.hasUUID("UUID")) {
                final UUID uUID2 = this.leashInfoTag.getUUID("UUID");
                final Entity akq3 = ((ServerLevel)this.level).getEntity(uUID2);
                if (akq3 != null) {
                    this.setLeashedTo(akq3, true);
                }
            }
            else if (this.leashInfoTag.contains("X", 99) && this.leashInfoTag.contains("Y", 99) && this.leashInfoTag.contains("Z", 99)) {
                final BlockPos fk2 = new BlockPos(this.leashInfoTag.getInt("X"), this.leashInfoTag.getInt("Y"), this.leashInfoTag.getInt("Z"));
                this.setLeashedTo(LeashFenceKnotEntity.getOrCreateKnot(this.level, fk2), true);
            }
            else {
                this.dropLeash(false, true);
            }
            this.leashInfoTag = null;
        }
    }
    
    @Override
    public boolean setSlot(final int integer, final ItemStack ben) {
        EquipmentSlot akv4;
        if (integer == 98) {
            akv4 = EquipmentSlot.MAINHAND;
        }
        else if (integer == 99) {
            akv4 = EquipmentSlot.OFFHAND;
        }
        else if (integer == 100 + EquipmentSlot.HEAD.getIndex()) {
            akv4 = EquipmentSlot.HEAD;
        }
        else if (integer == 100 + EquipmentSlot.CHEST.getIndex()) {
            akv4 = EquipmentSlot.CHEST;
        }
        else if (integer == 100 + EquipmentSlot.LEGS.getIndex()) {
            akv4 = EquipmentSlot.LEGS;
        }
        else {
            if (integer != 100 + EquipmentSlot.FEET.getIndex()) {
                return false;
            }
            akv4 = EquipmentSlot.FEET;
        }
        if (ben.isEmpty() || isValidSlotForItem(akv4, ben) || akv4 == EquipmentSlot.HEAD) {
            this.setItemSlot(akv4, ben);
            return true;
        }
        return false;
    }
    
    @Override
    public boolean isControlledByLocalInstance() {
        return this.canBeControlledByRider() && super.isControlledByLocalInstance();
    }
    
    public static boolean isValidSlotForItem(final EquipmentSlot akv, final ItemStack ben) {
        final EquipmentSlot akv2 = getEquipmentSlotForItem(ben);
        return akv2 == akv || (akv2 == EquipmentSlot.MAINHAND && akv == EquipmentSlot.OFFHAND) || (akv2 == EquipmentSlot.OFFHAND && akv == EquipmentSlot.MAINHAND);
    }
    
    @Override
    public boolean isEffectiveAi() {
        return super.isEffectiveAi() && !this.isNoAi();
    }
    
    public void setNoAi(final boolean boolean1) {
        final byte byte3 = this.entityData.<Byte>get(Mob.DATA_MOB_FLAGS_ID);
        this.entityData.<Byte>set(Mob.DATA_MOB_FLAGS_ID, boolean1 ? ((byte)(byte3 | 0x1)) : ((byte)(byte3 & 0xFFFFFFFE)));
    }
    
    public void setLeftHanded(final boolean boolean1) {
        final byte byte3 = this.entityData.<Byte>get(Mob.DATA_MOB_FLAGS_ID);
        this.entityData.<Byte>set(Mob.DATA_MOB_FLAGS_ID, boolean1 ? ((byte)(byte3 | 0x2)) : ((byte)(byte3 & 0xFFFFFFFD)));
    }
    
    public void setAggressive(final boolean boolean1) {
        final byte byte3 = this.entityData.<Byte>get(Mob.DATA_MOB_FLAGS_ID);
        this.entityData.<Byte>set(Mob.DATA_MOB_FLAGS_ID, boolean1 ? ((byte)(byte3 | 0x4)) : ((byte)(byte3 & 0xFFFFFFFB)));
    }
    
    public boolean isNoAi() {
        return (this.entityData.<Byte>get(Mob.DATA_MOB_FLAGS_ID) & 0x1) != 0x0;
    }
    
    public boolean isLeftHanded() {
        return (this.entityData.<Byte>get(Mob.DATA_MOB_FLAGS_ID) & 0x2) != 0x0;
    }
    
    public boolean isAggressive() {
        return (this.entityData.<Byte>get(Mob.DATA_MOB_FLAGS_ID) & 0x4) != 0x0;
    }
    
    @Override
    public HumanoidArm getMainArm() {
        return this.isLeftHanded() ? HumanoidArm.LEFT : HumanoidArm.RIGHT;
    }
    
    @Override
    public boolean canAttack(final LivingEntity akz) {
        return (akz.getType() != EntityType.PLAYER || !((Player)akz).abilities.invulnerable) && super.canAttack(akz);
    }
    
    @Override
    public boolean doHurtTarget(final Entity akq) {
        float float3 = (float)this.getAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).getValue();
        float float4 = (float)this.getAttribute(SharedMonsterAttributes.ATTACK_KNOCKBACK).getValue();
        if (akq instanceof LivingEntity) {
            float3 += EnchantmentHelper.getDamageBonus(this.getMainHandItem(), ((LivingEntity)akq).getMobType());
            float4 += EnchantmentHelper.getKnockbackBonus(this);
        }
        final int integer5 = EnchantmentHelper.getFireAspect(this);
        if (integer5 > 0) {
            akq.setSecondsOnFire(integer5 * 4);
        }
        final boolean boolean6 = akq.hurt(DamageSource.mobAttack(this), float3);
        if (boolean6) {
            if (float4 > 0.0f && akq instanceof LivingEntity) {
                ((LivingEntity)akq).knockback(this, float4 * 0.5f, Mth.sin(this.yRot * 0.017453292f), -Mth.cos(this.yRot * 0.017453292f));
                this.setDeltaMovement(this.getDeltaMovement().multiply(0.6, 1.0, 0.6));
            }
            if (akq instanceof Player) {
                final Player ayj7 = (Player)akq;
                final ItemStack ben8 = this.getMainHandItem();
                final ItemStack ben9 = ayj7.isUsingItem() ? ayj7.getUseItem() : ItemStack.EMPTY;
                if (!ben8.isEmpty() && !ben9.isEmpty() && ben8.getItem() instanceof AxeItem && ben9.getItem() == Items.SHIELD) {
                    final float float5 = 0.25f + EnchantmentHelper.getBlockEfficiency(this) * 0.05f;
                    if (this.random.nextFloat() < float5) {
                        ayj7.getCooldowns().addCooldown(Items.SHIELD, 100);
                        this.level.broadcastEntityEvent(ayj7, (byte)30);
                    }
                }
            }
            this.doEnchantDamageEffects(this, akq);
            this.setLastHurtMob(akq);
        }
        return boolean6;
    }
    
    protected boolean isSunBurnTick() {
        if (this.level.isDay() && !this.level.isClientSide) {
            final float float2 = this.getBrightness();
            final BlockPos fk3 = (this.getVehicle() instanceof Boat) ? new BlockPos(this.getX(), (double)Math.round(this.getY()), this.getZ()).above() : new BlockPos(this.getX(), (double)Math.round(this.getY()), this.getZ());
            if (float2 > 0.5f && this.random.nextFloat() * 30.0f < (float2 - 0.4f) * 2.0f && this.level.canSeeSky(fk3)) {
                return true;
            }
        }
        return false;
    }
    
    @Override
    protected void jumpInLiquid(final net.minecraft.tags.Tag<Fluid> aaz) {
        if (this.getNavigation().canFloat()) {
            super.jumpInLiquid(aaz);
        }
        else {
            this.setDeltaMovement(this.getDeltaMovement().add(0.0, 0.3, 0.0));
        }
    }
    
    public boolean isHolding(final Item bei) {
        return this.getMainHandItem().getItem() == bei || this.getOffhandItem().getItem() == bei;
    }
    
    static {
        DATA_MOB_FLAGS_ID = SynchedEntityData.<Byte>defineId(Mob.class, EntityDataSerializers.BYTE);
    }
}
