Portable Attached Blocks
- Moved Structures now pick up attached blocks such as torches, ladders or rails if the block they sit on is moved
This commit is contained in:
parent
2f5d2adc9f
commit
cb983bb017
5 changed files with 168 additions and 88 deletions
|
@ -1,19 +1,39 @@
|
|||
package com.simibubi.create.modules.contraptions.components.contraptions;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.modules.contraptions.components.actors.HarvesterBlock;
|
||||
import com.simibubi.create.modules.contraptions.components.actors.PortableStorageInterfaceBlock;
|
||||
import com.simibubi.create.modules.contraptions.components.contraptions.chassis.AbstractChassisBlock;
|
||||
|
||||
import net.minecraft.block.AbstractRailBlock;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.HorizontalFaceBlock;
|
||||
import net.minecraft.block.LadderBlock;
|
||||
import net.minecraft.block.RedstoneWallTorchBlock;
|
||||
import net.minecraft.block.TorchBlock;
|
||||
import net.minecraft.block.WallTorchBlock;
|
||||
import net.minecraft.block.material.PushReaction;
|
||||
import net.minecraft.state.properties.AttachFace;
|
||||
import net.minecraft.state.properties.BlockStateProperties;
|
||||
import net.minecraft.util.Direction;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public class BlockMovementTraits {
|
||||
|
||||
|
||||
public static boolean movementNecessary(World world, BlockPos pos) {
|
||||
BlockState state = world.getBlockState(pos);
|
||||
if (isBrittle(state))
|
||||
return true;
|
||||
if (state.getMaterial().isReplaceable())
|
||||
return false;
|
||||
if (state.getCollisionShape(world, pos).isEmpty())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean movementAllowed(World world, BlockPos pos) {
|
||||
BlockState blockState = world.getBlockState(pos);
|
||||
if (blockState.getBlock() instanceof AbstractChassisBlock)
|
||||
|
@ -26,7 +46,61 @@ public class BlockMovementTraits {
|
|||
return true;
|
||||
return blockState.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) {
|
||||
Block block = state.getBlock();
|
||||
if (state.has(BlockStateProperties.HANGING))
|
||||
return true;
|
||||
if (block instanceof LadderBlock)
|
||||
return true;
|
||||
if (block instanceof TorchBlock)
|
||||
return true;
|
||||
if (block instanceof HorizontalFaceBlock)
|
||||
return true;
|
||||
if (block instanceof AbstractRailBlock)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attached blocks will move if blocks they are attached to are moved
|
||||
*/
|
||||
public static boolean isBlockAttachedTowards(BlockState state, Direction direction) {
|
||||
Block block = state.getBlock();
|
||||
if (block instanceof LadderBlock)
|
||||
return state.get(LadderBlock.FACING) == direction.getOpposite();
|
||||
if (block instanceof WallTorchBlock)
|
||||
return state.get(WallTorchBlock.HORIZONTAL_FACING) == direction.getOpposite();
|
||||
if (block instanceof RedstoneWallTorchBlock)
|
||||
return state.get(RedstoneWallTorchBlock.FACING) == direction.getOpposite();
|
||||
if (block instanceof TorchBlock)
|
||||
return direction == Direction.DOWN;
|
||||
if (block instanceof HorizontalFaceBlock) {
|
||||
AttachFace attachFace = state.get(HorizontalFaceBlock.FACE);
|
||||
if (attachFace == AttachFace.CEILING)
|
||||
return direction == Direction.UP;
|
||||
if (attachFace == AttachFace.FLOOR)
|
||||
return direction == Direction.DOWN;
|
||||
if (attachFace == AttachFace.WALL)
|
||||
return direction.getOpposite() == state.get(HorizontalFaceBlock.HORIZONTAL_FACING);
|
||||
}
|
||||
if (state.has(BlockStateProperties.HANGING))
|
||||
return direction == (state.get(BlockStateProperties.HANGING) ? Direction.UP : Direction.DOWN);
|
||||
if (block instanceof AbstractRailBlock)
|
||||
return direction == Direction.DOWN;
|
||||
if (block instanceof HarvesterBlock)
|
||||
return direction == state.get(HarvesterBlock.HORIZONTAL_FACING).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) {
|
||||
if (AllBlocks.DRILL.typeOf(state))
|
||||
return state.get(BlockStateProperties.FACING) == facing;
|
||||
|
@ -36,9 +110,9 @@ public class BlockMovementTraits {
|
|||
return state.get(PortableStorageInterfaceBlock.FACING) == facing;
|
||||
if (AllBlocks.HARVESTER.typeOf(state))
|
||||
return state.get(BlockStateProperties.HORIZONTAL_FACING) == facing;
|
||||
return false;
|
||||
return isBrittle(state);
|
||||
}
|
||||
|
||||
|
||||
public static boolean movementIgnored(BlockState state) {
|
||||
if (AllBlocks.MECHANICAL_PISTON.typeOf(state))
|
||||
return true;
|
||||
|
|
|
@ -18,6 +18,7 @@ import org.apache.commons.lang3.tuple.Pair;
|
|||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.foundation.utility.WrappedWorld;
|
||||
|
@ -88,15 +89,12 @@ public abstract class Contraption {
|
|||
|
||||
for (BlockInfo info : blocks.values()) {
|
||||
BlockPos offsetPos = info.pos.offset(movementDirection);
|
||||
boolean hasNext = false;
|
||||
for (BlockInfo otherInfo : blocks.values()) {
|
||||
if (!otherInfo.pos.equals(offsetPos))
|
||||
continue;
|
||||
hasNext = true;
|
||||
break;
|
||||
}
|
||||
if (!hasNext)
|
||||
cachedColliders.add(info.pos);
|
||||
if (info.state.getCollisionShape(world, offsetPos).isEmpty())
|
||||
continue;
|
||||
if (blocks.containsKey(offsetPos)
|
||||
&& !blocks.get(offsetPos).state.getCollisionShape(world, offsetPos).isEmpty())
|
||||
continue;
|
||||
cachedColliders.add(info.pos);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -142,13 +140,11 @@ public abstract class Contraption {
|
|||
|
||||
if (!world.isBlockPresent(pos))
|
||||
return false;
|
||||
BlockState state = world.getBlockState(pos);
|
||||
if (state.getMaterial().isReplaceable())
|
||||
return true;
|
||||
if (state.getCollisionShape(world, pos).isEmpty())
|
||||
if (!BlockMovementTraits.movementNecessary(world, pos))
|
||||
return true;
|
||||
if (!BlockMovementTraits.movementAllowed(world, pos))
|
||||
return false;
|
||||
BlockState state = world.getBlockState(pos);
|
||||
if (isChassis(state) && !moveChassis(world, pos, forcedDirection, frontier, visited))
|
||||
return false;
|
||||
if (AllBlocks.FLEXCRATE.typeOf(state))
|
||||
|
@ -162,20 +158,21 @@ public abstract class Contraption {
|
|||
frontier.add(prevPos);
|
||||
}
|
||||
|
||||
if (state.getBlock() instanceof SlimeBlock)
|
||||
for (Direction offset : Direction.values()) {
|
||||
BlockPos offsetPos = pos.offset(offset);
|
||||
BlockState blockState = world.getBlockState(offsetPos);
|
||||
if (BlockMovementTraits.movementIgnored(blockState))
|
||||
continue;
|
||||
if (!BlockMovementTraits.movementAllowed(world, offsetPos)) {
|
||||
if (offset == forcedDirection)
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
if (!visited.contains(offsetPos))
|
||||
frontier.add(offsetPos);
|
||||
boolean isSlimeBlock = state.getBlock() instanceof SlimeBlock;
|
||||
for (Direction offset : Direction.values()) {
|
||||
BlockPos offsetPos = pos.offset(offset);
|
||||
BlockState blockState = world.getBlockState(offsetPos);
|
||||
if (BlockMovementTraits.movementIgnored(blockState))
|
||||
continue;
|
||||
if (!BlockMovementTraits.movementAllowed(world, offsetPos)) {
|
||||
if (offset == forcedDirection && isSlimeBlock)
|
||||
return false;
|
||||
continue;
|
||||
}
|
||||
if (!visited.contains(offsetPos)
|
||||
&& (isSlimeBlock || BlockMovementTraits.isBlockAttachedTowards(blockState, offset.getOpposite())))
|
||||
frontier.add(offsetPos);
|
||||
}
|
||||
|
||||
add(pos, capture(world, pos));
|
||||
return true;
|
||||
|
@ -382,12 +379,17 @@ public abstract class Contraption {
|
|||
|
||||
public void removeBlocksFromWorld(IWorld world, BlockPos offset, BiPredicate<BlockPos, BlockState> customRemoval) {
|
||||
storage.values().forEach(MountedStorage::empty);
|
||||
for (BlockInfo block : blocks.values()) {
|
||||
BlockPos add = block.pos.add(anchor).add(offset);
|
||||
if (customRemoval.test(add, block.state))
|
||||
continue;
|
||||
world.getWorld().removeTileEntity(add);
|
||||
world.setBlockState(add, Blocks.AIR.getDefaultState(), 67);
|
||||
for (boolean brittles : Iterate.trueAndFalse) {
|
||||
for (BlockInfo block : blocks.values()) {
|
||||
if (brittles != BlockMovementTraits.isBrittle(block.state))
|
||||
continue;
|
||||
|
||||
BlockPos add = block.pos.add(anchor).add(offset);
|
||||
if (customRemoval.test(add, block.state))
|
||||
continue;
|
||||
world.getWorld().removeTileEntity(add);
|
||||
world.setBlockState(add, Blocks.AIR.getDefaultState(), 67);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -397,51 +399,62 @@ public abstract class Contraption {
|
|||
|
||||
StructureTransform transform = new StructureTransform(offset, rotation);
|
||||
|
||||
for (BlockInfo block : blocks.values()) {
|
||||
BlockPos targetPos = transform.apply(block.pos);
|
||||
BlockState state = transform.apply(block.state);
|
||||
for (boolean nonBrittles : Iterate.trueAndFalse) {
|
||||
for (BlockInfo block : blocks.values()) {
|
||||
if (nonBrittles == BlockMovementTraits.isBrittle(block.state))
|
||||
continue;
|
||||
|
||||
if (customPlacement.test(targetPos, state))
|
||||
continue;
|
||||
BlockPos targetPos = transform.apply(block.pos);
|
||||
BlockState state = transform.apply(block.state);
|
||||
|
||||
for (Direction face : Direction.values())
|
||||
state = state.updatePostPlacement(face, world.getBlockState(targetPos.offset(face)), world, targetPos,
|
||||
targetPos.offset(face));
|
||||
if (AllBlocks.SAW.typeOf(state))
|
||||
state = state.with(SawBlock.RUNNING, false);
|
||||
if (customPlacement.test(targetPos, state))
|
||||
continue;
|
||||
|
||||
if (world.getBlockState(targetPos).getBlockHardness(world, targetPos) == -1)
|
||||
continue;
|
||||
world.destroyBlock(targetPos, world.getBlockState(targetPos).getCollisionShape(world, targetPos).isEmpty());
|
||||
world.setBlockState(targetPos, state, 3 | BlockFlags.IS_MOVING);
|
||||
TileEntity tileEntity = world.getTileEntity(targetPos);
|
||||
CompoundNBT tag = block.nbt;
|
||||
if (tileEntity != null && tag != null) {
|
||||
tag.putInt("x", targetPos.getX());
|
||||
tag.putInt("y", targetPos.getY());
|
||||
tag.putInt("z", targetPos.getZ());
|
||||
for (Direction face : Direction.values())
|
||||
state = state.updatePostPlacement(face, world.getBlockState(targetPos.offset(face)), world,
|
||||
targetPos, targetPos.offset(face));
|
||||
if (AllBlocks.SAW.typeOf(state))
|
||||
state = state.with(SawBlock.RUNNING, false);
|
||||
|
||||
if (tileEntity instanceof BeltTileEntity) {
|
||||
tag.remove("Length");
|
||||
tag.remove("Index");
|
||||
tag.putBoolean("DontClearAttachments", true);
|
||||
BlockState blockState = world.getBlockState(targetPos);
|
||||
if (blockState.getBlockHardness(world, targetPos) == -1)
|
||||
continue;
|
||||
if (state.getCollisionShape(world, targetPos).isEmpty()
|
||||
&& !blockState.getCollisionShape(world, targetPos).isEmpty())
|
||||
continue;
|
||||
|
||||
world.destroyBlock(targetPos, blockState.getCollisionShape(world, targetPos).isEmpty());
|
||||
world.setBlockState(targetPos, state, 3 | BlockFlags.IS_MOVING);
|
||||
TileEntity tileEntity = world.getTileEntity(targetPos);
|
||||
CompoundNBT tag = block.nbt;
|
||||
if (tileEntity != null && tag != null) {
|
||||
tag.putInt("x", targetPos.getX());
|
||||
tag.putInt("y", targetPos.getY());
|
||||
tag.putInt("z", targetPos.getZ());
|
||||
|
||||
if (tileEntity instanceof BeltTileEntity) {
|
||||
tag.remove("Length");
|
||||
tag.remove("Index");
|
||||
tag.putBoolean("DontClearAttachments", true);
|
||||
}
|
||||
|
||||
tileEntity.read(tag);
|
||||
|
||||
if (tileEntity instanceof KineticTileEntity) {
|
||||
KineticTileEntity kineticTileEntity = (KineticTileEntity) tileEntity;
|
||||
kineticTileEntity.source = null;
|
||||
kineticTileEntity.setSpeed(0);
|
||||
kineticTileEntity.network = null;
|
||||
kineticTileEntity.attachKinetics();
|
||||
}
|
||||
|
||||
if (storage.containsKey(block.pos)) {
|
||||
MountedStorage mountedStorage = storage.get(block.pos);
|
||||
if (mountedStorage.isWorking())
|
||||
mountedStorage.fill(tileEntity);
|
||||
}
|
||||
}
|
||||
|
||||
tileEntity.read(tag);
|
||||
|
||||
if (tileEntity instanceof KineticTileEntity) {
|
||||
KineticTileEntity kineticTileEntity = (KineticTileEntity) tileEntity;
|
||||
kineticTileEntity.source = null;
|
||||
kineticTileEntity.setSpeed(0);
|
||||
kineticTileEntity.network = null;
|
||||
kineticTileEntity.attachKinetics();
|
||||
}
|
||||
|
||||
if (storage.containsKey(block.pos)) {
|
||||
MountedStorage mountedStorage = storage.get(block.pos);
|
||||
if (mountedStorage.isWorking())
|
||||
mountedStorage.fill(tileEntity);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -165,9 +165,7 @@ public class ChassisTileEntity extends SmartTileEntity {
|
|||
break;
|
||||
|
||||
// Ignore replaceable Blocks and Air-like
|
||||
if (currentState.getMaterial().isReplaceable())
|
||||
break;
|
||||
if (currentState.getCollisionShape(world, current).isEmpty())
|
||||
if (!BlockMovementTraits.movementNecessary(world, current))
|
||||
break;
|
||||
if (AllBlocks.MECHANICAL_PISTON_HEAD.typeOf(currentState))
|
||||
break;
|
||||
|
@ -212,9 +210,7 @@ public class ChassisTileEntity extends SmartTileEntity {
|
|||
continue;
|
||||
if (!searchPos.withinDistance(pos, chassisRange + .5f))
|
||||
continue;
|
||||
if (searchedState.getMaterial().isReplaceable())
|
||||
continue;
|
||||
if (searchedState.getCollisionShape(world, searchPos).isEmpty())
|
||||
if (!BlockMovementTraits.movementNecessary(world, searchPos))
|
||||
continue;
|
||||
|
||||
localVisited.add(searchPos);
|
||||
|
|
|
@ -135,11 +135,9 @@ public class PistonContraption extends Contraption {
|
|||
BlockPos currentPos = pos.offset(orientation, offset + initialExtensionProgress);
|
||||
if (!world.isBlockPresent(currentPos))
|
||||
return false;
|
||||
if (!BlockMovementTraits.movementNecessary(world, currentPos))
|
||||
return true;
|
||||
BlockState state = world.getBlockState(currentPos);
|
||||
if (state.getMaterial().isReplaceable())
|
||||
return true;
|
||||
if (state.getCollisionShape(world, currentPos).isEmpty())
|
||||
return true;
|
||||
if (AllBlocks.MECHANICAL_PISTON_HEAD.typeOf(state) && state.get(FACING) == direction.getOpposite())
|
||||
return true;
|
||||
if (!BlockMovementTraits.movementAllowed(world, currentPos))
|
||||
|
|
|
@ -5,11 +5,11 @@ import com.simibubi.create.AllTileEntities;
|
|||
import com.simibubi.create.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.behaviour.CenteredSideValueBoxTransform;
|
||||
import com.simibubi.create.foundation.behaviour.ValueBoxTransform;
|
||||
import com.simibubi.create.modules.contraptions.components.contraptions.BlockMovementTraits;
|
||||
import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionCollider;
|
||||
import com.simibubi.create.modules.contraptions.components.contraptions.ContraptionEntity;
|
||||
import com.simibubi.create.modules.contraptions.components.contraptions.piston.LinearActuatorTileEntity;
|
||||
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.nbt.CompoundNBT;
|
||||
import net.minecraft.util.Direction;
|
||||
|
@ -129,8 +129,7 @@ public class PulleyTileEntity extends LinearActuatorTileEntity {
|
|||
return;
|
||||
|
||||
BlockPos posBelow = pos.down((int) (offset + getMovementSpeed()) + 1);
|
||||
BlockState stateBelow = world.getBlockState(posBelow);
|
||||
if (stateBelow.getMaterial().isReplaceable() || stateBelow.getShape(world, posBelow).isEmpty())
|
||||
if (!BlockMovementTraits.movementNecessary(world, posBelow))
|
||||
return;
|
||||
|
||||
disassemble();
|
||||
|
|
Loading…
Reference in a new issue