227 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			227 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.world.level.levelgen;
 | |
| 
 | |
| import java.util.Optional;
 | |
| import java.util.OptionalInt;
 | |
| import java.util.function.Predicate;
 | |
| import net.minecraft.core.BlockPos;
 | |
| import net.minecraft.core.Direction;
 | |
| import net.minecraft.world.level.LevelSimulatedReader;
 | |
| import net.minecraft.world.level.block.state.BlockState;
 | |
| 
 | |
| /**
 | |
|  * A representation of an integer valued interval, either bounded or unbounded.
 | |
|  * While the class itself does not imply any coordinate in particular, this is practically used to represent a column in the Y direction.
 | |
|  */
 | |
| public abstract class Column {
 | |
| 	/**
 | |
| 	 * @return A column of the closed interval [floor, ceiling].
 | |
| 	 */
 | |
| 	public static Column.Range around(int floor, int ceiling) {
 | |
| 		return new Column.Range(floor - 1, ceiling + 1);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @return A column of the open interval (floor, ceiling).
 | |
| 	 */
 | |
| 	public static Column.Range inside(int floor, int ceiling) {
 | |
| 		return new Column.Range(floor, ceiling);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @return A column of the unbounded interval (-infinity, ceiling).
 | |
| 	 */
 | |
| 	public static Column below(int ceiling) {
 | |
| 		return new Column.Ray(ceiling, false);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @return A column of the unbounded interval (-infinity, ceiling].
 | |
| 	 */
 | |
| 	public static Column fromHighest(int ceiling) {
 | |
| 		return new Column.Ray(ceiling + 1, false);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @return A column of the unbounded interval (floor, infinity).
 | |
| 	 */
 | |
| 	public static Column above(int floor) {
 | |
| 		return new Column.Ray(floor, true);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @return A column of the unbounded interval [floor, infinity).
 | |
| 	 */
 | |
| 	public static Column fromLowest(int floor) {
 | |
| 		return new Column.Ray(floor - 1, true);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @return A column of the unbounded interval (-infinity, infinity).
 | |
| 	 */
 | |
| 	public static Column line() {
 | |
| 		return Column.Line.INSTANCE;
 | |
| 	}
 | |
| 
 | |
| 	public static Column create(OptionalInt floor, OptionalInt ceiling) {
 | |
| 		if (floor.isPresent() && ceiling.isPresent()) {
 | |
| 			return inside(floor.getAsInt(), ceiling.getAsInt());
 | |
| 		} else if (floor.isPresent()) {
 | |
| 			return above(floor.getAsInt());
 | |
| 		} else {
 | |
| 			return ceiling.isPresent() ? below(ceiling.getAsInt()) : line();
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public abstract OptionalInt getCeiling();
 | |
| 
 | |
| 	public abstract OptionalInt getFloor();
 | |
| 
 | |
| 	public abstract OptionalInt getHeight();
 | |
| 
 | |
| 	public Column withFloor(OptionalInt floor) {
 | |
| 		return create(floor, this.getCeiling());
 | |
| 	}
 | |
| 
 | |
| 	public Column withCeiling(OptionalInt ceiling) {
 | |
| 		return create(this.getFloor(), ceiling);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Scans for a column of states satisfying {@code columnPredicate}, up to a length of {@code maxDistance} from the origin, and ending with a state which satisfies {@code tipPredicate}.
 | |
| 	 * @return A column representing the tips found. The column will be bounded if a tip was reached in the given direction, unbounded otherwise.
 | |
| 	 */
 | |
| 	public static Optional<Column> scan(
 | |
| 		LevelSimulatedReader level, BlockPos pos, int maxDistance, Predicate<BlockState> columnPredicate, Predicate<BlockState> tipPredicate
 | |
| 	) {
 | |
| 		BlockPos.MutableBlockPos mutableBlockPos = pos.mutable();
 | |
| 		if (!level.isStateAtPosition(pos, columnPredicate)) {
 | |
| 			return Optional.empty();
 | |
| 		} else {
 | |
| 			int i = pos.getY();
 | |
| 			OptionalInt optionalInt = scanDirection(level, maxDistance, columnPredicate, tipPredicate, mutableBlockPos, i, Direction.UP);
 | |
| 			OptionalInt optionalInt2 = scanDirection(level, maxDistance, columnPredicate, tipPredicate, mutableBlockPos, i, Direction.DOWN);
 | |
| 			return Optional.of(create(optionalInt2, optionalInt));
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Scans for a sequence of states in a given {@code direction}, up to a length of {@code maxDistance} which satisfy {@code columnPredicate}, and ending with a state which satisfies {@code tipPredicate}.
 | |
| 	 * @return The y position of the tip, if found.
 | |
| 	 */
 | |
| 	private static OptionalInt scanDirection(
 | |
| 		LevelSimulatedReader level,
 | |
| 		int maxDistance,
 | |
| 		Predicate<BlockState> columnPredicate,
 | |
| 		Predicate<BlockState> tipPredicate,
 | |
| 		BlockPos.MutableBlockPos mutablePos,
 | |
| 		int startY,
 | |
| 		Direction direction
 | |
| 	) {
 | |
| 		mutablePos.setY(startY);
 | |
| 
 | |
| 		for (int i = 1; i < maxDistance && level.isStateAtPosition(mutablePos, columnPredicate); i++) {
 | |
| 			mutablePos.move(direction);
 | |
| 		}
 | |
| 
 | |
| 		return level.isStateAtPosition(mutablePos, tipPredicate) ? OptionalInt.of(mutablePos.getY()) : OptionalInt.empty();
 | |
| 	}
 | |
| 
 | |
| 	public static final class Line extends Column {
 | |
| 		static final Column.Line INSTANCE = new Column.Line();
 | |
| 
 | |
| 		private Line() {
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public OptionalInt getCeiling() {
 | |
| 			return OptionalInt.empty();
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public OptionalInt getFloor() {
 | |
| 			return OptionalInt.empty();
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public OptionalInt getHeight() {
 | |
| 			return OptionalInt.empty();
 | |
| 		}
 | |
| 
 | |
| 		public String toString() {
 | |
| 			return "C(-)";
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public static final class Range extends Column {
 | |
| 		private final int floor;
 | |
| 		private final int ceiling;
 | |
| 
 | |
| 		protected Range(int floor, int ceiling) {
 | |
| 			this.floor = floor;
 | |
| 			this.ceiling = ceiling;
 | |
| 			if (this.height() < 0) {
 | |
| 				throw new IllegalArgumentException("Column of negative height: " + this);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public OptionalInt getCeiling() {
 | |
| 			return OptionalInt.of(this.ceiling);
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public OptionalInt getFloor() {
 | |
| 			return OptionalInt.of(this.floor);
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public OptionalInt getHeight() {
 | |
| 			return OptionalInt.of(this.height());
 | |
| 		}
 | |
| 
 | |
| 		public int ceiling() {
 | |
| 			return this.ceiling;
 | |
| 		}
 | |
| 
 | |
| 		public int floor() {
 | |
| 			return this.floor;
 | |
| 		}
 | |
| 
 | |
| 		public int height() {
 | |
| 			return this.ceiling - this.floor - 1;
 | |
| 		}
 | |
| 
 | |
| 		public String toString() {
 | |
| 			return "C(" + this.ceiling + "-" + this.floor + ")";
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public static final class Ray extends Column {
 | |
| 		private final int edge;
 | |
| 		private final boolean pointingUp;
 | |
| 
 | |
| 		public Ray(int edge, boolean pointingUp) {
 | |
| 			this.edge = edge;
 | |
| 			this.pointingUp = pointingUp;
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public OptionalInt getCeiling() {
 | |
| 			return this.pointingUp ? OptionalInt.empty() : OptionalInt.of(this.edge);
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public OptionalInt getFloor() {
 | |
| 			return this.pointingUp ? OptionalInt.of(this.edge) : OptionalInt.empty();
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public OptionalInt getHeight() {
 | |
| 			return OptionalInt.empty();
 | |
| 		}
 | |
| 
 | |
| 		public String toString() {
 | |
| 			return this.pointingUp ? "C(" + this.edge + "-)" : "C(-" + this.edge + ")";
 | |
| 		}
 | |
| 	}
 | |
| }
 |