2
1
Fork 1
mirror of https://github.com/ACGaming/Spackenmobs synced 2024-06-11 15:08:56 +02:00
Spackenmobs/src/main/java/mod/acgaming/spackenmobs/entity/SchalkerEntity.java
2022-03-06 10:15:32 +01:00

703 lines
24 KiB
Java

package mod.acgaming.spackenmobs.entity;
import java.util.*;
import javax.annotation.Nullable;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.PistonBlock;
import net.minecraft.block.PistonHeadBlock;
import net.minecraft.entity.*;
import net.minecraft.entity.ai.attributes.AttributeModifier;
import net.minecraft.entity.ai.attributes.AttributeModifierMap;
import net.minecraft.entity.ai.attributes.Attributes;
import net.minecraft.entity.ai.controller.BodyController;
import net.minecraft.entity.ai.goal.*;
import net.minecraft.entity.monster.IMob;
import net.minecraft.entity.passive.GolemEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.projectile.AbstractArrowEntity;
import net.minecraft.entity.projectile.ShulkerBulletEntity;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.network.datasync.DataParameter;
import net.minecraft.network.datasync.DataSerializers;
import net.minecraft.network.datasync.EntityDataManager;
import net.minecraft.util.*;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.Difficulty;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import mod.acgaming.spackenmobs.init.SpackenmobsRegistry;
public class SchalkerEntity extends GolemEntity implements IMob
{
protected static final DataParameter<Direction> ATTACHED_FACE = EntityDataManager.defineId(SchalkerEntity.class, DataSerializers.DIRECTION);
protected static final DataParameter<Optional<BlockPos>> ATTACHED_BLOCK_POS = EntityDataManager.defineId(SchalkerEntity.class, DataSerializers.OPTIONAL_BLOCK_POS);
protected static final DataParameter<Byte> PEEK_TICK = EntityDataManager.defineId(SchalkerEntity.class, DataSerializers.BYTE);
protected static final DataParameter<Byte> COLOR = EntityDataManager.defineId(SchalkerEntity.class, DataSerializers.BYTE);
private static final UUID COVERED_ARMOR_BONUS_ID = UUID.fromString("7E0292F2-9434-48D5-A29F-9583AF7DF27F");
private static final AttributeModifier COVERED_ARMOR_BONUS_MODIFIER = new AttributeModifier(COVERED_ARMOR_BONUS_ID, "Covered armor bonus", 20.0D, AttributeModifier.Operation.ADDITION);
public static AttributeModifierMap.MutableAttribute registerAttributes()
{
return MobEntity.createMobAttributes().add(Attributes.MAX_HEALTH, 30.0D);
}
private float prevPeekAmount;
private float peekAmount;
private BlockPos currentAttachmentPosition = null;
private int clientSideTeleportInterpolation;
public SchalkerEntity(EntityType<? extends SchalkerEntity> p_i50196_1_, World p_i50196_2_)
{
super(p_i50196_1_, p_i50196_2_);
this.xpReward = 5;
}
public void setPos(double x, double y, double z)
{
super.setPos(x, y, z);
if (this.entityData != null && this.tickCount != 0)
{
Optional<BlockPos> optional = this.entityData.get(ATTACHED_BLOCK_POS);
if (this.isAddedToWorld() && this.level instanceof net.minecraft.world.server.ServerWorld)
((net.minecraft.world.server.ServerWorld) this.level).updateChunkPos(this); // Forge - Process chunk registration after moving.
Optional<BlockPos> optional1 = Optional.of(new BlockPos(x, y, z));
if (!optional1.equals(optional))
{
this.entityData.set(ATTACHED_BLOCK_POS, optional1);
this.entityData.set(PEEK_TICK, (byte) 0);
this.hasImpulse = true;
}
}
}
public void move(MoverType typeIn, Vector3d pos)
{
if (typeIn == MoverType.SHULKER_BOX)
{
this.tryTeleportToNewPosition();
}
else
{
super.move(typeIn, pos);
}
}
protected boolean isMovementNoisy()
{
return false;
}
public float getPickRadius()
{
return 0.0F;
}
public SoundCategory getSoundSource()
{
return SoundCategory.HOSTILE;
}
public boolean hurt(DamageSource source, float amount)
{
if (this.isClosed())
{
Entity entity = source.getDirectEntity();
if (entity instanceof AbstractArrowEntity)
{
return false;
}
}
if (super.hurt(source, amount))
{
if ((double) this.getHealth() < (double) this.getMaxHealth() * 0.5D && this.random.nextInt(4) == 0)
{
this.tryTeleportToNewPosition();
}
return true;
}
else
{
return false;
}
}
protected float getSoundVolume()
{
return 0.6F;
}
public void push(Entity entityIn)
{
}
@OnlyIn(Dist.CLIENT)
public void lerpTo(double x, double y, double z, float yaw, float pitch, int posRotationIncrements, boolean teleport)
{
this.lerpSteps = 0;
}
public boolean isPickable()
{
return this.isAlive();
}
public void onSyncedDataUpdated(DataParameter<?> key)
{
if (ATTACHED_BLOCK_POS.equals(key) && this.level.isClientSide && !this.isPassenger())
{
BlockPos blockpos = this.getAttachmentPos();
if (blockpos != null)
{
if (this.currentAttachmentPosition == null)
{
this.currentAttachmentPosition = blockpos;
}
else
{
this.clientSideTeleportInterpolation = 6;
}
this.setPosAndOldPos((double) blockpos.getX() + 0.5D, blockpos.getY(), (double) blockpos.getZ() + 0.5D);
}
}
super.onSyncedDataUpdated(key);
}
protected float getStandingEyeHeight(Pose poseIn, EntitySize sizeIn)
{
return 0.5F;
}
public Direction getAttachmentFacing()
{
return this.entityData.get(ATTACHED_FACE);
}
@Nullable
public BlockPos getAttachmentPos()
{
return this.entityData.get(ATTACHED_BLOCK_POS).orElse(null);
}
public void setAttachmentPos(@Nullable BlockPos pos)
{
this.entityData.set(ATTACHED_BLOCK_POS, Optional.ofNullable(pos));
}
public int getPeekTick()
{
return this.entityData.get(PEEK_TICK);
}
public void updateArmorModifier(int p_184691_1_)
{
if (!this.level.isClientSide)
{
Objects.requireNonNull(this.getAttribute(Attributes.ARMOR)).removeModifier(COVERED_ARMOR_BONUS_MODIFIER);
if (p_184691_1_ == 0)
{
Objects.requireNonNull(this.getAttribute(Attributes.ARMOR)).addPermanentModifier(COVERED_ARMOR_BONUS_MODIFIER);
this.playSound(SoundEvents.SHULKER_CLOSE, 1.0F, 1.0F);
}
else
{
this.playSound(SpackenmobsRegistry.ENTITY_SCHALKER_OPEN.get(), 1.0F, 1.0F);
}
}
this.entityData.set(PEEK_TICK, (byte) p_184691_1_);
}
@OnlyIn(Dist.CLIENT)
public float getClientPeekAmount(float p_184688_1_)
{
return MathHelper.lerp(p_184688_1_, this.prevPeekAmount, this.peekAmount);
}
@OnlyIn(Dist.CLIENT)
public int getClientTeleportInterp()
{
return this.clientSideTeleportInterpolation;
}
@OnlyIn(Dist.CLIENT)
public BlockPos getOldAttachPos()
{
return this.currentAttachmentPosition;
}
@OnlyIn(Dist.CLIENT)
public boolean isAttachedToBlock()
{
return this.currentAttachmentPosition != null && this.getAttachmentPos() != null;
}
protected void registerGoals()
{
this.goalSelector.addGoal(1, new LookAtGoal(this, PlayerEntity.class, 8.0F));
this.goalSelector.addGoal(4, new SchalkerEntity.AttackGoal());
this.goalSelector.addGoal(7, new SchalkerEntity.PeekGoal());
this.goalSelector.addGoal(8, new LookRandomlyGoal(this));
this.targetSelector.addGoal(1, (new HurtByTargetGoal(this)).setAlertOthers());
this.targetSelector.addGoal(2, new SchalkerEntity.AttackNearestGoal(this));
this.targetSelector.addGoal(3, new SchalkerEntity.DefenseAttackGoal(this));
}
protected BodyController createBodyControl()
{
return new BodyHelperController(this);
}
protected void defineSynchedData()
{
super.defineSynchedData();
this.entityData.define(ATTACHED_FACE, Direction.DOWN);
this.entityData.define(ATTACHED_BLOCK_POS, Optional.empty());
this.entityData.define(PEEK_TICK, (byte) 0);
this.entityData.define(COLOR, (byte) 16);
}
public void playAmbientSound()
{
if (!this.isClosed())
{
super.playAmbientSound();
}
}
public void tick()
{
super.tick();
BlockPos blockpos = this.entityData.get(ATTACHED_BLOCK_POS).orElse(null);
if (blockpos == null && !this.level.isClientSide)
{
blockpos = this.blockPosition();
this.entityData.set(ATTACHED_BLOCK_POS, Optional.of(blockpos));
}
if (this.isPassenger())
{
blockpos = null;
float f = Objects.requireNonNull(this.getVehicle()).yRot;
this.yRot = f;
this.yBodyRot = f;
this.yBodyRotO = f;
this.clientSideTeleportInterpolation = 0;
}
else if (!this.level.isClientSide)
{
assert blockpos != null;
BlockState blockstate = this.level.getBlockState(blockpos);
if (!blockstate.isAir(this.level, blockpos))
{
if (blockstate.is(Blocks.MOVING_PISTON))
{
Direction direction = blockstate.getValue(PistonBlock.FACING);
if (this.level.isEmptyBlock(blockpos.relative(direction)))
{
blockpos = blockpos.relative(direction);
this.entityData.set(ATTACHED_BLOCK_POS, Optional.of(blockpos));
}
else
{
this.tryTeleportToNewPosition();
}
}
else if (blockstate.is(Blocks.PISTON_HEAD))
{
Direction direction3 = blockstate.getValue(PistonHeadBlock.FACING);
if (this.level.isEmptyBlock(blockpos.relative(direction3)))
{
blockpos = blockpos.relative(direction3);
this.entityData.set(ATTACHED_BLOCK_POS, Optional.of(blockpos));
}
else
{
this.tryTeleportToNewPosition();
}
}
else
{
this.tryTeleportToNewPosition();
}
}
Direction direction4 = this.getAttachmentFacing();
if (!this.canAttachOnBlockFace(blockpos, direction4))
{
Direction direction1 = this.findAttachableFace(blockpos);
if (direction1 != null)
{
this.entityData.set(ATTACHED_FACE, direction1);
}
else
{
this.tryTeleportToNewPosition();
}
}
}
float f1 = (float) this.getPeekTick() * 0.01F;
this.prevPeekAmount = this.peekAmount;
if (this.peekAmount > f1)
{
this.peekAmount = MathHelper.clamp(this.peekAmount - 0.05F, f1, 1.0F);
}
else if (this.peekAmount < f1)
{
this.peekAmount = MathHelper.clamp(this.peekAmount + 0.05F, 0.0F, f1);
}
if (blockpos != null)
{
if (this.level.isClientSide)
{
if (this.clientSideTeleportInterpolation > 0 && this.currentAttachmentPosition != null)
{
--this.clientSideTeleportInterpolation;
}
else
{
this.currentAttachmentPosition = blockpos;
}
}
this.setPosAndOldPos((double) blockpos.getX() + 0.5D, blockpos.getY(), (double) blockpos.getZ() + 0.5D);
double d2 = 0.5D - (double) MathHelper.sin((0.5F + this.peekAmount) * (float) Math.PI) * 0.5D;
double d0 = 0.5D - (double) MathHelper.sin((0.5F + this.prevPeekAmount) * (float) Math.PI) * 0.5D;
if (this.isAddedToWorld() && this.level instanceof net.minecraft.world.server.ServerWorld)
((net.minecraft.world.server.ServerWorld) this.level).updateChunkPos(this); // Forge - Process chunk registration after moving.
Direction direction2 = this.getAttachmentFacing().getOpposite();
this.setBoundingBox((new AxisAlignedBB(this.getX() - 0.5D, this.getY(), this.getZ() - 0.5D, this.getX() + 0.5D, this.getY() + 1.0D, this.getZ() + 0.5D)).expandTowards((double) direction2.getStepX() * d2, (double) direction2.getStepY() * d2, (double) direction2.getStepZ() * d2));
double d1 = d2 - d0;
if (d1 > 0.0D)
{
List<Entity> list = this.level.getEntities(this, this.getBoundingBox());
if (!list.isEmpty())
{
for (Entity entity : list)
{
if (!(entity instanceof SchalkerEntity) && !entity.noPhysics)
{
entity.move(MoverType.SHULKER, new Vector3d(d1 * (double) direction2.getStepX(), d1 * (double) direction2.getStepY(), d1 * (double) direction2.getStepZ()));
}
}
}
}
}
}
public void addAdditionalSaveData(CompoundNBT compound)
{
super.addAdditionalSaveData(compound);
compound.putByte("AttachFace", (byte) this.entityData.get(ATTACHED_FACE).get3DDataValue());
compound.putByte("Peek", this.entityData.get(PEEK_TICK));
compound.putByte("Color", this.entityData.get(COLOR));
BlockPos blockpos = this.getAttachmentPos();
if (blockpos != null)
{
compound.putInt("APX", blockpos.getX());
compound.putInt("APY", blockpos.getY());
compound.putInt("APZ", blockpos.getZ());
}
}
public void readAdditionalSaveData(CompoundNBT compound)
{
super.readAdditionalSaveData(compound);
this.entityData.set(ATTACHED_FACE, Direction.from3DDataValue(compound.getByte("AttachFace")));
this.entityData.set(PEEK_TICK, compound.getByte("Peek"));
this.entityData.set(COLOR, compound.getByte("Color"));
if (compound.contains("APX"))
{
int i = compound.getInt("APX");
int j = compound.getInt("APY");
int k = compound.getInt("APZ");
this.entityData.set(ATTACHED_BLOCK_POS, Optional.of(new BlockPos(i, j, k)));
}
else
{
this.entityData.set(ATTACHED_BLOCK_POS, Optional.empty());
}
}
public void aiStep()
{
super.aiStep();
this.setDeltaMovement(Vector3d.ZERO);
if (!this.isNoAi())
{
this.yBodyRotO = 0.0F;
this.yBodyRot = 0.0F;
}
}
public int getMaxHeadXRot()
{
return 180;
}
public int getMaxHeadYRot()
{
return 180;
}
protected SoundEvent getAmbientSound()
{
return SpackenmobsRegistry.ENTITY_SCHALKER_AMBIENT.get();
}
protected SoundEvent getHurtSound(DamageSource damageSourceIn)
{
return this.isClosed() ? SoundEvents.SHULKER_HURT_CLOSED : SoundEvents.SHULKER_HURT;
}
protected SoundEvent getDeathSound()
{
return SpackenmobsRegistry.ENTITY_SCHALKER_DEATH.get();
}
@Nullable
protected Direction findAttachableFace(BlockPos p_234299_1_)
{
for (Direction direction : Direction.values())
{
if (this.canAttachOnBlockFace(p_234299_1_, direction))
{
return direction;
}
}
return null;
}
protected boolean tryTeleportToNewPosition()
{
if (!this.isNoAi() && this.isAlive())
{
BlockPos blockpos = this.blockPosition();
for (int i = 0; i < 5; ++i)
{
BlockPos blockpos1 = blockpos.offset(8 - this.random.nextInt(17), 8 - this.random.nextInt(17), 8 - this.random.nextInt(17));
if (blockpos1.getY() > 0 && this.level.isEmptyBlock(blockpos1) && this.level.getWorldBorder().isWithinBounds(blockpos1) && this.level.noCollision(this, new AxisAlignedBB(blockpos1)))
{
Direction direction = this.findAttachableFace(blockpos1);
if (direction != null)
{
net.minecraftforge.event.entity.living.EnderTeleportEvent event = new net.minecraftforge.event.entity.living.EnderTeleportEvent(this, blockpos1.getX(), blockpos1.getY(), blockpos1.getZ(), 0);
if (net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(event)) direction = null;
blockpos1 = new BlockPos(event.getTargetX(), event.getTargetY(), event.getTargetZ());
}
if (direction != null)
{
this.entityData.set(ATTACHED_FACE, direction);
this.playSound(SoundEvents.SHULKER_TELEPORT, 1.0F, 1.0F);
this.entityData.set(ATTACHED_BLOCK_POS, Optional.of(blockpos1));
this.entityData.set(PEEK_TICK, (byte) 0);
this.setTarget(null);
return true;
}
}
}
return false;
}
else
{
return true;
}
}
private boolean canAttachOnBlockFace(BlockPos p_234298_1_, Direction p_234298_2_)
{
return this.level.loadedAndEntityCanStandOnFace(p_234298_1_.relative(p_234298_2_), this, p_234298_2_.getOpposite()) && this.level.noCollision(this, ShulkerAABBHelper.openBoundingBox(p_234298_1_, p_234298_2_.getOpposite()));
}
private boolean isClosed()
{
return this.getPeekTick() == 0;
}
static class DefenseAttackGoal extends NearestAttackableTargetGoal<LivingEntity>
{
public DefenseAttackGoal(SchalkerEntity schalker)
{
super(schalker, LivingEntity.class, 10, true, false, (p_200826_0_) ->
p_200826_0_ instanceof IMob);
}
public boolean canUse()
{
return this.mob.getTeam() != null && super.canUse();
}
protected AxisAlignedBB getTargetSearchArea(double targetDistance)
{
Direction direction = ((SchalkerEntity) this.mob).getAttachmentFacing();
if (direction.getAxis() == Direction.Axis.X)
{
return this.mob.getBoundingBox().inflate(4.0D, targetDistance, targetDistance);
}
else
{
return direction.getAxis() == Direction.Axis.Z ? this.mob.getBoundingBox().inflate(targetDistance, targetDistance, 4.0D) : this.mob.getBoundingBox().inflate(targetDistance, 4.0D, targetDistance);
}
}
}
static class BodyHelperController extends BodyController
{
public BodyHelperController(MobEntity p_i50612_2_)
{
super(p_i50612_2_);
}
public void clientTick()
{
}
}
class AttackGoal extends Goal
{
private int attackTime;
public AttackGoal()
{
this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK));
}
public boolean canUse()
{
LivingEntity livingentity = SchalkerEntity.this.getTarget();
if (livingentity != null && livingentity.isAlive())
{
return SchalkerEntity.this.level.getDifficulty() != Difficulty.PEACEFUL;
}
else
{
return false;
}
}
public void start()
{
this.attackTime = 20;
SchalkerEntity.this.updateArmorModifier(100);
}
public void stop()
{
SchalkerEntity.this.updateArmorModifier(0);
}
public void tick()
{
if (SchalkerEntity.this.level.getDifficulty() != Difficulty.PEACEFUL)
{
--this.attackTime;
LivingEntity livingentity = SchalkerEntity.this.getTarget();
assert livingentity != null;
SchalkerEntity.this.getLookControl().setLookAt(livingentity, 180.0F, 180.0F);
double d0 = SchalkerEntity.this.distanceToSqr(livingentity);
if (d0 < 400.0D)
{
if (this.attackTime <= 0)
{
this.attackTime = 20 + SchalkerEntity.this.random.nextInt(10) * 20 / 2;
SchalkerEntity.this.level.addFreshEntity(new ShulkerBulletEntity(SchalkerEntity.this.level, SchalkerEntity.this, livingentity, SchalkerEntity.this.getAttachmentFacing().getAxis()));
SchalkerEntity.this.playSound(SpackenmobsRegistry.ENTITY_SCHALKER_SHOOT.get(), 2.0F, (SchalkerEntity.this.random.nextFloat() - SchalkerEntity.this.random.nextFloat()) * 0.2F + 1.0F);
}
}
else
{
SchalkerEntity.this.setTarget(null);
}
super.tick();
}
}
}
class AttackNearestGoal extends NearestAttackableTargetGoal<PlayerEntity>
{
public AttackNearestGoal(SchalkerEntity schalker)
{
super(schalker, PlayerEntity.class, true);
}
public boolean canUse()
{
return SchalkerEntity.this.level.getDifficulty() != Difficulty.PEACEFUL && super.canUse();
}
protected AxisAlignedBB getTargetSearchArea(double targetDistance)
{
Direction direction = ((SchalkerEntity) this.mob).getAttachmentFacing();
if (direction.getAxis() == Direction.Axis.X)
{
return this.mob.getBoundingBox().inflate(4.0D, targetDistance, targetDistance);
}
else
{
return direction.getAxis() == Direction.Axis.Z ? this.mob.getBoundingBox().inflate(targetDistance, targetDistance, 4.0D) : this.mob.getBoundingBox().inflate(targetDistance, 4.0D, targetDistance);
}
}
}
class PeekGoal extends Goal
{
private int peekTime;
private PeekGoal()
{
}
public boolean canUse()
{
return SchalkerEntity.this.getTarget() == null && SchalkerEntity.this.random.nextInt(40) == 0;
}
public boolean canContinueToUse()
{
return SchalkerEntity.this.getTarget() == null && this.peekTime > 0;
}
public void start()
{
this.peekTime = 20 * (1 + SchalkerEntity.this.random.nextInt(3));
SchalkerEntity.this.updateArmorModifier(30);
}
public void stop()
{
if (SchalkerEntity.this.getTarget() == null)
{
SchalkerEntity.this.updateArmorModifier(0);
}
}
public void tick()
{
--this.peekTime;
}
}
}