637 lines
25 KiB
Java
637 lines
25 KiB
Java
package net.minecraft.world.entity.animal;
|
|
|
|
import net.minecraft.world.level.storage.loot.LootTable;
|
|
import java.util.Random;
|
|
import net.minecraft.world.entity.item.ItemEntity;
|
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
|
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
|
import net.minecraft.world.level.storage.loot.LootContext;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.world.level.storage.loot.BuiltInLootTables;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import net.minecraft.world.phys.AABB;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.block.state.properties.Property;
|
|
import net.minecraft.world.level.block.BedBlock;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.tags.BlockTags;
|
|
import net.minecraft.world.entity.EntitySelector;
|
|
import net.minecraft.world.entity.ai.goal.AvoidEntityGoal;
|
|
import net.minecraft.Util;
|
|
import com.google.common.collect.Maps;
|
|
import net.minecraft.network.syncher.SynchedEntityData;
|
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
|
import net.minecraft.world.item.Items;
|
|
import net.minecraft.world.level.ItemLike;
|
|
import java.util.HashMap;
|
|
import net.minecraft.world.entity.EntityDimensions;
|
|
import net.minecraft.world.item.Item;
|
|
import net.minecraft.world.item.DyeItem;
|
|
import net.minecraft.world.item.SpawnEggItem;
|
|
import net.minecraft.world.InteractionHand;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.world.level.levelgen.feature.Feature;
|
|
import net.minecraft.world.entity.SpawnGroupData;
|
|
import net.minecraft.world.entity.MobSpawnType;
|
|
import net.minecraft.world.DifficultyInstance;
|
|
import net.minecraft.world.level.LevelAccessor;
|
|
import net.minecraft.world.entity.AgableMob;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.entity.monster.SharedMonsterAttributes;
|
|
import net.minecraft.world.damagesource.DamageSource;
|
|
import javax.annotation.Nullable;
|
|
import net.minecraft.sounds.SoundEvents;
|
|
import net.minecraft.sounds.SoundEvent;
|
|
import net.minecraft.world.entity.Pose;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.world.item.DyeColor;
|
|
import java.util.function.Predicate;
|
|
import net.minecraft.world.entity.ai.goal.target.NonTameRandomTargetGoal;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal;
|
|
import net.minecraft.world.entity.PathfinderMob;
|
|
import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal;
|
|
import net.minecraft.world.entity.ai.goal.BreedGoal;
|
|
import net.minecraft.world.entity.ai.goal.OcelotAttackGoal;
|
|
import net.minecraft.world.entity.ai.goal.LeapAtTargetGoal;
|
|
import net.minecraft.world.entity.ai.goal.CatSitOnBlockGoal;
|
|
import net.minecraft.world.entity.ai.goal.FollowOwnerGoal;
|
|
import net.minecraft.world.entity.ai.goal.CatLieOnBedGoal;
|
|
import net.minecraft.world.entity.ai.goal.Goal;
|
|
import net.minecraft.world.entity.Mob;
|
|
import net.minecraft.world.entity.ai.goal.FloatGoal;
|
|
import net.minecraft.world.entity.ai.goal.SitGoal;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import net.minecraft.world.entity.ai.goal.TemptGoal;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import java.util.Map;
|
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
|
import net.minecraft.world.item.crafting.Ingredient;
|
|
import net.minecraft.world.entity.TamableAnimal;
|
|
|
|
public class Cat extends TamableAnimal {
|
|
private static final Ingredient TEMPT_INGREDIENT;
|
|
private static final EntityDataAccessor<Integer> DATA_TYPE_ID;
|
|
private static final EntityDataAccessor<Boolean> IS_LYING;
|
|
private static final EntityDataAccessor<Boolean> RELAX_STATE_ONE;
|
|
private static final EntityDataAccessor<Integer> DATA_COLLAR_COLOR;
|
|
public static final Map<Integer, ResourceLocation> TEXTURE_BY_TYPE;
|
|
private CatAvoidEntityGoal<Player> avoidPlayersGoal;
|
|
private TemptGoal temptGoal;
|
|
private float lieDownAmount;
|
|
private float lieDownAmountO;
|
|
private float lieDownAmountTail;
|
|
private float lieDownAmountOTail;
|
|
private float relaxStateOneAmount;
|
|
private float relaxStateOneAmountO;
|
|
|
|
public Cat(final EntityType<? extends Cat> akr, final Level bjt) {
|
|
super(akr, bjt);
|
|
}
|
|
|
|
public ResourceLocation getResourceLocation() {
|
|
return Cat.TEXTURE_BY_TYPE.getOrDefault(this.getCatType(), Cat.TEXTURE_BY_TYPE.get(0));
|
|
}
|
|
|
|
@Override
|
|
protected void registerGoals() {
|
|
this.sitGoal = new SitGoal(this);
|
|
this.temptGoal = new CatTemptGoal(this, 0.6, Cat.TEMPT_INGREDIENT, true);
|
|
this.goalSelector.addGoal(1, new FloatGoal(this));
|
|
this.goalSelector.addGoal(1, new CatRelaxOnOwnerGoal(this));
|
|
this.goalSelector.addGoal(2, this.sitGoal);
|
|
this.goalSelector.addGoal(3, this.temptGoal);
|
|
this.goalSelector.addGoal(5, new CatLieOnBedGoal(this, 1.1, 8));
|
|
this.goalSelector.addGoal(6, new FollowOwnerGoal(this, 1.0, 10.0f, 5.0f, false));
|
|
this.goalSelector.addGoal(7, new CatSitOnBlockGoal(this, 0.8));
|
|
this.goalSelector.addGoal(8, new LeapAtTargetGoal(this, 0.3f));
|
|
this.goalSelector.addGoal(9, new OcelotAttackGoal(this));
|
|
this.goalSelector.addGoal(10, new BreedGoal(this, 0.8));
|
|
this.goalSelector.addGoal(11, new WaterAvoidingRandomStrollGoal(this, 0.8, 1.0000001E-5f));
|
|
this.goalSelector.addGoal(12, new LookAtPlayerGoal(this, Player.class, 10.0f));
|
|
this.targetSelector.addGoal(1, new NonTameRandomTargetGoal<>(this, Rabbit.class, false, null));
|
|
this.targetSelector.addGoal(1, new NonTameRandomTargetGoal<>(this, Turtle.class, false, Turtle.BABY_ON_LAND_SELECTOR));
|
|
}
|
|
|
|
public int getCatType() {
|
|
return this.entityData.<Integer>get(Cat.DATA_TYPE_ID);
|
|
}
|
|
|
|
public void setCatType(int integer) {
|
|
if (integer < 0 || integer >= 11) {
|
|
integer = this.random.nextInt(10);
|
|
}
|
|
this.entityData.<Integer>set(Cat.DATA_TYPE_ID, integer);
|
|
}
|
|
|
|
public void setLying(final boolean boolean1) {
|
|
this.entityData.<Boolean>set(Cat.IS_LYING, boolean1);
|
|
}
|
|
|
|
public boolean isLying() {
|
|
return this.entityData.<Boolean>get(Cat.IS_LYING);
|
|
}
|
|
|
|
public void setRelaxStateOne(final boolean boolean1) {
|
|
this.entityData.<Boolean>set(Cat.RELAX_STATE_ONE, boolean1);
|
|
}
|
|
|
|
public boolean isRelaxStateOne() {
|
|
return this.entityData.<Boolean>get(Cat.RELAX_STATE_ONE);
|
|
}
|
|
|
|
public DyeColor getCollarColor() {
|
|
return DyeColor.byId(this.entityData.<Integer>get(Cat.DATA_COLLAR_COLOR));
|
|
}
|
|
|
|
public void setCollarColor(final DyeColor bdg) {
|
|
this.entityData.<Integer>set(Cat.DATA_COLLAR_COLOR, bdg.getId());
|
|
}
|
|
|
|
@Override
|
|
protected void defineSynchedData() {
|
|
super.defineSynchedData();
|
|
this.entityData.<Integer>define(Cat.DATA_TYPE_ID, 1);
|
|
this.entityData.<Boolean>define(Cat.IS_LYING, false);
|
|
this.entityData.<Boolean>define(Cat.RELAX_STATE_ONE, false);
|
|
this.entityData.<Integer>define(Cat.DATA_COLLAR_COLOR, DyeColor.RED.getId());
|
|
}
|
|
|
|
@Override
|
|
public void addAdditionalSaveData(final CompoundTag jt) {
|
|
super.addAdditionalSaveData(jt);
|
|
jt.putInt("CatType", this.getCatType());
|
|
jt.putByte("CollarColor", (byte)this.getCollarColor().getId());
|
|
}
|
|
|
|
@Override
|
|
public void readAdditionalSaveData(final CompoundTag jt) {
|
|
super.readAdditionalSaveData(jt);
|
|
this.setCatType(jt.getInt("CatType"));
|
|
if (jt.contains("CollarColor", 99)) {
|
|
this.setCollarColor(DyeColor.byId(jt.getInt("CollarColor")));
|
|
}
|
|
}
|
|
|
|
public void customServerAiStep() {
|
|
if (this.getMoveControl().hasWanted()) {
|
|
final double double2 = this.getMoveControl().getSpeedModifier();
|
|
if (double2 == 0.6) {
|
|
this.setPose(Pose.CROUCHING);
|
|
this.setSprinting(false);
|
|
}
|
|
else if (double2 == 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);
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
protected SoundEvent getAmbientSound() {
|
|
if (!this.isTame()) {
|
|
return SoundEvents.CAT_STRAY_AMBIENT;
|
|
}
|
|
if (this.isInLove()) {
|
|
return SoundEvents.CAT_PURR;
|
|
}
|
|
if (this.random.nextInt(4) == 0) {
|
|
return SoundEvents.CAT_PURREOW;
|
|
}
|
|
return SoundEvents.CAT_AMBIENT;
|
|
}
|
|
|
|
@Override
|
|
public int getAmbientSoundInterval() {
|
|
return 120;
|
|
}
|
|
|
|
public void hiss() {
|
|
this.playSound(SoundEvents.CAT_HISS, this.getSoundVolume(), this.getVoicePitch());
|
|
}
|
|
|
|
@Override
|
|
protected SoundEvent getHurtSound(final DamageSource ajw) {
|
|
return SoundEvents.CAT_HURT;
|
|
}
|
|
|
|
@Override
|
|
protected SoundEvent getDeathSound() {
|
|
return SoundEvents.CAT_DEATH;
|
|
}
|
|
|
|
@Override
|
|
protected void registerAttributes() {
|
|
super.registerAttributes();
|
|
this.getAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(10.0);
|
|
this.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.30000001192092896);
|
|
this.getAttributes().registerAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(3.0);
|
|
}
|
|
|
|
@Override
|
|
public boolean causeFallDamage(final float float1, final float float2) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
protected void usePlayerItem(final Player ayg, final ItemStack bek) {
|
|
if (this.isFood(bek)) {
|
|
this.playSound(SoundEvents.CAT_EAT, 1.0f, 1.0f);
|
|
}
|
|
super.usePlayerItem(ayg, bek);
|
|
}
|
|
|
|
private float getAttackDamage() {
|
|
return (float)this.getAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).getValue();
|
|
}
|
|
|
|
@Override
|
|
public boolean doHurtTarget(final Entity akn) {
|
|
return akn.hurt(DamageSource.mobAttack(this), this.getAttackDamage());
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
super.tick();
|
|
if (this.temptGoal != null && this.temptGoal.isRunning() && !this.isTame() && this.tickCount % 100 == 0) {
|
|
this.playSound(SoundEvents.CAT_BEG_FOR_FOOD, 1.0f, 1.0f);
|
|
}
|
|
this.handleLieDown();
|
|
}
|
|
|
|
private void handleLieDown() {
|
|
if ((this.isLying() || this.isRelaxStateOne()) && this.tickCount % 5 == 0) {
|
|
this.playSound(SoundEvents.CAT_PURR, 0.6f + 0.4f * (this.random.nextFloat() - this.random.nextFloat()), 1.0f);
|
|
}
|
|
this.updateLieDownAmount();
|
|
this.updateRelaxStateOneAmount();
|
|
}
|
|
|
|
private void updateLieDownAmount() {
|
|
this.lieDownAmountO = this.lieDownAmount;
|
|
this.lieDownAmountOTail = this.lieDownAmountTail;
|
|
if (this.isLying()) {
|
|
this.lieDownAmount = Math.min(1.0f, this.lieDownAmount + 0.15f);
|
|
this.lieDownAmountTail = Math.min(1.0f, this.lieDownAmountTail + 0.08f);
|
|
}
|
|
else {
|
|
this.lieDownAmount = Math.max(0.0f, this.lieDownAmount - 0.22f);
|
|
this.lieDownAmountTail = Math.max(0.0f, this.lieDownAmountTail - 0.13f);
|
|
}
|
|
}
|
|
|
|
private void updateRelaxStateOneAmount() {
|
|
this.relaxStateOneAmountO = this.relaxStateOneAmount;
|
|
if (this.isRelaxStateOne()) {
|
|
this.relaxStateOneAmount = Math.min(1.0f, this.relaxStateOneAmount + 0.1f);
|
|
}
|
|
else {
|
|
this.relaxStateOneAmount = Math.max(0.0f, this.relaxStateOneAmount - 0.13f);
|
|
}
|
|
}
|
|
|
|
public float getLieDownAmount(final float float1) {
|
|
return Mth.lerp(float1, this.lieDownAmountO, this.lieDownAmount);
|
|
}
|
|
|
|
public float getLieDownAmountTail(final float float1) {
|
|
return Mth.lerp(float1, this.lieDownAmountOTail, this.lieDownAmountTail);
|
|
}
|
|
|
|
public float getRelaxStateOneAmount(final float float1) {
|
|
return Mth.lerp(float1, this.relaxStateOneAmountO, this.relaxStateOneAmount);
|
|
}
|
|
|
|
@Override
|
|
public Cat getBreedOffspring(final AgableMob akl) {
|
|
final Cat atb3 = EntityType.CAT.create(this.level);
|
|
if (akl instanceof Cat) {
|
|
if (this.random.nextBoolean()) {
|
|
atb3.setCatType(this.getCatType());
|
|
}
|
|
else {
|
|
atb3.setCatType(((Cat)akl).getCatType());
|
|
}
|
|
if (this.isTame()) {
|
|
atb3.setOwnerUUID(this.getOwnerUUID());
|
|
atb3.setTame(true);
|
|
if (this.random.nextBoolean()) {
|
|
atb3.setCollarColor(this.getCollarColor());
|
|
}
|
|
else {
|
|
atb3.setCollarColor(((Cat)akl).getCollarColor());
|
|
}
|
|
}
|
|
}
|
|
return atb3;
|
|
}
|
|
|
|
@Override
|
|
public boolean canMate(final Animal asz) {
|
|
if (!this.isTame()) {
|
|
return false;
|
|
}
|
|
if (!(asz instanceof Cat)) {
|
|
return false;
|
|
}
|
|
final Cat atb3 = (Cat)asz;
|
|
return atb3.isTame() && super.canMate(asz);
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public SpawnGroupData finalizeSpawn(final LevelAccessor bju, final DifficultyInstance ajg, final MobSpawnType akz, @Nullable SpawnGroupData alj, @Nullable final CompoundTag jt) {
|
|
alj = super.finalizeSpawn(bju, ajg, akz, alj, jt);
|
|
if (bju.getMoonBrightness() > 0.9f) {
|
|
this.setCatType(this.random.nextInt(11));
|
|
}
|
|
else {
|
|
this.setCatType(this.random.nextInt(10));
|
|
}
|
|
if (Feature.SWAMP_HUT.isInsideFeature(bju, new BlockPos(this))) {
|
|
this.setCatType(10);
|
|
this.setPersistenceRequired();
|
|
}
|
|
return alj;
|
|
}
|
|
|
|
@Override
|
|
public boolean mobInteract(final Player ayg, final InteractionHand ajh) {
|
|
final ItemStack bek4 = ayg.getItemInHand(ajh);
|
|
final Item bef5 = bek4.getItem();
|
|
if (bek4.getItem() instanceof SpawnEggItem) {
|
|
return super.mobInteract(ayg, ajh);
|
|
}
|
|
if (this.level.isClientSide) {
|
|
return (this.isTame() && this.isOwnedBy(ayg)) || this.isFood(bek4);
|
|
}
|
|
if (this.isTame()) {
|
|
if (this.isOwnedBy(ayg)) {
|
|
if (bef5 instanceof DyeItem) {
|
|
final DyeColor bdg6 = ((DyeItem)bef5).getDyeColor();
|
|
if (bdg6 != this.getCollarColor()) {
|
|
this.setCollarColor(bdg6);
|
|
if (!ayg.abilities.instabuild) {
|
|
bek4.shrink(1);
|
|
}
|
|
this.setPersistenceRequired();
|
|
return true;
|
|
}
|
|
}
|
|
else {
|
|
if (bef5.isEdible() && this.isFood(bek4) && this.getHealth() < this.getMaxHealth()) {
|
|
this.usePlayerItem(ayg, bek4);
|
|
this.heal((float)bef5.getFoodProperties().getNutrition());
|
|
return true;
|
|
}
|
|
final boolean boolean6 = super.mobInteract(ayg, ajh);
|
|
if (!boolean6 || this.isBaby()) {
|
|
this.sitGoal.wantToSit(!this.isSitting());
|
|
}
|
|
return boolean6;
|
|
}
|
|
}
|
|
}
|
|
else if (this.isFood(bek4)) {
|
|
this.usePlayerItem(ayg, bek4);
|
|
if (this.random.nextInt(3) == 0) {
|
|
this.tame(ayg);
|
|
this.sitGoal.wantToSit(true);
|
|
this.level.broadcastEntityEvent(this, (byte)7);
|
|
}
|
|
else {
|
|
this.level.broadcastEntityEvent(this, (byte)6);
|
|
}
|
|
this.setPersistenceRequired();
|
|
return true;
|
|
}
|
|
final boolean boolean6 = super.mobInteract(ayg, ajh);
|
|
if (boolean6) {
|
|
this.setPersistenceRequired();
|
|
}
|
|
return boolean6;
|
|
}
|
|
|
|
@Override
|
|
public boolean isFood(final ItemStack bek) {
|
|
return Cat.TEMPT_INGREDIENT.test(bek);
|
|
}
|
|
|
|
@Override
|
|
protected float getStandingEyeHeight(final Pose alg, final EntityDimensions ako) {
|
|
return ako.height * 0.5f;
|
|
}
|
|
|
|
@Override
|
|
public boolean removeWhenFarAway(final double double1) {
|
|
return !this.isTame() && this.tickCount > 2400;
|
|
}
|
|
|
|
@Override
|
|
protected void reassessTameGoals() {
|
|
if (this.avoidPlayersGoal == null) {
|
|
this.avoidPlayersGoal = new CatAvoidEntityGoal<Player>(this, Player.class, 16.0f, 0.8, 1.33);
|
|
}
|
|
this.goalSelector.removeGoal(this.avoidPlayersGoal);
|
|
if (!this.isTame()) {
|
|
this.goalSelector.addGoal(4, this.avoidPlayersGoal);
|
|
}
|
|
}
|
|
|
|
static {
|
|
TEMPT_INGREDIENT = Ingredient.of(Items.COD, Items.SALMON);
|
|
DATA_TYPE_ID = SynchedEntityData.<Integer>defineId(Cat.class, EntityDataSerializers.INT);
|
|
IS_LYING = SynchedEntityData.<Boolean>defineId(Cat.class, EntityDataSerializers.BOOLEAN);
|
|
RELAX_STATE_ONE = SynchedEntityData.<Boolean>defineId(Cat.class, EntityDataSerializers.BOOLEAN);
|
|
DATA_COLLAR_COLOR = SynchedEntityData.<Integer>defineId(Cat.class, EntityDataSerializers.INT);
|
|
TEXTURE_BY_TYPE = Util.<Map<Integer, ResourceLocation>>make(Maps.newHashMap(), hashMap -> {
|
|
hashMap.put(0, new ResourceLocation("textures/entity/cat/tabby.png"));
|
|
hashMap.put(1, new ResourceLocation("textures/entity/cat/black.png"));
|
|
hashMap.put(2, new ResourceLocation("textures/entity/cat/red.png"));
|
|
hashMap.put(3, new ResourceLocation("textures/entity/cat/siamese.png"));
|
|
hashMap.put(4, new ResourceLocation("textures/entity/cat/british_shorthair.png"));
|
|
hashMap.put(5, new ResourceLocation("textures/entity/cat/calico.png"));
|
|
hashMap.put(6, new ResourceLocation("textures/entity/cat/persian.png"));
|
|
hashMap.put(7, new ResourceLocation("textures/entity/cat/ragdoll.png"));
|
|
hashMap.put(8, new ResourceLocation("textures/entity/cat/white.png"));
|
|
hashMap.put(9, new ResourceLocation("textures/entity/cat/jellie.png"));
|
|
hashMap.put(10, new ResourceLocation("textures/entity/cat/all_black.png"));
|
|
});
|
|
}
|
|
|
|
static class CatAvoidEntityGoal<T extends LivingEntity> extends AvoidEntityGoal<T> {
|
|
private final Cat cat;
|
|
|
|
public CatAvoidEntityGoal(final Cat atb, final Class<T> class2, final float float3, final double double4, final double double5) {
|
|
super(atb, class2, float3, double4, double5, EntitySelector.NO_CREATIVE_OR_SPECTATOR::test);
|
|
this.cat = atb;
|
|
}
|
|
|
|
@Override
|
|
public boolean canUse() {
|
|
return !this.cat.isTame() && super.canUse();
|
|
}
|
|
|
|
@Override
|
|
public boolean canContinueToUse() {
|
|
return !this.cat.isTame() && super.canContinueToUse();
|
|
}
|
|
}
|
|
|
|
static class CatTemptGoal extends TemptGoal {
|
|
@Nullable
|
|
private Player selectedPlayer;
|
|
private final Cat cat;
|
|
|
|
public CatTemptGoal(final Cat atb, final double double2, final Ingredient bgq, final boolean boolean4) {
|
|
super(atb, double2, bgq, boolean4);
|
|
this.cat = atb;
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
super.tick();
|
|
if (this.selectedPlayer == null && this.mob.getRandom().nextInt(600) == 0) {
|
|
this.selectedPlayer = this.player;
|
|
}
|
|
else if (this.mob.getRandom().nextInt(500) == 0) {
|
|
this.selectedPlayer = null;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected boolean canScare() {
|
|
return (this.selectedPlayer == null || !this.selectedPlayer.equals(this.player)) && super.canScare();
|
|
}
|
|
|
|
@Override
|
|
public boolean canUse() {
|
|
return super.canUse() && !this.cat.isTame();
|
|
}
|
|
}
|
|
|
|
static class CatRelaxOnOwnerGoal extends Goal {
|
|
private final Cat cat;
|
|
private Player ownerPlayer;
|
|
private BlockPos goalPos;
|
|
private int onBedTicks;
|
|
|
|
public CatRelaxOnOwnerGoal(final Cat atb) {
|
|
this.cat = atb;
|
|
}
|
|
|
|
@Override
|
|
public boolean canUse() {
|
|
if (!this.cat.isTame()) {
|
|
return false;
|
|
}
|
|
if (this.cat.isSitting()) {
|
|
return false;
|
|
}
|
|
final LivingEntity akw2 = this.cat.getOwner();
|
|
if (akw2 instanceof Player) {
|
|
this.ownerPlayer = (Player)akw2;
|
|
if (!akw2.isSleeping()) {
|
|
return false;
|
|
}
|
|
if (this.cat.distanceToSqr(this.ownerPlayer) > 100.0) {
|
|
return false;
|
|
}
|
|
final BlockPos fk3 = new BlockPos(this.ownerPlayer);
|
|
final BlockState byg4 = this.cat.level.getBlockState(fk3);
|
|
if (byg4.getBlock().is(BlockTags.BEDS)) {
|
|
final Direction fp5 = byg4.<Direction>getValue((Property<Direction>)BedBlock.FACING);
|
|
this.goalPos = new BlockPos(fk3.getX() - fp5.getStepX(), fk3.getY(), fk3.getZ() - fp5.getStepZ());
|
|
return !this.spaceIsOccupied();
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private boolean spaceIsOccupied() {
|
|
final List<Cat> list2 = this.cat.level.<Cat>getEntitiesOfClass(Cat.class, new AABB(this.goalPos).inflate(2.0));
|
|
for (final Cat atb4 : list2) {
|
|
if (atb4 != this.cat && (atb4.isLying() || atb4.isRelaxStateOne())) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean canContinueToUse() {
|
|
return this.cat.isTame() && !this.cat.isSitting() && this.ownerPlayer != null && this.ownerPlayer.isSleeping() && this.goalPos != null && !this.spaceIsOccupied();
|
|
}
|
|
|
|
@Override
|
|
public void start() {
|
|
if (this.goalPos != null) {
|
|
this.cat.getSitGoal().wantToSit(false);
|
|
this.cat.getNavigation().moveTo(this.goalPos.getX(), this.goalPos.getY(), this.goalPos.getZ(), 1.100000023841858);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void stop() {
|
|
this.cat.setLying(false);
|
|
final float float2 = this.cat.level.getTimeOfDay(1.0f);
|
|
if (this.ownerPlayer.getSleepTimer() >= 100 && float2 > 0.77 && float2 < 0.8 && this.cat.level.getRandom().nextFloat() < 0.7) {
|
|
this.giveMorningGift();
|
|
}
|
|
this.onBedTicks = 0;
|
|
this.cat.setRelaxStateOne(false);
|
|
this.cat.getNavigation().stop();
|
|
}
|
|
|
|
private void giveMorningGift() {
|
|
final Random random2 = this.cat.getRandom();
|
|
final BlockPos.MutableBlockPos a3 = new BlockPos.MutableBlockPos();
|
|
a3.set(this.cat);
|
|
this.cat.randomTeleport(a3.getX() + random2.nextInt(11) - 5, a3.getY() + random2.nextInt(5) - 2, a3.getZ() + random2.nextInt(11) - 5, false);
|
|
a3.set(this.cat);
|
|
final LootTable crx4 = this.cat.level.getServer().getLootTables().get(BuiltInLootTables.CAT_MORNING_GIFT);
|
|
final LootContext.Builder a4 = new LootContext.Builder((ServerLevel)this.cat.level).<BlockPos>withParameter(LootContextParams.BLOCK_POS, a3).<Entity>withParameter(LootContextParams.THIS_ENTITY, this.cat).withRandom(random2);
|
|
final List<ItemStack> list6 = crx4.getRandomItems(a4.create(LootContextParamSets.GIFT));
|
|
for (final ItemStack bek8 : list6) {
|
|
this.cat.level.addFreshEntity(new ItemEntity(this.cat.level, a3.getX() - Mth.sin(this.cat.yBodyRot * 0.017453292f), a3.getY(), a3.getZ() + Mth.cos(this.cat.yBodyRot * 0.017453292f), bek8));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
if (this.ownerPlayer != null && this.goalPos != null) {
|
|
this.cat.getSitGoal().wantToSit(false);
|
|
this.cat.getNavigation().moveTo(this.goalPos.getX(), this.goalPos.getY(), this.goalPos.getZ(), 1.100000023841858);
|
|
if (this.cat.distanceToSqr(this.ownerPlayer) < 2.5) {
|
|
++this.onBedTicks;
|
|
if (this.onBedTicks > 16) {
|
|
this.cat.setLying(true);
|
|
this.cat.setRelaxStateOne(false);
|
|
}
|
|
else {
|
|
this.cat.lookAt(this.ownerPlayer, 45.0f, 45.0f);
|
|
this.cat.setRelaxStateOne(true);
|
|
}
|
|
}
|
|
else {
|
|
this.cat.setLying(false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|