/* * Decompiled with CFR 0.152. * * Could not load the following classes: * org.jspecify.annotations.Nullable */ package net.minecraft.world.entity.animal; import java.util.List; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.tags.BiomeTags; import net.minecraft.tags.BlockTags; import net.minecraft.tags.DamageTypeTags; import net.minecraft.util.Mth; import net.minecraft.util.RandomSource; import net.minecraft.util.TimeUtil; import net.minecraft.util.valueproviders.UniformInt; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.AgeableMob; import net.minecraft.world.entity.EntityDimensions; import net.minecraft.world.entity.EntityReference; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.NeutralMob; import net.minecraft.world.entity.PathfinderMob; import net.minecraft.world.entity.Pose; import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.goal.FloatGoal; import net.minecraft.world.entity.ai.goal.FollowParentGoal; import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal; import net.minecraft.world.entity.ai.goal.MeleeAttackGoal; import net.minecraft.world.entity.ai.goal.PanicGoal; import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal; import net.minecraft.world.entity.ai.goal.RandomStrollGoal; import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal; import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; import net.minecraft.world.entity.ai.goal.target.ResetUniversalAngerTargetGoal; import net.minecraft.world.entity.animal.Animal; import net.minecraft.world.entity.animal.Fox; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.ServerLevelAccessor; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; import org.jspecify.annotations.Nullable; public class PolarBear extends Animal implements NeutralMob { private static final EntityDataAccessor DATA_STANDING_ID = SynchedEntityData.defineId(PolarBear.class, EntityDataSerializers.BOOLEAN); private static final float STAND_ANIMATION_TICKS = 6.0f; private float clientSideStandAnimationO; private float clientSideStandAnimation; private int warningSoundTicks; private static final UniformInt PERSISTENT_ANGER_TIME = TimeUtil.rangeOfSeconds(20, 39); private long persistentAngerEndTime; private @Nullable EntityReference persistentAngerTarget; public PolarBear(EntityType type, Level level) { super((EntityType)type, level); } @Override public @Nullable AgeableMob getBreedOffspring(ServerLevel level, AgeableMob partner) { return EntityType.POLAR_BEAR.create(level, EntitySpawnReason.BREEDING); } @Override public boolean isFood(ItemStack itemStack) { return false; } @Override protected void registerGoals() { super.registerGoals(); this.goalSelector.addGoal(0, new FloatGoal(this)); this.goalSelector.addGoal(1, new PolarBearMeleeAttackGoal()); this.goalSelector.addGoal(1, new PanicGoal((PathfinderMob)this, 2.0, bear -> bear.isBaby() ? DamageTypeTags.PANIC_CAUSES : DamageTypeTags.PANIC_ENVIRONMENTAL_CAUSES)); this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.25)); this.goalSelector.addGoal(5, new RandomStrollGoal(this, 1.0)); this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 6.0f)); this.goalSelector.addGoal(7, new RandomLookAroundGoal(this)); this.targetSelector.addGoal(1, new PolarBearHurtByTargetGoal()); this.targetSelector.addGoal(2, new PolarBearAttackPlayersGoal()); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal(this, Player.class, 10, true, false, this::isAngryAt)); this.targetSelector.addGoal(4, new NearestAttackableTargetGoal(this, Fox.class, 10, true, true, null)); this.targetSelector.addGoal(5, new ResetUniversalAngerTargetGoal(this, false)); } public static AttributeSupplier.Builder createAttributes() { return Animal.createAnimalAttributes().add(Attributes.MAX_HEALTH, 30.0).add(Attributes.FOLLOW_RANGE, 20.0).add(Attributes.MOVEMENT_SPEED, 0.25).add(Attributes.ATTACK_DAMAGE, 6.0); } public static boolean checkPolarBearSpawnRules(EntityType type, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random) { Holder biome = level.getBiome(pos); if (biome.is(BiomeTags.POLAR_BEARS_SPAWN_ON_ALTERNATE_BLOCKS)) { return PolarBear.isBrightEnoughToSpawn(level, pos) && level.getBlockState(pos.below()).is(BlockTags.POLAR_BEARS_SPAWNABLE_ON_ALTERNATE); } return PolarBear.checkAnimalSpawnRules(type, level, spawnReason, pos, random); } @Override protected void readAdditionalSaveData(ValueInput input) { super.readAdditionalSaveData(input); this.readPersistentAngerSaveData(this.level(), input); } @Override protected void addAdditionalSaveData(ValueOutput output) { super.addAdditionalSaveData(output); this.addPersistentAngerSaveData(output); } @Override public void startPersistentAngerTimer() { this.setTimeToRemainAngry(PERSISTENT_ANGER_TIME.sample(this.random)); } @Override public void setPersistentAngerEndTime(long endTime) { this.persistentAngerEndTime = endTime; } @Override public long getPersistentAngerEndTime() { return this.persistentAngerEndTime; } @Override public void setPersistentAngerTarget(@Nullable EntityReference persistentAngerTarget) { this.persistentAngerTarget = persistentAngerTarget; } @Override public @Nullable EntityReference getPersistentAngerTarget() { return this.persistentAngerTarget; } @Override protected SoundEvent getAmbientSound() { if (this.isBaby()) { return SoundEvents.POLAR_BEAR_AMBIENT_BABY; } return SoundEvents.POLAR_BEAR_AMBIENT; } @Override protected SoundEvent getHurtSound(DamageSource source) { return SoundEvents.POLAR_BEAR_HURT; } @Override protected SoundEvent getDeathSound() { return SoundEvents.POLAR_BEAR_DEATH; } @Override protected void playStepSound(BlockPos pos, BlockState blockState) { this.playSound(SoundEvents.POLAR_BEAR_STEP, 0.15f, 1.0f); } protected void playWarningSound() { if (this.warningSoundTicks <= 0) { this.makeSound(SoundEvents.POLAR_BEAR_WARNING); this.warningSoundTicks = 40; } } @Override protected void defineSynchedData(SynchedEntityData.Builder entityData) { super.defineSynchedData(entityData); entityData.define(DATA_STANDING_ID, false); } @Override public void tick() { super.tick(); if (this.level().isClientSide()) { if (this.clientSideStandAnimation != this.clientSideStandAnimationO) { this.refreshDimensions(); } this.clientSideStandAnimationO = this.clientSideStandAnimation; this.clientSideStandAnimation = this.isStanding() ? Mth.clamp(this.clientSideStandAnimation + 1.0f, 0.0f, 6.0f) : Mth.clamp(this.clientSideStandAnimation - 1.0f, 0.0f, 6.0f); } if (this.warningSoundTicks > 0) { --this.warningSoundTicks; } if (!this.level().isClientSide()) { this.updatePersistentAnger((ServerLevel)this.level(), true); } } @Override public EntityDimensions getDefaultDimensions(Pose pose) { if (this.clientSideStandAnimation > 0.0f) { float standFactor = this.clientSideStandAnimation / 6.0f; float heightScaleFactor = 1.0f + standFactor; return super.getDefaultDimensions(pose).scale(1.0f, heightScaleFactor); } return super.getDefaultDimensions(pose); } public boolean isStanding() { return this.entityData.get(DATA_STANDING_ID); } public void setStanding(boolean value) { this.entityData.set(DATA_STANDING_ID, value); } public float getStandingAnimationScale(float a) { return Mth.lerp(a, this.clientSideStandAnimationO, this.clientSideStandAnimation) / 6.0f; } @Override protected float getWaterSlowDown() { return 0.98f; } @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor level, DifficultyInstance difficulty, EntitySpawnReason spawnReason, @Nullable SpawnGroupData groupData) { if (groupData == null) { groupData = new AgeableMob.AgeableMobGroupData(1.0f); } return super.finalizeSpawn(level, difficulty, spawnReason, groupData); } private class PolarBearMeleeAttackGoal extends MeleeAttackGoal { public PolarBearMeleeAttackGoal() { super(PolarBear.this, 1.25, true); } @Override protected void checkAndPerformAttack(LivingEntity target) { if (this.canPerformAttack(target)) { this.resetAttackCooldown(); this.mob.doHurtTarget(PolarBearMeleeAttackGoal.getServerLevel(this.mob), target); PolarBear.this.setStanding(false); } else if (this.mob.distanceToSqr(target) < (double)((target.getBbWidth() + 3.0f) * (target.getBbWidth() + 3.0f))) { if (this.isTimeToAttack()) { PolarBear.this.setStanding(false); this.resetAttackCooldown(); } if (this.getTicksUntilNextAttack() <= 10) { PolarBear.this.setStanding(true); PolarBear.this.playWarningSound(); } } else { this.resetAttackCooldown(); PolarBear.this.setStanding(false); } } @Override public void stop() { PolarBear.this.setStanding(false); super.stop(); } } private class PolarBearHurtByTargetGoal extends HurtByTargetGoal { public PolarBearHurtByTargetGoal() { super(PolarBear.this, new Class[0]); } @Override public void start() { super.start(); if (PolarBear.this.isBaby()) { this.alertOthers(); this.stop(); } } @Override protected void alertOther(Mob other, LivingEntity hurtByMob) { if (other instanceof PolarBear && !other.isBaby()) { super.alertOther(other, hurtByMob); } } } private class PolarBearAttackPlayersGoal extends NearestAttackableTargetGoal { public PolarBearAttackPlayersGoal() { super(PolarBear.this, Player.class, 20, true, true, null); } @Override public boolean canUse() { if (PolarBear.this.isBaby()) { return false; } if (super.canUse()) { List bears = PolarBear.this.level().getEntitiesOfClass(PolarBear.class, PolarBear.this.getBoundingBox().inflate(8.0, 4.0, 8.0)); for (PolarBear bear : bears) { if (!bear.isBaby()) continue; return true; } } return false; } @Override protected double getFollowDistance() { return super.getFollowDistance() * 0.5; } } }