105 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			105 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.util;
 | |
| 
 | |
| import java.util.Optional;
 | |
| import net.minecraft.core.BlockPos;
 | |
| import net.minecraft.core.Direction;
 | |
| import net.minecraft.server.level.ServerLevel;
 | |
| import net.minecraft.tags.BlockTags;
 | |
| import net.minecraft.world.entity.EntitySpawnReason;
 | |
| import net.minecraft.world.entity.EntityType;
 | |
| import net.minecraft.world.entity.Mob;
 | |
| import net.minecraft.world.level.block.Block;
 | |
| import net.minecraft.world.level.block.Blocks;
 | |
| import net.minecraft.world.level.block.LeavesBlock;
 | |
| import net.minecraft.world.level.block.StainedGlassBlock;
 | |
| import net.minecraft.world.level.block.StainedGlassPaneBlock;
 | |
| import net.minecraft.world.level.block.state.BlockState;
 | |
| 
 | |
| public class SpawnUtil {
 | |
| 	public static <T extends Mob> Optional<T> trySpawnMob(
 | |
| 		EntityType<T> entityType,
 | |
| 		EntitySpawnReason spawnReason,
 | |
| 		ServerLevel level,
 | |
| 		BlockPos pos,
 | |
| 		int attempts,
 | |
| 		int range,
 | |
| 		int yOffset,
 | |
| 		SpawnUtil.Strategy strategy,
 | |
| 		boolean checkCollision
 | |
| 	) {
 | |
| 		BlockPos.MutableBlockPos mutableBlockPos = pos.mutable();
 | |
| 
 | |
| 		for (int i = 0; i < attempts; i++) {
 | |
| 			int j = Mth.randomBetweenInclusive(level.random, -range, range);
 | |
| 			int k = Mth.randomBetweenInclusive(level.random, -range, range);
 | |
| 			mutableBlockPos.setWithOffset(pos, j, yOffset, k);
 | |
| 			if (level.getWorldBorder().isWithinBounds(mutableBlockPos)
 | |
| 				&& moveToPossibleSpawnPosition(level, yOffset, mutableBlockPos, strategy)
 | |
| 				&& (!checkCollision || level.noCollision(entityType.getSpawnAABB(mutableBlockPos.getX() + 0.5, mutableBlockPos.getY(), mutableBlockPos.getZ() + 0.5)))) {
 | |
| 				T mob = (T)entityType.create(level, null, mutableBlockPos, spawnReason, false, false);
 | |
| 				if (mob != null) {
 | |
| 					if (mob.checkSpawnRules(level, spawnReason) && mob.checkSpawnObstruction(level)) {
 | |
| 						level.addFreshEntityWithPassengers(mob);
 | |
| 						mob.playAmbientSound();
 | |
| 						return Optional.of(mob);
 | |
| 					}
 | |
| 
 | |
| 					mob.discard();
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return Optional.empty();
 | |
| 	}
 | |
| 
 | |
| 	private static boolean moveToPossibleSpawnPosition(ServerLevel level, int yOffset, BlockPos.MutableBlockPos pos, SpawnUtil.Strategy strategy) {
 | |
| 		BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos().set(pos);
 | |
| 		BlockState blockState = level.getBlockState(mutableBlockPos);
 | |
| 
 | |
| 		for (int i = yOffset; i >= -yOffset; i--) {
 | |
| 			pos.move(Direction.DOWN);
 | |
| 			mutableBlockPos.setWithOffset(pos, Direction.UP);
 | |
| 			BlockState blockState2 = level.getBlockState(pos);
 | |
| 			if (strategy.canSpawnOn(level, pos, blockState2, mutableBlockPos, blockState)) {
 | |
| 				pos.move(Direction.UP);
 | |
| 				return true;
 | |
| 			}
 | |
| 
 | |
| 			blockState = blockState2;
 | |
| 		}
 | |
| 
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	public interface Strategy {
 | |
| 		@Deprecated
 | |
| 		SpawnUtil.Strategy LEGACY_IRON_GOLEM = (serverLevel, blockPos, blockState, blockPos2, blockState2) -> !blockState.is(Blocks.COBWEB)
 | |
| 				&& !blockState.is(Blocks.CACTUS)
 | |
| 				&& !blockState.is(Blocks.GLASS_PANE)
 | |
| 				&& !(blockState.getBlock() instanceof StainedGlassPaneBlock)
 | |
| 				&& !(blockState.getBlock() instanceof StainedGlassBlock)
 | |
| 				&& !(blockState.getBlock() instanceof LeavesBlock)
 | |
| 				&& !blockState.is(Blocks.CONDUIT)
 | |
| 				&& !blockState.is(Blocks.ICE)
 | |
| 				&& !blockState.is(Blocks.TNT)
 | |
| 				&& !blockState.is(Blocks.GLOWSTONE)
 | |
| 				&& !blockState.is(Blocks.BEACON)
 | |
| 				&& !blockState.is(Blocks.SEA_LANTERN)
 | |
| 				&& !blockState.is(Blocks.FROSTED_ICE)
 | |
| 				&& !blockState.is(Blocks.TINTED_GLASS)
 | |
| 				&& !blockState.is(Blocks.GLASS)
 | |
| 			? (blockState2.isAir() || blockState2.liquid()) && (blockState.isSolid() || blockState.is(Blocks.POWDER_SNOW))
 | |
| 			: false;
 | |
| 		SpawnUtil.Strategy ON_TOP_OF_COLLIDER = (serverLevel, blockPos, blockState, blockPos2, blockState2) -> blockState2.getCollisionShape(serverLevel, blockPos2)
 | |
| 				.isEmpty()
 | |
| 			&& Block.isFaceFull(blockState.getCollisionShape(serverLevel, blockPos), Direction.UP);
 | |
| 		SpawnUtil.Strategy ON_TOP_OF_COLLIDER_NO_LEAVES = (serverLevel, blockPos, blockState, blockPos2, blockState2) -> blockState2.getCollisionShape(
 | |
| 					serverLevel, blockPos2
 | |
| 				)
 | |
| 				.isEmpty()
 | |
| 			&& !blockState.is(BlockTags.LEAVES)
 | |
| 			&& Block.isFaceFull(blockState.getCollisionShape(serverLevel, blockPos), Direction.UP);
 | |
| 
 | |
| 		boolean canSpawnOn(ServerLevel serverLevel, BlockPos blockPos, BlockState blockState, BlockPos blockPos2, BlockState blockState2);
 | |
| 	}
 | |
| }
 |