package net.minecraft.world.entity.monster; import java.util.EnumSet; import net.minecraft.core.particles.ParticleTypes; 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.world.damagesource.DamageSource; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.goal.Goal; import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal; import net.minecraft.world.entity.ai.goal.MoveTowardsRestrictionGoal; import net.minecraft.world.entity.ai.goal.RandomLookAroundGoal; import net.minecraft.world.entity.ai.goal.WaterAvoidingRandomStrollGoal; import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal; import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.SmallFireball; import net.minecraft.world.level.Level; import net.minecraft.world.level.pathfinder.PathType; import net.minecraft.world.phys.Vec3; public class Blaze extends Monster { private float allowedHeightOffset = 0.5F; private int nextHeightOffsetChangeTick; private static final EntityDataAccessor DATA_FLAGS_ID = SynchedEntityData.defineId(Blaze.class, EntityDataSerializers.BYTE); public Blaze(EntityType p_32219_, Level p_32220_) { super(p_32219_, p_32220_); this.setPathfindingMalus(PathType.WATER, -1.0F); this.setPathfindingMalus(PathType.LAVA, 8.0F); this.setPathfindingMalus(PathType.DANGER_FIRE, 0.0F); this.setPathfindingMalus(PathType.DAMAGE_FIRE, 0.0F); this.xpReward = 10; } @Override protected void registerGoals() { this.goalSelector.addGoal(4, new Blaze.BlazeAttackGoal(this)); this.goalSelector.addGoal(5, new MoveTowardsRestrictionGoal(this, 1.0)); this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0, 0.0F)); this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); this.targetSelector.addGoal(1, new HurtByTargetGoal(this).setAlertOthers()); this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); } public static AttributeSupplier.Builder createAttributes() { return Monster.createMonsterAttributes().add(Attributes.ATTACK_DAMAGE, 6.0).add(Attributes.MOVEMENT_SPEED, 0.23F).add(Attributes.FOLLOW_RANGE, 48.0); } @Override protected void defineSynchedData(SynchedEntityData.Builder p_330007_) { super.defineSynchedData(p_330007_); p_330007_.define(DATA_FLAGS_ID, (byte)0); } @Override protected SoundEvent getAmbientSound() { return SoundEvents.BLAZE_AMBIENT; } @Override protected SoundEvent getHurtSound(DamageSource p_32235_) { return SoundEvents.BLAZE_HURT; } @Override protected SoundEvent getDeathSound() { return SoundEvents.BLAZE_DEATH; } @Override public float getLightLevelDependentMagicValue() { return 1.0F; } @Override public void aiStep() { if (!this.onGround() && this.getDeltaMovement().y < 0.0) { this.setDeltaMovement(this.getDeltaMovement().multiply(1.0, 0.6, 1.0)); } if (this.level().isClientSide) { if (this.random.nextInt(24) == 0 && !this.isSilent()) { this.level() .playLocalSound( this.getX() + 0.5, this.getY() + 0.5, this.getZ() + 0.5, SoundEvents.BLAZE_BURN, this.getSoundSource(), 1.0F + this.random.nextFloat(), this.random.nextFloat() * 0.7F + 0.3F, false ); } for (int i = 0; i < 2; i++) { this.level().addParticle(ParticleTypes.LARGE_SMOKE, this.getRandomX(0.5), this.getRandomY(), this.getRandomZ(0.5), 0.0, 0.0, 0.0); } } super.aiStep(); } @Override public boolean isSensitiveToWater() { return true; } @Override protected void customServerAiStep(ServerLevel p_367684_) { this.nextHeightOffsetChangeTick--; if (this.nextHeightOffsetChangeTick <= 0) { this.nextHeightOffsetChangeTick = 100; this.allowedHeightOffset = (float)this.random.triangle(0.5, 6.891); } LivingEntity livingentity = this.getTarget(); if (livingentity != null && livingentity.getEyeY() > this.getEyeY() + this.allowedHeightOffset && this.canAttack(livingentity)) { Vec3 vec3 = this.getDeltaMovement(); this.setDeltaMovement(this.getDeltaMovement().add(0.0, (0.3F - vec3.y) * 0.3F, 0.0)); this.hasImpulse = true; } super.customServerAiStep(p_367684_); } @Override public boolean isOnFire() { return this.isCharged(); } private boolean isCharged() { return (this.entityData.get(DATA_FLAGS_ID) & 1) != 0; } void setCharged(boolean p_32241_) { byte b0 = this.entityData.get(DATA_FLAGS_ID); if (p_32241_) { b0 = (byte)(b0 | 1); } else { b0 = (byte)(b0 & -2); } this.entityData.set(DATA_FLAGS_ID, b0); } static class BlazeAttackGoal extends Goal { private final Blaze blaze; private int attackStep; private int attackTime; private int lastSeen; public BlazeAttackGoal(Blaze p_32247_) { this.blaze = p_32247_; this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK)); } @Override public boolean canUse() { LivingEntity livingentity = this.blaze.getTarget(); return livingentity != null && livingentity.isAlive() && this.blaze.canAttack(livingentity); } @Override public void start() { this.attackStep = 0; } @Override public void stop() { this.blaze.setCharged(false); this.lastSeen = 0; } @Override public boolean requiresUpdateEveryTick() { return true; } @Override public void tick() { this.attackTime--; LivingEntity livingentity = this.blaze.getTarget(); if (livingentity != null) { boolean flag = this.blaze.getSensing().hasLineOfSight(livingentity); if (flag) { this.lastSeen = 0; } else { this.lastSeen++; } double d0 = this.blaze.distanceToSqr(livingentity); if (d0 < 4.0) { if (!flag) { return; } if (this.attackTime <= 0) { this.attackTime = 20; this.blaze.doHurtTarget(getServerLevel(this.blaze), livingentity); } this.blaze.getMoveControl().setWantedPosition(livingentity.getX(), livingentity.getY(), livingentity.getZ(), 1.0); } else if (d0 < this.getFollowDistance() * this.getFollowDistance() && flag) { double d1 = livingentity.getX() - this.blaze.getX(); double d2 = livingentity.getY(0.5) - this.blaze.getY(0.5); double d3 = livingentity.getZ() - this.blaze.getZ(); if (this.attackTime <= 0) { this.attackStep++; if (this.attackStep == 1) { this.attackTime = 60; this.blaze.setCharged(true); } else if (this.attackStep <= 4) { this.attackTime = 6; } else { this.attackTime = 100; this.attackStep = 0; this.blaze.setCharged(false); } if (this.attackStep > 1) { double d4 = Math.sqrt(Math.sqrt(d0)) * 0.5; if (!this.blaze.isSilent()) { this.blaze.level().levelEvent(null, 1018, this.blaze.blockPosition(), 0); } for (int i = 0; i < 1; i++) { Vec3 vec3 = new Vec3( this.blaze.getRandom().triangle(d1, 2.297 * d4), d2, this.blaze.getRandom().triangle(d3, 2.297 * d4) ); SmallFireball smallfireball = new SmallFireball(this.blaze.level(), this.blaze, vec3.normalize()); smallfireball.setPos(smallfireball.getX(), this.blaze.getY(0.5) + 0.5, smallfireball.getZ()); this.blaze.level().addFreshEntity(smallfireball); } } } this.blaze.getLookControl().setLookAt(livingentity, 10.0F, 10.0F); } else if (this.lastSeen < 5) { this.blaze.getMoveControl().setWantedPosition(livingentity.getX(), livingentity.getY(), livingentity.getZ(), 1.0); } super.tick(); } } private double getFollowDistance() { return this.blaze.getAttributeValue(Attributes.FOLLOW_RANGE); } } }