diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementTraits.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementChecks.java similarity index 67% rename from src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementTraits.java rename to src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementChecks.java index a7bfd1806..8e2a8fc7c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementTraits.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementChecks.java @@ -1,5 +1,8 @@ package com.simibubi.create.content.contraptions.components.structureMovement; +import java.util.ArrayList; +import java.util.List; + import com.simibubi.create.AllBlocks; import com.simibubi.create.AllTags.AllBlockTags; import com.simibubi.create.content.contraptions.components.actors.AttachedActorBlock; @@ -53,15 +56,118 @@ import net.minecraft.state.properties.AttachFace; import net.minecraft.state.properties.BedPart; import net.minecraft.state.properties.BellAttachment; import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.state.properties.DoubleBlockHalf; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IBlockReader; import net.minecraft.world.World; -public class BlockMovementTraits { +public class BlockMovementChecks { - public static boolean movementNecessary(BlockState state, World world, BlockPos pos) { + private static final List MOVEMENT_NECESSARY_CHECKS = new ArrayList<>(); + private static final List MOVEMENT_ALLOWED_CHECKS = new ArrayList<>(); + private static final List BRITTLE_CHECKS = new ArrayList<>(); + private static final List ATTACHED_CHECKS = new ArrayList<>(); + private static final List NOT_SUPPORTIVE_CHECKS = new ArrayList<>(); + + // Registration + // Add new checks to the front instead of the end + + public static void registerMovementNecessaryCheck(MovementNecessaryCheck check) { + MOVEMENT_NECESSARY_CHECKS.add(0, check); + } + + public static void registerMovementAllowedCheck(MovementAllowedCheck check) { + MOVEMENT_ALLOWED_CHECKS.add(0, check); + } + + public static void registerBrittleCheck(BrittleCheck check) { + BRITTLE_CHECKS.add(0, check); + } + + public static void registerAttachedCheck(AttachedCheck check) { + ATTACHED_CHECKS.add(0, check); + } + + public static void registerNotSupportiveCheck(NotSupportiveCheck check) { + NOT_SUPPORTIVE_CHECKS.add(0, check); + } + + public static void registerAllChecks(AllChecks checks) { + registerMovementNecessaryCheck(checks); + registerMovementAllowedCheck(checks); + registerBrittleCheck(checks); + registerAttachedCheck(checks); + registerNotSupportiveCheck(checks); + } + + // Actual check methods + + public static boolean isMovementNecessary(BlockState state, World world, BlockPos pos) { + for (MovementNecessaryCheck check : MOVEMENT_NECESSARY_CHECKS) { + CheckResult result = check.isMovementNecessary(state, world, pos); + if (result != CheckResult.PASS) { + return result.toBoolean(); + } + } + return isMovementNecessaryFallback(state, world, pos); + } + + public static boolean isMovementAllowed(BlockState state, World world, BlockPos pos) { + for (MovementAllowedCheck check : MOVEMENT_ALLOWED_CHECKS) { + CheckResult result = check.isMovementAllowed(state, world, pos); + if (result != CheckResult.PASS) { + return result.toBoolean(); + } + } + return isMovementAllowedFallback(state, world, pos); + } + + /** + * Brittle blocks will be collected first, as they may break when other blocks + * are removed before them + */ + public static boolean isBrittle(BlockState state) { + for (BrittleCheck check : BRITTLE_CHECKS) { + CheckResult result = check.isBrittle(state); + if (result != CheckResult.PASS) { + return result.toBoolean(); + } + } + return isBrittleFallback(state); + } + + /** + * Attached blocks will move if blocks they are attached to are moved + */ + public static boolean isBlockAttachedTowards(BlockState state, World world, BlockPos pos, + Direction direction) { + for (AttachedCheck check : ATTACHED_CHECKS) { + CheckResult result = check.isBlockAttachedTowards(state, world, pos, direction); + if (result != CheckResult.PASS) { + return result.toBoolean(); + } + } + return isBlockAttachedTowardsFallback(state, world, pos, direction); + } + + /** + * Non-Supportive blocks will not continue a chain of blocks picked up by e.g. a + * piston + */ + public static boolean isNotSupportive(BlockState state, Direction facing) { + for (NotSupportiveCheck check : NOT_SUPPORTIVE_CHECKS) { + CheckResult result = check.isNotSupportive(state, facing); + if (result != CheckResult.PASS) { + return result.toBoolean(); + } + } + return isNotSupportiveFallback(state, facing); + } + + // Fallback checks + + private static boolean isMovementNecessaryFallback(BlockState state, World world, BlockPos pos) { if (isBrittle(state)) return true; if (state.getBlock() instanceof FenceGateBlock) @@ -75,7 +181,7 @@ public class BlockMovementTraits { return true; } - public static boolean movementAllowed(BlockState state, World world, BlockPos pos) { + private static boolean isMovementAllowedFallback(BlockState state, World world, BlockPos pos) { Block block = state.getBlock(); if (block instanceof AbstractChassisBlock) return true; @@ -115,11 +221,7 @@ public class BlockMovementTraits { return state.getPushReaction() != PushReaction.BLOCK; } - /** - * Brittle blocks will be collected first, as they may break when other blocks - * are removed before them - */ - public static boolean isBrittle(BlockState state) { + private static boolean isBrittleFallback(BlockState state) { Block block = state.getBlock(); if (state.contains(BlockStateProperties.HANGING)) return true; @@ -147,10 +249,7 @@ public class BlockMovementTraits { return AllBlockTags.BRITTLE.tag.contains(block); } - /** - * Attached blocks will move if blocks they are attached to are moved - */ - public static boolean isBlockAttachedTowards(IBlockReader world, BlockPos pos, BlockState state, + private static boolean isBlockAttachedTowardsFallback(BlockState state, World world, BlockPos pos, Direction direction) { Block block = state.getBlock(); if (block instanceof LadderBlock) @@ -163,13 +262,15 @@ public class BlockMovementTraits { return direction == Direction.DOWN; if (block instanceof AbstractPressurePlateBlock) return direction == Direction.DOWN; - if (block instanceof DoorBlock) + if (block instanceof DoorBlock) { + if (state.get(DoorBlock.HALF) == DoubleBlockHalf.LOWER && direction == Direction.UP) + return true; return direction == Direction.DOWN; + } if (block instanceof BedBlock) { Direction facing = state.get(BedBlock.HORIZONTAL_FACING); - if (state.get(BedBlock.PART) == BedPart.HEAD) { + if (state.get(BedBlock.PART) == BedPart.HEAD) facing = facing.getOpposite(); - } return direction == facing; } if (block instanceof RedstoneLinkBlock) @@ -226,16 +327,12 @@ public class BlockMovementTraits { return FluidTankConnectivityHandler.isConnected(world, pos, pos.offset(direction)); if (AllBlocks.STICKER.has(state) && state.get(StickerBlock.EXTENDED)) { return direction == state.get(StickerBlock.FACING) - && !notSupportive(world.getBlockState(pos.offset(direction)), direction.getOpposite()); + && !isNotSupportive(world.getBlockState(pos.offset(direction)), direction.getOpposite()); } return false; } - /** - * Non-Supportive blocks will not continue a chain of blocks picked up by e.g. a - * piston - */ - public static boolean notSupportive(BlockState state, Direction facing) { + private static boolean isNotSupportiveFallback(BlockState state, Direction facing) { if (AllBlocks.MECHANICAL_DRILL.has(state)) return state.get(BlockStateProperties.FACING) == facing; if (AllBlocks.MECHANICAL_BEARING.has(state)) @@ -266,4 +363,58 @@ public class BlockMovementTraits { return isBrittle(state); } + // Check classes + + public static interface MovementNecessaryCheck { + public CheckResult isMovementNecessary(BlockState state, World world, BlockPos pos); + } + + public static interface MovementAllowedCheck { + public CheckResult isMovementAllowed(BlockState state, World world, BlockPos pos); + } + + public static interface BrittleCheck { + /** + * Brittle blocks will be collected first, as they may break when other blocks + * are removed before them + */ + public CheckResult isBrittle(BlockState state); + } + + public static interface AttachedCheck { + /** + * Attached blocks will move if blocks they are attached to are moved + */ + public CheckResult isBlockAttachedTowards(BlockState state, World world, BlockPos pos, Direction direction); + } + + public static interface NotSupportiveCheck { + /** + * Non-Supportive blocks will not continue a chain of blocks picked up by e.g. a + * piston + */ + public CheckResult isNotSupportive(BlockState state, Direction direction); + } + + public static interface AllChecks extends MovementNecessaryCheck, MovementAllowedCheck, BrittleCheck, AttachedCheck, NotSupportiveCheck { + } + + public static enum CheckResult { + SUCCESS, + FAIL, + PASS; + + public Boolean toBoolean() { + return this == PASS ? null : (this == SUCCESS ? true : false); + } + + public static CheckResult of(boolean b) { + return b ? SUCCESS : FAIL; + } + + public static CheckResult of(Boolean b) { + return b == null ? PASS : (b ? SUCCESS : FAIL); + } + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java index 9ab82f1dc..32f9a2a34 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java @@ -73,7 +73,6 @@ import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.ChestBlock; -import net.minecraft.block.DoorBlock; import net.minecraft.block.IWaterLoggable; import net.minecraft.block.PressurePlateBlock; import net.minecraft.block.material.PushReaction; @@ -87,7 +86,6 @@ import net.minecraft.nbt.ListNBT; import net.minecraft.nbt.NBTUtil; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.ChestType; -import net.minecraft.state.properties.DoubleBlockHalf; import net.minecraft.state.properties.PistonType; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; @@ -212,7 +210,7 @@ public abstract class Contraption { if (bounds == null) bounds = new AxisAlignedBB(BlockPos.ZERO); - if (!BlockMovementTraits.isBrittle(world.getBlockState(pos))) + if (!BlockMovementChecks.isBrittle(world.getBlockState(pos))) frontier.add(pos); if (!addToInitialFrontier(world, pos, forcedDirection, frontier)) return false; @@ -312,7 +310,7 @@ public abstract class Contraption { if (isAnchoringBlockAt(pos)) return true; BlockState state = world.getBlockState(pos); - if (!BlockMovementTraits.movementNecessary(state, world, pos)) + if (!BlockMovementChecks.isMovementNecessary(state, world, pos)) return true; if (!movementAllowed(state, world, pos)) throw AssemblyException.unmovableBlock(pos, state); @@ -336,7 +334,7 @@ public abstract class Contraption { Direction offset = state.get(StickerBlock.FACING); BlockPos attached = pos.offset(offset); if (!visited.contains(attached) - && !BlockMovementTraits.notSupportive(world.getBlockState(attached), offset.getOpposite())) + && !BlockMovementChecks.isNotSupportive(world.getBlockState(attached), offset.getOpposite())) frontier.add(attached); } @@ -365,13 +363,6 @@ public abstract class Contraption { if (isPistonHead(state)) movePistonHead(world, pos, frontier, visited, state); - // Doors try to stay whole - if (state.getBlock() instanceof DoorBlock) { - BlockPos otherPartPos = pos.up(state.get(DoorBlock.HALF) == DoubleBlockHalf.LOWER ? 1 : -1); - if (!visited.contains(otherPartPos)) - frontier.add(otherPartPos); - } - // Cart assemblers attach themselves BlockPos posDown = pos.down(); BlockState stateBelow = world.getBlockState(posDown); @@ -395,24 +386,24 @@ public abstract class Contraption { boolean wasVisited = visited.contains(offsetPos); boolean faceHasGlue = superglue.containsKey(offset); boolean blockAttachedTowardsFace = - BlockMovementTraits.isBlockAttachedTowards(world, offsetPos, blockState, offset.getOpposite()); - boolean brittle = BlockMovementTraits.isBrittle(blockState); + BlockMovementChecks.isBlockAttachedTowards(blockState, world, offsetPos, offset.getOpposite()); + boolean brittle = BlockMovementChecks.isBrittle(blockState); boolean canStick = !brittle && state.canStickTo(blockState) && blockState.canStickTo(state); if (canStick) { if (state.getPushReaction() == PushReaction.PUSH_ONLY || blockState.getPushReaction() == PushReaction.PUSH_ONLY) { canStick = false; } - if (BlockMovementTraits.notSupportive(state, offset)) { + if (BlockMovementChecks.isNotSupportive(state, offset)) { canStick = false; } - if (BlockMovementTraits.notSupportive(blockState, offset.getOpposite())) { + if (BlockMovementChecks.isNotSupportive(blockState, offset.getOpposite())) { canStick = false; } } if (!wasVisited && (canStick || blockAttachedTowardsFace || faceHasGlue - || (offset == forcedDirection && !BlockMovementTraits.notSupportive(state, forcedDirection)))) + || (offset == forcedDirection && !BlockMovementChecks.isNotSupportive(state, forcedDirection)))) frontier.add(offsetPos); if (faceHasGlue) addGlue(superglue.get(offset)); @@ -674,7 +665,7 @@ public abstract class Contraption { } protected boolean movementAllowed(BlockState state, World world, BlockPos pos) { - return BlockMovementTraits.movementAllowed(state, world, pos); + return BlockMovementChecks.isMovementAllowed(state, world, pos); } protected boolean isAnchoringBlockAt(BlockPos pos) { @@ -944,7 +935,7 @@ public abstract class Contraption { for (Iterator iterator = blocks.values() .iterator(); iterator.hasNext();) { BlockInfo block = iterator.next(); - if (brittles != BlockMovementTraits.isBrittle(block.state)) + if (brittles != BlockMovementChecks.isBrittle(block.state)) continue; BlockPos add = block.pos.add(anchor) @@ -981,7 +972,7 @@ public abstract class Contraption { public void addBlocksToWorld(World world, StructureTransform transform) { for (boolean nonBrittles : Iterate.trueAndFalse) { for (BlockInfo block : blocks.values()) { - if (nonBrittles == BlockMovementTraits.isBrittle(block.state)) + if (nonBrittles == BlockMovementChecks.isBrittle(block.state)) continue; BlockPos targetPos = transform.apply(block.pos); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/ChassisTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/ChassisTileEntity.java index 0c21d2b83..51e17c7fc 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/ChassisTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/chassis/ChassisTileEntity.java @@ -11,7 +11,7 @@ import java.util.Queue; import java.util.Set; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementTraits; +import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementChecks; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; @@ -165,14 +165,14 @@ public class ChassisTileEntity extends SmartTileEntity { break; // Ignore replaceable Blocks and Air-like - if (!BlockMovementTraits.movementNecessary(currentState, world, current)) + if (!BlockMovementChecks.isMovementNecessary(currentState, world, current)) break; - if (BlockMovementTraits.isBrittle(currentState)) + if (BlockMovementChecks.isBrittle(currentState)) break; positions.add(current); - if (BlockMovementTraits.notSupportive(currentState, facing)) + if (BlockMovementChecks.isNotSupportive(currentState, facing)) break; } } @@ -206,9 +206,9 @@ public class ChassisTileEntity extends SmartTileEntity { continue; if (!searchPos.withinDistance(pos, chassisRange + .5f)) continue; - if (!BlockMovementTraits.movementNecessary(searchedState, world, searchPos)) + if (!BlockMovementChecks.isMovementNecessary(searchedState, world, searchPos)) continue; - if (BlockMovementTraits.isBrittle(searchedState)) + if (BlockMovementChecks.isBrittle(searchedState)) continue; localVisited.add(searchPos); @@ -220,7 +220,7 @@ public class ChassisTileEntity extends SmartTileEntity { continue; if (searchPos.equals(pos) && offset != facing) continue; - if (BlockMovementTraits.notSupportive(searchedState, offset)) + if (BlockMovementChecks.isNotSupportive(searchedState, offset)) continue; localFrontier.add(searchPos.offset(offset)); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java index 5a7957c92..a66c769ba 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/glue/SuperGlueEntity.java @@ -9,7 +9,7 @@ import com.simibubi.create.AllEntityTypes; import com.simibubi.create.AllItems; import com.simibubi.create.AllSoundEvents; import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock; -import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementTraits; +import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementChecks; import com.simibubi.create.content.contraptions.components.structureMovement.bearing.BearingBlock; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.AbstractChassisBlock; import com.simibubi.create.content.schematics.ISpecialEntityItemRequirement; @@ -195,11 +195,11 @@ public class SuperGlueEntity extends Entity implements IEntityAdditionalSpawnDat public static boolean isValidFace(World world, BlockPos pos, Direction direction) { BlockState state = world.getBlockState(pos); - if (BlockMovementTraits.isBlockAttachedTowards(world, pos, state, direction)) + if (BlockMovementChecks.isBlockAttachedTowards(state, world, pos, direction)) return true; - if (!BlockMovementTraits.movementNecessary(state, world, pos)) + if (!BlockMovementChecks.isMovementNecessary(state, world, pos)) return false; - if (BlockMovementTraits.notSupportive(state, direction)) + if (BlockMovementChecks.isNotSupportive(state, direction)) return false; return true; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java index 7c1ba23b0..b8c33f45b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java @@ -15,7 +15,7 @@ import java.util.Queue; import org.apache.commons.lang3.tuple.Pair; import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementTraits; +import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementChecks; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; import com.simibubi.create.content.contraptions.components.structureMovement.TranslatingContraption; @@ -169,13 +169,13 @@ public class PistonContraption extends TranslatingContraption { if (!world.isBlockPresent(currentPos)) throw AssemblyException.unloadedChunk(currentPos); BlockState state = world.getBlockState(currentPos); - if (!BlockMovementTraits.movementNecessary(state, world, currentPos)) + if (!BlockMovementChecks.isMovementNecessary(state, world, currentPos)) return true; - if (BlockMovementTraits.isBrittle(state) && !(state.getBlock() instanceof CarpetBlock)) + if (BlockMovementChecks.isBrittle(state) && !(state.getBlock() instanceof CarpetBlock)) return true; if (isPistonHead(state) && state.get(FACING) == direction.getOpposite()) return true; - if (!BlockMovementTraits.movementAllowed(state, world, currentPos)) + if (!BlockMovementChecks.isMovementAllowed(state, world, currentPos)) if (retracting) return true; else @@ -183,7 +183,7 @@ public class PistonContraption extends TranslatingContraption { if (retracting && state.getPushReaction() == PushReaction.PUSH_ONLY) return true; frontier.add(currentPos); - if (BlockMovementTraits.notSupportive(state, orientation)) + if (BlockMovementChecks.isNotSupportive(state, orientation)) return true; } return true; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java index 075d08335..ec522e422 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java @@ -2,7 +2,7 @@ package com.simibubi.create.content.contraptions.components.structureMovement.pu import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; -import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementTraits; +import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementChecks; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionCollider; import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.piston.LinearActuatorTileEntity; @@ -186,9 +186,9 @@ public class PulleyTileEntity extends LinearActuatorTileEntity { BlockPos posBelow = pos.down((int) (offset + getMovementSpeed()) + 1); BlockState state = world.getBlockState(posBelow); - if (!BlockMovementTraits.movementNecessary(state, world, posBelow)) + if (!BlockMovementChecks.isMovementNecessary(state, world, posBelow)) return; - if (BlockMovementTraits.isBrittle(state)) + if (BlockMovementChecks.isBrittle(state)) return; disassemble();