package net.minecraft.world.entity.monster; import java.util.function.Predicate; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.util.RandomSource; import net.minecraft.world.Difficulty; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.EntitySpawnReason; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.PathfinderMob; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.ai.attributes.AttributeSupplier.Builder; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.ProjectileWeaponItem; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.ServerLevelAccessor; import net.minecraft.world.level.dimension.DimensionType; public abstract class Monster extends PathfinderMob implements Enemy { protected Monster(EntityType entityType, Level level) { super(entityType, level); this.xpReward = 5; } @Override public SoundSource getSoundSource() { return SoundSource.HOSTILE; } @Override public void aiStep() { this.updateSwingTime(); this.updateNoActionTime(); super.aiStep(); } protected void updateNoActionTime() { float f = this.getLightLevelDependentMagicValue(); if (f > 0.5F) { this.noActionTime += 2; } } @Override protected boolean shouldDespawnInPeaceful() { return true; } @Override protected SoundEvent getSwimSound() { return SoundEvents.HOSTILE_SWIM; } @Override protected SoundEvent getSwimSplashSound() { return SoundEvents.HOSTILE_SPLASH; } @Override protected SoundEvent getHurtSound(DamageSource damageSource) { return SoundEvents.HOSTILE_HURT; } @Override protected SoundEvent getDeathSound() { return SoundEvents.HOSTILE_DEATH; } @Override public LivingEntity.Fallsounds getFallSounds() { return new LivingEntity.Fallsounds(SoundEvents.HOSTILE_SMALL_FALL, SoundEvents.HOSTILE_BIG_FALL); } @Override public float getWalkTargetValue(BlockPos pos, LevelReader level) { return -level.getPathfindingCostFromLightLevels(pos); } /** * Static predicate for determining if the current light level and environmental conditions allow for a monster to spawn. */ public static boolean isDarkEnoughToSpawn(ServerLevelAccessor level, BlockPos pos, RandomSource random) { if (level.getBrightness(LightLayer.SKY, pos) > random.nextInt(32)) { return false; } else { DimensionType dimensionType = level.dimensionType(); int i = dimensionType.monsterSpawnBlockLightLimit(); if (i < 15 && level.getBrightness(LightLayer.BLOCK, pos) > i) { return false; } else { int j = level.getLevel().isThundering() ? level.getMaxLocalRawBrightness(pos, 10) : level.getMaxLocalRawBrightness(pos); return j <= dimensionType.monsterSpawnLightTest().sample(random); } } } public static boolean checkMonsterSpawnRules( EntityType entityType, ServerLevelAccessor serverLevelAccessor, EntitySpawnReason entitySpawnReason, BlockPos blockPos, RandomSource randomSource ) { return serverLevelAccessor.getDifficulty() != Difficulty.PEACEFUL && (EntitySpawnReason.ignoresLightRequirements(entitySpawnReason) || isDarkEnoughToSpawn(serverLevelAccessor, blockPos, randomSource)) && checkMobSpawnRules(entityType, serverLevelAccessor, entitySpawnReason, blockPos, randomSource); } public static boolean checkAnyLightMonsterSpawnRules( EntityType entityType, LevelAccessor levelAccessor, EntitySpawnReason entitySpawnReason, BlockPos blockPos, RandomSource randomSource ) { return levelAccessor.getDifficulty() != Difficulty.PEACEFUL && checkMobSpawnRules(entityType, levelAccessor, entitySpawnReason, blockPos, randomSource); } public static Builder createMonsterAttributes() { return Mob.createMobAttributes().add(Attributes.ATTACK_DAMAGE); } @Override public boolean shouldDropExperience() { return true; } @Override protected boolean shouldDropLoot() { return true; } public boolean isPreventingPlayerRest(ServerLevel serverLevel, Player player) { return true; } @Override public ItemStack getProjectile(ItemStack weaponStack) { if (weaponStack.getItem() instanceof ProjectileWeaponItem) { Predicate predicate = ((ProjectileWeaponItem)weaponStack.getItem()).getSupportedHeldProjectiles(); ItemStack itemStack = ProjectileWeaponItem.getHeldProjectile(this, predicate); return itemStack.isEmpty() ? new ItemStack(Items.ARROW) : itemStack; } else { return ItemStack.EMPTY; } } }