package net.minecraft.world.entity.monster; import javax.annotation.Nullable; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.util.RandomSource; import net.minecraft.world.Difficulty; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectInstance; import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.SpawnGroupData; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.goal.AvoidEntityGoal; import net.minecraft.world.entity.ai.goal.FloatGoal; import net.minecraft.world.entity.ai.goal.LeapAtTargetGoal; import net.minecraft.world.entity.ai.goal.LookAtPlayerGoal; import net.minecraft.world.entity.ai.goal.MeleeAttackGoal; 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.ai.navigation.PathNavigation; import net.minecraft.world.entity.ai.navigation.WallClimberNavigation; import net.minecraft.world.entity.animal.IronGolem; import net.minecraft.world.entity.animal.armadillo.Armadillo; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraft.world.level.ServerLevelAccessor; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; public class Spider extends Monster { private static final EntityDataAccessor DATA_FLAGS_ID = SynchedEntityData.defineId(Spider.class, EntityDataSerializers.BYTE); private static final float SPIDER_SPECIAL_EFFECT_CHANCE = 0.1F; public Spider(EntityType p_33786_, Level p_33787_) { super(p_33786_, p_33787_); } @Override protected void registerGoals() { this.goalSelector.addGoal(1, new FloatGoal(this)); this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, Armadillo.class, 6.0F, 1.0, 1.2, p_328323_ -> !((Armadillo)p_328323_).isScared())); this.goalSelector.addGoal(3, new LeapAtTargetGoal(this, 0.4F)); this.goalSelector.addGoal(4, new Spider.SpiderAttackGoal(this)); this.goalSelector.addGoal(5, new WaterAvoidingRandomStrollGoal(this, 0.8)); this.goalSelector.addGoal(6, new LookAtPlayerGoal(this, Player.class, 8.0F)); this.goalSelector.addGoal(6, new RandomLookAroundGoal(this)); this.targetSelector.addGoal(1, new HurtByTargetGoal(this)); this.targetSelector.addGoal(2, new Spider.SpiderTargetGoal<>(this, Player.class)); this.targetSelector.addGoal(3, new Spider.SpiderTargetGoal<>(this, IronGolem.class)); } @Override protected PathNavigation createNavigation(Level p_33802_) { return new WallClimberNavigation(this, p_33802_); } @Override protected void defineSynchedData(SynchedEntityData.Builder p_334759_) { super.defineSynchedData(p_334759_); p_334759_.define(DATA_FLAGS_ID, (byte)0); } @Override public void tick() { super.tick(); if (!this.level().isClientSide) { this.setClimbing(this.horizontalCollision); } } public static AttributeSupplier.Builder createAttributes() { return Monster.createMonsterAttributes().add(Attributes.MAX_HEALTH, 16.0).add(Attributes.MOVEMENT_SPEED, 0.3F); } @Override protected SoundEvent getAmbientSound() { return SoundEvents.SPIDER_AMBIENT; } @Override protected SoundEvent getHurtSound(DamageSource p_33814_) { return SoundEvents.SPIDER_HURT; } @Override protected SoundEvent getDeathSound() { return SoundEvents.SPIDER_DEATH; } @Override protected void playStepSound(BlockPos p_33804_, BlockState p_33805_) { this.playSound(SoundEvents.SPIDER_STEP, 0.15F, 1.0F); } @Override public boolean onClimbable() { return this.isClimbing(); } @Override public void makeStuckInBlock(BlockState p_33796_, Vec3 p_33797_) { if (!p_33796_.is(Blocks.COBWEB)) { super.makeStuckInBlock(p_33796_, p_33797_); } } @Override public boolean canBeAffected(MobEffectInstance p_33809_) { return p_33809_.is(MobEffects.POISON) ? false : super.canBeAffected(p_33809_); } public boolean isClimbing() { return (this.entityData.get(DATA_FLAGS_ID) & 1) != 0; } public void setClimbing(boolean p_33820_) { byte b0 = this.entityData.get(DATA_FLAGS_ID); if (p_33820_) { b0 = (byte)(b0 | 1); } else { b0 = (byte)(b0 & -2); } this.entityData.set(DATA_FLAGS_ID, b0); } @Nullable @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor p_33790_, DifficultyInstance p_33791_, EntitySpawnReason p_368176_, @Nullable SpawnGroupData p_33793_) { p_33793_ = super.finalizeSpawn(p_33790_, p_33791_, p_368176_, p_33793_); RandomSource randomsource = p_33790_.getRandom(); if (randomsource.nextInt(100) == 0) { Skeleton skeleton = EntityType.SKELETON.create(this.level(), EntitySpawnReason.JOCKEY); if (skeleton != null) { skeleton.snapTo(this.getX(), this.getY(), this.getZ(), this.getYRot(), 0.0F); skeleton.finalizeSpawn(p_33790_, p_33791_, p_368176_, null); skeleton.startRiding(this); } } if (p_33793_ == null) { p_33793_ = new Spider.SpiderEffectsGroupData(); if (p_33790_.getDifficulty() == Difficulty.HARD && randomsource.nextFloat() < 0.1F * p_33791_.getSpecialMultiplier()) { ((Spider.SpiderEffectsGroupData)p_33793_).setRandomEffect(randomsource); } } if (p_33793_ instanceof Spider.SpiderEffectsGroupData spider$spidereffectsgroupdata) { Holder holder = spider$spidereffectsgroupdata.effect; if (holder != null) { this.addEffect(new MobEffectInstance(holder, -1)); } } return p_33793_; } @Override public Vec3 getVehicleAttachmentPoint(Entity p_333349_) { return p_333349_.getBbWidth() <= this.getBbWidth() ? new Vec3(0.0, 0.3125 * this.getScale(), 0.0) : super.getVehicleAttachmentPoint(p_333349_); } static class SpiderAttackGoal extends MeleeAttackGoal { public SpiderAttackGoal(Spider p_33822_) { super(p_33822_, 1.0, true); } @Override public boolean canUse() { return super.canUse() && !this.mob.isVehicle(); } @Override public boolean canContinueToUse() { float f = this.mob.getLightLevelDependentMagicValue(); if (f >= 0.5F && this.mob.getRandom().nextInt(100) == 0) { this.mob.setTarget(null); return false; } else { return super.canContinueToUse(); } } } public static class SpiderEffectsGroupData implements SpawnGroupData { @Nullable public Holder effect; public void setRandomEffect(RandomSource p_219119_) { int i = p_219119_.nextInt(5); if (i <= 1) { this.effect = MobEffects.SPEED; } else if (i <= 2) { this.effect = MobEffects.STRENGTH; } else if (i <= 3) { this.effect = MobEffects.REGENERATION; } else if (i <= 4) { this.effect = MobEffects.INVISIBILITY; } } } static class SpiderTargetGoal extends NearestAttackableTargetGoal { public SpiderTargetGoal(Spider p_33832_, Class p_33833_) { super(p_33832_, p_33833_, true); } @Override public boolean canUse() { float f = this.mob.getLightLevelDependentMagicValue(); return f >= 0.5F ? false : super.canUse(); } } }