package net.minecraft.world.entity.animal; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; 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.sounds.SoundSource; import net.minecraft.tags.ItemTags; import net.minecraft.world.Difficulty; 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.ConversionParams; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.ItemBasedSteering; import net.minecraft.world.entity.ItemSteerable; import net.minecraft.world.entity.LightningBolt; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.Pose; import net.minecraft.world.entity.Saddleable; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.attributes.AttributeSupplier.Builder; import net.minecraft.world.entity.ai.goal.BreedGoal; import net.minecraft.world.entity.ai.goal.FloatGoal; import net.minecraft.world.entity.ai.goal.FollowParentGoal; import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal; import net.minecraft.world.entity.ai.goal.PanicGoal; import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal; import net.minecraft.world.entity.ai.goal.TemptGoal; import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal; import net.minecraft.world.entity.monster.ZombifiedPiglin; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.vehicle.DismountHelper; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; public class Pig extends Animal implements ItemSteerable, Saddleable { private static final EntityDataAccessor DATA_SADDLE_ID = SynchedEntityData.defineId(Pig.class, EntityDataSerializers.BOOLEAN); private static final EntityDataAccessor DATA_BOOST_TIME = SynchedEntityData.defineId(Pig.class, EntityDataSerializers.INT); private final ItemBasedSteering steering = new ItemBasedSteering(this.entityData, DATA_BOOST_TIME, DATA_SADDLE_ID); public Pig(EntityType entityType, Level level) { super(entityType, level); } @Override protected void registerGoals() { this.goalSelector.addGoal(0, new FloatGoal(this)); this.goalSelector.addGoal(1, new PanicGoal(this, 1.25)); this.goalSelector.addGoal(3, new BreedGoal(this, 1.0)); this.goalSelector.addGoal(4, new TemptGoal(this, 1.2, itemStack -> itemStack.is(Items.CARROT_ON_A_STICK), false)); this.goalSelector.addGoal(4, new TemptGoal(this, 1.2, itemStack -> itemStack.is(ItemTags.PIG_FOOD), false)); this.goalSelector.addGoal(5, new FollowParentGoal(this, 1.1)); this.goalSelector.addGoal(6, new WaterAvoidingRandomStrollGoal(this, 1.0)); this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 6.0F)); this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); } public static Builder createAttributes() { return Animal.createAnimalAttributes().add(Attributes.MAX_HEALTH, 10.0).add(Attributes.MOVEMENT_SPEED, 0.25); } @Nullable @Override public LivingEntity getControllingPassenger() { return (LivingEntity)(this.isSaddled() && this.getFirstPassenger() instanceof Player player && player.isHolding(Items.CARROT_ON_A_STICK) ? player : super.getControllingPassenger()); } @Override public void onSyncedDataUpdated(EntityDataAccessor dataAccessor) { if (DATA_BOOST_TIME.equals(dataAccessor) && this.level().isClientSide) { this.steering.onSynced(); } super.onSyncedDataUpdated(dataAccessor); } @Override protected void defineSynchedData(net.minecraft.network.syncher.SynchedEntityData.Builder builder) { super.defineSynchedData(builder); builder.define(DATA_SADDLE_ID, false); builder.define(DATA_BOOST_TIME, 0); } @Override public void addAdditionalSaveData(CompoundTag compound) { super.addAdditionalSaveData(compound); this.steering.addAdditionalSaveData(compound); } @Override public void readAdditionalSaveData(CompoundTag compound) { super.readAdditionalSaveData(compound); this.steering.readAdditionalSaveData(compound); } @Override protected SoundEvent getAmbientSound() { return SoundEvents.PIG_AMBIENT; } @Override protected SoundEvent getHurtSound(DamageSource damageSource) { return SoundEvents.PIG_HURT; } @Override protected SoundEvent getDeathSound() { return SoundEvents.PIG_DEATH; } @Override protected void playStepSound(BlockPos pos, BlockState state) { this.playSound(SoundEvents.PIG_STEP, 0.15F, 1.0F); } @Override public InteractionResult mobInteract(Player player, InteractionHand hand) { boolean bl = this.isFood(player.getItemInHand(hand)); if (!bl && this.isSaddled() && !this.isVehicle() && !player.isSecondaryUseActive()) { if (!this.level().isClientSide) { player.startRiding(this); } return InteractionResult.SUCCESS; } else { InteractionResult interactionResult = super.mobInteract(player, hand); if (!interactionResult.consumesAction()) { ItemStack itemStack = player.getItemInHand(hand); return (InteractionResult)(itemStack.is(Items.SADDLE) ? itemStack.interactLivingEntity(player, this, hand) : InteractionResult.PASS); } else { return interactionResult; } } } @Override public boolean isSaddleable() { return this.isAlive() && !this.isBaby(); } @Override protected void dropEquipment(ServerLevel serverLevel) { super.dropEquipment(serverLevel); if (this.isSaddled()) { this.spawnAtLocation(serverLevel, Items.SADDLE); } } @Override public boolean isSaddled() { return this.steering.hasSaddle(); } @Override public void equipSaddle(ItemStack stack, @Nullable SoundSource soundSource) { this.steering.setSaddle(true); if (soundSource != null) { this.level().playSound(null, this, SoundEvents.PIG_SADDLE, soundSource, 0.5F, 1.0F); } } @Override public Vec3 getDismountLocationForPassenger(LivingEntity passenger) { Direction direction = this.getMotionDirection(); if (direction.getAxis() == Direction.Axis.Y) { return super.getDismountLocationForPassenger(passenger); } else { int[][] is = DismountHelper.offsetsForDirection(direction); BlockPos blockPos = this.blockPosition(); BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); for (Pose pose : passenger.getDismountPoses()) { AABB aABB = passenger.getLocalBoundsForPose(pose); for (int[] js : is) { mutableBlockPos.set(blockPos.getX() + js[0], blockPos.getY(), blockPos.getZ() + js[1]); double d = this.level().getBlockFloorHeight(mutableBlockPos); if (DismountHelper.isBlockFloorValid(d)) { Vec3 vec3 = Vec3.upFromBottomCenterOf(mutableBlockPos, d); if (DismountHelper.canDismountTo(this.level(), passenger, aABB.move(vec3))) { passenger.setPose(pose); return vec3; } } } } return super.getDismountLocationForPassenger(passenger); } } @Override public void thunderHit(ServerLevel level, LightningBolt lightning) { if (level.getDifficulty() != Difficulty.PEACEFUL) { ZombifiedPiglin zombifiedPiglin = this.convertTo(EntityType.ZOMBIFIED_PIGLIN, ConversionParams.single(this, false, true), zombifiedPiglinx -> { if (this.getMainHandItem().isEmpty()) { zombifiedPiglinx.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(Items.GOLDEN_SWORD)); } zombifiedPiglinx.setPersistenceRequired(); }); if (zombifiedPiglin == null) { super.thunderHit(level, lightning); } } else { super.thunderHit(level, lightning); } } @Override protected void tickRidden(Player player, Vec3 travelVector) { super.tickRidden(player, travelVector); this.setRot(player.getYRot(), player.getXRot() * 0.5F); this.yRotO = this.yBodyRot = this.yHeadRot = this.getYRot(); this.steering.tickBoost(); } @Override protected Vec3 getRiddenInput(Player player, Vec3 travelVector) { return new Vec3(0.0, 0.0, 1.0); } @Override protected float getRiddenSpeed(Player player) { return (float)(this.getAttributeValue(Attributes.MOVEMENT_SPEED) * 0.225 * this.steering.boostFactor()); } @Override public boolean boost() { return this.steering.boost(this.getRandom()); } @Nullable public Pig getBreedOffspring(ServerLevel level, AgeableMob otherParent) { return EntityType.PIG.create(level, EntitySpawnReason.BREEDING); } @Override public boolean isFood(ItemStack stack) { return stack.is(ItemTags.PIG_FOOD); } @Override public Vec3 getLeashOffset() { return new Vec3(0.0, 0.6F * this.getEyeHeight(), this.getBbWidth() * 0.4F); } }