diff --git a/build.gradle b/build.gradle index 98d10e012..228483274 100644 --- a/build.gradle +++ b/build.gradle @@ -209,6 +209,15 @@ jar { } } +task jarJarRelease { + doLast { + tasks.jarJar { + classifier = '' + } + } + finalizedBy tasks.jarJar +} + java { withSourcesJar() withJavadocJar() diff --git a/src/main/java/com/simibubi/create/api/behaviour/BlockSpoutingBehaviour.java b/src/main/java/com/simibubi/create/api/behaviour/BlockSpoutingBehaviour.java index 1a569284d..f96d95176 100644 --- a/src/main/java/com/simibubi/create/api/behaviour/BlockSpoutingBehaviour.java +++ b/src/main/java/com/simibubi/create/api/behaviour/BlockSpoutingBehaviour.java @@ -1,6 +1,7 @@ package com.simibubi.create.api.behaviour; import java.util.HashMap; +import java.util.Map; import java.util.function.Consumer; import com.simibubi.create.Create; @@ -14,7 +15,7 @@ import net.minecraftforge.fluids.FluidStack; public abstract class BlockSpoutingBehaviour { - private static final HashMap BLOCK_SPOUTING_BEHAVIOURS = new HashMap<>(); + private static final Map BLOCK_SPOUTING_BEHAVIOURS = new HashMap<>(); public static void addCustomSpoutInteraction(ResourceLocation resourceLocation, BlockSpoutingBehaviour movementBehaviour) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/base/DirectionalAxisKineticBlock.java b/src/main/java/com/simibubi/create/content/contraptions/base/DirectionalAxisKineticBlock.java index 9de9138d8..de3f0345d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/base/DirectionalAxisKineticBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/base/DirectionalAxisKineticBlock.java @@ -1,6 +1,7 @@ package com.simibubi.create.content.contraptions.base; -import com.simibubi.create.foundation.utility.DirectionHelper; +import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.foundation.utility.Iterate; import net.minecraft.core.BlockPos; @@ -15,7 +16,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition.Builder; import net.minecraft.world.level.block.state.properties.BooleanProperty; -public abstract class DirectionalAxisKineticBlock extends DirectionalKineticBlock { +public abstract class DirectionalAxisKineticBlock extends DirectionalKineticBlock implements ITransformableBlock { public static final BooleanProperty AXIS_ALONG_FIRST_COORDINATE = BooleanProperty.create("axis_along_first"); @@ -53,7 +54,7 @@ public abstract class DirectionalAxisKineticBlock extends DirectionalKineticBloc if (faceAxis.isHorizontal()) { alongFirst = faceAxis == Axis.Z; - Direction positivePerpendicular = DirectionHelper.getPositivePerpendicular(faceAxis); + Direction positivePerpendicular = faceAxis == Axis.X ? Direction.SOUTH : Direction.EAST; boolean shaftAbove = prefersConnectionTo(world, pos, Direction.UP, true); boolean shaftBelow = prefersConnectionTo(world, pos, Direction.DOWN, true); @@ -121,6 +122,23 @@ public abstract class DirectionalAxisKineticBlock extends DirectionalKineticBloc return super.rotate(state, rot); } + @Override + public BlockState transform(BlockState state, StructureTransform transform) { + if (transform.mirror != null) { + state = mirror(state, transform.mirror); + } + + if (transform.rotationAxis == Direction.Axis.Y) { + return rotate(state, transform.rotation); + } + + Direction newFacing = transform.rotateFacing(state.getValue(FACING)); + if (transform.rotationAxis == newFacing.getAxis() && transform.rotation.ordinal() % 2 == 1) { + state = state.cycle(AXIS_ALONG_FIRST_COORDINATE); + } + return state.setValue(FACING, newFacing); + } + @Override public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) { return face.getAxis() == getRotationAxis(state); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ITransformableBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ITransformableBlock.java new file mode 100644 index 000000000..3e5fc78eb --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ITransformableBlock.java @@ -0,0 +1,7 @@ +package com.simibubi.create.content.contraptions.components.structureMovement; + +import net.minecraft.world.level.block.state.BlockState; + +public interface ITransformableBlock { + BlockState transform(BlockState state, StructureTransform transform); +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/StructureTransform.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/StructureTransform.java index 1fd7d9b89..e03b8b994 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/StructureTransform.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/StructureTransform.java @@ -4,13 +4,6 @@ import static net.minecraft.world.level.block.state.properties.BlockStatePropert import static net.minecraft.world.level.block.state.properties.BlockStateProperties.FACING; import static net.minecraft.world.level.block.state.properties.BlockStateProperties.HORIZONTAL_FACING; -import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.base.DirectionalAxisKineticBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.chassis.AbstractChassisBlock; -import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; -import com.simibubi.create.content.contraptions.relays.belt.BeltSlope; -import com.simibubi.create.foundation.utility.DirectionHelper; -import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.core.BlockPos; @@ -30,7 +23,6 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.AttachFace; import net.minecraft.world.level.block.state.properties.BellAttachType; import net.minecraft.world.level.block.state.properties.BlockStateProperties; -import net.minecraft.world.level.block.state.properties.BooleanProperty; import net.minecraft.world.level.block.state.properties.DirectionProperty; import net.minecraft.world.level.block.state.properties.EnumProperty; import net.minecraft.world.level.block.state.properties.Half; @@ -55,7 +47,7 @@ public class StructureTransform { } public StructureTransform(BlockPos offset, Axis axis, Rotation rotation, Mirror mirror) { - this(offset, rotation == Rotation.NONE ? 0 : (4 - rotation.ordinal())*90, axis, rotation, mirror); + this(offset, rotation == Rotation.NONE ? 0 : (4 - rotation.ordinal()) * 90, axis, rotation, mirror); } public StructureTransform(BlockPos offset, float xRotation, float yRotation, float zRotation) { @@ -96,7 +88,7 @@ public class StructureTransform { vec = VecHelper.rotate(vec, angle, rotationAxis); return vec; } - + public Vec3 applyWithoutOffset(Vec3 localVec) { Vec3 vec = localVec; if (mirror != null) @@ -124,16 +116,18 @@ public class StructureTransform { } /** - * Minecraft does not support blockstate rotation around axes other than y. Add - * specific cases here for blockstates, that should react to rotations around - * horizontal axes + * Vanilla does not support block state rotation around axes other than Y. Add + * specific cases here for vanilla block states so that they can react to rotations + * around horizontal axes. For Create blocks, implement ITransformableBlock. */ public BlockState apply(BlockState state) { + Block block = state.getBlock(); + if (block instanceof ITransformableBlock transformable) + return transformable.transform(state, this); + if (mirror != null) state = state.mirror(mirror); - Block block = state.getBlock(); - if (rotationAxis == Axis.Y) { if (block instanceof BellBlock) { if (state.getValue(BlockStateProperties.BELL_ATTACHMENT) == BellAttachType.DOUBLE_WALL) @@ -141,12 +135,10 @@ public class StructureTransform { return state.setValue(BellBlock.FACING, rotation.rotate(state.getValue(BellBlock.FACING))); } + return state.rotate(rotation); } - if (block instanceof AbstractChassisBlock) - return rotateChassis(state); - if (block instanceof FaceAttachedHorizontalDirectionalBlock) { DirectionProperty facingProperty = FaceAttachedHorizontalDirectionalBlock.FACING; EnumProperty faceProperty = FaceAttachedHorizontalDirectionalBlock.FACE; @@ -185,30 +177,11 @@ public class StructureTransform { return state; } - if (AllBlocks.BELT.has(state)) { - state = transformBelt(state, halfTurn); - return state; - } - if (state.hasProperty(FACING)) { - Direction newFacing = transformFacing(state.getValue(FACING)); - if (state.hasProperty(DirectionalAxisKineticBlock.AXIS_ALONG_FIRST_COORDINATE)) { - if (rotationAxis == newFacing.getAxis() && rotation.ordinal() % 2 == 1) - state = state.cycle(DirectionalAxisKineticBlock.AXIS_ALONG_FIRST_COORDINATE); - } - state = state.setValue(FACING, newFacing); - + state = state.setValue(FACING, rotateFacing(state.getValue(FACING))); } else if (state.hasProperty(AXIS)) { - state = state.setValue(AXIS, transformAxis(state.getValue(AXIS))); - + state = state.setValue(AXIS, rotateAxis(state.getValue(AXIS))); } else if (halfTurn) { - - if (state.hasProperty(FACING)) { - Direction stateFacing = state.getValue(FACING); - if (stateFacing.getAxis() == rotationAxis) - return state; - } - if (state.hasProperty(HORIZONTAL_FACING)) { Direction stateFacing = state.getValue(HORIZONTAL_FACING); if (stateFacing.getAxis() == rotationAxis) @@ -216,6 +189,7 @@ public class StructureTransform { } state = state.rotate(rotation); + if (state.hasProperty(SlabBlock.TYPE) && state.getValue(SlabBlock.TYPE) != SlabType.DOUBLE) state = state.setValue(SlabBlock.TYPE, state.getValue(SlabBlock.TYPE) == SlabType.BOTTOM ? SlabType.TOP : SlabType.BOTTOM); @@ -244,125 +218,21 @@ public class StructureTransform { return state; } - protected BlockState transformBelt(BlockState state, boolean halfTurn) { - Direction initialDirection = state.getValue(BeltBlock.HORIZONTAL_FACING); - boolean diagonal = - state.getValue(BeltBlock.SLOPE) == BeltSlope.DOWNWARD || state.getValue(BeltBlock.SLOPE) == BeltSlope.UPWARD; - - if (!diagonal) { - for (int i = 0; i < rotation.ordinal(); i++) { - Direction direction = state.getValue(BeltBlock.HORIZONTAL_FACING); - BeltSlope slope = state.getValue(BeltBlock.SLOPE); - boolean vertical = slope == BeltSlope.VERTICAL; - boolean horizontal = slope == BeltSlope.HORIZONTAL; - boolean sideways = slope == BeltSlope.SIDEWAYS; - - Direction newDirection = direction.getOpposite(); - BeltSlope newSlope = BeltSlope.VERTICAL; - - if (vertical) { - if (direction.getAxis() == rotationAxis) { - newDirection = direction.getCounterClockWise(); - newSlope = BeltSlope.SIDEWAYS; - } else { - newSlope = BeltSlope.HORIZONTAL; - newDirection = direction; - if (direction.getAxis() == Axis.Z) - newDirection = direction.getOpposite(); - } - } - - if (sideways) { - newDirection = direction; - if (direction.getAxis() == rotationAxis) - newSlope = BeltSlope.HORIZONTAL; - else - newDirection = direction.getCounterClockWise(); - } - - if (horizontal) { - newDirection = direction; - if (direction.getAxis() == rotationAxis) - newSlope = BeltSlope.SIDEWAYS; - else if (direction.getAxis() != Axis.Z) - newDirection = direction.getOpposite(); - } - - state = state.setValue(BeltBlock.HORIZONTAL_FACING, newDirection); - state = state.setValue(BeltBlock.SLOPE, newSlope); - } - - } else if (initialDirection.getAxis() != rotationAxis) { - for (int i = 0; i < rotation.ordinal(); i++) { - Direction direction = state.getValue(BeltBlock.HORIZONTAL_FACING); - Direction newDirection = direction.getOpposite(); - BeltSlope slope = state.getValue(BeltBlock.SLOPE); - boolean upward = slope == BeltSlope.UPWARD; - boolean downward = slope == BeltSlope.DOWNWARD; - - // Rotate diagonal - if (direction.getAxisDirection() == AxisDirection.POSITIVE ^ downward ^ direction.getAxis() == Axis.Z) { - state = state.setValue(BeltBlock.SLOPE, upward ? BeltSlope.DOWNWARD : BeltSlope.UPWARD); - } else { - state = state.setValue(BeltBlock.HORIZONTAL_FACING, newDirection); - } - } - - } else if (halfTurn) { - Direction direction = state.getValue(BeltBlock.HORIZONTAL_FACING); - Direction newDirection = direction.getOpposite(); - BeltSlope slope = state.getValue(BeltBlock.SLOPE); - boolean vertical = slope == BeltSlope.VERTICAL; - - if (diagonal) { - state = state.setValue(BeltBlock.SLOPE, slope == BeltSlope.UPWARD ? BeltSlope.DOWNWARD - : slope == BeltSlope.DOWNWARD ? BeltSlope.UPWARD : slope); - } else if (vertical) { - state = state.setValue(BeltBlock.HORIZONTAL_FACING, newDirection); - } - } - return state; - } - - public Axis transformAxis(Axis axisIn) { - Direction facing = Direction.get(AxisDirection.POSITIVE, axisIn); - facing = transformFacing(facing); - Axis axis = facing.getAxis(); - return axis; - } - - public Direction transformFacing(Direction facing) { + public Direction mirrorFacing(Direction facing) { if (mirror != null) - facing = mirror.mirror(facing); - for (int i = 0; i < rotation.ordinal(); i++) - facing = DirectionHelper.rotateAround(facing, rotationAxis); + return mirror.mirror(facing); return facing; } - private BlockState rotateChassis(BlockState state) { - if (rotation == Rotation.NONE) - return state; + public Axis rotateAxis(Axis axis) { + Direction facing = Direction.get(AxisDirection.POSITIVE, axis); + return rotateFacing(facing).getAxis(); + } - BlockState rotated = state.setValue(AXIS, transformAxis(state.getValue(AXIS))); - AbstractChassisBlock block = (AbstractChassisBlock) state.getBlock(); - - for (Direction face : Iterate.directions) { - BooleanProperty glueableSide = block.getGlueableSide(rotated, face); - if (glueableSide != null) - rotated = rotated.setValue(glueableSide, false); - } - - for (Direction face : Iterate.directions) { - BooleanProperty glueableSide = block.getGlueableSide(state, face); - if (glueableSide == null || !state.getValue(glueableSide)) - continue; - Direction rotatedFacing = transformFacing(face); - BooleanProperty rotatedGlueableSide = block.getGlueableSide(rotated, rotatedFacing); - if (rotatedGlueableSide != null) - rotated = rotated.setValue(rotatedGlueableSide, true); - } - - return rotated; + public Direction rotateFacing(Direction facing) { + for (int i = 0; i < rotation.ordinal(); i++) + facing = facing.getClockWise(rotationAxis); + return facing; } public static StructureTransform fromBuffer(FriendlyByteBuf buffer) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/AbstractChassisBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/AbstractChassisBlock.java index 3c1ae6875..34f6e27fb 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/AbstractChassisBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/AbstractChassisBlock.java @@ -3,6 +3,8 @@ package com.simibubi.create.content.contraptions.components.structureMovement.ch import com.simibubi.create.AllItems; import com.simibubi.create.AllSoundEvents; import com.simibubi.create.AllTileEntities; +import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; +import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlock; import com.simibubi.create.content.contraptions.wrench.IWrenchable; import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.utility.Iterate; @@ -26,7 +28,7 @@ import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.Vec3; import net.minecraftforge.common.Tags; -public abstract class AbstractChassisBlock extends RotatedPillarBlock implements IWrenchable, ITE { +public abstract class AbstractChassisBlock extends RotatedPillarBlock implements IWrenchable, ITE, ITransformableBlock { public AbstractChassisBlock(Properties properties) { super(properties); @@ -132,6 +134,44 @@ public abstract class AbstractChassisBlock extends RotatedPillarBlock implements return mirrored; } + @Override + public BlockState transform(BlockState state, StructureTransform transform) { + if (transform.mirror != null) { + state = mirror(state, transform.mirror); + } + + if (transform.rotationAxis == Direction.Axis.Y) { + return rotate(state, transform.rotation); + } + return transformInner(state, transform); + } + + protected BlockState transformInner(BlockState state, StructureTransform transform) { + if (transform.rotation == Rotation.NONE) + return state; + + BlockState rotated = state.setValue(AXIS, transform.rotateAxis(state.getValue(AXIS))); + AbstractChassisBlock block = (AbstractChassisBlock) state.getBlock(); + + for (Direction face : Iterate.directions) { + BooleanProperty glueableSide = block.getGlueableSide(rotated, face); + if (glueableSide != null) + rotated = rotated.setValue(glueableSide, false); + } + + for (Direction face : Iterate.directions) { + BooleanProperty glueableSide = block.getGlueableSide(state, face); + if (glueableSide == null || !state.getValue(glueableSide)) + continue; + Direction rotatedFacing = transform.rotateFacing(face); + BooleanProperty rotatedGlueableSide = block.getGlueableSide(rotated, rotatedFacing); + if (rotatedGlueableSide != null) + rotated = rotated.setValue(rotatedGlueableSide, true); + } + + return rotated; + } + public abstract BooleanProperty getGlueableSide(BlockState state, Direction face); protected boolean glueAllowedOnSide(BlockGetter world, BlockPos pos, BlockState state, Direction side) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftBlock.java index c7c15ce82..c375f7d4d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/advanced/sequencer/SequencedGearshiftBlock.java @@ -7,6 +7,8 @@ import com.simibubi.create.AllTileEntities; import com.simibubi.create.content.contraptions.base.HorizontalAxisKineticBlock; import com.simibubi.create.content.contraptions.base.KineticBlock; import com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.foundation.block.ITE; import com.simibubi.create.foundation.gui.ScreenOpener; @@ -35,7 +37,7 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fml.DistExecutor; -public class SequencedGearshiftBlock extends HorizontalAxisKineticBlock implements ITE { +public class SequencedGearshiftBlock extends HorizontalAxisKineticBlock implements ITE, ITransformableBlock { public static final BooleanProperty VERTICAL = BooleanProperty.create("vertical"); public static final IntegerProperty STATE = IntegerProperty.create("state", 0, 5); @@ -166,4 +168,24 @@ public class SequencedGearshiftBlock extends HorizontalAxisKineticBlock implemen .intValue(); } + @Override + public BlockState transform(BlockState state, StructureTransform transform) { + if (transform.mirror != null) { + state = mirror(state, transform.mirror); + } + + if (transform.rotationAxis == Direction.Axis.Y) { + return rotate(state, transform.rotation); + } + + if (transform.rotation.ordinal() % 2 == 1) { + if (transform.rotationAxis != state.getValue(HORIZONTAL_AXIS)) { + return state.cycle(VERTICAL); + } else if (state.getValue(VERTICAL)) { + return state.cycle(VERTICAL).cycle(HORIZONTAL_AXIS); + } + } + return state; + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltBlock.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltBlock.java index 501ed451f..8581b69ee 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/BeltBlock.java @@ -13,6 +13,8 @@ import com.simibubi.create.AllTileEntities; import com.simibubi.create.Create; import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock; import com.simibubi.create.content.contraptions.base.KineticTileEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.contraptions.processing.EmptyingByBasin; import com.simibubi.create.content.contraptions.relays.belt.BeltSlicer.Feedback; import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity.CasingType; @@ -82,7 +84,7 @@ import net.minecraftforge.common.Tags; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; -public class BeltBlock extends HorizontalKineticBlock implements ITE, ISpecialBlockItemRequirement { +public class BeltBlock extends HorizontalKineticBlock implements ITE, ISpecialBlockItemRequirement, ITransformableBlock { public static final Property SLOPE = EnumProperty.create("slope", BeltSlope.class); public static final Property PART = EnumProperty.create("part", BeltPart.class); @@ -594,6 +596,100 @@ public class BeltBlock extends HorizontalKineticBlock implements ITE, ISpecialBlockItemRequirement { + implements ICogWheel, ITE, ISpecialBlockItemRequirement, ITransformableBlock { public static final BooleanProperty TOP_SHAFT = BooleanProperty.create("top_shaft"); public static final BooleanProperty BOTTOM_SHAFT = BooleanProperty.create("bottom_shaft"); @@ -120,6 +125,16 @@ public class EncasedCogwheelBlock extends RotatedPillarKineticBlock return InteractionResult.SUCCESS; } + @Override + public BlockState getRotatedBlockState(BlockState originalState, Direction targetedFace) { + originalState = swapShaftsForRotation(originalState, Rotation.CLOCKWISE_90, targetedFace.getAxis()); + return originalState.setValue(RotatedPillarKineticBlock.AXIS, + VoxelShaper + .axisAsFace(originalState.getValue(RotatedPillarKineticBlock.AXIS)) + .getClockWise(targetedFace.getAxis()) + .getAxis()); + } + @Override public InteractionResult onSneakWrenched(BlockState state, UseOnContext context) { if (context.getLevel().isClientSide) @@ -170,6 +185,81 @@ public class EncasedCogwheelBlock extends RotatedPillarKineticBlock return state.getValue(AXIS); } + public BlockState swapShafts(BlockState state) { + boolean bottom = state.getValue(BOTTOM_SHAFT); + boolean top = state.getValue(TOP_SHAFT); + state = state.setValue(BOTTOM_SHAFT, top); + state = state.setValue(TOP_SHAFT, bottom); + return state; + } + + public BlockState swapShaftsForRotation(BlockState state, Rotation rotation, Direction.Axis rotationAxis) { + if (rotation == Rotation.NONE) { + return state; + } + + Direction.Axis axis = state.getValue(AXIS); + if (axis == rotationAxis) { + return state; + } + + if (rotation == Rotation.CLOCKWISE_180) { + return swapShafts(state); + } + + boolean clockwise = rotation == Rotation.CLOCKWISE_90; + + if (rotationAxis == Direction.Axis.X) { + if ( axis == Direction.Axis.Z && !clockwise + || axis == Direction.Axis.Y && clockwise) { + return swapShafts(state); + } + } else if (rotationAxis == Direction.Axis.Y) { + if ( axis == Direction.Axis.X && !clockwise + || axis == Direction.Axis.Z && clockwise) { + return swapShafts(state); + } + } else if (rotationAxis == Direction.Axis.Z) { + if ( axis == Direction.Axis.Y && !clockwise + || axis == Direction.Axis.X && clockwise) { + return swapShafts(state); + } + } + + return state; + } + + @Override + public BlockState mirror(BlockState state, Mirror mirror) { + Direction.Axis axis = state.getValue(AXIS); + if (axis == Direction.Axis.X && mirror == Mirror.FRONT_BACK + || axis == Direction.Axis.Z && mirror == Mirror.LEFT_RIGHT) { + return swapShafts(state); + } + return state; + } + + @Override + public BlockState rotate(BlockState state, Rotation rotation) { + state = swapShaftsForRotation(state, rotation, Direction.Axis.Y); + return super.rotate(state, rotation); + } + + @Override + public BlockState transform(BlockState state, StructureTransform transform) { + if (transform.mirror != null) { + state = mirror(state, transform.mirror); + } + + if (transform.rotationAxis == Direction.Axis.Y) { + return rotate(state, transform.rotation); + } + + state = swapShaftsForRotation(state, transform.rotation, transform.rotationAxis); + state = state.setValue(AXIS, transform.rotateAxis(state.getValue(AXIS))); + return state; + } + @Override public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { return ItemRequirement diff --git a/src/main/java/com/simibubi/create/content/contraptions/wrench/IWrenchable.java b/src/main/java/com/simibubi/create/content/contraptions/wrench/IWrenchable.java index dc2a85735..a00346689 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/wrench/IWrenchable.java +++ b/src/main/java/com/simibubi/create/content/contraptions/wrench/IWrenchable.java @@ -9,7 +9,6 @@ import com.simibubi.create.content.contraptions.base.HorizontalAxisKineticBlock; import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.RotatedPillarKineticBlock; -import com.simibubi.create.foundation.utility.DirectionHelper; import com.simibubi.create.foundation.utility.VoxelShaper; import net.minecraft.core.BlockPos; @@ -81,20 +80,20 @@ public interface IWrenchable { if (targetedFace.getAxis() == Direction.Axis.Y) { if (originalState.hasProperty(HorizontalAxisKineticBlock.HORIZONTAL_AXIS)) - return originalState.setValue(HorizontalAxisKineticBlock.HORIZONTAL_AXIS, DirectionHelper - .rotateAround(VoxelShaper.axisAsFace(originalState.getValue(HorizontalAxisKineticBlock.HORIZONTAL_AXIS)), - targetedFace.getAxis()) + return originalState.setValue(HorizontalAxisKineticBlock.HORIZONTAL_AXIS, VoxelShaper + .axisAsFace(originalState.getValue(HorizontalAxisKineticBlock.HORIZONTAL_AXIS)) + .getClockWise(targetedFace.getAxis()) .getAxis()); if (originalState.hasProperty(HorizontalKineticBlock.HORIZONTAL_FACING)) - return originalState.setValue(HorizontalKineticBlock.HORIZONTAL_FACING, DirectionHelper - .rotateAround(originalState.getValue(HorizontalKineticBlock.HORIZONTAL_FACING), targetedFace.getAxis())); + return originalState.setValue(HorizontalKineticBlock.HORIZONTAL_FACING, originalState + .getValue(HorizontalKineticBlock.HORIZONTAL_FACING).getClockWise(targetedFace.getAxis())); } if (originalState.hasProperty(RotatedPillarKineticBlock.AXIS)) return originalState.setValue(RotatedPillarKineticBlock.AXIS, - DirectionHelper - .rotateAround(VoxelShaper.axisAsFace(originalState.getValue(RotatedPillarKineticBlock.AXIS)), - targetedFace.getAxis()) + VoxelShaper + .axisAsFace(originalState.getValue(RotatedPillarKineticBlock.AXIS)) + .getClockWise(targetedFace.getAxis()) .getAxis()); if (!originalState.hasProperty(DirectionalKineticBlock.FACING)) @@ -111,7 +110,7 @@ public interface IWrenchable { } else { do { newState = newState.setValue(DirectionalKineticBlock.FACING, - DirectionHelper.rotateAround(newState.getValue(DirectionalKineticBlock.FACING), targetedFace.getAxis())); + newState.getValue(DirectionalKineticBlock.FACING).getClockWise(targetedFace.getAxis())); if (targetedFace.getAxis() == Direction.Axis.Y && newState.hasProperty(DirectionalAxisKineticBlock.AXIS_ALONG_FIRST_COORDINATE)) newState = newState.cycle(DirectionalAxisKineticBlock.AXIS_ALONG_FIRST_COORDINATE); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPoint.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPoint.java index b6fe03b8c..e4a129ded 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPoint.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmInteractionPoint.java @@ -151,7 +151,10 @@ public class ArmInteractionPoint { if (type == null) return null; BlockPos pos = NbtUtils.readBlockPos(nbt.getCompound("Pos")).offset(anchor); - ArmInteractionPoint point = type.createPoint(level, pos, level.getBlockState(pos)); + BlockState state = level.getBlockState(pos); + if (!type.canCreatePoint(level, pos, state)) + return null; + ArmInteractionPoint point = type.createPoint(level, pos, state); if (point == null) return null; point.deserialize(nbt, anchor); diff --git a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java index 8ac68137a..c50b791ee 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/mechanicalArm/ArmTileEntity.java @@ -27,6 +27,7 @@ import com.simibubi.create.foundation.utility.animation.LerpedFloat; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.core.SectionPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.Tag; @@ -39,6 +40,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.JukeboxBlock; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.ChunkSource; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; @@ -410,10 +412,45 @@ public class ArmTileEntity extends KineticTileEntity implements ITransformableTE notifyUpdate(); } + // ClientLevel#hasChunk (and consequently #isAreaLoaded) always returns true, + // so manually check the ChunkSource to avoid weird behavior on the client side + protected boolean isAreaActuallyLoaded(BlockPos center, int range) { + if (!level.isAreaLoaded(center, range)) { + return false; + } + if (level.isClientSide) { + int minY = center.getY() - range; + int maxY = center.getY() + range; + if (maxY < level.getMinBuildHeight() || minY >= level.getMaxBuildHeight()) { + return false; + } + + int minX = center.getX() - range; + int minZ = center.getZ() - range; + int maxX = center.getX() + range; + int maxZ = center.getZ() + range; + + int minChunkX = SectionPos.blockToSectionCoord(minX); + int maxChunkX = SectionPos.blockToSectionCoord(maxX); + int minChunkZ = SectionPos.blockToSectionCoord(minZ); + int maxChunkZ = SectionPos.blockToSectionCoord(maxZ); + + ChunkSource chunkSource = level.getChunkSource(); + for (int chunkX = minChunkX; chunkX <= maxChunkX; ++chunkX) { + for (int chunkZ = minChunkZ; chunkZ <= maxChunkZ; ++chunkZ) { + if (!chunkSource.hasChunk(chunkX, chunkZ)) { + return false; + } + } + } + } + return true; + } + protected void initInteractionPoints() { if (!updateInteractionPoints || interactionPointTag == null) return; - if (!level.isAreaLoaded(worldPosition, getRange() + 1)) + if (!isAreaActuallyLoaded(worldPosition, getRange() + 1)) return; inputs.clear(); outputs.clear(); @@ -506,7 +543,7 @@ public class ArmTileEntity extends KineticTileEntity implements ITransformableTE previousTarget = previousPoint == null ? ArmAngleTarget.NO_TARGET : previousPoint.getTargetAngles(worldPosition, ceiling); if (previousPoint != null) - previousBaseAngle = previousPoint.getTargetAngles(worldPosition, ceiling).baseAngle; + previousBaseAngle = previousTarget.baseAngle; ArmInteractionPoint targetedPoint = getTargetedInteractionPoint(); if (targetedPoint != null) diff --git a/src/main/java/com/simibubi/create/foundation/block/WrenchableDirectionalBlock.java b/src/main/java/com/simibubi/create/foundation/block/WrenchableDirectionalBlock.java index 2714f87dd..7d8820886 100644 --- a/src/main/java/com/simibubi/create/foundation/block/WrenchableDirectionalBlock.java +++ b/src/main/java/com/simibubi/create/foundation/block/WrenchableDirectionalBlock.java @@ -1,7 +1,6 @@ package com.simibubi.create.foundation.block; import com.simibubi.create.content.contraptions.wrench.IWrenchable; -import com.simibubi.create.foundation.utility.DirectionHelper; import net.minecraft.core.Direction; import net.minecraft.world.item.context.BlockPlaceContext; @@ -31,7 +30,7 @@ public class WrenchableDirectionalBlock extends DirectionalBlock implements IWre if (facing.getAxis() == targetedFace.getAxis()) return originalState; - Direction newFacing = DirectionHelper.rotateAround(facing, targetedFace.getAxis()); + Direction newFacing = facing.getClockWise(targetedFace.getAxis()); return originalState.setValue(FACING, newFacing); } diff --git a/src/main/java/com/simibubi/create/foundation/utility/DirectionHelper.java b/src/main/java/com/simibubi/create/foundation/utility/DirectionHelper.java deleted file mode 100644 index a5ea227fa..000000000 --- a/src/main/java/com/simibubi/create/foundation/utility/DirectionHelper.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.simibubi.create.foundation.utility; - -import static net.minecraft.core.Direction.DOWN; -import static net.minecraft.core.Direction.EAST; -import static net.minecraft.core.Direction.NORTH; -import static net.minecraft.core.Direction.SOUTH; -import static net.minecraft.core.Direction.UP; -import static net.minecraft.core.Direction.WEST; - -import net.minecraft.core.Direction; -import net.minecraft.core.Direction.Axis; - -/** - * A bunch of methods that got stripped out of Direction in 1.15 - * - * @author Mojang - */ -public class DirectionHelper { - - public static Direction rotateAround(Direction dir, Direction.Axis axis) { - switch (axis) { - case X: - if (dir != WEST && dir != EAST) { - return rotateX(dir); - } - - return dir; - case Y: - if (dir != UP && dir != DOWN) { - return dir.getClockWise(); - } - - return dir; - case Z: - if (dir != NORTH && dir != SOUTH) { - return rotateZ(dir); - } - - return dir; - default: - throw new IllegalStateException("Unable to get CW facing for axis " + axis); - } - } - - public static Direction rotateX(Direction dir) { - switch (dir) { - case NORTH: - return DOWN; - case EAST: - case WEST: - default: - throw new IllegalStateException("Unable to get X-rotated facing of " + dir); - case SOUTH: - return UP; - case UP: - return NORTH; - case DOWN: - return SOUTH; - } - } - - public static Direction rotateZ(Direction dir) { - switch (dir) { - case EAST: - return DOWN; - case SOUTH: - default: - throw new IllegalStateException("Unable to get Z-rotated facing of " + dir); - case WEST: - return UP; - case UP: - return EAST; - case DOWN: - return WEST; - } - } - - public static Direction getPositivePerpendicular(Axis horizontalAxis) { - return horizontalAxis == Axis.X ? SOUTH : EAST; - } - -} diff --git a/src/main/java/com/simibubi/create/foundation/utility/Pointing.java b/src/main/java/com/simibubi/create/foundation/utility/Pointing.java index e0829811b..9e7ebd128 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/Pointing.java +++ b/src/main/java/com/simibubi/create/foundation/utility/Pointing.java @@ -28,7 +28,7 @@ public enum Pointing implements StringRepresentable { Direction top = axis == Axis.Y ? Direction.SOUTH : Direction.UP; int rotations = direction.getAxisDirection() == AxisDirection.NEGATIVE ? 4 - ordinal() : ordinal(); for (int i = 0; i < rotations; i++) - top = DirectionHelper.rotateAround(top, axis); + top = top.getClockWise(axis); return top; }