minecraft-src/net/minecraft/world/phys/shapes/DiscreteVoxelShape.java
2025-07-04 03:45:38 +03:00

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);
}
}