224 lines
6.6 KiB
Java
224 lines
6.6 KiB
Java
package net.minecraft.world.phys.shapes;
|
|
|
|
import java.util.BitSet;
|
|
import net.minecraft.core.Direction;
|
|
|
|
public final class BitSetDiscreteVoxelShape extends DiscreteVoxelShape {
|
|
private final BitSet storage;
|
|
private int xMin;
|
|
private int yMin;
|
|
private int zMin;
|
|
private int xMax;
|
|
private int yMax;
|
|
private int zMax;
|
|
|
|
public BitSetDiscreteVoxelShape(int i, int j, int k) {
|
|
super(i, j, k);
|
|
this.storage = new BitSet(i * j * k);
|
|
this.xMin = i;
|
|
this.yMin = j;
|
|
this.zMin = k;
|
|
}
|
|
|
|
public static BitSetDiscreteVoxelShape withFilledBounds(int x, int y, int z, int xMin, int yMin, int zMin, int xMax, int yMax, int zMax) {
|
|
BitSetDiscreteVoxelShape bitSetDiscreteVoxelShape = new BitSetDiscreteVoxelShape(x, y, z);
|
|
bitSetDiscreteVoxelShape.xMin = xMin;
|
|
bitSetDiscreteVoxelShape.yMin = yMin;
|
|
bitSetDiscreteVoxelShape.zMin = zMin;
|
|
bitSetDiscreteVoxelShape.xMax = xMax;
|
|
bitSetDiscreteVoxelShape.yMax = yMax;
|
|
bitSetDiscreteVoxelShape.zMax = zMax;
|
|
|
|
for (int i = xMin; i < xMax; i++) {
|
|
for (int j = yMin; j < yMax; j++) {
|
|
for (int k = zMin; k < zMax; k++) {
|
|
bitSetDiscreteVoxelShape.fillUpdateBounds(i, j, k, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
return bitSetDiscreteVoxelShape;
|
|
}
|
|
|
|
public BitSetDiscreteVoxelShape(DiscreteVoxelShape shape) {
|
|
super(shape.xSize, shape.ySize, shape.zSize);
|
|
if (shape instanceof BitSetDiscreteVoxelShape) {
|
|
this.storage = (BitSet)((BitSetDiscreteVoxelShape)shape).storage.clone();
|
|
} else {
|
|
this.storage = new BitSet(this.xSize * this.ySize * this.zSize);
|
|
|
|
for (int i = 0; i < this.xSize; i++) {
|
|
for (int j = 0; j < this.ySize; j++) {
|
|
for (int k = 0; k < this.zSize; k++) {
|
|
if (shape.isFull(i, j, k)) {
|
|
this.storage.set(this.getIndex(i, j, k));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this.xMin = shape.firstFull(Direction.Axis.X);
|
|
this.yMin = shape.firstFull(Direction.Axis.Y);
|
|
this.zMin = shape.firstFull(Direction.Axis.Z);
|
|
this.xMax = shape.lastFull(Direction.Axis.X);
|
|
this.yMax = shape.lastFull(Direction.Axis.Y);
|
|
this.zMax = shape.lastFull(Direction.Axis.Z);
|
|
}
|
|
|
|
protected int getIndex(int x, int y, int z) {
|
|
return (x * this.ySize + y) * this.zSize + z;
|
|
}
|
|
|
|
@Override
|
|
public boolean isFull(int x, int y, int z) {
|
|
return this.storage.get(this.getIndex(x, y, z));
|
|
}
|
|
|
|
private void fillUpdateBounds(int x, int y, int z, boolean update) {
|
|
this.storage.set(this.getIndex(x, y, z));
|
|
if (update) {
|
|
this.xMin = Math.min(this.xMin, x);
|
|
this.yMin = Math.min(this.yMin, y);
|
|
this.zMin = Math.min(this.zMin, z);
|
|
this.xMax = Math.max(this.xMax, x + 1);
|
|
this.yMax = Math.max(this.yMax, y + 1);
|
|
this.zMax = Math.max(this.zMax, z + 1);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void fill(int x, int y, int z) {
|
|
this.fillUpdateBounds(x, y, z, true);
|
|
}
|
|
|
|
@Override
|
|
public boolean isEmpty() {
|
|
return this.storage.isEmpty();
|
|
}
|
|
|
|
@Override
|
|
public int firstFull(Direction.Axis axis) {
|
|
return axis.choose(this.xMin, this.yMin, this.zMin);
|
|
}
|
|
|
|
@Override
|
|
public int lastFull(Direction.Axis axis) {
|
|
return axis.choose(this.xMax, this.yMax, this.zMax);
|
|
}
|
|
|
|
static BitSetDiscreteVoxelShape join(
|
|
DiscreteVoxelShape mainShape, DiscreteVoxelShape secondaryShape, IndexMerger mergerX, IndexMerger mergerY, IndexMerger mergerZ, BooleanOp operator
|
|
) {
|
|
BitSetDiscreteVoxelShape bitSetDiscreteVoxelShape = new BitSetDiscreteVoxelShape(mergerX.size() - 1, mergerY.size() - 1, mergerZ.size() - 1);
|
|
int[] is = new int[]{Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE};
|
|
mergerX.forMergedIndexes((i, j, k) -> {
|
|
boolean[] bls = new boolean[]{false};
|
|
mergerY.forMergedIndexes((l, m, n) -> {
|
|
boolean[] bls2 = new boolean[]{false};
|
|
mergerZ.forMergedIndexes((o, p, q) -> {
|
|
if (operator.apply(mainShape.isFullWide(i, l, o), secondaryShape.isFullWide(j, m, p))) {
|
|
bitSetDiscreteVoxelShape.storage.set(bitSetDiscreteVoxelShape.getIndex(k, n, q));
|
|
is[2] = Math.min(is[2], q);
|
|
is[5] = Math.max(is[5], q);
|
|
bls2[0] = true;
|
|
}
|
|
|
|
return true;
|
|
});
|
|
if (bls2[0]) {
|
|
is[1] = Math.min(is[1], n);
|
|
is[4] = Math.max(is[4], n);
|
|
bls[0] = true;
|
|
}
|
|
|
|
return true;
|
|
});
|
|
if (bls[0]) {
|
|
is[0] = Math.min(is[0], k);
|
|
is[3] = Math.max(is[3], k);
|
|
}
|
|
|
|
return true;
|
|
});
|
|
bitSetDiscreteVoxelShape.xMin = is[0];
|
|
bitSetDiscreteVoxelShape.yMin = is[1];
|
|
bitSetDiscreteVoxelShape.zMin = is[2];
|
|
bitSetDiscreteVoxelShape.xMax = is[3] + 1;
|
|
bitSetDiscreteVoxelShape.yMax = is[4] + 1;
|
|
bitSetDiscreteVoxelShape.zMax = is[5] + 1;
|
|
return bitSetDiscreteVoxelShape;
|
|
}
|
|
|
|
protected static void forAllBoxes(DiscreteVoxelShape shape, DiscreteVoxelShape.IntLineConsumer consumer, boolean combine) {
|
|
BitSetDiscreteVoxelShape bitSetDiscreteVoxelShape = new BitSetDiscreteVoxelShape(shape);
|
|
|
|
for (int i = 0; i < bitSetDiscreteVoxelShape.ySize; i++) {
|
|
for (int j = 0; j < bitSetDiscreteVoxelShape.xSize; j++) {
|
|
int k = -1;
|
|
|
|
for (int l = 0; l <= bitSetDiscreteVoxelShape.zSize; l++) {
|
|
if (bitSetDiscreteVoxelShape.isFullWide(j, i, l)) {
|
|
if (combine) {
|
|
if (k == -1) {
|
|
k = l;
|
|
}
|
|
} else {
|
|
consumer.consume(j, i, l, j + 1, i + 1, l + 1);
|
|
}
|
|
} else if (k != -1) {
|
|
int m = j;
|
|
int n = i;
|
|
bitSetDiscreteVoxelShape.clearZStrip(k, l, j, i);
|
|
|
|
while (bitSetDiscreteVoxelShape.isZStripFull(k, l, m + 1, i)) {
|
|
bitSetDiscreteVoxelShape.clearZStrip(k, l, m + 1, i);
|
|
m++;
|
|
}
|
|
|
|
while (bitSetDiscreteVoxelShape.isXZRectangleFull(j, m + 1, k, l, n + 1)) {
|
|
for (int o = j; o <= m; o++) {
|
|
bitSetDiscreteVoxelShape.clearZStrip(k, l, o, n + 1);
|
|
}
|
|
|
|
n++;
|
|
}
|
|
|
|
consumer.consume(j, i, k, m + 1, n + 1, l);
|
|
k = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private boolean isZStripFull(int zMin, int zMax, int x, int y) {
|
|
return x < this.xSize && y < this.ySize ? this.storage.nextClearBit(this.getIndex(x, y, zMin)) >= this.getIndex(x, y, zMax) : false;
|
|
}
|
|
|
|
private boolean isXZRectangleFull(int xMin, int xMax, int zMin, int zMax, int y) {
|
|
for (int i = xMin; i < xMax; i++) {
|
|
if (!this.isZStripFull(zMin, zMax, i, y)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private void clearZStrip(int zMin, int zMax, int x, int y) {
|
|
this.storage.clear(this.getIndex(x, y, zMin), this.getIndex(x, y, zMax));
|
|
}
|
|
|
|
public boolean isInterior(int x, int y, int z) {
|
|
boolean bl = x > 0 && x < this.xSize - 1 && y > 0 && y < this.ySize - 1 && z > 0 && z < this.zSize - 1;
|
|
return bl
|
|
&& this.isFull(x, y, z)
|
|
&& this.isFull(x - 1, y, z)
|
|
&& this.isFull(x + 1, y, z)
|
|
&& this.isFull(x, y - 1, z)
|
|
&& this.isFull(x, y + 1, z)
|
|
&& this.isFull(x, y, z - 1)
|
|
&& this.isFull(x, y, z + 1);
|
|
}
|
|
}
|