2025-11-24 22:52:51 +03:00

304 lines
12 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.function.Predicate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.core.particles.SimpleParticleType;
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.BlockTags;
import net.minecraft.tags.ItemTags;
import net.minecraft.util.RandomSource;
import net.minecraft.world.DifficultyInstance;
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.EntitySelector;
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.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.AvoidEntityGoal;
import net.minecraft.world.entity.ai.goal.BreedGoal;
import net.minecraft.world.entity.ai.goal.FloatGoal;
import net.minecraft.world.entity.ai.goal.LeapAtTargetGoal;
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
import net.minecraft.world.entity.ai.goal.OcelotAttackGoal;
import net.minecraft.world.entity.ai.goal.TemptGoal;
import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.animal.Animal;
import net.minecraft.world.entity.animal.Chicken;
import net.minecraft.world.entity.animal.Turtle;
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.LevelReader;
import net.minecraft.world.level.ServerLevelAccessor;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import net.minecraft.world.phys.Vec3;
import org.jspecify.annotations.Nullable;
public class Ocelot
extends Animal {
public static final double CROUCH_SPEED_MOD = 0.6;
public static final double WALK_SPEED_MOD = 0.8;
public static final double SPRINT_SPEED_MOD = 1.33;
private static final EntityDataAccessor<Boolean> DATA_TRUSTING = SynchedEntityData.defineId(Ocelot.class, EntityDataSerializers.BOOLEAN);
private static final boolean DEFAULT_TRUSTING = false;
private @Nullable OcelotAvoidEntityGoal<Player> ocelotAvoidPlayersGoal;
private @Nullable OcelotTemptGoal temptGoal;
public Ocelot(EntityType<? extends Ocelot> type, Level level) {
super((EntityType<? extends Animal>)type, level);
this.reassessTrustingGoals();
}
private boolean isTrusting() {
return this.entityData.get(DATA_TRUSTING);
}
private void setTrusting(boolean trusting) {
this.entityData.set(DATA_TRUSTING, trusting);
this.reassessTrustingGoals();
}
@Override
protected void addAdditionalSaveData(ValueOutput output) {
super.addAdditionalSaveData(output);
output.putBoolean("Trusting", this.isTrusting());
}
@Override
protected void readAdditionalSaveData(ValueInput input) {
super.readAdditionalSaveData(input);
this.setTrusting(input.getBooleanOr("Trusting", false));
}
@Override
protected void defineSynchedData(SynchedEntityData.Builder entityData) {
super.defineSynchedData(entityData);
entityData.define(DATA_TRUSTING, false);
}
@Override
protected void registerGoals() {
this.temptGoal = new OcelotTemptGoal(this, 0.6, i -> i.is(ItemTags.OCELOT_FOOD), true);
this.goalSelector.addGoal(1, new FloatGoal(this));
this.goalSelector.addGoal(3, this.temptGoal);
this.goalSelector.addGoal(7, new LeapAtTargetGoal(this, 0.3f));
this.goalSelector.addGoal(8, new OcelotAttackGoal(this));
this.goalSelector.addGoal(9, new BreedGoal(this, 0.8));
this.goalSelector.addGoal(10, new WaterAvoidingRandomStrollGoal((PathfinderMob)this, 0.8, 1.0000001E-5f));
this.goalSelector.addGoal(11, new LookAtPlayerGoal(this, Player.class, 10.0f));
this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<Chicken>((Mob)this, Chicken.class, false));
this.targetSelector.addGoal(1, new NearestAttackableTargetGoal<Turtle>(this, Turtle.class, 10, false, false, Turtle.BABY_ON_LAND_SELECTOR));
}
@Override
public void customServerAiStep(ServerLevel level) {
if (this.getMoveControl().hasWanted()) {
double speed = this.getMoveControl().getSpeedModifier();
if (speed == 0.6) {
this.setPose(Pose.CROUCHING);
this.setSprinting(false);
} else if (speed == 1.33) {
this.setPose(Pose.STANDING);
this.setSprinting(true);
} else {
this.setPose(Pose.STANDING);
this.setSprinting(false);
}
} else {
this.setPose(Pose.STANDING);
this.setSprinting(false);
}
}
@Override
public boolean removeWhenFarAway(double distSqr) {
return !this.isTrusting() && this.tickCount > 2400;
}
public static AttributeSupplier.Builder createAttributes() {
return Animal.createAnimalAttributes().add(Attributes.MAX_HEALTH, 10.0).add(Attributes.MOVEMENT_SPEED, 0.3f).add(Attributes.ATTACK_DAMAGE, 3.0);
}
@Override
protected @Nullable SoundEvent getAmbientSound() {
return SoundEvents.OCELOT_AMBIENT;
}
@Override
public int getAmbientSoundInterval() {
return 900;
}
@Override
protected SoundEvent getHurtSound(DamageSource source) {
return SoundEvents.OCELOT_HURT;
}
@Override
protected SoundEvent getDeathSound() {
return SoundEvents.OCELOT_DEATH;
}
@Override
public InteractionResult mobInteract(Player player, InteractionHand hand) {
ItemStack itemStack = player.getItemInHand(hand);
if ((this.temptGoal == null || this.temptGoal.isRunning()) && !this.isTrusting() && this.isFood(itemStack) && player.distanceToSqr(this) < 9.0) {
this.usePlayerItem(player, hand, itemStack);
if (!this.level().isClientSide()) {
if (this.random.nextInt(3) == 0) {
this.setTrusting(true);
this.spawnTrustingParticles(true);
this.level().broadcastEntityEvent(this, (byte)41);
} else {
this.spawnTrustingParticles(false);
this.level().broadcastEntityEvent(this, (byte)40);
}
}
return InteractionResult.SUCCESS;
}
return super.mobInteract(player, hand);
}
@Override
public void handleEntityEvent(byte id) {
if (id == 41) {
this.spawnTrustingParticles(true);
} else if (id == 40) {
this.spawnTrustingParticles(false);
} else {
super.handleEntityEvent(id);
}
}
private void spawnTrustingParticles(boolean success) {
SimpleParticleType particle = ParticleTypes.HEART;
if (!success) {
particle = ParticleTypes.SMOKE;
}
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(particle, this.getRandomX(1.0), this.getRandomY() + 0.5, this.getRandomZ(1.0), xa, ya, za);
}
}
protected void reassessTrustingGoals() {
if (this.ocelotAvoidPlayersGoal == null) {
this.ocelotAvoidPlayersGoal = new OcelotAvoidEntityGoal<Player>(this, Player.class, 16.0f, 0.8, 1.33);
}
this.goalSelector.removeGoal(this.ocelotAvoidPlayersGoal);
if (!this.isTrusting()) {
this.goalSelector.addGoal(4, this.ocelotAvoidPlayersGoal);
}
}
@Override
public @Nullable Ocelot getBreedOffspring(ServerLevel level, AgeableMob partner) {
return EntityType.OCELOT.create(level, EntitySpawnReason.BREEDING);
}
@Override
public boolean isFood(ItemStack itemStack) {
return itemStack.is(ItemTags.OCELOT_FOOD);
}
public static boolean checkOcelotSpawnRules(EntityType<Ocelot> type, LevelAccessor level, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random) {
return random.nextInt(3) != 0;
}
@Override
public boolean checkSpawnObstruction(LevelReader level) {
if (level.isUnobstructed(this) && !level.containsAnyLiquid(this.getBoundingBox())) {
BlockPos pos = this.blockPosition();
if (pos.getY() < level.getSeaLevel()) {
return false;
}
BlockState state = level.getBlockState(pos.below());
if (state.is(Blocks.GRASS_BLOCK) || state.is(BlockTags.LEAVES)) {
return true;
}
}
return false;
}
@Override
public @Nullable 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);
}
@Override
public Vec3 getLeashOffset() {
return new Vec3(0.0, 0.5f * this.getEyeHeight(), this.getBbWidth() * 0.4f);
}
@Override
public boolean isSteppingCarefully() {
return this.isCrouching() || super.isSteppingCarefully();
}
private static class OcelotTemptGoal
extends TemptGoal {
private final Ocelot ocelot;
public OcelotTemptGoal(Ocelot ocelot, double speedModifier, Predicate<ItemStack> items, boolean canScare) {
super(ocelot, speedModifier, items, canScare);
this.ocelot = ocelot;
}
@Override
protected boolean canScare() {
return super.canScare() && !this.ocelot.isTrusting();
}
}
private static class OcelotAvoidEntityGoal<T extends LivingEntity>
extends AvoidEntityGoal<T> {
private final Ocelot ocelot;
public OcelotAvoidEntityGoal(Ocelot ocelot, Class<T> avoidClass, float maxDist, double walkSpeedModifier, double sprintSpeedModifier) {
super(ocelot, avoidClass, maxDist, walkSpeedModifier, sprintSpeedModifier, EntitySelector.NO_CREATIVE_OR_SPECTATOR);
this.ocelot = ocelot;
}
@Override
public boolean canUse() {
return !this.ocelot.isTrusting() && super.canUse();
}
@Override
public boolean canContinueToUse() {
return !this.ocelot.isTrusting() && super.canContinueToUse();
}
}
}