From a587ad352b4179f84e9d08179ad1adda73099fc6 Mon Sep 17 00:00:00 2001
From: FalsePattern <30945458+FalsePattern@users.noreply.github.com>
Date: Fri, 6 May 2022 17:41:02 +0200
Subject: [PATCH] backport some stuff
---
.../com/falsepattern/lib/compat/BlockPos.java | 569 ++++++++++++++++++
.../com/falsepattern/lib/compat/ChunkPos.java | 95 +++
.../com/falsepattern/lib/compat/Rotation.java | 128 ++++
.../com/falsepattern/lib/compat/Vec3i.java | 119 ++++
4 files changed, 911 insertions(+)
create mode 100644 src/main/java/com/falsepattern/lib/compat/BlockPos.java
create mode 100644 src/main/java/com/falsepattern/lib/compat/ChunkPos.java
create mode 100644 src/main/java/com/falsepattern/lib/compat/Rotation.java
create mode 100644 src/main/java/com/falsepattern/lib/compat/Vec3i.java
diff --git a/src/main/java/com/falsepattern/lib/compat/BlockPos.java b/src/main/java/com/falsepattern/lib/compat/BlockPos.java
new file mode 100644
index 0000000..ab999b9
--- /dev/null
+++ b/src/main/java/com/falsepattern/lib/compat/BlockPos.java
@@ -0,0 +1,569 @@
+package com.falsepattern.lib.compat;
+
+import com.google.common.collect.AbstractIterator;
+import com.google.common.collect.Lists;
+import cpw.mods.fml.relauncher.Side;
+import cpw.mods.fml.relauncher.SideOnly;
+import net.minecraft.entity.Entity;
+import net.minecraft.util.EnumFacing;
+import net.minecraft.util.MathHelper;
+import net.minecraft.util.Vec3;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
+import javax.annotation.concurrent.Immutable;
+import java.util.Iterator;
+import java.util.List;
+
+@Immutable
+public class BlockPos extends Vec3i {
+ /**
+ * An immutable block pos with zero as all coordinates.
+ */
+ public static final BlockPos ORIGIN = new BlockPos(0, 0, 0);
+ private static final Logger LOGGER = LogManager.getLogger();
+ private static final int NUM_X_BITS = 1 + MathHelper.calculateLogBaseTwo(MathHelper.roundUpToPowerOfTwo(30000000));
+ private static final int NUM_Z_BITS = NUM_X_BITS;
+ private static final int NUM_Y_BITS = 64 - NUM_X_BITS - NUM_Z_BITS;
+ private static final long Y_MASK = (1L << NUM_Y_BITS) - 1L;
+ private static final int Y_SHIFT = NUM_Z_BITS;
+ private static final int X_SHIFT = Y_SHIFT + NUM_Y_BITS;
+ private static final long Z_MASK = (1L << NUM_Z_BITS) - 1L;
+ private static final long X_MASK = (1L << NUM_X_BITS) - 1L;
+
+ public BlockPos(int x, int y, int z) {
+ super(x, y, z);
+ }
+
+ public BlockPos(double x, double y, double z) {
+ super(x, y, z);
+ }
+
+ public BlockPos(Entity source) {
+ this(source.posX, source.posY, source.posZ);
+ }
+
+ public BlockPos(Vec3 vec) {
+ this(vec.xCoord, vec.yCoord, vec.zCoord);
+ }
+
+ public BlockPos(Vec3i source) {
+ this(source.getX(), source.getY(), source.getZ());
+ }
+
+ /**
+ * Create a BlockPos from a serialized long value (created by toLong)
+ */
+ public static BlockPos fromLong(long serialized) {
+ int i = (int) (serialized << 64 - X_SHIFT - NUM_X_BITS >> 64 - NUM_X_BITS);
+ int j = (int) (serialized << 64 - Y_SHIFT - NUM_Y_BITS >> 64 - NUM_Y_BITS);
+ int k = (int) (serialized << 64 - NUM_Z_BITS >> 64 - NUM_Z_BITS);
+ return new BlockPos(i, j, k);
+ }
+
+ /**
+ * Create an Iterable that returns all positions in the box specified by the given corners. There is no requirement
+ * that one corner is greater than the other; individual coordinates will be swapped as needed.
+ *
+ * In situations where it is usable, prefer {@link #getAllInBoxMutable(BlockPos, BlockPos) instead as it has better
+ * performance (fewer allocations)
+ *
+ * @param from One corner of the box
+ * @param to Another corner of the box
+ * @see #getAllInBox(int, int, int, int, int, int)
+ * @see #getAllInBoxMutable(BlockPos, BlockPos)
+ */
+ public static Iterable getAllInBox(BlockPos from, BlockPos to) {
+ return getAllInBox(Math.min(from.getX(), to.getX()), Math.min(from.getY(), to.getY()), Math.min(from.getZ(), to.getZ()), Math.max(from.getX(), to.getX()), Math.max(from.getY(), to.getY()), Math.max(from.getZ(), to.getZ()));
+ }
+
+ /**
+ * Create an Iterable that returns all positions in the box specified by the coordinates. Coordinates must
+ * be in order; e.g. x1 <= x2.
+ *
+ * In situations where it is usable, prefer {@link #getAllInBoxMutable(BlockPos, BlockPos) instead as it has better
+ * performance (fewer allocations)
+ *
+ * @param x1 The lower x coordinate
+ * @param y1 The lower y coordinate
+ * @param z1 The lower z coordinate
+ * @param x2 The upper x coordinate
+ * @param y2 The upper y coordinate
+ * @param z2 The upper z coordinate
+ * @see #getAllInBox(BlockPos, BlockPos)
+ * @see #getAllInBoxMutable(BlockPos, BlockPos)
+ */
+ public static Iterable getAllInBox(final int x1, final int y1, final int z1, final int x2, final int y2, final int z2) {
+ return new Iterable() {
+ public Iterator iterator() {
+ return new AbstractIterator() {
+ private boolean first = true;
+ private int lastPosX;
+ private int lastPosY;
+ private int lastPosZ;
+
+ protected BlockPos computeNext() {
+ if (this.first) {
+ this.first = false;
+ this.lastPosX = x1;
+ this.lastPosY = y1;
+ this.lastPosZ = z1;
+ return new BlockPos(x1, y1, z1);
+ } else if (this.lastPosX == x2 && this.lastPosY == y2 && this.lastPosZ == z2) {
+ return this.endOfData();
+ } else {
+ if (this.lastPosX < x2) {
+ ++this.lastPosX;
+ } else if (this.lastPosY < y2) {
+ this.lastPosX = x1;
+ ++this.lastPosY;
+ } else if (this.lastPosZ < z2) {
+ this.lastPosX = x1;
+ this.lastPosY = y1;
+ ++this.lastPosZ;
+ }
+
+ return new BlockPos(this.lastPosX, this.lastPosY, this.lastPosZ);
+ }
+ }
+ };
+ }
+ };
+ }
+
+ /**
+ * Creates an Iterable that returns all positions in the box specified by the given corners. There is no requirement
+ * that one corner is greater than the other; individual coordinates will be swapped as needed.
+ *
+ * This method uses {@link BlockPos.MutableBlockPos MutableBlockPos} instead of regular BlockPos, which grants
+ * better performance. However, the resulting BlockPos instances can only be used inside the iteration loop (as
+ * otherwise the value will change), unless {@link #toImmutable()} is called. This method is ideal for searching
+ * large areas and only storing a few locations.
+ *
+ * @param from One corner of the box
+ * @param to Another corner of the box
+ * @see #getAllInBox(BlockPos, BlockPos)
+ * @see #getAllInBox(int, int, int, int, int, int)
+ * @see #getAllInBoxMutable(BlockPos, BlockPos)
+ */
+ public static Iterable getAllInBoxMutable(BlockPos from, BlockPos to) {
+ return getAllInBoxMutable(Math.min(from.getX(), to.getX()), Math.min(from.getY(), to.getY()), Math.min(from.getZ(), to.getZ()), Math.max(from.getX(), to.getX()), Math.max(from.getY(), to.getY()), Math.max(from.getZ(), to.getZ()));
+ }
+
+ /**
+ * Creates an Iterable that returns all positions in the box specified by the given corners. Coordinates
+ * must be in order; e.g. x1 <= x2.
+ *
+ * This method uses {@link BlockPos.MutableBlockPos MutableBlockPos} instead of regular BlockPos, which grants
+ * better performance. However, the resulting BlockPos instances can only be used inside the iteration loop (as
+ * otherwise the value will change), unless {@link #toImmutable()} is called. This method is ideal for searching
+ * large areas and only storing a few locations.
+ *
+ * @param x1 The lower x coordinate
+ * @param y1 The lower y coordinate
+ * @param z1 The lower z coordinate
+ * @param x2 The upper x coordinate
+ * @param y2 The upper y coordinate
+ * @param z2 The upper z coordinate
+ * @see #getAllInBox(BlockPos, BlockPos)
+ * @see #getAllInBox(int, int, int, int, int, int)
+ * @see #getAllInBoxMutable(BlockPos, BlockPos)
+ */
+ public static Iterable getAllInBoxMutable(final int x1, final int y1, final int z1, final int x2, final int y2, final int z2) {
+ return new Iterable() {
+ public Iterator iterator() {
+ return new AbstractIterator() {
+ private BlockPos.MutableBlockPos pos;
+
+ protected BlockPos.MutableBlockPos computeNext() {
+ if (this.pos == null) {
+ this.pos = new BlockPos.MutableBlockPos(x1, y1, z1);
+ return this.pos;
+ } else if (this.pos.x == x2 && this.pos.y == y2 && this.pos.z == z2) {
+ return this.endOfData();
+ } else {
+ if (this.pos.x < x2) {
+ ++this.pos.x;
+ } else if (this.pos.y < y2) {
+ this.pos.x = x1;
+ ++this.pos.y;
+ } else if (this.pos.z < z2) {
+ this.pos.x = x1;
+ this.pos.y = y1;
+ ++this.pos.z;
+ }
+
+ return this.pos;
+ }
+ }
+ };
+ }
+ };
+ }
+
+ /**
+ * Add the given coordinates to the coordinates of this BlockPos
+ */
+ public BlockPos add(double x, double y, double z) {
+ return x == 0.0D && y == 0.0D && z == 0.0D ? this : new BlockPos((double) this.getX() + x, (double) this.getY() + y, (double) this.getZ() + z);
+ }
+
+ /**
+ * Add the given coordinates to the coordinates of this BlockPos
+ */
+ public BlockPos add(int x, int y, int z) {
+ return x == 0 && y == 0 && z == 0 ? this : new BlockPos(this.getX() + x, this.getY() + y, this.getZ() + z);
+ }
+
+ /**
+ * Add the given Vector to this BlockPos
+ */
+ public BlockPos add(Vec3i vec) {
+ return this.add(vec.getX(), vec.getY(), vec.getZ());
+ }
+
+ /**
+ * Subtract the given Vector from this BlockPos
+ */
+ public BlockPos subtract(Vec3i vec) {
+ return this.add(-vec.getX(), -vec.getY(), -vec.getZ());
+ }
+
+ /**
+ * Offset this BlockPos 1 block up
+ */
+ public BlockPos up() {
+ return this.up(1);
+ }
+
+ /**
+ * Offset this BlockPos n blocks up
+ */
+ public BlockPos up(int n) {
+ return this.offset(EnumFacing.UP, n);
+ }
+
+ /**
+ * Offset this BlockPos 1 block down
+ */
+ public BlockPos down() {
+ return this.down(1);
+ }
+
+ /**
+ * Offset this BlockPos n blocks down
+ */
+ public BlockPos down(int n) {
+ return this.offset(EnumFacing.DOWN, n);
+ }
+
+ /**
+ * Offset this BlockPos 1 block in northern direction
+ */
+ public BlockPos north() {
+ return this.north(1);
+ }
+
+ /**
+ * Offset this BlockPos n blocks in northern direction
+ */
+ public BlockPos north(int n) {
+ return this.offset(EnumFacing.NORTH, n);
+ }
+
+ /**
+ * Offset this BlockPos 1 block in southern direction
+ */
+ public BlockPos south() {
+ return this.south(1);
+ }
+
+ /**
+ * Offset this BlockPos n blocks in southern direction
+ */
+ public BlockPos south(int n) {
+ return this.offset(EnumFacing.SOUTH, n);
+ }
+
+ /**
+ * Offset this BlockPos 1 block in western direction
+ */
+ public BlockPos west() {
+ return this.west(1);
+ }
+
+ /**
+ * Offset this BlockPos n blocks in western direction
+ */
+ public BlockPos west(int n) {
+ return this.offset(EnumFacing.WEST, n);
+ }
+
+ /**
+ * Offset this BlockPos 1 block in eastern direction
+ */
+ public BlockPos east() {
+ return this.east(1);
+ }
+
+ /**
+ * Offset this BlockPos n blocks in eastern direction
+ */
+ public BlockPos east(int n) {
+ return this.offset(EnumFacing.EAST, n);
+ }
+
+ /**
+ * Offset this BlockPos 1 block in the given direction
+ */
+ public BlockPos offset(EnumFacing facing) {
+ return this.offset(facing, 1);
+ }
+
+ /**
+ * Offsets this BlockPos n blocks in the given direction
+ */
+ public BlockPos offset(EnumFacing facing, int n) {
+ return n == 0 ? this : new BlockPos(this.getX() + facing.getFrontOffsetX() * n, this.getY() + facing.getFrontOffsetY() * n, this.getZ() + facing.getFrontOffsetZ() * n);
+ }
+
+ public BlockPos rotate(Rotation rotationIn) {
+ switch (rotationIn) {
+ case NONE:
+ default:
+ return this;
+ case CLOCKWISE_90:
+ return new BlockPos(-this.getZ(), this.getY(), this.getX());
+ case CLOCKWISE_180:
+ return new BlockPos(-this.getX(), this.getY(), -this.getZ());
+ case COUNTERCLOCKWISE_90:
+ return new BlockPos(this.getZ(), this.getY(), -this.getX());
+ }
+ }
+
+ /**
+ * Calculate the cross product of this and the given Vector
+ */
+ public BlockPos crossProduct(Vec3i vec) {
+ return new BlockPos(this.getY() * vec.getZ() - this.getZ() * vec.getY(), this.getZ() * vec.getX() - this.getX() * vec.getZ(), this.getX() * vec.getY() - this.getY() * vec.getX());
+ }
+
+ /**
+ * Serialize this BlockPos into a long value
+ */
+ public long toLong() {
+ return ((long) this.getX() & X_MASK) << X_SHIFT | ((long) this.getY() & Y_MASK) << Y_SHIFT | ((long) this.getZ() & Z_MASK);
+ }
+
+ /**
+ * Returns a version of this BlockPos that is guaranteed to be immutable.
+ *
+ * When storing a BlockPos given to you for an extended period of time, make sure you
+ * use this in case the value is changed internally.
+ */
+ public BlockPos toImmutable() {
+ return this;
+ }
+
+ public static class MutableBlockPos extends BlockPos {
+ /**
+ * Mutable X Coordinate
+ */
+ protected int x;
+ /**
+ * Mutable Y Coordinate
+ */
+ protected int y;
+ /**
+ * Mutable Z Coordinate
+ */
+ protected int z;
+
+ public MutableBlockPos() {
+ this(0, 0, 0);
+ }
+
+ public MutableBlockPos(BlockPos pos) {
+ this(pos.getX(), pos.getY(), pos.getZ());
+ }
+
+ public MutableBlockPos(int x_, int y_, int z_) {
+ super(0, 0, 0);
+ this.x = x_;
+ this.y = y_;
+ this.z = z_;
+ }
+
+ /**
+ * Add the given coordinates to the coordinates of this BlockPos
+ */
+ public BlockPos add(double x, double y, double z) {
+ return super.add(x, y, z).toImmutable();
+ }
+
+ /**
+ * Add the given coordinates to the coordinates of this BlockPos
+ */
+ public BlockPos add(int x, int y, int z) {
+ return super.add(x, y, z).toImmutable();
+ }
+
+ /**
+ * Offsets this BlockPos n blocks in the given direction
+ */
+ public BlockPos offset(EnumFacing facing, int n) {
+ return super.offset(facing, n).toImmutable();
+ }
+
+ public BlockPos rotate(Rotation rotationIn) {
+ return super.rotate(rotationIn).toImmutable();
+ }
+
+ /**
+ * Gets the X coordinate.
+ */
+ public int getX() {
+ return this.x;
+ }
+
+ /**
+ * Gets the Y coordinate.
+ */
+ public int getY() {
+ return this.y;
+ }
+
+ public void setY(int yIn) {
+ this.y = yIn;
+ }
+
+ /**
+ * Gets the Z coordinate.
+ */
+ public int getZ() {
+ return this.z;
+ }
+
+ /**
+ * None
+ */
+ public BlockPos.MutableBlockPos setPos(int xIn, int yIn, int zIn) {
+ this.x = xIn;
+ this.y = yIn;
+ this.z = zIn;
+ return this;
+ }
+
+ public BlockPos.MutableBlockPos setPos(double xIn, double yIn, double zIn) {
+ return this.setPos(MathHelper.floor_double(xIn), MathHelper.floor_double(yIn), MathHelper.floor_double(zIn));
+ }
+
+ @SideOnly(Side.CLIENT)
+ public BlockPos.MutableBlockPos setPos(Entity entityIn) {
+ return this.setPos(entityIn.posX, entityIn.posY, entityIn.posZ);
+ }
+
+ public BlockPos.MutableBlockPos setPos(Vec3i vec) {
+ return this.setPos(vec.getX(), vec.getY(), vec.getZ());
+ }
+
+ public BlockPos.MutableBlockPos move(EnumFacing facing) {
+ return this.move(facing, 1);
+ }
+
+ public BlockPos.MutableBlockPos move(EnumFacing facing, int n) {
+ return this.setPos(this.x + facing.getFrontOffsetX() * n, this.y + facing.getFrontOffsetY() * n, this.z + facing.getFrontOffsetZ() * n);
+ }
+
+ /**
+ * Returns a version of this BlockPos that is guaranteed to be immutable.
+ *
+ * When storing a BlockPos given to you for an extended period of time, make sure you
+ * use this in case the value is changed internally.
+ */
+ public BlockPos toImmutable() {
+ return new BlockPos(this);
+ }
+ }
+
+ public static final class PooledMutableBlockPos extends BlockPos.MutableBlockPos {
+ private static final List POOL = Lists.newArrayList();
+ private boolean released;
+
+ private PooledMutableBlockPos(int xIn, int yIn, int zIn) {
+ super(xIn, yIn, zIn);
+ }
+
+ public static BlockPos.PooledMutableBlockPos retain() {
+ return retain(0, 0, 0);
+ }
+
+ public static BlockPos.PooledMutableBlockPos retain(double xIn, double yIn, double zIn) {
+ return retain(MathHelper.floor_double(xIn), MathHelper.floor_double(yIn), MathHelper.floor_double(zIn));
+ }
+
+ @SideOnly(Side.CLIENT)
+ public static BlockPos.PooledMutableBlockPos retain(Vec3i vec) {
+ return retain(vec.getX(), vec.getY(), vec.getZ());
+ }
+
+ public static BlockPos.PooledMutableBlockPos retain(int xIn, int yIn, int zIn) {
+ synchronized (POOL) {
+ if (!POOL.isEmpty()) {
+ BlockPos.PooledMutableBlockPos pos = POOL.remove(POOL.size() - 1);
+
+ if (pos != null && pos.released) {
+ pos.released = false;
+ pos.setPos(xIn, yIn, zIn);
+ return pos;
+ }
+ }
+ }
+
+ return new BlockPos.PooledMutableBlockPos(xIn, yIn, zIn);
+ }
+
+ public void release() {
+ synchronized (POOL) {
+ if (POOL.size() < 100) {
+ POOL.add(this);
+ }
+
+ this.released = true;
+ }
+ }
+
+ /**
+ * None
+ */
+ public BlockPos.PooledMutableBlockPos setPos(int xIn, int yIn, int zIn) {
+ if (this.released) {
+ BlockPos.LOGGER.error("PooledMutableBlockPosition modified after it was released.", new Throwable());
+ this.released = false;
+ }
+
+ return (BlockPos.PooledMutableBlockPos) super.setPos(xIn, yIn, zIn);
+ }
+
+ @SideOnly(Side.CLIENT)
+ public BlockPos.PooledMutableBlockPos setPos(Entity entityIn) {
+ return (BlockPos.PooledMutableBlockPos) super.setPos(entityIn);
+ }
+
+ public BlockPos.PooledMutableBlockPos setPos(double xIn, double yIn, double zIn) {
+ return (BlockPos.PooledMutableBlockPos) super.setPos(xIn, yIn, zIn);
+ }
+
+ public BlockPos.PooledMutableBlockPos setPos(Vec3i vec) {
+ return (BlockPos.PooledMutableBlockPos) super.setPos(vec);
+ }
+
+ public BlockPos.PooledMutableBlockPos move(EnumFacing facing) {
+ return (BlockPos.PooledMutableBlockPos) super.move(facing);
+ }
+
+ public BlockPos.PooledMutableBlockPos move(EnumFacing facing, int n) {
+ return (BlockPos.PooledMutableBlockPos) super.move(facing, n);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/falsepattern/lib/compat/ChunkPos.java b/src/main/java/com/falsepattern/lib/compat/ChunkPos.java
new file mode 100644
index 0000000..fd5b5b8
--- /dev/null
+++ b/src/main/java/com/falsepattern/lib/compat/ChunkPos.java
@@ -0,0 +1,95 @@
+package com.falsepattern.lib.compat;
+
+import net.minecraft.entity.Entity;
+
+public class ChunkPos {
+ /**
+ * The X position of this Chunk Coordinate Pair
+ */
+ public final int x;
+ /**
+ * The Z position of this Chunk Coordinate Pair
+ */
+ public final int z;
+
+ public ChunkPos(int x, int z) {
+ this.x = x;
+ this.z = z;
+ }
+
+ public ChunkPos(BlockPos pos) {
+ this.x = pos.getX() >> 4;
+ this.z = pos.getZ() >> 4;
+ }
+
+ /**
+ * Converts the chunk coordinate pair to a long
+ */
+ public static long asLong(int x, int z) {
+ return (long) x & 4294967295L | ((long) z & 4294967295L) << 32;
+ }
+
+ public int hashCode() {
+ int i = 1664525 * this.x + 1013904223;
+ int j = 1664525 * (this.z ^ -559038737) + 1013904223;
+ return i ^ j;
+ }
+
+ public boolean equals(Object p_equals_1_) {
+ if (this == p_equals_1_) {
+ return true;
+ } else if (!(p_equals_1_ instanceof ChunkPos)) {
+ return false;
+ } else {
+ ChunkPos chunkpos = (ChunkPos) p_equals_1_;
+ return this.x == chunkpos.x && this.z == chunkpos.z;
+ }
+ }
+
+ public double getDistanceSq(Entity entityIn) {
+ double d0 = this.x * 16 + 8;
+ double d1 = this.z * 16 + 8;
+ double d2 = d0 - entityIn.posX;
+ double d3 = d1 - entityIn.posZ;
+ return d2 * d2 + d3 * d3;
+ }
+
+ /**
+ * Get the first world X coordinate that belongs to this Chunk
+ */
+ public int getXStart() {
+ return this.x << 4;
+ }
+
+ /**
+ * Get the first world Z coordinate that belongs to this Chunk
+ */
+ public int getZStart() {
+ return this.z << 4;
+ }
+
+ /**
+ * Get the last world X coordinate that belongs to this Chunk
+ */
+ public int getXEnd() {
+ return (this.x << 4) + 15;
+ }
+
+ /**
+ * Get the last world Z coordinate that belongs to this Chunk
+ */
+ public int getZEnd() {
+ return (this.z << 4) + 15;
+ }
+
+ /**
+ * Get the World coordinates of the Block with the given Chunk coordinates relative to this chunk
+ */
+ public BlockPos getBlock(int x, int y, int z) {
+ return new BlockPos((this.x << 4) + x, y, (this.z << 4) + z);
+ }
+
+ public String toString() {
+ return "[" + this.x + ", " + this.z + "]";
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/falsepattern/lib/compat/Rotation.java b/src/main/java/com/falsepattern/lib/compat/Rotation.java
new file mode 100644
index 0000000..c2e9bbc
--- /dev/null
+++ b/src/main/java/com/falsepattern/lib/compat/Rotation.java
@@ -0,0 +1,128 @@
+package com.falsepattern.lib.compat;
+
+import net.minecraft.util.EnumFacing;
+
+public enum Rotation {
+ NONE("rotate_0"),
+ CLOCKWISE_90("rotate_90"),
+ CLOCKWISE_180("rotate_180"),
+ COUNTERCLOCKWISE_90("rotate_270");
+
+ private static final String[] rotationNames = new String[values().length];
+
+ static {
+ int i = 0;
+
+ for (Rotation rotation : values()) {
+ rotationNames[i++] = rotation.name;
+ }
+ }
+
+ private final String name;
+
+ Rotation(String nameIn) {
+ this.name = nameIn;
+ }
+
+ public Rotation add(Rotation rotation) {
+ switch (rotation) {
+ case CLOCKWISE_180:
+ switch (this) {
+ case NONE:
+ return CLOCKWISE_180;
+ case CLOCKWISE_90:
+ return COUNTERCLOCKWISE_90;
+ case CLOCKWISE_180:
+ return NONE;
+ case COUNTERCLOCKWISE_90:
+ return CLOCKWISE_90;
+ }
+ case COUNTERCLOCKWISE_90:
+ switch (this) {
+ case NONE:
+ return COUNTERCLOCKWISE_90;
+ case CLOCKWISE_90:
+ return NONE;
+ case CLOCKWISE_180:
+ return CLOCKWISE_90;
+ case COUNTERCLOCKWISE_90:
+ return CLOCKWISE_180;
+ }
+ case CLOCKWISE_90:
+ switch (this) {
+ case NONE:
+ return CLOCKWISE_90;
+ case CLOCKWISE_90:
+ return CLOCKWISE_180;
+ case CLOCKWISE_180:
+ return COUNTERCLOCKWISE_90;
+ case COUNTERCLOCKWISE_90:
+ return NONE;
+ }
+ default:
+ return this;
+ }
+ }
+
+ public EnumFacing rotate(EnumFacing facing) {
+ if (facing == EnumFacing.UP || facing == EnumFacing.DOWN) {
+ return facing;
+ }
+ switch (this) {
+ case CLOCKWISE_90:
+ switch (facing) {
+ case NORTH:
+ return EnumFacing.EAST;
+ case EAST:
+ return EnumFacing.SOUTH;
+ case SOUTH:
+ return EnumFacing.WEST;
+ case WEST:
+ return EnumFacing.NORTH;
+ default:
+ throw new IllegalStateException("Unable to get Y-rotated facing of " + facing);
+ }
+ case CLOCKWISE_180:
+ switch (facing) {
+ case NORTH:
+ return EnumFacing.SOUTH;
+ case EAST:
+ return EnumFacing.WEST;
+ case SOUTH:
+ return EnumFacing.NORTH;
+ case WEST:
+ return EnumFacing.EAST;
+ default:
+ throw new IllegalStateException("Unable to get Y-rotated facing of " + facing);
+ }
+ case COUNTERCLOCKWISE_90:
+ switch (facing) {
+ case NORTH:
+ return EnumFacing.WEST;
+ case EAST:
+ return EnumFacing.NORTH;
+ case SOUTH:
+ return EnumFacing.EAST;
+ case WEST:
+ return EnumFacing.SOUTH;
+ default:
+ throw new IllegalStateException("Unable to get Y-rotated facing of " + facing);
+ }
+ default:
+ return facing;
+ }
+ }
+
+ public int rotate(int x, int z) {
+ switch (this) {
+ case CLOCKWISE_90:
+ return (x + z / 4) % z;
+ case CLOCKWISE_180:
+ return (x + z / 2) % z;
+ case COUNTERCLOCKWISE_90:
+ return (x + z * 3 / 4) % z;
+ default:
+ return x;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/falsepattern/lib/compat/Vec3i.java b/src/main/java/com/falsepattern/lib/compat/Vec3i.java
new file mode 100644
index 0000000..1bcc224
--- /dev/null
+++ b/src/main/java/com/falsepattern/lib/compat/Vec3i.java
@@ -0,0 +1,119 @@
+package com.falsepattern.lib.compat;
+
+import net.minecraft.util.MathHelper;
+
+import javax.annotation.concurrent.Immutable;
+import java.util.Objects;
+
+@Immutable
+public class Vec3i implements Comparable {
+ /**
+ * An immutable vector with zero as all coordinates.
+ */
+ public static final Vec3i NULL_VECTOR = new Vec3i(0, 0, 0);
+ /**
+ * X coordinate
+ */
+ private final int x;
+ /**
+ * Y coordinate
+ */
+ private final int y;
+ /**
+ * Z coordinate
+ */
+ private final int z;
+
+ public Vec3i(int xIn, int yIn, int zIn) {
+ this.x = xIn;
+ this.y = yIn;
+ this.z = zIn;
+ }
+
+ public Vec3i(double xIn, double yIn, double zIn) {
+ this(MathHelper.floor_double(xIn), MathHelper.floor_double(yIn), MathHelper.floor_double(zIn));
+ }
+
+ public int compareTo(Vec3i p_compareTo_1_) {
+ if (this.getY() == p_compareTo_1_.getY()) {
+ return this.getZ() == p_compareTo_1_.getZ() ? this.getX() - p_compareTo_1_.getX() : this.getZ() - p_compareTo_1_.getZ();
+ } else {
+ return this.getY() - p_compareTo_1_.getY();
+ }
+ }
+
+ /**
+ * Gets the X coordinate.
+ */
+ public int getX() {
+ return this.x;
+ }
+
+ /**
+ * Gets the Y coordinate.
+ */
+ public int getY() {
+ return this.y;
+ }
+
+ /**
+ * Gets the Z coordinate.
+ */
+ public int getZ() {
+ return this.z;
+ }
+
+ /**
+ * Calculate the cross product of this and the given Vector
+ */
+ public Vec3i crossProduct(Vec3i vec) {
+ return new Vec3i(this.getY() * vec.getZ() - this.getZ() * vec.getY(), this.getZ() * vec.getX() - this.getX() * vec.getZ(), this.getX() * vec.getY() - this.getY() * vec.getX());
+ }
+
+ public double getDistance(int xIn, int yIn, int zIn) {
+ double d0 = (this.getX() - xIn);
+ double d1 = (this.getY() - yIn);
+ double d2 = (this.getZ() - zIn);
+ return Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2);
+ }
+
+ /**
+ * Calculate squared distance to the given coordinates
+ */
+ public double distanceSq(double toX, double toY, double toZ) {
+ double d0 = (double) this.getX() - toX;
+ double d1 = (double) this.getY() - toY;
+ double d2 = (double) this.getZ() - toZ;
+ return d0 * d0 + d1 * d1 + d2 * d2;
+ }
+
+ /**
+ * Compute square of distance from point x, y, z to center of this Block
+ */
+ public double distanceSqToCenter(double xIn, double yIn, double zIn) {
+ double d0 = (double) this.getX() + 0.5D - xIn;
+ double d1 = (double) this.getY() + 0.5D - yIn;
+ double d2 = (double) this.getZ() + 0.5D - zIn;
+ return d0 * d0 + d1 * d1 + d2 * d2;
+ }
+
+ /**
+ * Calculate squared distance to the given Vector
+ */
+ public double distanceSq(Vec3i to) {
+ return this.distanceSq(to.getX(), to.getY(), to.getZ());
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Vec3i vec3i = (Vec3i) o;
+ return getX() == vec3i.getX() && getY() == vec3i.getY() && getZ() == vec3i.getZ();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getX(), getY(), getZ());
+ }
+}
\ No newline at end of file