package net.minecraft.world.entity.animal.horse; import java.util.EnumSet; import javax.annotation.Nullable; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.entity.AgeableMob; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.entity.ai.goal.Goal; import net.minecraft.world.entity.ai.goal.PanicGoal; import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; import net.minecraft.world.entity.ai.goal.target.TargetGoal; import net.minecraft.world.entity.ai.targeting.TargetingConditions; import net.minecraft.world.entity.monster.AbstractIllager; import net.minecraft.world.entity.monster.Zombie; import net.minecraft.world.entity.npc.WanderingTrader; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; public class TraderLlama extends Llama { private static final int DEFAULT_DESPAWN_DELAY = 47999; private int despawnDelay = 47999; public TraderLlama(EntityType p_30939_, Level p_30940_) { super(p_30939_, p_30940_); } @Override public boolean isTraderLlama() { return true; } @Nullable @Override protected Llama makeNewLlama() { return EntityType.TRADER_LLAMA.create(this.level(), EntitySpawnReason.BREEDING); } @Override public void addAdditionalSaveData(CompoundTag p_30950_) { super.addAdditionalSaveData(p_30950_); p_30950_.putInt("DespawnDelay", this.despawnDelay); } @Override public void readAdditionalSaveData(CompoundTag p_30948_) { super.readAdditionalSaveData(p_30948_); this.despawnDelay = p_30948_.getIntOr("DespawnDelay", 47999); } @Override protected void registerGoals() { super.registerGoals(); this.goalSelector.addGoal(1, new PanicGoal(this, 2.0)); this.targetSelector.addGoal(1, new TraderLlama.TraderLlamaDefendWanderingTraderGoal(this)); this.targetSelector .addGoal(2, new NearestAttackableTargetGoal<>(this, Zombie.class, true, (p_390669_, p_390670_) -> p_390669_.getType() != EntityType.ZOMBIFIED_PIGLIN)); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, AbstractIllager.class, true)); } public void setDespawnDelay(int p_149556_) { this.despawnDelay = p_149556_; } @Override protected void doPlayerRide(Player p_30958_) { Entity entity = this.getLeashHolder(); if (!(entity instanceof WanderingTrader)) { super.doPlayerRide(p_30958_); } } @Override public void aiStep() { super.aiStep(); if (!this.level().isClientSide) { this.maybeDespawn(); } } private void maybeDespawn() { if (this.canDespawn()) { this.despawnDelay = this.isLeashedToWanderingTrader() ? ((WanderingTrader)this.getLeashHolder()).getDespawnDelay() - 1 : this.despawnDelay - 1; if (this.despawnDelay <= 0) { this.removeLeash(); this.discard(); } } } private boolean canDespawn() { return !this.isTamed() && !this.isLeashedToSomethingOtherThanTheWanderingTrader() && !this.hasExactlyOnePlayerPassenger(); } private boolean isLeashedToWanderingTrader() { return this.getLeashHolder() instanceof WanderingTrader; } private boolean isLeashedToSomethingOtherThanTheWanderingTrader() { return this.isLeashed() && !this.isLeashedToWanderingTrader(); } @Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor p_30942_, DifficultyInstance p_30943_, EntitySpawnReason p_367657_, @Nullable SpawnGroupData p_30945_) { if (p_367657_ == EntitySpawnReason.EVENT) { this.setAge(0); } if (p_30945_ == null) { p_30945_ = new AgeableMob.AgeableMobGroupData(false); } return super.finalizeSpawn(p_30942_, p_30943_, p_367657_, p_30945_); } protected static class TraderLlamaDefendWanderingTraderGoal extends TargetGoal { private final Llama llama; private LivingEntity ownerLastHurtBy; private int timestamp; public TraderLlamaDefendWanderingTraderGoal(Llama p_149558_) { super(p_149558_, false); this.llama = p_149558_; this.setFlags(EnumSet.of(Goal.Flag.TARGET)); } @Override public boolean canUse() { if (!this.llama.isLeashed()) { return false; } else if (!(this.llama.getLeashHolder() instanceof WanderingTrader wanderingtrader)) { return false; } else { this.ownerLastHurtBy = wanderingtrader.getLastHurtByMob(); int i = wanderingtrader.getLastHurtByMobTimestamp(); return i != this.timestamp && this.canAttack(this.ownerLastHurtBy, TargetingConditions.DEFAULT); } } @Override public void start() { this.mob.setTarget(this.ownerLastHurtBy); Entity entity = this.llama.getLeashHolder(); if (entity instanceof WanderingTrader) { this.timestamp = ((WanderingTrader)entity).getLastHurtByMobTimestamp(); } super.start(); } } }