269 lines
9.2 KiB
Java
269 lines
9.2 KiB
Java
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.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.Mob;
|
|
import net.minecraft.world.entity.Pose;
|
|
import net.minecraft.world.entity.Saddleable;
|
|
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
|
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<Boolean> DATA_SADDLE_ID = SynchedEntityData.defineId(Pig.class, EntityDataSerializers.BOOLEAN);
|
|
private static final EntityDataAccessor<Integer> 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<? extends Pig> 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 AttributeSupplier.Builder createAttributes() {
|
|
return Mob.createMobAttributes().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(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.sidedSuccess(this.level().isClientSide);
|
|
} else {
|
|
InteractionResult interactionResult = super.mobInteract(player, hand);
|
|
if (!interactionResult.consumesAction()) {
|
|
ItemStack itemStack = player.getItemInHand(hand);
|
|
return 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() {
|
|
super.dropEquipment();
|
|
if (this.isSaddled()) {
|
|
this.spawnAtLocation(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 = EntityType.ZOMBIFIED_PIGLIN.create(level);
|
|
if (zombifiedPiglin != null) {
|
|
zombifiedPiglin.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(Items.GOLDEN_SWORD));
|
|
zombifiedPiglin.moveTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot());
|
|
zombifiedPiglin.setNoAi(this.isNoAi());
|
|
zombifiedPiglin.setBaby(this.isBaby());
|
|
if (this.hasCustomName()) {
|
|
zombifiedPiglin.setCustomName(this.getCustomName());
|
|
zombifiedPiglin.setCustomNameVisible(this.isCustomNameVisible());
|
|
}
|
|
|
|
zombifiedPiglin.setPersistenceRequired();
|
|
level.addFreshEntity(zombifiedPiglin);
|
|
this.discard();
|
|
} else {
|
|
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);
|
|
}
|
|
|
|
@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);
|
|
}
|
|
}
|