/* * Decompiled with CFR 0.152. * * Could not load the following classes: * org.jspecify.annotations.Nullable */ package net.minecraft.world.entity.animal; import java.util.Optional; import net.minecraft.advancements.CriteriaTriggers; import net.minecraft.core.BlockPos; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.stats.Stats; import net.minecraft.tags.BlockTags; import net.minecraft.util.RandomSource; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.AgeableMob; import net.minecraft.world.entity.EntityReference; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.ExperienceOrb; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.BlockAndTintGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.gamerules.GameRules; import net.minecraft.world.level.pathfinder.PathType; import net.minecraft.world.level.storage.ValueInput; import net.minecraft.world.level.storage.ValueOutput; import org.jspecify.annotations.Nullable; public abstract class Animal extends AgeableMob { protected static final int PARENT_AGE_AFTER_BREEDING = 6000; private static final int DEFAULT_IN_LOVE_TIME = 0; private int inLove = 0; private @Nullable EntityReference loveCause; protected Animal(EntityType type, Level level) { super((EntityType)type, level); this.setPathfindingMalus(PathType.DANGER_FIRE, 16.0f); this.setPathfindingMalus(PathType.DAMAGE_FIRE, -1.0f); } public static AttributeSupplier.Builder createAnimalAttributes() { return Mob.createMobAttributes().add(Attributes.TEMPT_RANGE, 10.0); } @Override protected void customServerAiStep(ServerLevel level) { if (this.getAge() != 0) { this.inLove = 0; } super.customServerAiStep(level); } @Override public void aiStep() { super.aiStep(); if (this.getAge() != 0) { this.inLove = 0; } if (this.inLove > 0) { --this.inLove; if (this.inLove % 10 == 0) { double xa = this.random.nextGaussian() * 0.02; double ya = this.random.nextGaussian() * 0.02; double za = this.random.nextGaussian() * 0.02; this.level().addParticle(ParticleTypes.HEART, this.getRandomX(1.0), this.getRandomY() + 0.5, this.getRandomZ(1.0), xa, ya, za); } } } @Override protected void actuallyHurt(ServerLevel level, DamageSource source, float dmg) { this.resetLove(); super.actuallyHurt(level, source, dmg); } @Override public float getWalkTargetValue(BlockPos pos, LevelReader level) { if (level.getBlockState(pos.below()).is(Blocks.GRASS_BLOCK)) { return 10.0f; } return level.getPathfindingCostFromLightLevels(pos); } @Override protected void addAdditionalSaveData(ValueOutput output) { super.addAdditionalSaveData(output); output.putInt("InLove", this.inLove); EntityReference.store(this.loveCause, output, "LoveCause"); } @Override protected void readAdditionalSaveData(ValueInput input) { super.readAdditionalSaveData(input); this.inLove = input.getIntOr("InLove", 0); this.loveCause = EntityReference.read(input, "LoveCause"); } public static boolean checkAnimalSpawnRules(EntityType type, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random) { boolean brightEnoughToSpawn = EntitySpawnReason.ignoresLightRequirements(spawnReason) || Animal.isBrightEnoughToSpawn(level, pos); return level.getBlockState(pos.below()).is(BlockTags.ANIMALS_SPAWNABLE_ON) && brightEnoughToSpawn; } protected static boolean isBrightEnoughToSpawn(BlockAndTintGetter level, BlockPos pos) { return level.getRawBrightness(pos, 0) > 8; } @Override public int getAmbientSoundInterval() { return 120; } @Override public boolean removeWhenFarAway(double distSqr) { return false; } @Override protected int getBaseExperienceReward(ServerLevel level) { return 1 + this.random.nextInt(3); } public abstract boolean isFood(ItemStack var1); @Override public InteractionResult mobInteract(Player player, InteractionHand hand) { ItemStack itemStack = player.getItemInHand(hand); if (this.isFood(itemStack)) { int age = this.getAge(); if (player instanceof ServerPlayer) { ServerPlayer serverPlayer = (ServerPlayer)player; if (age == 0 && this.canFallInLove()) { this.usePlayerItem(player, hand, itemStack); this.setInLove(serverPlayer); this.playEatingSound(); return InteractionResult.SUCCESS_SERVER; } } if (this.isBaby()) { this.usePlayerItem(player, hand, itemStack); this.ageUp(Animal.getSpeedUpSecondsWhenFeeding(-age), true); this.playEatingSound(); return InteractionResult.SUCCESS; } if (this.level().isClientSide()) { return InteractionResult.CONSUME; } } return super.mobInteract(player, hand); } protected void playEatingSound() { } public boolean canFallInLove() { return this.inLove <= 0; } public void setInLove(@Nullable Player player) { this.inLove = 600; if (player instanceof ServerPlayer) { ServerPlayer serverPlayer = (ServerPlayer)player; this.loveCause = EntityReference.of(serverPlayer); } this.level().broadcastEntityEvent(this, (byte)18); } public void setInLoveTime(int time) { this.inLove = time; } public int getInLoveTime() { return this.inLove; } public @Nullable ServerPlayer getLoveCause() { return EntityReference.get(this.loveCause, this.level(), ServerPlayer.class); } public boolean isInLove() { return this.inLove > 0; } public void resetLove() { this.inLove = 0; } public boolean canMate(Animal partner) { if (partner == this) { return false; } if (partner.getClass() != this.getClass()) { return false; } return this.isInLove() && partner.isInLove(); } public void spawnChildFromBreeding(ServerLevel level, Animal partner) { AgeableMob offspring = this.getBreedOffspring(level, partner); if (offspring == null) { return; } offspring.setBaby(true); offspring.snapTo(this.getX(), this.getY(), this.getZ(), 0.0f, 0.0f); this.finalizeSpawnChildFromBreeding(level, partner, offspring); level.addFreshEntityWithPassengers(offspring); } public void finalizeSpawnChildFromBreeding(ServerLevel level, Animal partner, @Nullable AgeableMob offspring) { Optional.ofNullable(this.getLoveCause()).or(() -> Optional.ofNullable(partner.getLoveCause())).ifPresent(cause -> { cause.awardStat(Stats.ANIMALS_BRED); CriteriaTriggers.BRED_ANIMALS.trigger((ServerPlayer)cause, this, partner, offspring); }); this.setAge(6000); partner.setAge(6000); this.resetLove(); partner.resetLove(); level.broadcastEntityEvent(this, (byte)18); if (level.getGameRules().get(GameRules.MOB_DROPS).booleanValue()) { level.addFreshEntity(new ExperienceOrb(level, this.getX(), this.getY(), this.getZ(), this.getRandom().nextInt(7) + 1)); } } @Override public void handleEntityEvent(byte id) { if (id == 18) { for (int i = 0; i < 7; ++i) { double xa = this.random.nextGaussian() * 0.02; double ya = this.random.nextGaussian() * 0.02; double za = this.random.nextGaussian() * 0.02; this.level().addParticle(ParticleTypes.HEART, this.getRandomX(1.0), this.getRandomY() + 0.5, this.getRandomZ(1.0), xa, ya, za); } } else { super.handleEntityEvent(id); } } }