306 lines
9.7 KiB
Java
306 lines
9.7 KiB
Java
package top.r3944realms.lib39.util.shape;
|
||
|
||
import net.minecraft.core.Direction;
|
||
import net.minecraft.world.level.block.state.properties.DoubleBlockHalf;
|
||
import net.minecraft.world.phys.shapes.Shapes;
|
||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||
import org.jetbrains.annotations.Contract;
|
||
import org.jetbrains.annotations.NotNull;
|
||
|
||
import java.util.*;
|
||
|
||
/**
|
||
* The type Shape util.
|
||
*/
|
||
@SuppressWarnings("unused")
|
||
public class ShapeUtil {
|
||
|
||
// ==================== 基础形状创建 ====================
|
||
|
||
/**
|
||
* 创建基于像素的碰撞箱(将像素坐标转换为方块坐标)
|
||
*
|
||
* @param minX the min x
|
||
* @param minY the min y
|
||
* @param minZ the min z
|
||
* @param maxX the max x
|
||
* @param maxY the max y
|
||
* @param maxZ the max z
|
||
* @return the voxel shape
|
||
*/
|
||
public static @NotNull VoxelShape createPixelBasedShape(double minX, double minY, double minZ,
|
||
double maxX, double maxY, double maxZ) {
|
||
return Shapes.box(minX / 16.0d, minY / 16.0d, minZ / 16.0d,
|
||
maxX / 16.0d, maxY / 16.0d, maxZ / 16.0d);
|
||
}
|
||
|
||
/**
|
||
* 便捷方法:创建方块碰撞箱
|
||
*
|
||
* @param minX the min x
|
||
* @param minY the min y
|
||
* @param minZ the min z
|
||
* @param maxX the max x
|
||
* @param maxY the max y
|
||
* @param maxZ the max z
|
||
* @return the voxel shape
|
||
*/
|
||
public static @NotNull VoxelShape createBox(double minX, double minY, double minZ,
|
||
double maxX, double maxY, double maxZ) {
|
||
return Shapes.box(minX, minY, minZ, maxX, maxY, maxZ);
|
||
}
|
||
|
||
// ==================== 多部分方块形状映射 ====================
|
||
|
||
/**
|
||
* 创建单一形状的方向映射
|
||
*
|
||
* @param shape the shape
|
||
* @return the map
|
||
*/
|
||
public static @NotNull Map<Direction, VoxelShape> createUniformDirectionMap(VoxelShape shape) {
|
||
return createRotatedDirectionMap(shape);
|
||
}
|
||
|
||
/**
|
||
* 创建支持全方向的形状映射(包括上下)
|
||
*
|
||
* @param shape 基础形状(默认为NORTH方向)
|
||
* @return 全方向形状映射
|
||
*/
|
||
public static @NotNull Map<Direction, VoxelShape> createFullDirectionMap(VoxelShape shape) {
|
||
EnumMap<Direction, VoxelShape> directionMap = new EnumMap<>(Direction.class);
|
||
|
||
// 水平方向
|
||
directionMap.put(Direction.NORTH, shape);
|
||
directionMap.put(Direction.EAST, rotateShape(shape, 90));
|
||
directionMap.put(Direction.SOUTH, rotateShape(shape, 180));
|
||
directionMap.put(Direction.WEST, rotateShape(shape, 270));
|
||
|
||
// 垂直方向
|
||
directionMap.put(Direction.UP, rotateShapeToUp(shape));
|
||
directionMap.put(Direction.DOWN, rotateShapeToDown(shape));
|
||
|
||
return directionMap;
|
||
}
|
||
|
||
/**
|
||
* 创建原版双方块的形状映射
|
||
*
|
||
* @param lowerShape the lower shape
|
||
* @param upperShape the upper shape
|
||
* @return the map
|
||
*/
|
||
public static @NotNull Map<DoubleBlockHalf, Map<Direction, VoxelShape>> createDoubleBlockShapeMap(VoxelShape lowerShape, VoxelShape upperShape) {
|
||
EnumMap<DoubleBlockHalf, Map<Direction, VoxelShape>> shapeMap = new EnumMap<>(DoubleBlockHalf.class);
|
||
shapeMap.put(DoubleBlockHalf.LOWER, createRotatedDirectionMap(lowerShape));
|
||
shapeMap.put(DoubleBlockHalf.UPPER, createRotatedDirectionMap(upperShape));
|
||
return shapeMap;
|
||
}
|
||
|
||
// ==================== 形状旋转 ====================
|
||
|
||
/**
|
||
* 顺时针旋转碰撞箱(Y轴旋转)
|
||
*
|
||
* @param shape the shape
|
||
* @return the voxel shape
|
||
*/
|
||
public static @NotNull VoxelShape rotateVoxelShapeClockwise(@NotNull VoxelShape shape) {
|
||
final List<VoxelShape> generatedShapes = new ArrayList<>();
|
||
shape.forAllBoxes((minX, minY, minZ, maxX, maxY, maxZ) -> {
|
||
VoxelShape rotated = Shapes.box(1.0 - maxZ, minY, minX, 1.0 - minZ, maxY, maxX);
|
||
generatedShapes.add(rotated);
|
||
});
|
||
return combineShapes(generatedShapes);
|
||
}
|
||
|
||
/**
|
||
* 绕X轴旋转碰撞箱
|
||
*
|
||
* @param shape the shape
|
||
* @return the voxel shape
|
||
*/
|
||
public static @NotNull VoxelShape rotateVoxelShapeXAxis(@NotNull VoxelShape shape) {
|
||
return rotateShapeToUp(shape);
|
||
}
|
||
|
||
/**
|
||
* 绕Z轴旋转碰撞箱
|
||
*
|
||
* @param shape the shape
|
||
* @return the voxel shape
|
||
*/
|
||
@SuppressWarnings("SuspiciousNameCombination")
|
||
public static @NotNull VoxelShape rotateVoxelShapeZAxis(@NotNull VoxelShape shape) {
|
||
final List<VoxelShape> generatedShapes = new ArrayList<>();
|
||
shape.forAllBoxes((minX, minY, minZ, maxX, maxY, maxZ) -> {
|
||
VoxelShape rotated = Shapes.box(minY, minX, minZ, maxY, maxX, maxZ);
|
||
generatedShapes.add(rotated);
|
||
});
|
||
return combineShapes(generatedShapes);
|
||
}
|
||
|
||
/**
|
||
* 按指定角度旋转碰撞箱
|
||
*
|
||
* @param shape the shape
|
||
* @param degrees the degrees
|
||
* @return the voxel shape
|
||
*/
|
||
public static @NotNull VoxelShape rotateShape(@NotNull VoxelShape shape, int degrees) {
|
||
int rotations = (degrees / 90) % 4;
|
||
VoxelShape result = shape;
|
||
|
||
for (int i = 0; i < rotations; i++) {
|
||
result = rotateVoxelShapeClockwise(result);
|
||
}
|
||
return result;
|
||
}
|
||
/**
|
||
* 将形状旋转到向上方向(绕X轴-90度)
|
||
*
|
||
* @param shape the shape
|
||
* @return the voxel shape
|
||
*/
|
||
public static @NotNull VoxelShape rotateShapeToUp(@NotNull VoxelShape shape) {
|
||
final List<VoxelShape> generatedShapes = new ArrayList<>();
|
||
shape.forAllBoxes((minX, minY, minZ, maxX, maxY, maxZ) -> {
|
||
VoxelShape rotated = Shapes.box(minX, 1.0 - maxZ, minY, maxX, 1.0 - minZ, maxY);
|
||
generatedShapes.add(rotated);
|
||
});
|
||
return combineShapes(generatedShapes);
|
||
}
|
||
|
||
/**
|
||
* 将形状旋转到向下方向(绕X轴90度)
|
||
*
|
||
* @param shape the shape
|
||
* @return the voxel shape
|
||
*/
|
||
public static @NotNull VoxelShape rotateShapeToDown(@NotNull VoxelShape shape) {
|
||
final List<VoxelShape> generatedShapes = new ArrayList<>();
|
||
shape.forAllBoxes((minX, minY, minZ, maxX, maxY, maxZ) -> {
|
||
VoxelShape rotated = Shapes.box(minX, minZ, minY, maxX, maxZ, maxY);
|
||
generatedShapes.add(rotated);
|
||
});
|
||
return combineShapes(generatedShapes);
|
||
}
|
||
|
||
// ==================== 形状组合与优化 ====================
|
||
|
||
/**
|
||
* 组合多个形状列表
|
||
*/
|
||
@NotNull
|
||
private static VoxelShape combineShapes(@NotNull List<VoxelShape> shapes) {
|
||
if (shapes.isEmpty()) {
|
||
return Shapes.block();
|
||
}
|
||
|
||
VoxelShape result = shapes.get(0);
|
||
for (int i = 1; i < shapes.size(); i++) {
|
||
result = Shapes.or(result, shapes.get(i));
|
||
}
|
||
|
||
return result.optimize();
|
||
}
|
||
|
||
/**
|
||
* 组合多个形状
|
||
*
|
||
* @param shapes the shapes
|
||
* @return the voxel shape
|
||
*/
|
||
public static @NotNull VoxelShape combineShapes(VoxelShape... shapes) {
|
||
return combineShapes(Arrays.asList(shapes));
|
||
}
|
||
|
||
// ==================== 内部工具方法 ====================
|
||
|
||
/**
|
||
* 创建旋转方向映射
|
||
*/
|
||
private static @NotNull Map<Direction, VoxelShape> createRotatedDirectionMap(VoxelShape baseShape) {
|
||
EnumMap<Direction, VoxelShape> directionMap = new EnumMap<>(Direction.class);
|
||
directionMap.put(Direction.NORTH, baseShape);
|
||
directionMap.put(Direction.EAST, rotateShape(baseShape, 90));
|
||
directionMap.put(Direction.SOUTH, rotateShape(baseShape, 180));
|
||
directionMap.put(Direction.WEST, rotateShape(baseShape, 270));
|
||
return directionMap;
|
||
}
|
||
|
||
|
||
// ==================== 便捷构建器 ====================
|
||
|
||
/**
|
||
* 形状构建器 - 流畅API
|
||
*/
|
||
public static class ShapeBuilder {
|
||
private final List<VoxelShape> shapes = new ArrayList<>();
|
||
|
||
/**
|
||
* Add pixel box shape builder.
|
||
*
|
||
* @param minX the min x
|
||
* @param minY the min y
|
||
* @param minZ the min z
|
||
* @param maxX the max x
|
||
* @param maxY the max y
|
||
* @param maxZ the max z
|
||
* @return the shape builder
|
||
*/
|
||
public ShapeBuilder addPixelBox(double minX, double minY, double minZ,
|
||
double maxX, double maxY, double maxZ) {
|
||
shapes.add(createPixelBasedShape(minX, minY, minZ, maxX, maxY, maxZ));
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* Add box shape builder.
|
||
*
|
||
* @param minX the min x
|
||
* @param minY the min y
|
||
* @param minZ the min z
|
||
* @param maxX the max x
|
||
* @param maxY the max y
|
||
* @param maxZ the max z
|
||
* @return the shape builder
|
||
*/
|
||
public ShapeBuilder addBox(double minX, double minY, double minZ,
|
||
double maxX, double maxY, double maxZ) {
|
||
shapes.add(createBox(minX, minY, minZ, maxX, maxY, maxZ));
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* Add shape shape builder.
|
||
*
|
||
* @param shape the shape
|
||
* @return the shape builder
|
||
*/
|
||
public ShapeBuilder addShape(VoxelShape shape) {
|
||
shapes.add(shape);
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* Build voxel shape.
|
||
*
|
||
* @return the voxel shape
|
||
*/
|
||
public VoxelShape build() {
|
||
return combineShapes(shapes);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 创建形状构建器
|
||
*
|
||
* @return the shape builder
|
||
*/
|
||
@Contract(" -> new")
|
||
public static @NotNull ShapeBuilder builder() {
|
||
return new ShapeBuilder();
|
||
}
|
||
} |