Files
FalsePatternLib/src/main/java/com/falsepattern/lib/compat/BlockPos.java
T

538 lines
19 KiB
Java
Raw Normal View History

2022-07-30 15:21:11 +02:00
/**
* Copyright (C) 2022 FalsePattern
* All Rights Reserved
*
* The above copyright notice, this permission notice and the word "SNEED"
* shall be included in all copies or substantial portions of the Software.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
2022-05-06 17:41:02 +02:00
package com.falsepattern.lib.compat;
2022-05-06 23:53:11 +02:00
import com.falsepattern.lib.StableAPI;
2022-05-06 17:41:02 +02:00
import com.google.common.collect.AbstractIterator;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
2022-06-08 16:01:06 +02:00
import java.util.ArrayList;
import java.util.List;
import javax.annotation.concurrent.Immutable;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import lombok.val;
2022-05-06 17:41:02 +02:00
import net.minecraft.entity.Entity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.Vec3;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
2022-06-08 16:01:06 +02:00
import static net.minecraft.util.EnumFacing.DOWN;
import static net.minecraft.util.EnumFacing.EAST;
import static net.minecraft.util.EnumFacing.NORTH;
import static net.minecraft.util.EnumFacing.SOUTH;
import static net.minecraft.util.EnumFacing.UP;
import static net.minecraft.util.EnumFacing.WEST;
2022-05-31 14:24:40 +01:00
2022-05-06 17:41:02 +02:00
@Immutable
2022-05-06 23:53:11 +02:00
@StableAPI(since = "0.6.0")
2022-05-06 17:41:02 +02:00
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;
2022-06-08 16:01:06 +02:00
public BlockPos(@NonNull Entity source) {
this(source.posX, source.posY, source.posZ);
2022-05-06 17:41:02 +02:00
}
public BlockPos(double x, double y, double z) {
super(x, y, z);
}
2022-05-31 14:24:40 +01:00
public BlockPos(@NonNull Vec3 vec) {
2022-05-06 17:41:02 +02:00
this(vec.xCoord, vec.yCoord, vec.zCoord);
}
2022-05-31 14:24:40 +01:00
public BlockPos(@NonNull Vec3i source) {
2022-05-06 17:41:02 +02:00
this(source.getX(), source.getY(), source.getZ());
}
2022-06-08 16:01:06 +02:00
public BlockPos(int x, int y, int z) {
super(x, y, z);
}
2022-05-06 17:41:02 +02:00
/**
* Create a BlockPos from a serialized long value (created by toLong)
*/
public static BlockPos fromLong(long serialized) {
2022-06-08 16:01:06 +02:00
return new BlockPos((int) (serialized << 64 - X_SHIFT - NUM_X_BITS >> 64 - NUM_X_BITS),
(int) (serialized << 64 - Y_SHIFT - NUM_Y_BITS >> 64 - NUM_Y_BITS),
(int) (serialized << 64 - NUM_Z_BITS >> 64 - NUM_Z_BITS));
2022-05-06 17:41:02 +02:00
}
/**
* 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.
* <p>
2022-06-08 16:01:06 +02:00
* In situations where it is usable, prefer
* {@link #getAllInBoxMutable(BlockPos, BlockPos) instead as it has better performance (fewer allocations)
2022-05-06 17:41:02 +02:00
*
* @param from One corner of the box
* @param to Another corner of the box
2022-06-08 16:01:06 +02:00
*
2022-05-06 17:41:02 +02:00
* @see #getAllInBox(int, int, int, int, int, int)
* @see #getAllInBoxMutable(BlockPos, BlockPos)
*/
2022-05-31 14:24:40 +01:00
public static Iterable<BlockPos> getAllInBox(@NonNull BlockPos from, @NonNull BlockPos to) {
2022-06-08 16:01:06 +02:00
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()));
2022-05-06 17:41:02 +02:00
}
/**
* Create an Iterable that returns all positions in the box specified by the coordinates. <strong>Coordinates must
2022-05-31 14:24:40 +01:00
* be in order</strong>; e.g. x0 <= x1.
2022-05-06 17:41:02 +02:00
* <p>
2022-06-08 16:01:06 +02:00
* In situations where it is usable, prefer
* {@link #getAllInBoxMutable(BlockPos, BlockPos) instead as it has better performance (fewer allocations)
2022-05-06 17:41:02 +02:00
*
2022-05-31 14:24:40 +01:00
* @param x0 The lower x coordinate
* @param y0 The lower y coordinate
* @param z0 The lower z coordinate
* @param x1 The upper x coordinate
* @param y1 The upper y coordinate
* @param z1 The upper z coordinate
2022-06-08 16:01:06 +02:00
*
2022-05-06 17:41:02 +02:00
* @see #getAllInBox(BlockPos, BlockPos)
* @see #getAllInBoxMutable(BlockPos, BlockPos)
*/
2022-06-08 16:01:06 +02:00
public static Iterable<BlockPos> getAllInBox(final int x0,
final int y0,
final int z0,
final int x1,
final int y1,
final int z1) {
2022-05-31 14:24:40 +01:00
return () -> new AbstractIterator<BlockPos>() {
private boolean first = true;
private int lastX;
private int lastY;
private int lastZ;
@Override
protected BlockPos computeNext() {
if (first) {
first = false;
lastX = x0;
lastY = y0;
lastZ = z0;
return new BlockPos(x0, y0, z0);
}
2022-06-08 16:01:06 +02:00
if (lastX == x1 && lastY == y1 && lastZ == z1) {
2022-05-31 14:24:40 +01:00
return endOfData();
2022-06-08 16:01:06 +02:00
}
2022-05-31 14:24:40 +01:00
if (lastX < x1) {
lastX++;
} else if (lastY < y1) {
lastX = x0;
lastY++;
} else if (lastZ < z1) {
lastX = x0;
lastY = y0;
lastZ++;
}
return new BlockPos(lastX, lastY, lastZ);
2022-05-06 17:41:02 +02:00
}
};
}
/**
* 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.
* <p>
* 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
2022-06-08 16:01:06 +02:00
*
2022-05-06 17:41:02 +02:00
* @see #getAllInBox(BlockPos, BlockPos)
* @see #getAllInBox(int, int, int, int, int, int)
* @see #getAllInBoxMutable(BlockPos, BlockPos)
*/
2022-05-31 14:24:40 +01:00
public static Iterable<BlockPos.MutableBlockPos> getAllInBoxMutable(@NonNull BlockPos from, @NonNull BlockPos to) {
2022-06-08 16:01:06 +02:00
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()));
2022-05-06 17:41:02 +02:00
}
/**
* Creates an Iterable that returns all positions in the box specified by the given corners. <strong>Coordinates
2022-05-31 14:24:40 +01:00
* must be in order</strong>; e.g. x0 <= x1.
2022-05-06 17:41:02 +02:00
* <p>
* 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.
*
2022-05-31 14:24:40 +01:00
* @param x0 The lower x coordinate
* @param y0 The lower y coordinate
* @param z0 The lower z coordinate
* @param x1 The upper x coordinate
* @param y1 The upper y coordinate
* @param z1 The upper z coordinate
2022-06-08 16:01:06 +02:00
*
2022-05-06 17:41:02 +02:00
* @see #getAllInBox(BlockPos, BlockPos)
* @see #getAllInBox(int, int, int, int, int, int)
* @see #getAllInBoxMutable(BlockPos, BlockPos)
*/
2022-06-08 16:01:06 +02:00
public static Iterable<BlockPos.MutableBlockPos> getAllInBoxMutable(final int x0,
final int y0,
final int z0,
final int x1,
final int y1,
final int z1) {
2022-05-31 14:24:40 +01:00
return () -> new AbstractIterator<MutableBlockPos>() {
private MutableBlockPos pos;
@Override
protected MutableBlockPos computeNext() {
if (pos == null) {
pos = new MutableBlockPos(x0, y0, z0);
return pos;
} else if (pos.x == x1 && pos.y == y1 && pos.z == z1) {
return endOfData();
} else {
if (pos.x < x1) {
pos.x++;
} else if (pos.y < y1) {
pos.x = x0;
pos.y++;
} else if (pos.z < z1) {
pos.x = x0;
pos.y = y0;
pos.z++;
2022-05-06 17:41:02 +02:00
}
2022-05-31 14:24:40 +01:00
return pos;
}
2022-05-06 17:41:02 +02:00
}
};
}
2022-06-08 16:01:06 +02:00
public long toLong() {
return ((long) x & X_MASK) << X_SHIFT | ((long) y & Y_MASK) << Y_SHIFT | ((long) z & Z_MASK);
2022-05-06 17:41:02 +02:00
}
/**
* Add the given coordinates to the coordinates of this BlockPos
*/
2022-06-08 16:01:06 +02:00
public BlockPos add(double x, double y, double z) {
if (x == 0.0D && y == 0.0D && z == 0.0D) {
2022-05-31 14:24:40 +01:00
return this;
2022-06-08 16:01:06 +02:00
}
2022-05-31 14:24:40 +01:00
return new BlockPos(this.x + x, this.y + y, this.z + z);
2022-05-06 17:41:02 +02:00
}
/**
* Add the given Vector to this BlockPos
*/
2022-05-31 14:24:40 +01:00
public BlockPos add(@NonNull Vec3i vec) {
return add(vec.getX(), vec.getY(), vec.getZ());
2022-05-06 17:41:02 +02:00
}
2022-06-08 16:01:06 +02:00
/**
* Add the given coordinates to the coordinates of this BlockPos
*/
public BlockPos add(int x, int y, int z) {
if (x == 0 && y == 0 && z == 0) {
return this;
}
return new BlockPos(this.x + x, this.y + y, this.z + z);
}
2022-05-06 17:41:02 +02:00
/**
* Subtract the given Vector from this BlockPos
*/
2022-05-31 14:24:40 +01:00
public BlockPos subtract(@NonNull Vec3i vec) {
return add(-vec.getX(), -vec.getY(), -vec.getZ());
2022-05-06 17:41:02 +02:00
}
public BlockPos up() {
2022-05-31 14:24:40 +01:00
return up(1);
2022-05-06 17:41:02 +02:00
}
2022-05-31 14:24:40 +01:00
public BlockPos up(int blocks) {
return offset(UP, blocks);
2022-05-06 17:41:02 +02:00
}
2022-06-08 16:01:06 +02:00
public BlockPos offset(@NonNull EnumFacing facing, int blocks) {
if (blocks == 0) {
return this;
}
return new BlockPos(x + facing.getFrontOffsetX() * blocks,
y + facing.getFrontOffsetY() * blocks,
z + facing.getFrontOffsetZ() * blocks);
}
2022-05-06 17:41:02 +02:00
public BlockPos down() {
2022-05-31 14:24:40 +01:00
return down(1);
2022-05-06 17:41:02 +02:00
}
2022-05-31 14:24:40 +01:00
public BlockPos down(int blocks) {
return offset(DOWN, blocks);
2022-05-06 17:41:02 +02:00
}
public BlockPos north() {
2022-05-31 14:24:40 +01:00
return north(1);
2022-05-06 17:41:02 +02:00
}
2022-05-31 14:24:40 +01:00
public BlockPos north(int blocks) {
return offset(NORTH, blocks);
2022-05-06 17:41:02 +02:00
}
public BlockPos south() {
2022-05-31 14:24:40 +01:00
return south(1);
2022-05-06 17:41:02 +02:00
}
2022-05-31 14:24:40 +01:00
public BlockPos south(int blocks) {
return offset(SOUTH, blocks);
2022-05-06 17:41:02 +02:00
}
public BlockPos west() {
2022-05-31 14:24:40 +01:00
return west(1);
2022-05-06 17:41:02 +02:00
}
2022-05-31 14:24:40 +01:00
public BlockPos west(int blocks) {
return offset(WEST, blocks);
2022-05-06 17:41:02 +02:00
}
public BlockPos east() {
2022-05-31 14:24:40 +01:00
return east(1);
2022-05-06 17:41:02 +02:00
}
2022-05-31 14:24:40 +01:00
public BlockPos east(int blocks) {
return offset(EAST, blocks);
2022-05-06 17:41:02 +02:00
}
2022-05-31 14:24:40 +01:00
public BlockPos offset(@NonNull EnumFacing facing) {
return offset(facing, 1);
2022-05-06 17:41:02 +02:00
}
2022-05-31 14:24:40 +01:00
public BlockPos rotate(@NonNull Rotation rotation) {
switch (rotation) {
2022-05-06 17:41:02 +02:00
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());
}
}
2022-05-31 14:24:40 +01:00
@Override
public BlockPos crossProduct(@NonNull Vec3i vec) {
2022-06-08 16:01:06 +02:00
return new BlockPos(y * vec.getZ() - z * vec.getY(),
z * vec.getX() - x * vec.getZ(),
x * vec.getY() - y * vec.getX());
2022-05-06 17:41:02 +02:00
}
public BlockPos toImmutable() {
return this;
}
2022-05-31 14:24:40 +01:00
@Setter
@Getter
2022-05-06 17:41:02 +02:00
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() {
2022-05-31 14:24:40 +01:00
this(ORIGIN);
2022-05-06 17:41:02 +02:00
}
2022-05-31 14:24:40 +01:00
public MutableBlockPos(@NonNull BlockPos blockPos) {
this(blockPos.getX(), blockPos.getY(), blockPos.getZ());
2022-05-06 17:41:02 +02:00
}
2022-05-31 14:24:40 +01:00
public MutableBlockPos(int x, int y, int z) {
super(ORIGIN);
this.x = x;
this.y = y;
this.z = z;
2022-05-06 17:41:02 +02:00
}
2022-05-31 14:24:40 +01:00
@Override
2022-05-06 17:41:02 +02:00
public BlockPos add(double x, double y, double z) {
return super.add(x, y, z).toImmutable();
}
2022-05-31 14:24:40 +01:00
@Override
2022-05-06 17:41:02 +02:00
public BlockPos add(int x, int y, int z) {
return super.add(x, y, z).toImmutable();
}
2022-05-31 14:24:40 +01:00
@Override
public BlockPos offset(@NonNull EnumFacing facing, int blocks) {
return super.offset(facing, blocks).toImmutable();
2022-05-06 17:41:02 +02:00
}
2022-05-31 14:24:40 +01:00
@Override
public BlockPos rotate(@NonNull Rotation rotation) {
return super.rotate(rotation).toImmutable();
2022-05-06 17:41:02 +02:00
}
2022-06-08 16:01:06 +02:00
public BlockPos toImmutable() {
return new BlockPos(this);
}
@SideOnly(Side.CLIENT)
public BlockPos.MutableBlockPos setPos(@NonNull Entity entity) {
return this.setPos(entity.posX, entity.posY, entity.posZ);
}
2022-05-31 14:24:40 +01:00
public BlockPos.MutableBlockPos setPos(double x, double y, double z) {
2022-06-08 16:01:06 +02:00
return setPos(MathHelper.floor_double(x), MathHelper.floor_double(y), MathHelper.floor_double(z));
2022-05-06 17:41:02 +02:00
}
2022-05-31 14:24:40 +01:00
public BlockPos.MutableBlockPos setPos(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
2022-05-06 17:41:02 +02:00
return this;
}
2022-05-31 14:24:40 +01:00
public BlockPos.MutableBlockPos setPos(@NonNull Vec3i vec) {
2022-05-06 17:41:02 +02:00
return this.setPos(vec.getX(), vec.getY(), vec.getZ());
}
2022-05-31 14:24:40 +01:00
public BlockPos.MutableBlockPos move(@NonNull EnumFacing facing) {
2022-05-06 17:41:02 +02:00
return this.move(facing, 1);
}
2022-05-31 14:24:40 +01:00
public BlockPos.MutableBlockPos move(@NonNull EnumFacing facing, int blocks) {
2022-06-08 16:01:06 +02:00
return this.setPos(x + facing.getFrontOffsetX() * blocks,
y + facing.getFrontOffsetY() * blocks,
z + facing.getFrontOffsetZ() * blocks);
2022-05-06 17:41:02 +02:00
}
}
public static final class PooledMutableBlockPos extends BlockPos.MutableBlockPos {
2022-05-31 14:24:40 +01:00
private static final List<BlockPos.PooledMutableBlockPos> POOL = new ArrayList<>();
2022-05-06 17:41:02 +02:00
private boolean released;
2022-05-31 14:24:40 +01:00
private PooledMutableBlockPos(int x, int y, int z) {
super(x, y, z);
2022-05-06 17:41:02 +02:00
}
public static BlockPos.PooledMutableBlockPos retain() {
return retain(0, 0, 0);
}
2022-05-31 14:24:40 +01:00
public static BlockPos.PooledMutableBlockPos retain(int x, int y, int z) {
2022-05-06 17:41:02 +02:00
synchronized (POOL) {
if (!POOL.isEmpty()) {
2022-05-31 14:24:40 +01:00
val pos = POOL.remove(POOL.size() - 1);
2022-05-06 17:41:02 +02:00
if (pos != null && pos.released) {
pos.released = false;
2022-05-31 14:24:40 +01:00
pos.setPos(x, y, z);
2022-05-06 17:41:02 +02:00
return pos;
}
}
}
2022-05-31 14:24:40 +01:00
return new BlockPos.PooledMutableBlockPos(x, y, z);
2022-05-06 17:41:02 +02:00
}
2022-06-08 16:01:06 +02:00
public static BlockPos.PooledMutableBlockPos retain(double x, double y, double z) {
return retain(MathHelper.floor_double(x), MathHelper.floor_double(y), MathHelper.floor_double(z));
}
@SideOnly(Side.CLIENT)
public static BlockPos.PooledMutableBlockPos retain(@NonNull Vec3i vec) {
return retain(vec.getX(), vec.getY(), vec.getZ());
}
2022-05-06 17:41:02 +02:00
public void release() {
synchronized (POOL) {
if (POOL.size() < 100) {
POOL.add(this);
}
this.released = true;
}
}
2022-05-31 14:24:40 +01:00
@Override
2022-05-06 17:41:02 +02:00
@SideOnly(Side.CLIENT)
2022-05-31 14:24:40 +01:00
public BlockPos.PooledMutableBlockPos setPos(@NonNull Entity entity) {
return (BlockPos.PooledMutableBlockPos) super.setPos(entity);
2022-05-06 17:41:02 +02:00
}
2022-05-31 14:24:40 +01:00
@Override
public BlockPos.PooledMutableBlockPos setPos(double x, double y, double z) {
return (BlockPos.PooledMutableBlockPos) super.setPos(x, y, z);
2022-05-06 17:41:02 +02:00
}
2022-06-08 16:01:06 +02:00
@Override
public BlockPos.PooledMutableBlockPos setPos(int x, int y, int z) {
if (released) {
BlockPos.LOGGER.error("PooledMutableBlockPosition modified after it was released.", new Throwable());
released = false;
}
return (BlockPos.PooledMutableBlockPos) super.setPos(x, y, z);
}
2022-05-31 14:24:40 +01:00
@Override
public BlockPos.PooledMutableBlockPos setPos(@NonNull Vec3i vec) {
2022-05-06 17:41:02 +02:00
return (BlockPos.PooledMutableBlockPos) super.setPos(vec);
}
2022-05-31 14:24:40 +01:00
@Override
public BlockPos.PooledMutableBlockPos move(@NonNull EnumFacing facing) {
2022-05-06 17:41:02 +02:00
return (BlockPos.PooledMutableBlockPos) super.move(facing);
}
2022-05-31 14:24:40 +01:00
@Override
public BlockPos.PooledMutableBlockPos move(@NonNull EnumFacing facing, int blocks) {
return (BlockPos.PooledMutableBlockPos) super.move(facing, blocks);
2022-05-06 17:41:02 +02:00
}
}
}