refactor to VoxelShaper

VoxelShaper is more flexible now
belt tunnel shape reworked

Signed-off-by: Zelophed <zefren1@googlemail.com>
This commit is contained in:
zelophed 2019-12-09 20:43:30 +01:00 committed by Zelophed
parent 6fb24e0d86
commit 70eafb997d
6 changed files with 135 additions and 134 deletions

View file

@ -1,7 +1,9 @@
package com.simibubi.create.foundation.utility;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import org.apache.commons.lang3.mutable.MutableObject;
@ -12,12 +14,9 @@ import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import org.apache.commons.lang3.tuple.ImmutablePair;
public class VoxelShaper {
//big todo lul
private Map<Direction, VoxelShape> shapes = new HashMap<>();
public VoxelShape get(Direction direction) {
@ -28,108 +27,76 @@ public class VoxelShaper {
return shapes.get(axisAsFace(axis));
}
public static VoxelShaper forHorizontal(VoxelShape southShape) {
VoxelShaper voxelShaper = new VoxelShaper();
for (Direction facing : Direction.values()) {
if (facing.getAxis().isVertical())
continue;
voxelShaper.shapes.put(facing, rotatedCopy(southShape, 0, (int) -facing.getHorizontalAngle()));
}
return voxelShaper;
public static VoxelShaper forHorizontal(VoxelShape shape, Direction facing){
shape = rotateUp(shape, facing);
return forDirectionsWithRotation(shape, Direction.Plane.HORIZONTAL, new DefaultRotationValues());
}
public static VoxelShaper forHorizontalAxis(VoxelShape zShape) {
VoxelShaper voxelShaper = new VoxelShaper();
for (Axis axis : Axis.values()) {
if (axis.isVertical())
continue;
Direction facing = axisAsFace(axis);
voxelShaper.shapes.put(facing, rotatedCopy(zShape, 0, (int) -facing.getHorizontalAngle()));
}
return voxelShaper;
public static VoxelShaper forHorizontalAxis(VoxelShape shape, Direction facing){
shape = rotateUp(shape, facing);
return forDirectionsWithRotation(shape, Arrays.asList(Direction.SOUTH, Direction.EAST), new DefaultRotationValues());
}
public static VoxelShaper forVerticalBelt(VoxelShape southBeltShape){
VoxelShaper voxelShaper = new VoxelShaper();
for (Direction facing : Direction.values()) {
if (facing.getAxis().isVertical())
continue;
voxelShaper.shapes.put(facing, rotatedCopy(rotatedCopy(southBeltShape, facing.getAxisDirection() == AxisDirection.NEGATIVE ? 90 : 270, 0),0,(int) -facing.getHorizontalAngle()));
}
return voxelShaper;
}
public static VoxelShaper forRotatedPillar(VoxelShape zShape) {
public static VoxelShaper forRotatedPillar(VoxelShape zShape) {//dunno what this was intended for
VoxelShaper voxelShaper = new VoxelShaper();
for (Axis axis : Axis.values()) {
Direction facing = axisAsFace(axis);
voxelShaper.shapes.put(facing, rotatedCopy(zShape, 0, (int) -facing.getHorizontalAngle()));
voxelShaper.shapes.put(facing, rotatedCopy(zShape, new Vec3d(0, (int) -facing.getHorizontalAngle(),0)));
}
return voxelShaper;
}
public static VoxelShaper forDirectional(VoxelShape southShape) {
return forDirectional(southShape, Direction.SOUTH);
}
public static VoxelShaper forDirectional(VoxelShape shape, Direction facing){
if (facing != Direction.UP) {
ImmutablePair<Integer, Integer> rot = rotationValuesForDirection(facing);
shape = rotatedCopy(shape, 360 - rot.getLeft(), 360 - rot.getRight());
}
return forDirectionsFacingUp(shape, Direction.values());
shape = rotateUp(shape, facing);
return forDirectionsWithRotation(shape, Arrays.asList(Direction.values()), new DefaultRotationValues());
}
private static VoxelShaper forDirectionsFacingUp(VoxelShape shape, Direction[] directions){
protected static VoxelShaper forDirectionsWithRotation(VoxelShape shape, Iterable<Direction> directions, Function<Direction, Vec3d> rotationValues){
VoxelShaper voxelShaper = new VoxelShaper();
for (Direction dir : directions) {
ImmutablePair<Integer, Integer> rotation = rotationValuesForDirection(dir);
voxelShaper.shapes.put(dir, rotatedCopy(shape, rotation.getLeft(), rotation.getRight()));
}
return voxelShaper;
}
public static VoxelShaper forDirectionalOld(VoxelShape southShape) {
VoxelShaper voxelShaper = new VoxelShaper();
for (Direction facing : Direction.values()) {
int rotX = facing.getAxis().isVertical() ? (facing == Direction.UP ? 270 : 90) : 0;
int rotY = facing.getAxis().isVertical() ? 0 : (int) -facing.getHorizontalAngle();
voxelShaper.shapes.put(facing, rotatedCopy(southShape, rotX, rotY));
voxelShaper.shapes.put(dir, rotatedCopy(shape, rotationValues.apply(dir)));
}
return voxelShaper;
}
public VoxelShaper withVerticalShapes(VoxelShape upShape) {
shapes.put(Direction.UP, upShape);
shapes.put(Direction.DOWN, rotatedCopy(upShape, 180, 0));
shapes.put(Direction.DOWN, rotatedCopy(upShape, new Vec3d(0, 180, 0)));
return this;
}
private static ImmutablePair<Integer, Integer> rotationValuesForDirection(Direction facing) {
//assume facing up as the default rotation
return ImmutablePair.of(
facing == Direction.UP ? 0 : (Direction.Plane.VERTICAL.test(facing) ? 180 : 90),
Direction.Plane.VERTICAL.test(facing) ? 0 : (int) -facing.getHorizontalAngle());
public VoxelShaper withShape(VoxelShape shape, Direction facing){
shapes.put(facing, shape);
return this;
}
public static Direction axisAsFace(Axis axis) {
return Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis);
}
private static VoxelShape rotatedCopy(VoxelShape shape, int rotationX, int rotationY) {
private static VoxelShape rotateUp(VoxelShape shape, Direction facing){
if (facing != Direction.UP) {
Vec3d rot = new DefaultRotationValues().apply(facing);
shape = rotatedCopy(shape, new Vec3d(360, 360,360).subtract(rot));
}
return shape;
}
protected static VoxelShape rotatedCopy(VoxelShape shape, Vec3d rotation){
MutableObject<VoxelShape> result = new MutableObject<>(VoxelShapes.empty());
Vec3d center = new Vec3d(8, 8, 8);
shape.forEachBox((x1, y1, z1, x2, y2, z2) -> {
Vec3d center = new Vec3d(8, 8, 8);
Vec3d v1 = new Vec3d(x1, y1, z1).scale(16).subtract(center);
Vec3d v2 = new Vec3d(x2, y2, z2).scale(16).subtract(center);
v1 = VecHelper.rotate(v1, rotationX, Axis.X);
v1 = VecHelper.rotate(v1, rotationY, Axis.Y).add(center);
v2 = VecHelper.rotate(v2, rotationX, Axis.X);
v2 = VecHelper.rotate(v2, rotationY, Axis.Y).add(center);
v1 = VecHelper.rotate(v1, (float) rotation.x, Axis.X);
v1 = VecHelper.rotate(v1, (float) rotation.y, Axis.Y);
v1 = VecHelper.rotate(v1, (float) rotation.z, Axis.Z).add(center);
v2 = VecHelper.rotate(v2, (float) rotation.x, Axis.X);
v2 = VecHelper.rotate(v2, (float) rotation.y, Axis.Y);
v2 = VecHelper.rotate(v2, (float) rotation.z, Axis.Z).add(center);
VoxelShape rotated = Block.makeCuboidShape(v1.x, v1.y, v1.z, v2.x, v2.y, v2.z);
result.setValue(VoxelShapes.or(result.getValue(), rotated));
@ -138,4 +105,17 @@ public class VoxelShaper {
return result.getValue();
}
protected static class DefaultRotationValues implements Function<Direction, Vec3d> {
//assume facing up as the default rotation
@Override
public Vec3d apply(Direction direction) {
return new Vec3d(
direction == Direction.UP ? 0 : (Direction.Plane.VERTICAL.test(direction) ? 180 : 90),
Direction.Plane.VERTICAL.test(direction) ? 0 : (int) -direction.getHorizontalAngle(),
0
);
}
}
}

View file

@ -1,6 +1,5 @@
package com.simibubi.create.foundation.utility;
import net.minecraft.block.Block;
import net.minecraft.util.Direction;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
@ -37,7 +36,8 @@ public class VoxelShapers {
public static final VoxelShaper
SHORT_CASING = VoxelShaper.forDirectional(makeCuboidShape(0, 0, 0, 16, 12, 16), Direction.UP),
LOGISTICAL_CASING_MIDDLE = VoxelShaper.forDirectional(LOGISTICAL_CASING_MIDDLE_SHAPE, Direction.UP),
LOGISTICAL_CASING_CAP = VoxelShaper.forDirectional(LOGISTICAL_CASING_CAP_SHAPE, Direction.UP)
LOGISTICAL_CASING_CAP = VoxelShaper.forDirectional(LOGISTICAL_CASING_CAP_SHAPE, Direction.UP),
HARVESTER_BASE = VoxelShaper.forHorizontal(makeCuboidShape(0, 2, 0, 16, 14, 3), Direction.SOUTH)
;

View file

@ -5,7 +5,7 @@ import java.util.List;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.block.IRenderUtilityBlock;
import com.simibubi.create.foundation.utility.SuperByteBuffer;
import com.simibubi.create.foundation.utility.VoxelShaper;
import com.simibubi.create.foundation.utility.VoxelShapers;
import com.simibubi.create.modules.contraptions.receivers.constructs.IHaveMovementBehavior;
import net.minecraft.block.Block;
@ -39,8 +39,6 @@ import net.minecraftforge.common.IPlantable;
public class HarvesterBlock extends HorizontalBlock implements IHaveMovementBehavior {
private static VoxelShaper SHAPER = VoxelShaper.forHorizontal(Block.makeCuboidShape(0, 2, 0, 16, 14, 3));
public HarvesterBlock() {
super(Properties.from(Blocks.IRON_BLOCK));
}
@ -63,7 +61,7 @@ public class HarvesterBlock extends HorizontalBlock implements IHaveMovementBeha
@Override
public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
Direction direction = state.get(HORIZONTAL_FACING);
return SHAPER.get(direction);
return VoxelShapers.HARVESTER_BASE.get(direction);
}
@Override

View file

@ -9,7 +9,7 @@ import com.simibubi.create.modules.contraptions.relays.belt.BeltBlock.Slope;
import net.minecraft.block.BlockState;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.math.Vec3i;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.math.shapes.IBooleanFunction;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
@ -77,22 +77,22 @@ public class BeltShapes {
//Vertical Shapes
private static final VoxelShaper
VERTICAL_FULL = VoxelShaper.forVerticalBelt(FLAT_FULL_PART),
VERTICAL_END = VoxelShaper.forVerticalBelt(compose(FLAT_END_PART, FLAT_FULL_PART)),
VERTICAL_START = VoxelShaper.forVerticalBelt(compose(FLAT_FULL_PART, FLAT_END_PART));
VERTICAL_FULL = VerticalBeltShaper.make(FLAT_FULL_PART),
VERTICAL_END = VerticalBeltShaper.make(compose(FLAT_END_PART, FLAT_FULL_PART)),
VERTICAL_START = VerticalBeltShaper.make(compose(FLAT_FULL_PART, FLAT_END_PART));
//Flat Shapes
private static final VoxelShaper
FLAT_FULL = VoxelShaper.forHorizontalAxis(FLAT_FULL_PART),
FLAT_END = VoxelShaper.forHorizontal(compose(FLAT_END_PART, FLAT_FULL_PART)),
FLAT_START = VoxelShaper.forHorizontal(compose(FLAT_FULL_PART, FLAT_END_PART));
FLAT_FULL = VoxelShaper.forHorizontalAxis(FLAT_FULL_PART, Direction.SOUTH),
FLAT_END = VoxelShaper.forHorizontal(compose(FLAT_END_PART, FLAT_FULL_PART), Direction.SOUTH),
FLAT_START = VoxelShaper.forHorizontal(compose(FLAT_FULL_PART, FLAT_END_PART), Direction.SOUTH);
//Sloped Shapes
private static final VoxelShaper
SLOPE_DESC = VoxelShaper.forHorizontal(SLOPE_DESC_PART),
SLOPE_ASC = VoxelShaper.forHorizontal(SLOPE_ASC_PART),
SLOPE_DESC_END = VoxelShaper.forHorizontal(compose(FLAT_END_PART, SLOPE_DESC_PART)),
SLOPE_DESC_START = VoxelShaper.forHorizontal(compose(SLOPE_DESC_PART, FLAT_END_PART)),
SLOPE_ASC_END = VoxelShaper.forHorizontal(compose(FLAT_END_PART, SLOPE_ASC_PART)),
SLOPE_ASC_START = VoxelShaper.forHorizontal(compose(SLOPE_ASC_PART, FLAT_END_PART));
SLOPE_DESC = VoxelShaper.forHorizontal(SLOPE_DESC_PART, Direction.SOUTH),
SLOPE_ASC = VoxelShaper.forHorizontal(SLOPE_ASC_PART, Direction.SOUTH),
SLOPE_DESC_END = VoxelShaper.forHorizontal(compose(FLAT_END_PART, SLOPE_DESC_PART), Direction.SOUTH),
SLOPE_DESC_START = VoxelShaper.forHorizontal(compose(SLOPE_DESC_PART, FLAT_END_PART), Direction.SOUTH),
SLOPE_ASC_END = VoxelShaper.forHorizontal(compose(FLAT_END_PART, SLOPE_ASC_PART), Direction.SOUTH),
SLOPE_ASC_START = VoxelShaper.forHorizontal(compose(SLOPE_ASC_PART, FLAT_END_PART), Direction.SOUTH);
@ -132,7 +132,7 @@ public class BeltShapes {
private static final VoxelShape CASING_HORIZONTAL = makeCuboidShape(0, 0, 0, 16, 11, 16);
//todo still need to remove these two
private static final VoxelShaper CASING_TOP_END = VoxelShaper.forHorizontal(makeCuboidShape(0, 0, 0, 16, 11, 11));
private static final VoxelShaper CASING_TOP_END = VoxelShaper.forHorizontal(makeCuboidShape(0, 0, 0, 16, 11, 11), Direction.SOUTH);
public static VoxelShape getShape(BlockState state) {
Direction facing = state.get(BeltBlock.HORIZONTAL_FACING);
@ -199,4 +199,12 @@ public class BeltShapes {
return CASING_TOP_END.get(facing.getOpposite());
}
private static class VerticalBeltShaper extends VoxelShaper {
public static VoxelShaper make(VoxelShape southBeltShape){
return forDirectionsWithRotation(southBeltShape, Direction.Plane.HORIZONTAL,//idk, this can probably be improved :S
direction -> new Vec3d(direction.getAxisDirection() == Direction.AxisDirection.NEGATIVE ? 90 : 270, -direction.getHorizontalAngle(), 0));
}
}
}

View file

@ -58,13 +58,7 @@ public class BeltTunnelBlock extends Block implements IWithTileEntity<BeltTunnel
@Override
public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
return BeltTunnelShapes.getFilledShape(state);
}
@Override
public VoxelShape getCollisionShape(BlockState state, IBlockReader worldIn, BlockPos pos,
ISelectionContext context) {
return BeltTunnelShapes.getFrameShape(state);
return BeltTunnelShapes.getShape(state);
}
@Override

View file

@ -1,54 +1,75 @@
package com.simibubi.create.modules.contraptions.relays.belt;
import static com.simibubi.create.foundation.utility.VoxelShaper.forHorizontalAxis;
import static net.minecraft.block.Block.makeCuboidShape;
import static net.minecraft.util.math.shapes.VoxelShapes.or;
import com.simibubi.create.foundation.utility.VoxelShaper;
import net.minecraft.block.BlockState;
import net.minecraft.util.Direction;
import net.minecraft.util.math.shapes.IBooleanFunction;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import static net.minecraft.block.Block.makeCuboidShape;
public class BeltTunnelShapes {
private static final VoxelShape TOP = makeCuboidShape(0, 8, 0, 16, 16, 16),
INNER = makeCuboidShape(2, -5, 2, 14, 16, 14);
private static VoxelShape block = makeCuboidShape(0, -5, 0, 16, 16, 16);
private static final VoxelShaper WALL = VoxelShaper.forHorizontal(makeCuboidShape(0, -5, 14, 16, 16, 16)),
POLES = VoxelShaper
.forHorizontal(or(makeCuboidShape(0, -5, 14, 2, 16, 16), makeCuboidShape(14, -5, 14, 16, 16, 16)));
private static VoxelShaper opening = VoxelShaper.forHorizontal( makeCuboidShape(2, -5, 14, 14, 8, 16), Direction.SOUTH);
private static VoxelShaper notch = VoxelShaper.forHorizontal(makeCuboidShape(2, 14, 14, 14, 16, 16), Direction.SOUTH);
private static final VoxelShaper STRAIGHT = forHorizontalAxis(
VoxelShapes.or(TOP, WALL.get(Direction.EAST), WALL.get(Direction.WEST))),
T_LEFT = forHorizontalAxis(VoxelShapes.or(TOP, WALL.get(Direction.EAST), POLES.get(Direction.WEST))),
T_RIGHT = forHorizontalAxis(VoxelShapes.or(TOP, POLES.get(Direction.EAST), WALL.get(Direction.WEST))),
CROSS = forHorizontalAxis(VoxelShapes.or(TOP, POLES.get(Direction.EAST), POLES.get(Direction.WEST)));
private static final VoxelShaper
STRAIGHT = VoxelShaper.forHorizontalAxis(
VoxelShapes.combineAndSimplify(
block,
VoxelShapes.or(
opening.get(Direction.SOUTH),
opening.get(Direction.NORTH),
notch.get(Direction.WEST),
notch.get(Direction.EAST)
),
IBooleanFunction.NOT_SAME),
Direction.SOUTH),
public static VoxelShape getFrameShape(BlockState state) {
VoxelShaper shaper = null;
switch (state.get(BeltTunnelBlock.SHAPE)) {
case CROSS:
shaper = CROSS;
break;
case T_LEFT:
shaper = T_LEFT;
break;
case T_RIGHT:
shaper = T_RIGHT;
break;
case STRAIGHT:
case WINDOW:
default:
shaper = STRAIGHT;
break;
}
return shaper.get(state.get(BeltTunnelBlock.HORIZONTAL_AXIS));
TEE = VoxelShaper.forHorizontal(
VoxelShapes.combineAndSimplify(
block,
VoxelShapes.or(
notch.get(Direction.SOUTH),
opening.get(Direction.NORTH),
opening.get(Direction.WEST),
opening.get(Direction.EAST)
),
IBooleanFunction.NOT_SAME),
Direction.SOUTH);
private static final VoxelShape
CROSS = VoxelShapes.combineAndSimplify(
block,
VoxelShapes.or(
opening.get(Direction.SOUTH),
opening.get(Direction.NORTH),
opening.get(Direction.WEST),
opening.get(Direction.EAST)
),
IBooleanFunction.NOT_SAME);
public static VoxelShape getShape(BlockState state) {
BeltTunnelBlock.Shape shape = state.get(BeltTunnelBlock.SHAPE);
Direction.Axis axis = state.get(BeltTunnelBlock.HORIZONTAL_AXIS);
if (shape == BeltTunnelBlock.Shape.CROSS)
return CROSS;
if (shape == BeltTunnelBlock.Shape.STRAIGHT || shape == BeltTunnelBlock.Shape.WINDOW)
return STRAIGHT.get(axis);
if (shape == BeltTunnelBlock.Shape.T_LEFT)
return TEE.get(axis == Direction.Axis.Z ? Direction.EAST : Direction.NORTH);
if (shape == BeltTunnelBlock.Shape.T_RIGHT)
return TEE.get(axis == Direction.Axis.Z ? Direction.WEST : Direction.SOUTH);
//something went wrong
return VoxelShapes.fullCube();
}
public static VoxelShape getFilledShape(BlockState state) {
return or(getFrameShape(state), INNER);
}
}