263 lines
9.3 KiB
Java
263 lines
9.3 KiB
Java
package net.minecraft.world.entity.ambient;
|
|
|
|
import java.time.LocalDate;
|
|
import java.time.temporal.ChronoField;
|
|
import javax.annotation.Nullable;
|
|
import net.minecraft.core.BlockPos;
|
|
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.tags.BlockTags;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.util.RandomSource;
|
|
import net.minecraft.world.damagesource.DamageSource;
|
|
import net.minecraft.world.entity.AnimationState;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.EntitySpawnReason;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import net.minecraft.world.entity.Mob;
|
|
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
|
|
import net.minecraft.world.entity.ai.attributes.Attributes;
|
|
import net.minecraft.world.entity.ai.targeting.TargetingConditions;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.LevelAccessor;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.levelgen.Heightmap;
|
|
import net.minecraft.world.phys.Vec3;
|
|
|
|
public class Bat extends AmbientCreature {
|
|
public static final float FLAP_LENGTH_SECONDS = 0.5F;
|
|
public static final float TICKS_PER_FLAP = 10.0F;
|
|
private static final EntityDataAccessor<Byte> DATA_ID_FLAGS = SynchedEntityData.defineId(Bat.class, EntityDataSerializers.BYTE);
|
|
private static final int FLAG_RESTING = 1;
|
|
private static final TargetingConditions BAT_RESTING_TARGETING = TargetingConditions.forNonCombat().range(4.0);
|
|
private static final byte DEFAULT_FLAGS = 0;
|
|
public final AnimationState flyAnimationState = new AnimationState();
|
|
public final AnimationState restAnimationState = new AnimationState();
|
|
@Nullable
|
|
private BlockPos targetPosition;
|
|
|
|
public Bat(EntityType<? extends Bat> p_27412_, Level p_27413_) {
|
|
super(p_27412_, p_27413_);
|
|
if (!p_27413_.isClientSide) {
|
|
this.setResting(true);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean isFlapping() {
|
|
return !this.isResting() && this.tickCount % 10.0F == 0.0F;
|
|
}
|
|
|
|
@Override
|
|
protected void defineSynchedData(SynchedEntityData.Builder p_332675_) {
|
|
super.defineSynchedData(p_332675_);
|
|
p_332675_.define(DATA_ID_FLAGS, (byte)0);
|
|
}
|
|
|
|
@Override
|
|
protected float getSoundVolume() {
|
|
return 0.1F;
|
|
}
|
|
|
|
@Override
|
|
public float getVoicePitch() {
|
|
return super.getVoicePitch() * 0.95F;
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public SoundEvent getAmbientSound() {
|
|
return this.isResting() && this.random.nextInt(4) != 0 ? null : SoundEvents.BAT_AMBIENT;
|
|
}
|
|
|
|
@Override
|
|
protected SoundEvent getHurtSound(DamageSource p_27451_) {
|
|
return SoundEvents.BAT_HURT;
|
|
}
|
|
|
|
@Override
|
|
protected SoundEvent getDeathSound() {
|
|
return SoundEvents.BAT_DEATH;
|
|
}
|
|
|
|
@Override
|
|
public boolean isPushable() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
protected void doPush(Entity p_27415_) {
|
|
}
|
|
|
|
@Override
|
|
protected void pushEntities() {
|
|
}
|
|
|
|
public static AttributeSupplier.Builder createAttributes() {
|
|
return Mob.createMobAttributes().add(Attributes.MAX_HEALTH, 6.0);
|
|
}
|
|
|
|
public boolean isResting() {
|
|
return (this.entityData.get(DATA_ID_FLAGS) & 1) != 0;
|
|
}
|
|
|
|
public void setResting(boolean p_27457_) {
|
|
byte b0 = this.entityData.get(DATA_ID_FLAGS);
|
|
if (p_27457_) {
|
|
this.entityData.set(DATA_ID_FLAGS, (byte)(b0 | 1));
|
|
} else {
|
|
this.entityData.set(DATA_ID_FLAGS, (byte)(b0 & -2));
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
super.tick();
|
|
if (this.isResting()) {
|
|
this.setDeltaMovement(Vec3.ZERO);
|
|
this.setPosRaw(this.getX(), Mth.floor(this.getY()) + 1.0 - this.getBbHeight(), this.getZ());
|
|
} else {
|
|
this.setDeltaMovement(this.getDeltaMovement().multiply(1.0, 0.6, 1.0));
|
|
}
|
|
|
|
this.setupAnimationStates();
|
|
}
|
|
|
|
@Override
|
|
protected void customServerAiStep(ServerLevel p_369019_) {
|
|
super.customServerAiStep(p_369019_);
|
|
BlockPos blockpos = this.blockPosition();
|
|
BlockPos blockpos1 = blockpos.above();
|
|
if (this.isResting()) {
|
|
boolean flag = this.isSilent();
|
|
if (p_369019_.getBlockState(blockpos1).isRedstoneConductor(p_369019_, blockpos)) {
|
|
if (this.random.nextInt(200) == 0) {
|
|
this.yHeadRot = this.random.nextInt(360);
|
|
}
|
|
|
|
if (p_369019_.getNearestPlayer(BAT_RESTING_TARGETING, this) != null) {
|
|
this.setResting(false);
|
|
if (!flag) {
|
|
p_369019_.levelEvent(null, 1025, blockpos, 0);
|
|
}
|
|
}
|
|
} else {
|
|
this.setResting(false);
|
|
if (!flag) {
|
|
p_369019_.levelEvent(null, 1025, blockpos, 0);
|
|
}
|
|
}
|
|
} else {
|
|
if (this.targetPosition != null && (!p_369019_.isEmptyBlock(this.targetPosition) || this.targetPosition.getY() <= p_369019_.getMinY())) {
|
|
this.targetPosition = null;
|
|
}
|
|
|
|
if (this.targetPosition == null || this.random.nextInt(30) == 0 || this.targetPosition.closerToCenterThan(this.position(), 2.0)) {
|
|
this.targetPosition = BlockPos.containing(
|
|
this.getX() + this.random.nextInt(7) - this.random.nextInt(7),
|
|
this.getY() + this.random.nextInt(6) - 2.0,
|
|
this.getZ() + this.random.nextInt(7) - this.random.nextInt(7)
|
|
);
|
|
}
|
|
|
|
double d2 = this.targetPosition.getX() + 0.5 - this.getX();
|
|
double d0 = this.targetPosition.getY() + 0.1 - this.getY();
|
|
double d1 = this.targetPosition.getZ() + 0.5 - this.getZ();
|
|
Vec3 vec3 = this.getDeltaMovement();
|
|
Vec3 vec31 = vec3.add(
|
|
(Math.signum(d2) * 0.5 - vec3.x) * 0.1F, (Math.signum(d0) * 0.7F - vec3.y) * 0.1F, (Math.signum(d1) * 0.5 - vec3.z) * 0.1F
|
|
);
|
|
this.setDeltaMovement(vec31);
|
|
float f = (float)(Mth.atan2(vec31.z, vec31.x) * 180.0F / (float)Math.PI) - 90.0F;
|
|
float f1 = Mth.wrapDegrees(f - this.getYRot());
|
|
this.zza = 0.5F;
|
|
this.setYRot(this.getYRot() + f1);
|
|
if (this.random.nextInt(100) == 0 && p_369019_.getBlockState(blockpos1).isRedstoneConductor(p_369019_, blockpos1)) {
|
|
this.setResting(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected Entity.MovementEmission getMovementEmission() {
|
|
return Entity.MovementEmission.EVENTS;
|
|
}
|
|
|
|
@Override
|
|
protected void checkFallDamage(double p_27419_, boolean p_27420_, BlockState p_27421_, BlockPos p_27422_) {
|
|
}
|
|
|
|
@Override
|
|
public boolean isIgnoringBlockTriggers() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean hurtServer(ServerLevel p_361230_, DamageSource p_366357_, float p_366075_) {
|
|
if (this.isInvulnerableTo(p_361230_, p_366357_)) {
|
|
return false;
|
|
} else {
|
|
if (this.isResting()) {
|
|
this.setResting(false);
|
|
}
|
|
|
|
return super.hurtServer(p_361230_, p_366357_, p_366075_);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void readAdditionalSaveData(CompoundTag p_27427_) {
|
|
super.readAdditionalSaveData(p_27427_);
|
|
this.entityData.set(DATA_ID_FLAGS, p_27427_.getByteOr("BatFlags", (byte)0));
|
|
}
|
|
|
|
@Override
|
|
public void addAdditionalSaveData(CompoundTag p_27443_) {
|
|
super.addAdditionalSaveData(p_27443_);
|
|
p_27443_.putByte("BatFlags", this.entityData.get(DATA_ID_FLAGS));
|
|
}
|
|
|
|
public static boolean checkBatSpawnRules(EntityType<Bat> p_218099_, LevelAccessor p_218100_, EntitySpawnReason p_364019_, BlockPos p_218102_, RandomSource p_218103_) {
|
|
if (p_218102_.getY() >= p_218100_.getHeightmapPos(Heightmap.Types.WORLD_SURFACE, p_218102_).getY()) {
|
|
return false;
|
|
} else {
|
|
int i = p_218100_.getMaxLocalRawBrightness(p_218102_);
|
|
int j = 4;
|
|
if (isHalloween()) {
|
|
j = 7;
|
|
} else if (p_218103_.nextBoolean()) {
|
|
return false;
|
|
}
|
|
|
|
if (i > p_218103_.nextInt(j)) {
|
|
return false;
|
|
} else {
|
|
return !p_218100_.getBlockState(p_218102_.below()).is(BlockTags.BATS_SPAWNABLE_ON)
|
|
? false
|
|
: checkMobSpawnRules(p_218099_, p_218100_, p_364019_, p_218102_, p_218103_);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static boolean isHalloween() {
|
|
LocalDate localdate = LocalDate.now();
|
|
int i = localdate.get(ChronoField.DAY_OF_MONTH);
|
|
int j = localdate.get(ChronoField.MONTH_OF_YEAR);
|
|
return j == 10 && i >= 20 || j == 11 && i <= 3;
|
|
}
|
|
|
|
private void setupAnimationStates() {
|
|
if (this.isResting()) {
|
|
this.flyAnimationState.stop();
|
|
this.restAnimationState.startIfStopped(this.tickCount);
|
|
} else {
|
|
this.restAnimationState.stop();
|
|
this.flyAnimationState.startIfStopped(this.tickCount);
|
|
}
|
|
}
|
|
} |