270 lines
8.1 KiB
Java
270 lines
8.1 KiB
Java
package net.minecraft.world.phys.shapes;
|
|
|
|
import com.mojang.math.OctahedralGroup;
|
|
import net.minecraft.core.AxisCycle;
|
|
import net.minecraft.core.Direction;
|
|
|
|
public abstract class DiscreteVoxelShape {
|
|
private static final Direction.Axis[] AXIS_VALUES = Direction.Axis.values();
|
|
protected final int xSize;
|
|
protected final int ySize;
|
|
protected final int zSize;
|
|
|
|
protected DiscreteVoxelShape(int xSize, int ySize, int zSize) {
|
|
if (xSize >= 0 && ySize >= 0 && zSize >= 0) {
|
|
this.xSize = xSize;
|
|
this.ySize = ySize;
|
|
this.zSize = zSize;
|
|
} else {
|
|
throw new IllegalArgumentException("Need all positive sizes: x: " + xSize + ", y: " + ySize + ", z: " + zSize);
|
|
}
|
|
}
|
|
|
|
public DiscreteVoxelShape rotate(OctahedralGroup octahedralGroup) {
|
|
if (octahedralGroup == OctahedralGroup.IDENTITY) {
|
|
return this;
|
|
} else {
|
|
Direction.Axis axis = octahedralGroup.permute(Direction.Axis.X);
|
|
Direction.Axis axis2 = octahedralGroup.permute(Direction.Axis.Y);
|
|
Direction.Axis axis3 = octahedralGroup.permute(Direction.Axis.Z);
|
|
int i = axis.choose(this.xSize, this.ySize, this.zSize);
|
|
int j = axis2.choose(this.xSize, this.ySize, this.zSize);
|
|
int k = axis3.choose(this.xSize, this.ySize, this.zSize);
|
|
boolean bl = octahedralGroup.inverts(axis);
|
|
boolean bl2 = octahedralGroup.inverts(axis2);
|
|
boolean bl3 = octahedralGroup.inverts(axis3);
|
|
boolean bl4 = axis.choose(bl, bl2, bl3);
|
|
boolean bl5 = axis2.choose(bl, bl2, bl3);
|
|
boolean bl6 = axis3.choose(bl, bl2, bl3);
|
|
DiscreteVoxelShape discreteVoxelShape = new BitSetDiscreteVoxelShape(i, j, k);
|
|
|
|
for (int l = 0; l < this.xSize; l++) {
|
|
for (int m = 0; m < this.ySize; m++) {
|
|
for (int n = 0; n < this.zSize; n++) {
|
|
if (this.isFull(l, m, n)) {
|
|
int o = axis.choose(l, m, n);
|
|
int p = axis2.choose(l, m, n);
|
|
int q = axis3.choose(l, m, n);
|
|
discreteVoxelShape.fill(bl4 ? i - 1 - o : o, bl5 ? j - 1 - p : p, bl6 ? k - 1 - q : q);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return discreteVoxelShape;
|
|
}
|
|
}
|
|
|
|
public boolean isFullWide(AxisCycle axis, int x, int y, int z) {
|
|
return this.isFullWide(axis.cycle(x, y, z, Direction.Axis.X), axis.cycle(x, y, z, Direction.Axis.Y), axis.cycle(x, y, z, Direction.Axis.Z));
|
|
}
|
|
|
|
public boolean isFullWide(int x, int y, int z) {
|
|
if (x < 0 || y < 0 || z < 0) {
|
|
return false;
|
|
} else {
|
|
return x < this.xSize && y < this.ySize && z < this.zSize ? this.isFull(x, y, z) : false;
|
|
}
|
|
}
|
|
|
|
public boolean isFull(AxisCycle rotation, int x, int y, int z) {
|
|
return this.isFull(rotation.cycle(x, y, z, Direction.Axis.X), rotation.cycle(x, y, z, Direction.Axis.Y), rotation.cycle(x, y, z, Direction.Axis.Z));
|
|
}
|
|
|
|
public abstract boolean isFull(int x, int y, int z);
|
|
|
|
public abstract void fill(int x, int y, int z);
|
|
|
|
public boolean isEmpty() {
|
|
for (Direction.Axis axis : AXIS_VALUES) {
|
|
if (this.firstFull(axis) >= this.lastFull(axis)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public abstract int firstFull(Direction.Axis axis);
|
|
|
|
public abstract int lastFull(Direction.Axis axis);
|
|
|
|
public int firstFull(Direction.Axis axis, int y, int z) {
|
|
int i = this.getSize(axis);
|
|
if (y >= 0 && z >= 0) {
|
|
Direction.Axis axis2 = AxisCycle.FORWARD.cycle(axis);
|
|
Direction.Axis axis3 = AxisCycle.BACKWARD.cycle(axis);
|
|
if (y < this.getSize(axis2) && z < this.getSize(axis3)) {
|
|
AxisCycle axisCycle = AxisCycle.between(Direction.Axis.X, axis);
|
|
|
|
for (int j = 0; j < i; j++) {
|
|
if (this.isFull(axisCycle, j, y, z)) {
|
|
return j;
|
|
}
|
|
}
|
|
|
|
return i;
|
|
} else {
|
|
return i;
|
|
}
|
|
} else {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gives the index of the last filled part in the column.
|
|
*/
|
|
public int lastFull(Direction.Axis axis, int y, int z) {
|
|
if (y >= 0 && z >= 0) {
|
|
Direction.Axis axis2 = AxisCycle.FORWARD.cycle(axis);
|
|
Direction.Axis axis3 = AxisCycle.BACKWARD.cycle(axis);
|
|
if (y < this.getSize(axis2) && z < this.getSize(axis3)) {
|
|
int i = this.getSize(axis);
|
|
AxisCycle axisCycle = AxisCycle.between(Direction.Axis.X, axis);
|
|
|
|
for (int j = i - 1; j >= 0; j--) {
|
|
if (this.isFull(axisCycle, j, y, z)) {
|
|
return j + 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
} else {
|
|
return 0;
|
|
}
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
public int getSize(Direction.Axis axis) {
|
|
return axis.choose(this.xSize, this.ySize, this.zSize);
|
|
}
|
|
|
|
public int getXSize() {
|
|
return this.getSize(Direction.Axis.X);
|
|
}
|
|
|
|
public int getYSize() {
|
|
return this.getSize(Direction.Axis.Y);
|
|
}
|
|
|
|
public int getZSize() {
|
|
return this.getSize(Direction.Axis.Z);
|
|
}
|
|
|
|
public void forAllEdges(DiscreteVoxelShape.IntLineConsumer consumer, boolean combine) {
|
|
this.forAllAxisEdges(consumer, AxisCycle.NONE, combine);
|
|
this.forAllAxisEdges(consumer, AxisCycle.FORWARD, combine);
|
|
this.forAllAxisEdges(consumer, AxisCycle.BACKWARD, combine);
|
|
}
|
|
|
|
private void forAllAxisEdges(DiscreteVoxelShape.IntLineConsumer lineConsumer, AxisCycle axis, boolean combine) {
|
|
AxisCycle axisCycle = axis.inverse();
|
|
int i = this.getSize(axisCycle.cycle(Direction.Axis.X));
|
|
int j = this.getSize(axisCycle.cycle(Direction.Axis.Y));
|
|
int k = this.getSize(axisCycle.cycle(Direction.Axis.Z));
|
|
|
|
for (int l = 0; l <= i; l++) {
|
|
for (int m = 0; m <= j; m++) {
|
|
int n = -1;
|
|
|
|
for (int o = 0; o <= k; o++) {
|
|
int p = 0;
|
|
int q = 0;
|
|
|
|
for (int r = 0; r <= 1; r++) {
|
|
for (int s = 0; s <= 1; s++) {
|
|
if (this.isFullWide(axisCycle, l + r - 1, m + s - 1, o)) {
|
|
p++;
|
|
q ^= r ^ s;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (p == 1 || p == 3 || p == 2 && (q & 1) == 0) {
|
|
if (combine) {
|
|
if (n == -1) {
|
|
n = o;
|
|
}
|
|
} else {
|
|
lineConsumer.consume(
|
|
axisCycle.cycle(l, m, o, Direction.Axis.X),
|
|
axisCycle.cycle(l, m, o, Direction.Axis.Y),
|
|
axisCycle.cycle(l, m, o, Direction.Axis.Z),
|
|
axisCycle.cycle(l, m, o + 1, Direction.Axis.X),
|
|
axisCycle.cycle(l, m, o + 1, Direction.Axis.Y),
|
|
axisCycle.cycle(l, m, o + 1, Direction.Axis.Z)
|
|
);
|
|
}
|
|
} else if (n != -1) {
|
|
lineConsumer.consume(
|
|
axisCycle.cycle(l, m, n, Direction.Axis.X),
|
|
axisCycle.cycle(l, m, n, Direction.Axis.Y),
|
|
axisCycle.cycle(l, m, n, Direction.Axis.Z),
|
|
axisCycle.cycle(l, m, o, Direction.Axis.X),
|
|
axisCycle.cycle(l, m, o, Direction.Axis.Y),
|
|
axisCycle.cycle(l, m, o, Direction.Axis.Z)
|
|
);
|
|
n = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void forAllBoxes(DiscreteVoxelShape.IntLineConsumer consumer, boolean combine) {
|
|
BitSetDiscreteVoxelShape.forAllBoxes(this, consumer, combine);
|
|
}
|
|
|
|
public void forAllFaces(DiscreteVoxelShape.IntFaceConsumer faceConsumer) {
|
|
this.forAllAxisFaces(faceConsumer, AxisCycle.NONE);
|
|
this.forAllAxisFaces(faceConsumer, AxisCycle.FORWARD);
|
|
this.forAllAxisFaces(faceConsumer, AxisCycle.BACKWARD);
|
|
}
|
|
|
|
private void forAllAxisFaces(DiscreteVoxelShape.IntFaceConsumer faceConsumer, AxisCycle axisRotation) {
|
|
AxisCycle axisCycle = axisRotation.inverse();
|
|
Direction.Axis axis = axisCycle.cycle(Direction.Axis.Z);
|
|
int i = this.getSize(axisCycle.cycle(Direction.Axis.X));
|
|
int j = this.getSize(axisCycle.cycle(Direction.Axis.Y));
|
|
int k = this.getSize(axis);
|
|
Direction direction = Direction.fromAxisAndDirection(axis, Direction.AxisDirection.NEGATIVE);
|
|
Direction direction2 = Direction.fromAxisAndDirection(axis, Direction.AxisDirection.POSITIVE);
|
|
|
|
for (int l = 0; l < i; l++) {
|
|
for (int m = 0; m < j; m++) {
|
|
boolean bl = false;
|
|
|
|
for (int n = 0; n <= k; n++) {
|
|
boolean bl2 = n != k && this.isFull(axisCycle, l, m, n);
|
|
if (!bl && bl2) {
|
|
faceConsumer.consume(
|
|
direction, axisCycle.cycle(l, m, n, Direction.Axis.X), axisCycle.cycle(l, m, n, Direction.Axis.Y), axisCycle.cycle(l, m, n, Direction.Axis.Z)
|
|
);
|
|
}
|
|
|
|
if (bl && !bl2) {
|
|
faceConsumer.consume(
|
|
direction2,
|
|
axisCycle.cycle(l, m, n - 1, Direction.Axis.X),
|
|
axisCycle.cycle(l, m, n - 1, Direction.Axis.Y),
|
|
axisCycle.cycle(l, m, n - 1, Direction.Axis.Z)
|
|
);
|
|
}
|
|
|
|
bl = bl2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public interface IntFaceConsumer {
|
|
void consume(Direction direction, int i, int j, int k);
|
|
}
|
|
|
|
public interface IntLineConsumer {
|
|
void consume(int i, int j, int k, int l, int m, int n);
|
|
}
|
|
}
|