Code/net/minecraft/world/phys/shapes/VoxelShape.java

327 lines
13 KiB
Java
Raw Normal View History

2025-07-01 06:20:03 +00:00
package net.minecraft.world.phys.shapes;
import com.google.common.collect.Lists;
import com.google.common.math.DoubleMath;
import it.unimi.dsi.fastutil.doubles.DoubleList;
import java.util.List;
import java.util.Optional;
import javax.annotation.Nullable;
import net.minecraft.Util;
import net.minecraft.core.AxisCycle;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Vec3i;
import net.minecraft.util.Mth;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
public abstract class VoxelShape {
protected final DiscreteVoxelShape shape;
@Nullable
private VoxelShape[] faces;
protected VoxelShape(DiscreteVoxelShape p_83214_) {
this.shape = p_83214_;
}
public double min(Direction.Axis p_83289_) {
int i = this.shape.firstFull(p_83289_);
return i >= this.shape.getSize(p_83289_) ? Double.POSITIVE_INFINITY : this.get(p_83289_, i);
}
public double max(Direction.Axis p_83298_) {
int i = this.shape.lastFull(p_83298_);
return i <= 0 ? Double.NEGATIVE_INFINITY : this.get(p_83298_, i);
}
public AABB bounds() {
if (this.isEmpty()) {
throw (UnsupportedOperationException)Util.pauseInIde(new UnsupportedOperationException("No bounds for empty shape."));
} else {
return new AABB(
this.min(Direction.Axis.X),
this.min(Direction.Axis.Y),
this.min(Direction.Axis.Z),
this.max(Direction.Axis.X),
this.max(Direction.Axis.Y),
this.max(Direction.Axis.Z)
);
}
}
public VoxelShape singleEncompassing() {
return this.isEmpty()
? Shapes.empty()
: Shapes.box(
this.min(Direction.Axis.X),
this.min(Direction.Axis.Y),
this.min(Direction.Axis.Z),
this.max(Direction.Axis.X),
this.max(Direction.Axis.Y),
this.max(Direction.Axis.Z)
);
}
protected double get(Direction.Axis p_83257_, int p_83258_) {
return this.getCoords(p_83257_).getDouble(p_83258_);
}
public abstract DoubleList getCoords(Direction.Axis p_83249_);
public boolean isEmpty() {
return this.shape.isEmpty();
}
public VoxelShape move(Vec3 p_366733_) {
return this.move(p_366733_.x, p_366733_.y, p_366733_.z);
}
public VoxelShape move(Vec3i p_395919_) {
return this.move(p_395919_.getX(), p_395919_.getY(), p_395919_.getZ());
}
public VoxelShape move(double p_83217_, double p_83218_, double p_83219_) {
return (VoxelShape)(this.isEmpty()
? Shapes.empty()
: new ArrayVoxelShape(
this.shape,
new OffsetDoubleList(this.getCoords(Direction.Axis.X), p_83217_),
new OffsetDoubleList(this.getCoords(Direction.Axis.Y), p_83218_),
new OffsetDoubleList(this.getCoords(Direction.Axis.Z), p_83219_)
));
}
public VoxelShape optimize() {
VoxelShape[] avoxelshape = new VoxelShape[]{Shapes.empty()};
this.forAllBoxes(
(p_83275_, p_83276_, p_83277_, p_83278_, p_83279_, p_83280_) -> avoxelshape[0] = Shapes.joinUnoptimized(
avoxelshape[0], Shapes.box(p_83275_, p_83276_, p_83277_, p_83278_, p_83279_, p_83280_), BooleanOp.OR
)
);
return avoxelshape[0];
}
public void forAllEdges(Shapes.DoubleLineConsumer p_83225_) {
this.shape
.forAllEdges(
(p_83228_, p_83229_, p_83230_, p_83231_, p_83232_, p_83233_) -> p_83225_.consume(
this.get(Direction.Axis.X, p_83228_),
this.get(Direction.Axis.Y, p_83229_),
this.get(Direction.Axis.Z, p_83230_),
this.get(Direction.Axis.X, p_83231_),
this.get(Direction.Axis.Y, p_83232_),
this.get(Direction.Axis.Z, p_83233_)
),
true
);
}
public void forAllBoxes(Shapes.DoubleLineConsumer p_83287_) {
DoubleList doublelist = this.getCoords(Direction.Axis.X);
DoubleList doublelist1 = this.getCoords(Direction.Axis.Y);
DoubleList doublelist2 = this.getCoords(Direction.Axis.Z);
this.shape
.forAllBoxes(
(p_83239_, p_83240_, p_83241_, p_83242_, p_83243_, p_83244_) -> p_83287_.consume(
doublelist.getDouble(p_83239_),
doublelist1.getDouble(p_83240_),
doublelist2.getDouble(p_83241_),
doublelist.getDouble(p_83242_),
doublelist1.getDouble(p_83243_),
doublelist2.getDouble(p_83244_)
),
true
);
}
public List<AABB> toAabbs() {
List<AABB> list = Lists.newArrayList();
this.forAllBoxes(
(p_83267_, p_83268_, p_83269_, p_83270_, p_83271_, p_83272_) -> list.add(new AABB(p_83267_, p_83268_, p_83269_, p_83270_, p_83271_, p_83272_))
);
return list;
}
public double min(Direction.Axis p_166079_, double p_166080_, double p_166081_) {
Direction.Axis direction$axis = AxisCycle.FORWARD.cycle(p_166079_);
Direction.Axis direction$axis1 = AxisCycle.BACKWARD.cycle(p_166079_);
int i = this.findIndex(direction$axis, p_166080_);
int j = this.findIndex(direction$axis1, p_166081_);
int k = this.shape.firstFull(p_166079_, i, j);
return k >= this.shape.getSize(p_166079_) ? Double.POSITIVE_INFINITY : this.get(p_166079_, k);
}
public double max(Direction.Axis p_83291_, double p_83292_, double p_83293_) {
Direction.Axis direction$axis = AxisCycle.FORWARD.cycle(p_83291_);
Direction.Axis direction$axis1 = AxisCycle.BACKWARD.cycle(p_83291_);
int i = this.findIndex(direction$axis, p_83292_);
int j = this.findIndex(direction$axis1, p_83293_);
int k = this.shape.lastFull(p_83291_, i, j);
return k <= 0 ? Double.NEGATIVE_INFINITY : this.get(p_83291_, k);
}
protected int findIndex(Direction.Axis p_83250_, double p_83251_) {
return Mth.binarySearch(0, this.shape.getSize(p_83250_) + 1, p_166066_ -> p_83251_ < this.get(p_83250_, p_166066_)) - 1;
}
@Nullable
public BlockHitResult clip(Vec3 p_83221_, Vec3 p_83222_, BlockPos p_83223_) {
if (this.isEmpty()) {
return null;
} else {
Vec3 vec3 = p_83222_.subtract(p_83221_);
if (vec3.lengthSqr() < 1.0E-7) {
return null;
} else {
Vec3 vec31 = p_83221_.add(vec3.scale(0.001));
return this.shape
.isFullWide(
this.findIndex(Direction.Axis.X, vec31.x - p_83223_.getX()),
this.findIndex(Direction.Axis.Y, vec31.y - p_83223_.getY()),
this.findIndex(Direction.Axis.Z, vec31.z - p_83223_.getZ())
)
? new BlockHitResult(vec31, Direction.getApproximateNearest(vec3.x, vec3.y, vec3.z).getOpposite(), p_83223_, true)
: AABB.clip(this.toAabbs(), p_83221_, p_83222_, p_83223_);
}
}
}
public Optional<Vec3> closestPointTo(Vec3 p_166068_) {
if (this.isEmpty()) {
return Optional.empty();
} else {
Vec3[] avec3 = new Vec3[1];
this.forAllBoxes((p_166072_, p_166073_, p_166074_, p_166075_, p_166076_, p_166077_) -> {
double d0 = Mth.clamp(p_166068_.x(), p_166072_, p_166075_);
double d1 = Mth.clamp(p_166068_.y(), p_166073_, p_166076_);
double d2 = Mth.clamp(p_166068_.z(), p_166074_, p_166077_);
if (avec3[0] == null || p_166068_.distanceToSqr(d0, d1, d2) < p_166068_.distanceToSqr(avec3[0])) {
avec3[0] = new Vec3(d0, d1, d2);
}
});
return Optional.of(avec3[0]);
}
}
public VoxelShape getFaceShape(Direction p_83264_) {
if (!this.isEmpty() && this != Shapes.block()) {
if (this.faces != null) {
VoxelShape voxelshape = this.faces[p_83264_.ordinal()];
if (voxelshape != null) {
return voxelshape;
}
} else {
this.faces = new VoxelShape[6];
}
VoxelShape voxelshape1 = this.calculateFace(p_83264_);
this.faces[p_83264_.ordinal()] = voxelshape1;
return voxelshape1;
} else {
return this;
}
}
private VoxelShape calculateFace(Direction p_83295_) {
Direction.Axis direction$axis = p_83295_.getAxis();
if (this.isCubeLikeAlong(direction$axis)) {
return this;
} else {
Direction.AxisDirection direction$axisdirection = p_83295_.getAxisDirection();
int i = this.findIndex(direction$axis, direction$axisdirection == Direction.AxisDirection.POSITIVE ? 0.9999999 : 1.0E-7);
SliceShape sliceshape = new SliceShape(this, direction$axis, i);
if (sliceshape.isEmpty()) {
return Shapes.empty();
} else {
return (VoxelShape)(sliceshape.isCubeLike() ? Shapes.block() : sliceshape);
}
}
}
protected boolean isCubeLike() {
for (Direction.Axis direction$axis : Direction.Axis.VALUES) {
if (!this.isCubeLikeAlong(direction$axis)) {
return false;
}
}
return true;
}
private boolean isCubeLikeAlong(Direction.Axis p_363919_) {
DoubleList doublelist = this.getCoords(p_363919_);
return doublelist.size() == 2
&& DoubleMath.fuzzyEquals(doublelist.getDouble(0), 0.0, 1.0E-7)
&& DoubleMath.fuzzyEquals(doublelist.getDouble(1), 1.0, 1.0E-7);
}
public double collide(Direction.Axis p_83260_, AABB p_83261_, double p_83262_) {
return this.collideX(AxisCycle.between(p_83260_, Direction.Axis.X), p_83261_, p_83262_);
}
protected double collideX(AxisCycle p_83246_, AABB p_83247_, double p_83248_) {
if (this.isEmpty()) {
return p_83248_;
} else if (Math.abs(p_83248_) < 1.0E-7) {
return 0.0;
} else {
AxisCycle axiscycle = p_83246_.inverse();
Direction.Axis direction$axis = axiscycle.cycle(Direction.Axis.X);
Direction.Axis direction$axis1 = axiscycle.cycle(Direction.Axis.Y);
Direction.Axis direction$axis2 = axiscycle.cycle(Direction.Axis.Z);
double d0 = p_83247_.max(direction$axis);
double d1 = p_83247_.min(direction$axis);
int i = this.findIndex(direction$axis, d1 + 1.0E-7);
int j = this.findIndex(direction$axis, d0 - 1.0E-7);
int k = Math.max(0, this.findIndex(direction$axis1, p_83247_.min(direction$axis1) + 1.0E-7));
int l = Math.min(this.shape.getSize(direction$axis1), this.findIndex(direction$axis1, p_83247_.max(direction$axis1) - 1.0E-7) + 1);
int i1 = Math.max(0, this.findIndex(direction$axis2, p_83247_.min(direction$axis2) + 1.0E-7));
int j1 = Math.min(this.shape.getSize(direction$axis2), this.findIndex(direction$axis2, p_83247_.max(direction$axis2) - 1.0E-7) + 1);
int k1 = this.shape.getSize(direction$axis);
if (p_83248_ > 0.0) {
for (int l1 = j + 1; l1 < k1; l1++) {
for (int i2 = k; i2 < l; i2++) {
for (int j2 = i1; j2 < j1; j2++) {
if (this.shape.isFullWide(axiscycle, l1, i2, j2)) {
double d2 = this.get(direction$axis, l1) - d0;
if (d2 >= -1.0E-7) {
p_83248_ = Math.min(p_83248_, d2);
}
return p_83248_;
}
}
}
}
} else if (p_83248_ < 0.0) {
for (int k2 = i - 1; k2 >= 0; k2--) {
for (int l2 = k; l2 < l; l2++) {
for (int i3 = i1; i3 < j1; i3++) {
if (this.shape.isFullWide(axiscycle, k2, l2, i3)) {
double d3 = this.get(direction$axis, k2 + 1) - d1;
if (d3 <= 1.0E-7) {
p_83248_ = Math.max(p_83248_, d3);
}
return p_83248_;
}
}
}
}
}
return p_83248_;
}
}
@Override
public boolean equals(Object p_394599_) {
return super.equals(p_394599_);
}
@Override
public String toString() {
return this.isEmpty() ? "EMPTY" : "VoxelShape[" + this.bounds() + "]";
}
}