685 lines
		
	
	
	
		
			19 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			685 lines
		
	
	
	
		
			19 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.core;
 | |
| 
 | |
| import com.google.common.collect.Iterators;
 | |
| import com.mojang.serialization.Codec;
 | |
| import com.mojang.serialization.DataResult;
 | |
| import io.netty.buffer.ByteBuf;
 | |
| import java.util.Arrays;
 | |
| import java.util.Collection;
 | |
| import java.util.Comparator;
 | |
| import java.util.Iterator;
 | |
| import java.util.List;
 | |
| import java.util.function.IntFunction;
 | |
| import java.util.function.Predicate;
 | |
| import java.util.stream.Stream;
 | |
| import net.minecraft.Util;
 | |
| import net.minecraft.network.codec.ByteBufCodecs;
 | |
| import net.minecraft.network.codec.StreamCodec;
 | |
| import net.minecraft.util.ByIdMap;
 | |
| import net.minecraft.util.Mth;
 | |
| import net.minecraft.util.RandomSource;
 | |
| import net.minecraft.util.StringRepresentable;
 | |
| import net.minecraft.world.entity.Entity;
 | |
| import net.minecraft.world.phys.Vec3;
 | |
| import org.jetbrains.annotations.Contract;
 | |
| import org.jetbrains.annotations.Nullable;
 | |
| import org.joml.Matrix4fc;
 | |
| import org.joml.Quaternionf;
 | |
| import org.joml.Vector3f;
 | |
| import org.joml.Vector3fc;
 | |
| 
 | |
| public enum Direction implements StringRepresentable {
 | |
| 	DOWN(0, 1, -1, "down", Direction.AxisDirection.NEGATIVE, Direction.Axis.Y, new Vec3i(0, -1, 0)),
 | |
| 	UP(1, 0, -1, "up", Direction.AxisDirection.POSITIVE, Direction.Axis.Y, new Vec3i(0, 1, 0)),
 | |
| 	NORTH(2, 3, 2, "north", Direction.AxisDirection.NEGATIVE, Direction.Axis.Z, new Vec3i(0, 0, -1)),
 | |
| 	SOUTH(3, 2, 0, "south", Direction.AxisDirection.POSITIVE, Direction.Axis.Z, new Vec3i(0, 0, 1)),
 | |
| 	WEST(4, 5, 1, "west", Direction.AxisDirection.NEGATIVE, Direction.Axis.X, new Vec3i(-1, 0, 0)),
 | |
| 	EAST(5, 4, 3, "east", Direction.AxisDirection.POSITIVE, Direction.Axis.X, new Vec3i(1, 0, 0));
 | |
| 
 | |
| 	public static final StringRepresentable.EnumCodec<Direction> CODEC = StringRepresentable.fromEnum(Direction::values);
 | |
| 	public static final Codec<Direction> VERTICAL_CODEC = CODEC.validate(Direction::verifyVertical);
 | |
| 	public static final IntFunction<Direction> BY_ID = ByIdMap.continuous(Direction::get3DDataValue, values(), ByIdMap.OutOfBoundsStrategy.WRAP);
 | |
| 	public static final StreamCodec<ByteBuf, Direction> STREAM_CODEC = ByteBufCodecs.idMapper(BY_ID, Direction::get3DDataValue);
 | |
| 	@Deprecated
 | |
| 	public static final Codec<Direction> LEGACY_ID_CODEC = Codec.BYTE.xmap(Direction::from3DDataValue, direction -> (byte)direction.get3DDataValue());
 | |
| 	@Deprecated
 | |
| 	public static final Codec<Direction> LEGACY_ID_CODEC_2D = Codec.BYTE.xmap(Direction::from2DDataValue, direction -> (byte)direction.get2DDataValue());
 | |
| 	/**
 | |
| 	 * Ordering index for D-U-N-S-W-E
 | |
| 	 */
 | |
| 	private final int data3d;
 | |
| 	/**
 | |
| 	 * Index of the opposite Direction in the VALUES array
 | |
| 	 */
 | |
| 	private final int oppositeIndex;
 | |
| 	/**
 | |
| 	 * Ordering index for the HORIZONTALS field (S-W-N-E)
 | |
| 	 */
 | |
| 	private final int data2d;
 | |
| 	private final String name;
 | |
| 	private final Direction.Axis axis;
 | |
| 	private final Direction.AxisDirection axisDirection;
 | |
| 	/**
 | |
| 	 * Normalized vector that points in the direction of this Direction
 | |
| 	 */
 | |
| 	private final Vec3i normal;
 | |
| 	private final Vec3 normalVec3;
 | |
| 	private final Vector3fc normalVec3f;
 | |
| 	private static final Direction[] VALUES = values();
 | |
| 	private static final Direction[] BY_3D_DATA = (Direction[])Arrays.stream(VALUES)
 | |
| 		.sorted(Comparator.comparingInt(direction -> direction.data3d))
 | |
| 		.toArray(Direction[]::new);
 | |
| 	/**
 | |
| 	 * All Facings with horizontal axis in order S-W-N-E
 | |
| 	 */
 | |
| 	private static final Direction[] BY_2D_DATA = (Direction[])Arrays.stream(VALUES)
 | |
| 		.filter(direction -> direction.getAxis().isHorizontal())
 | |
| 		.sorted(Comparator.comparingInt(direction -> direction.data2d))
 | |
| 		.toArray(Direction[]::new);
 | |
| 
 | |
| 	private Direction(
 | |
| 		final int data3d,
 | |
| 		final int oppositeIndex,
 | |
| 		final int data2d,
 | |
| 		final String name,
 | |
| 		final Direction.AxisDirection axisDirection,
 | |
| 		final Direction.Axis axis,
 | |
| 		final Vec3i normal
 | |
| 	) {
 | |
| 		this.data3d = data3d;
 | |
| 		this.data2d = data2d;
 | |
| 		this.oppositeIndex = oppositeIndex;
 | |
| 		this.name = name;
 | |
| 		this.axis = axis;
 | |
| 		this.axisDirection = axisDirection;
 | |
| 		this.normal = normal;
 | |
| 		this.normalVec3 = Vec3.atLowerCornerOf(normal);
 | |
| 		this.normalVec3f = new Vector3f(normal.getX(), normal.getY(), normal.getZ());
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Gets the {@code Direction} values for the provided entity's
 | |
| 	 * looking direction. Dependent on yaw and pitch of entity looking.
 | |
| 	 */
 | |
| 	public static Direction[] orderedByNearest(Entity entity) {
 | |
| 		float f = entity.getViewXRot(1.0F) * (float) (Math.PI / 180.0);
 | |
| 		float g = -entity.getViewYRot(1.0F) * (float) (Math.PI / 180.0);
 | |
| 		float h = Mth.sin(f);
 | |
| 		float i = Mth.cos(f);
 | |
| 		float j = Mth.sin(g);
 | |
| 		float k = Mth.cos(g);
 | |
| 		boolean bl = j > 0.0F;
 | |
| 		boolean bl2 = h < 0.0F;
 | |
| 		boolean bl3 = k > 0.0F;
 | |
| 		float l = bl ? j : -j;
 | |
| 		float m = bl2 ? -h : h;
 | |
| 		float n = bl3 ? k : -k;
 | |
| 		float o = l * i;
 | |
| 		float p = n * i;
 | |
| 		Direction direction = bl ? EAST : WEST;
 | |
| 		Direction direction2 = bl2 ? UP : DOWN;
 | |
| 		Direction direction3 = bl3 ? SOUTH : NORTH;
 | |
| 		if (l > n) {
 | |
| 			if (m > o) {
 | |
| 				return makeDirectionArray(direction2, direction, direction3);
 | |
| 			} else {
 | |
| 				return p > m ? makeDirectionArray(direction, direction3, direction2) : makeDirectionArray(direction, direction2, direction3);
 | |
| 			}
 | |
| 		} else if (m > p) {
 | |
| 			return makeDirectionArray(direction2, direction3, direction);
 | |
| 		} else {
 | |
| 			return o > m ? makeDirectionArray(direction3, direction, direction2) : makeDirectionArray(direction3, direction2, direction);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private static Direction[] makeDirectionArray(Direction first, Direction second, Direction third) {
 | |
| 		return new Direction[]{first, second, third, third.getOpposite(), second.getOpposite(), first.getOpposite()};
 | |
| 	}
 | |
| 
 | |
| 	public static Direction rotate(Matrix4fc matrix, Direction direction) {
 | |
| 		Vector3f vector3f = matrix.transformDirection(direction.normalVec3f, new Vector3f());
 | |
| 		return getApproximateNearest(vector3f.x(), vector3f.y(), vector3f.z());
 | |
| 	}
 | |
| 
 | |
| 	public static Collection<Direction> allShuffled(RandomSource random) {
 | |
| 		return Util.<Direction>shuffledCopy(values(), random);
 | |
| 	}
 | |
| 
 | |
| 	public static Stream<Direction> stream() {
 | |
| 		return Stream.of(VALUES);
 | |
| 	}
 | |
| 
 | |
| 	public static float getYRot(Direction direction) {
 | |
| 		return switch (direction) {
 | |
| 			case NORTH -> 180.0F;
 | |
| 			case SOUTH -> 0.0F;
 | |
| 			case WEST -> 90.0F;
 | |
| 			case EAST -> -90.0F;
 | |
| 			default -> throw new IllegalStateException("No y-Rot for vertical axis: " + direction);
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	public Quaternionf getRotation() {
 | |
| 		return switch (this) {
 | |
| 			case DOWN -> new Quaternionf().rotationX((float) Math.PI);
 | |
| 			case UP -> new Quaternionf();
 | |
| 			case NORTH -> new Quaternionf().rotationXYZ((float) (Math.PI / 2), 0.0F, (float) Math.PI);
 | |
| 			case SOUTH -> new Quaternionf().rotationX((float) (Math.PI / 2));
 | |
| 			case WEST -> new Quaternionf().rotationXYZ((float) (Math.PI / 2), 0.0F, (float) (Math.PI / 2));
 | |
| 			case EAST -> new Quaternionf().rotationXYZ((float) (Math.PI / 2), 0.0F, (float) (-Math.PI / 2));
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @return the index of this Direction (0-5). The order is D-U-N-S-W-E
 | |
| 	 */
 | |
| 	public int get3DDataValue() {
 | |
| 		return this.data3d;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @return the index of this horizontal facing (0-3). The order is S-W-N-E
 | |
| 	 */
 | |
| 	public int get2DDataValue() {
 | |
| 		return this.data2d;
 | |
| 	}
 | |
| 
 | |
| 	public Direction.AxisDirection getAxisDirection() {
 | |
| 		return this.axisDirection;
 | |
| 	}
 | |
| 
 | |
| 	public static Direction getFacingAxis(Entity entity, Direction.Axis axis) {
 | |
| 		return switch (axis) {
 | |
| 			case X -> EAST.isFacingAngle(entity.getViewYRot(1.0F)) ? EAST : WEST;
 | |
| 			case Y -> entity.getViewXRot(1.0F) < 0.0F ? UP : DOWN;
 | |
| 			case Z -> SOUTH.isFacingAngle(entity.getViewYRot(1.0F)) ? SOUTH : NORTH;
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @return the opposite Direction (e.g. DOWN => UP)
 | |
| 	 */
 | |
| 	public Direction getOpposite() {
 | |
| 		return from3DDataValue(this.oppositeIndex);
 | |
| 	}
 | |
| 
 | |
| 	public Direction getClockWise(Direction.Axis axis) {
 | |
| 		return switch (axis) {
 | |
| 			case X -> this != WEST && this != EAST ? this.getClockWiseX() : this;
 | |
| 			case Y -> this != UP && this != DOWN ? this.getClockWise() : this;
 | |
| 			case Z -> this != NORTH && this != SOUTH ? this.getClockWiseZ() : this;
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	public Direction getCounterClockWise(Direction.Axis axis) {
 | |
| 		return switch (axis) {
 | |
| 			case X -> this != WEST && this != EAST ? this.getCounterClockWiseX() : this;
 | |
| 			case Y -> this != UP && this != DOWN ? this.getCounterClockWise() : this;
 | |
| 			case Z -> this != NORTH && this != SOUTH ? this.getCounterClockWiseZ() : this;
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Rotate this Direction around the Y axis clockwise (NORTH => EAST => SOUTH => WEST => NORTH)
 | |
| 	 */
 | |
| 	public Direction getClockWise() {
 | |
| 		return switch (this) {
 | |
| 			case NORTH -> EAST;
 | |
| 			case SOUTH -> WEST;
 | |
| 			case WEST -> NORTH;
 | |
| 			case EAST -> SOUTH;
 | |
| 			default -> throw new IllegalStateException("Unable to get Y-rotated facing of " + this);
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	private Direction getClockWiseX() {
 | |
| 		return switch (this) {
 | |
| 			case DOWN -> SOUTH;
 | |
| 			case UP -> NORTH;
 | |
| 			case NORTH -> DOWN;
 | |
| 			case SOUTH -> UP;
 | |
| 			default -> throw new IllegalStateException("Unable to get X-rotated facing of " + this);
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	private Direction getCounterClockWiseX() {
 | |
| 		return switch (this) {
 | |
| 			case DOWN -> NORTH;
 | |
| 			case UP -> SOUTH;
 | |
| 			case NORTH -> UP;
 | |
| 			case SOUTH -> DOWN;
 | |
| 			default -> throw new IllegalStateException("Unable to get X-rotated facing of " + this);
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	private Direction getClockWiseZ() {
 | |
| 		return switch (this) {
 | |
| 			case DOWN -> WEST;
 | |
| 			case UP -> EAST;
 | |
| 			default -> throw new IllegalStateException("Unable to get Z-rotated facing of " + this);
 | |
| 			case WEST -> UP;
 | |
| 			case EAST -> DOWN;
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	private Direction getCounterClockWiseZ() {
 | |
| 		return switch (this) {
 | |
| 			case DOWN -> EAST;
 | |
| 			case UP -> WEST;
 | |
| 			default -> throw new IllegalStateException("Unable to get Z-rotated facing of " + this);
 | |
| 			case WEST -> DOWN;
 | |
| 			case EAST -> UP;
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Rotate this Direction around the Y axis counter-clockwise (NORTH => WEST => SOUTH => EAST => NORTH)
 | |
| 	 */
 | |
| 	public Direction getCounterClockWise() {
 | |
| 		return switch (this) {
 | |
| 			case NORTH -> WEST;
 | |
| 			case SOUTH -> EAST;
 | |
| 			case WEST -> SOUTH;
 | |
| 			case EAST -> NORTH;
 | |
| 			default -> throw new IllegalStateException("Unable to get CCW facing of " + this);
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @return the offset in the x direction
 | |
| 	 */
 | |
| 	public int getStepX() {
 | |
| 		return this.normal.getX();
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @return the offset in the y direction
 | |
| 	 */
 | |
| 	public int getStepY() {
 | |
| 		return this.normal.getY();
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @return the offset in the z direction
 | |
| 	 */
 | |
| 	public int getStepZ() {
 | |
| 		return this.normal.getZ();
 | |
| 	}
 | |
| 
 | |
| 	public Vector3f step() {
 | |
| 		return new Vector3f(this.normalVec3f);
 | |
| 	}
 | |
| 
 | |
| 	public String getName() {
 | |
| 		return this.name;
 | |
| 	}
 | |
| 
 | |
| 	public Direction.Axis getAxis() {
 | |
| 		return this.axis;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @return the Direction specified by the given name or null if no such Direction exists
 | |
| 	 */
 | |
| 	@Nullable
 | |
| 	public static Direction byName(@Nullable String name) {
 | |
| 		return (Direction)CODEC.byName(name);
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @return the {@code Direction} corresponding to the given index (0-5). Out of bounds values are wrapped around. The order is D-U-N-S-W-E.
 | |
| 	 * @see #get3DDataValue
 | |
| 	 */
 | |
| 	public static Direction from3DDataValue(int index) {
 | |
| 		return BY_3D_DATA[Mth.abs(index % BY_3D_DATA.length)];
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @return the Direction corresponding to the given horizontal index (0-3). Out of bounds values are wrapped around. The order is S-W-N-E.
 | |
| 	 * @see #get2DDataValue
 | |
| 	 */
 | |
| 	public static Direction from2DDataValue(int horizontalIndex) {
 | |
| 		return BY_2D_DATA[Mth.abs(horizontalIndex % BY_2D_DATA.length)];
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @return the Direction corresponding to the given angle in degrees (0-360). Out of bounds values are wrapped around. An angle of 0 is SOUTH, an angle of 90 would be WEST.
 | |
| 	 */
 | |
| 	public static Direction fromYRot(double angle) {
 | |
| 		return from2DDataValue(Mth.floor(angle / 90.0 + 0.5) & 3);
 | |
| 	}
 | |
| 
 | |
| 	public static Direction fromAxisAndDirection(Direction.Axis axis, Direction.AxisDirection axisDirection) {
 | |
| 		return switch (axis) {
 | |
| 			case X -> axisDirection == Direction.AxisDirection.POSITIVE ? EAST : WEST;
 | |
| 			case Y -> axisDirection == Direction.AxisDirection.POSITIVE ? UP : DOWN;
 | |
| 			case Z -> axisDirection == Direction.AxisDirection.POSITIVE ? SOUTH : NORTH;
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * @return the angle in degrees corresponding to this Direction.
 | |
| 	 * @see #fromYRot
 | |
| 	 */
 | |
| 	public float toYRot() {
 | |
| 		return (this.data2d & 3) * 90;
 | |
| 	}
 | |
| 
 | |
| 	public static Direction getRandom(RandomSource random) {
 | |
| 		return Util.getRandom(VALUES, random);
 | |
| 	}
 | |
| 
 | |
| 	public static Direction getApproximateNearest(double x, double y, double z) {
 | |
| 		return getApproximateNearest((float)x, (float)y, (float)z);
 | |
| 	}
 | |
| 
 | |
| 	public static Direction getApproximateNearest(float x, float y, float z) {
 | |
| 		Direction direction = NORTH;
 | |
| 		float f = Float.MIN_VALUE;
 | |
| 
 | |
| 		for (Direction direction2 : VALUES) {
 | |
| 			float g = x * direction2.normal.getX() + y * direction2.normal.getY() + z * direction2.normal.getZ();
 | |
| 			if (g > f) {
 | |
| 				f = g;
 | |
| 				direction = direction2;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return direction;
 | |
| 	}
 | |
| 
 | |
| 	public static Direction getApproximateNearest(Vec3 vector) {
 | |
| 		return getApproximateNearest(vector.x, vector.y, vector.z);
 | |
| 	}
 | |
| 
 | |
| 	@Nullable
 | |
| 	@Contract("_,_,_,!null->!null;_,_,_,_->_")
 | |
| 	public static Direction getNearest(int x, int y, int z, @Nullable Direction defaultValue) {
 | |
| 		int i = Math.abs(x);
 | |
| 		int j = Math.abs(y);
 | |
| 		int k = Math.abs(z);
 | |
| 		if (i > k && i > j) {
 | |
| 			return x < 0 ? WEST : EAST;
 | |
| 		} else if (k > i && k > j) {
 | |
| 			return z < 0 ? NORTH : SOUTH;
 | |
| 		} else if (j > i && j > k) {
 | |
| 			return y < 0 ? DOWN : UP;
 | |
| 		} else {
 | |
| 			return defaultValue;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@Nullable
 | |
| 	@Contract("_,!null->!null;_,_->_")
 | |
| 	public static Direction getNearest(Vec3i vector, @Nullable Direction defaultValue) {
 | |
| 		return getNearest(vector.getX(), vector.getY(), vector.getZ(), defaultValue);
 | |
| 	}
 | |
| 
 | |
| 	public String toString() {
 | |
| 		return this.name;
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public String getSerializedName() {
 | |
| 		return this.name;
 | |
| 	}
 | |
| 
 | |
| 	private static DataResult<Direction> verifyVertical(Direction direction) {
 | |
| 		return direction.getAxis().isVertical() ? DataResult.success(direction) : DataResult.error(() -> "Expected a vertical direction");
 | |
| 	}
 | |
| 
 | |
| 	public static Direction get(Direction.AxisDirection axisDirection, Direction.Axis axis) {
 | |
| 		for (Direction direction : VALUES) {
 | |
| 			if (direction.getAxisDirection() == axisDirection && direction.getAxis() == axis) {
 | |
| 				return direction;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		throw new IllegalArgumentException("No such direction: " + axisDirection + " " + axis);
 | |
| 	}
 | |
| 
 | |
| 	public Vec3i getUnitVec3i() {
 | |
| 		return this.normal;
 | |
| 	}
 | |
| 
 | |
| 	public Vec3 getUnitVec3() {
 | |
| 		return this.normalVec3;
 | |
| 	}
 | |
| 
 | |
| 	public Vector3fc getUnitVec3f() {
 | |
| 		return this.normalVec3f;
 | |
| 	}
 | |
| 
 | |
| 	public boolean isFacingAngle(float degrees) {
 | |
| 		float f = degrees * (float) (Math.PI / 180.0);
 | |
| 		float g = -Mth.sin(f);
 | |
| 		float h = Mth.cos(f);
 | |
| 		return this.normal.getX() * g + this.normal.getZ() * h > 0.0F;
 | |
| 	}
 | |
| 
 | |
| 	public static enum Axis implements StringRepresentable, Predicate<Direction> {
 | |
| 		X("x") {
 | |
| 			@Override
 | |
| 			public int choose(int x, int y, int z) {
 | |
| 				return x;
 | |
| 			}
 | |
| 
 | |
| 			@Override
 | |
| 			public boolean choose(boolean x, boolean y, boolean z) {
 | |
| 				return x;
 | |
| 			}
 | |
| 
 | |
| 			@Override
 | |
| 			public double choose(double x, double y, double z) {
 | |
| 				return x;
 | |
| 			}
 | |
| 
 | |
| 			@Override
 | |
| 			public Direction getPositive() {
 | |
| 				return Direction.EAST;
 | |
| 			}
 | |
| 
 | |
| 			@Override
 | |
| 			public Direction getNegative() {
 | |
| 				return Direction.WEST;
 | |
| 			}
 | |
| 		},
 | |
| 		Y("y") {
 | |
| 			@Override
 | |
| 			public int choose(int x, int y, int z) {
 | |
| 				return y;
 | |
| 			}
 | |
| 
 | |
| 			@Override
 | |
| 			public double choose(double x, double y, double z) {
 | |
| 				return y;
 | |
| 			}
 | |
| 
 | |
| 			@Override
 | |
| 			public boolean choose(boolean x, boolean y, boolean z) {
 | |
| 				return y;
 | |
| 			}
 | |
| 
 | |
| 			@Override
 | |
| 			public Direction getPositive() {
 | |
| 				return Direction.UP;
 | |
| 			}
 | |
| 
 | |
| 			@Override
 | |
| 			public Direction getNegative() {
 | |
| 				return Direction.DOWN;
 | |
| 			}
 | |
| 		},
 | |
| 		Z("z") {
 | |
| 			@Override
 | |
| 			public int choose(int x, int y, int z) {
 | |
| 				return z;
 | |
| 			}
 | |
| 
 | |
| 			@Override
 | |
| 			public double choose(double x, double y, double z) {
 | |
| 				return z;
 | |
| 			}
 | |
| 
 | |
| 			@Override
 | |
| 			public boolean choose(boolean x, boolean y, boolean z) {
 | |
| 				return z;
 | |
| 			}
 | |
| 
 | |
| 			@Override
 | |
| 			public Direction getPositive() {
 | |
| 				return Direction.SOUTH;
 | |
| 			}
 | |
| 
 | |
| 			@Override
 | |
| 			public Direction getNegative() {
 | |
| 				return Direction.NORTH;
 | |
| 			}
 | |
| 		};
 | |
| 
 | |
| 		public static final Direction.Axis[] VALUES = values();
 | |
| 		public static final StringRepresentable.EnumCodec<Direction.Axis> CODEC = StringRepresentable.fromEnum(Direction.Axis::values);
 | |
| 		private final String name;
 | |
| 
 | |
| 		Axis(final String name) {
 | |
| 			this.name = name;
 | |
| 		}
 | |
| 
 | |
| 		/**
 | |
| 		 * @return the Axis specified by the given name or {@code null} if no such Axis exists
 | |
| 		 */
 | |
| 		@Nullable
 | |
| 		public static Direction.Axis byName(String name) {
 | |
| 			return (Direction.Axis)CODEC.byName(name);
 | |
| 		}
 | |
| 
 | |
| 		public String getName() {
 | |
| 			return this.name;
 | |
| 		}
 | |
| 
 | |
| 		public boolean isVertical() {
 | |
| 			return this == Y;
 | |
| 		}
 | |
| 
 | |
| 		/**
 | |
| 		 * @return whether this Axis is on the horizontal plane (true for X and Z)
 | |
| 		 */
 | |
| 		public boolean isHorizontal() {
 | |
| 			return this == X || this == Z;
 | |
| 		}
 | |
| 
 | |
| 		public abstract Direction getPositive();
 | |
| 
 | |
| 		public abstract Direction getNegative();
 | |
| 
 | |
| 		public Direction[] getDirections() {
 | |
| 			return new Direction[]{this.getPositive(), this.getNegative()};
 | |
| 		}
 | |
| 
 | |
| 		public String toString() {
 | |
| 			return this.name;
 | |
| 		}
 | |
| 
 | |
| 		public static Direction.Axis getRandom(RandomSource random) {
 | |
| 			return Util.getRandom(VALUES, random);
 | |
| 		}
 | |
| 
 | |
| 		public boolean test(@Nullable Direction direction) {
 | |
| 			return direction != null && direction.getAxis() == this;
 | |
| 		}
 | |
| 
 | |
| 		/**
 | |
| 		 * @return this Axis' Plane (VERTICAL for Y, HORIZONTAL for X and Z)
 | |
| 		 */
 | |
| 		public Direction.Plane getPlane() {
 | |
| 			return switch (this) {
 | |
| 				case X, Z -> Direction.Plane.HORIZONTAL;
 | |
| 				case Y -> Direction.Plane.VERTICAL;
 | |
| 			};
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public String getSerializedName() {
 | |
| 			return this.name;
 | |
| 		}
 | |
| 
 | |
| 		public abstract int choose(int x, int y, int z);
 | |
| 
 | |
| 		public abstract double choose(double x, double y, double z);
 | |
| 
 | |
| 		public abstract boolean choose(boolean x, boolean y, boolean z);
 | |
| 	}
 | |
| 
 | |
| 	public static enum AxisDirection {
 | |
| 		POSITIVE(1, "Towards positive"),
 | |
| 		NEGATIVE(-1, "Towards negative");
 | |
| 
 | |
| 		private final int step;
 | |
| 		private final String name;
 | |
| 
 | |
| 		private AxisDirection(final int step, final String name) {
 | |
| 			this.step = step;
 | |
| 			this.name = name;
 | |
| 		}
 | |
| 
 | |
| 		/**
 | |
| 		 * @return the offset for this AxisDirection. 1 for POSITIVE, -1 for NEGATIVE
 | |
| 		 */
 | |
| 		public int getStep() {
 | |
| 			return this.step;
 | |
| 		}
 | |
| 
 | |
| 		public String getName() {
 | |
| 			return this.name;
 | |
| 		}
 | |
| 
 | |
| 		public String toString() {
 | |
| 			return this.name;
 | |
| 		}
 | |
| 
 | |
| 		public Direction.AxisDirection opposite() {
 | |
| 			return this == POSITIVE ? NEGATIVE : POSITIVE;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public static enum Plane implements Iterable<Direction>, Predicate<Direction> {
 | |
| 		HORIZONTAL(new Direction[]{Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST}, new Direction.Axis[]{Direction.Axis.X, Direction.Axis.Z}),
 | |
| 		VERTICAL(new Direction[]{Direction.UP, Direction.DOWN}, new Direction.Axis[]{Direction.Axis.Y});
 | |
| 
 | |
| 		private final Direction[] faces;
 | |
| 		private final Direction.Axis[] axis;
 | |
| 
 | |
| 		private Plane(final Direction[] faces, final Direction.Axis[] axis) {
 | |
| 			this.faces = faces;
 | |
| 			this.axis = axis;
 | |
| 		}
 | |
| 
 | |
| 		public Direction getRandomDirection(RandomSource random) {
 | |
| 			return Util.getRandom(this.faces, random);
 | |
| 		}
 | |
| 
 | |
| 		public Direction.Axis getRandomAxis(RandomSource random) {
 | |
| 			return Util.getRandom(this.axis, random);
 | |
| 		}
 | |
| 
 | |
| 		public boolean test(@Nullable Direction direction) {
 | |
| 			return direction != null && direction.getAxis().getPlane() == this;
 | |
| 		}
 | |
| 
 | |
| 		public Iterator<Direction> iterator() {
 | |
| 			return Iterators.forArray(this.faces);
 | |
| 		}
 | |
| 
 | |
| 		public Stream<Direction> stream() {
 | |
| 			return Arrays.stream(this.faces);
 | |
| 		}
 | |
| 
 | |
| 		public List<Direction> shuffledCopy(RandomSource random) {
 | |
| 			return Util.shuffledCopy(this.faces, random);
 | |
| 		}
 | |
| 
 | |
| 		public int length() {
 | |
| 			return this.faces.length;
 | |
| 		}
 | |
| 	}
 | |
| }
 |