252 lines
8.8 KiB
Java
252 lines
8.8 KiB
Java
/*
|
|
* 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<ServerPlayer> loveCause;
|
|
|
|
protected Animal(EntityType<? extends Animal> type, Level level) {
|
|
super((EntityType<? extends AgeableMob>)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<? extends Animal> 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);
|
|
}
|
|
}
|
|
}
|
|
|