319 lines
11 KiB
Java
319 lines
11 KiB
Java
package com.simibubi.create.content.contraptions.relays.advanced;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.function.Predicate;
|
|
|
|
import com.simibubi.create.AllBlocks;
|
|
import com.simibubi.create.AllShapes;
|
|
import com.simibubi.create.AllTileEntities;
|
|
import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock;
|
|
import com.simibubi.create.content.contraptions.solver.ConnectionsBuilder;
|
|
import com.simibubi.create.foundation.block.ITE;
|
|
import com.simibubi.create.foundation.utility.Iterate;
|
|
import com.simibubi.create.foundation.utility.Lang;
|
|
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
|
|
import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
|
|
import com.simibubi.create.foundation.utility.placement.PlacementOffset;
|
|
import com.simibubi.create.foundation.utility.placement.util.PoleHelper;
|
|
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.core.Direction.Axis;
|
|
import net.minecraft.util.StringRepresentable;
|
|
import net.minecraft.world.InteractionHand;
|
|
import net.minecraft.world.InteractionResult;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.item.BlockItem;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.item.context.BlockPlaceContext;
|
|
import net.minecraft.world.item.context.UseOnContext;
|
|
import net.minecraft.world.level.BlockGetter;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.LevelAccessor;
|
|
import net.minecraft.world.level.block.Block;
|
|
import net.minecraft.world.level.block.RenderShape;
|
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
|
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.BlockStateProperties;
|
|
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
|
import net.minecraft.world.level.block.state.properties.EnumProperty;
|
|
import net.minecraft.world.level.block.state.properties.Property;
|
|
import net.minecraft.world.level.pathfinder.PathComputationType;
|
|
import net.minecraft.world.phys.BlockHitResult;
|
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
|
|
|
public class GantryShaftBlock extends DirectionalKineticBlock implements ITE<GantryShaftTileEntity> {
|
|
|
|
public static final Property<Part> PART = EnumProperty.create("part", Part.class);
|
|
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
|
|
|
|
private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper());
|
|
|
|
public enum Part implements StringRepresentable {
|
|
START, MIDDLE, END, SINGLE;
|
|
|
|
@Override
|
|
public String getSerializedName() {
|
|
return Lang.asId(name());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void createBlockStateDefinition(Builder<Block, BlockState> builder) {
|
|
super.createBlockStateDefinition(builder.add(PART, POWERED));
|
|
}
|
|
|
|
@Override
|
|
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand,
|
|
BlockHitResult ray) {
|
|
ItemStack heldItem = player.getItemInHand(hand);
|
|
|
|
IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId);
|
|
if (!placementHelper.matchesItem(heldItem))
|
|
return InteractionResult.PASS;
|
|
|
|
return placementHelper.getOffset(player, world, state, pos, ray)
|
|
.placeInWorld(world, ((BlockItem) heldItem.getItem()), player, hand, ray);
|
|
}
|
|
|
|
@Override
|
|
public VoxelShape getShape(BlockState state, BlockGetter p_220053_2_, BlockPos p_220053_3_,
|
|
CollisionContext p_220053_4_) {
|
|
return AllShapes.EIGHT_VOXEL_POLE.get(state.getValue(FACING)
|
|
.getAxis());
|
|
}
|
|
|
|
@Override
|
|
public RenderShape getRenderShape(BlockState state) {
|
|
return RenderShape.ENTITYBLOCK_ANIMATED;
|
|
}
|
|
|
|
@Override
|
|
public BlockState updateShape(BlockState state, Direction direction, BlockState neighbour, LevelAccessor world,
|
|
BlockPos pos, BlockPos neighbourPos) {
|
|
Direction facing = state.getValue(FACING);
|
|
Axis axis = facing.getAxis();
|
|
if (direction.getAxis() != axis)
|
|
return state;
|
|
boolean connect = AllBlocks.GANTRY_SHAFT.has(neighbour) && neighbour.getValue(FACING) == facing;
|
|
|
|
Part part = state.getValue(PART);
|
|
if (direction.getAxisDirection() == facing.getAxisDirection()) {
|
|
if (connect) {
|
|
if (part == Part.END)
|
|
part = Part.MIDDLE;
|
|
if (part == Part.SINGLE)
|
|
part = Part.START;
|
|
} else {
|
|
if (part == Part.MIDDLE)
|
|
part = Part.END;
|
|
if (part == Part.START)
|
|
part = Part.SINGLE;
|
|
}
|
|
} else {
|
|
if (connect) {
|
|
if (part == Part.START)
|
|
part = Part.MIDDLE;
|
|
if (part == Part.SINGLE)
|
|
part = Part.END;
|
|
} else {
|
|
if (part == Part.MIDDLE)
|
|
part = Part.START;
|
|
if (part == Part.END)
|
|
part = Part.SINGLE;
|
|
}
|
|
}
|
|
|
|
return state.setValue(PART, part);
|
|
}
|
|
|
|
public GantryShaftBlock(Properties properties) {
|
|
super(properties);
|
|
registerDefaultState(defaultBlockState().setValue(POWERED, false)
|
|
.setValue(PART, Part.SINGLE));
|
|
}
|
|
|
|
@Override
|
|
public BlockState getStateForPlacement(BlockPlaceContext context) {
|
|
BlockState state = super.getStateForPlacement(context);
|
|
BlockPos pos = context.getClickedPos();
|
|
Level world = context.getLevel();
|
|
Direction face = context.getClickedFace();
|
|
|
|
BlockState neighbour = world.getBlockState(pos.relative(state.getValue(FACING)
|
|
.getOpposite()));
|
|
|
|
BlockState clickedState =
|
|
AllBlocks.GANTRY_SHAFT.has(neighbour) ? neighbour : world.getBlockState(pos.relative(face.getOpposite()));
|
|
|
|
if (AllBlocks.GANTRY_SHAFT.has(clickedState) && clickedState.getValue(FACING)
|
|
.getAxis() == state.getValue(FACING)
|
|
.getAxis()) {
|
|
Direction facing = clickedState.getValue(FACING);
|
|
state = state.setValue(FACING, context.getPlayer() == null || !context.getPlayer()
|
|
.isShiftKeyDown() ? facing : facing.getOpposite());
|
|
}
|
|
|
|
return state.setValue(POWERED, shouldBePowered(state, world, pos));
|
|
}
|
|
|
|
@Override
|
|
public InteractionResult onWrenched(BlockState state, UseOnContext context) {
|
|
InteractionResult onWrenched = super.onWrenched(state, context);
|
|
if (onWrenched.consumesAction()) {
|
|
BlockPos pos = context.getClickedPos();
|
|
Level world = context.getLevel();
|
|
neighborChanged(world.getBlockState(pos), world, pos, state.getBlock(), pos, false);
|
|
}
|
|
return onWrenched;
|
|
}
|
|
|
|
@Override
|
|
public void onPlace(BlockState state, Level worldIn, BlockPos pos, BlockState oldState, boolean isMoving) {
|
|
super.onPlace(state, worldIn, pos, oldState, isMoving);
|
|
|
|
if (oldState.is(AllBlocks.GANTRY_SHAFT.get())) {
|
|
if (!worldIn.isClientSide()) {
|
|
Part oldPart = oldState.getValue(PART), part = state.getValue(PART);
|
|
if ((oldPart != Part.MIDDLE && part == Part.MIDDLE) || (oldPart == Part.SINGLE && part != Part.SINGLE)) {
|
|
withTileEntityDo(worldIn, pos, GantryShaftTileEntity::checkAttachedCarriageBlocks);
|
|
}
|
|
}
|
|
|
|
boolean oldPowered = oldState.getValue(POWERED), powered = state.getValue(POWERED);
|
|
if (oldPowered != powered) {
|
|
withTileEntityDo(worldIn, pos, kte -> kte.updateConnections(state));
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block p_220069_4_, BlockPos p_220069_5_,
|
|
boolean p_220069_6_) {
|
|
if (worldIn.isClientSide)
|
|
return;
|
|
boolean previouslyPowered = state.getValue(POWERED);
|
|
boolean shouldPower = worldIn.hasNeighborSignal(pos); // shouldBePowered(state, worldIn, pos);
|
|
|
|
if (!previouslyPowered && !shouldPower && shouldBePowered(state, worldIn, pos)) {
|
|
worldIn.setBlock(pos, state.setValue(POWERED, true), 3);
|
|
return;
|
|
}
|
|
|
|
if (previouslyPowered == shouldPower)
|
|
return;
|
|
|
|
// Collect affected gantry shafts
|
|
List<BlockPos> toUpdate = new ArrayList<>();
|
|
Direction facing = state.getValue(FACING);
|
|
Axis axis = facing.getAxis();
|
|
for (Direction d : Iterate.directionsInAxis(axis)) {
|
|
BlockPos currentPos = pos.relative(d);
|
|
while (true) {
|
|
if (!worldIn.isLoaded(currentPos))
|
|
break;
|
|
BlockState currentState = worldIn.getBlockState(currentPos);
|
|
if (!(currentState.getBlock() instanceof GantryShaftBlock))
|
|
break;
|
|
if (currentState.getValue(FACING) != facing)
|
|
break;
|
|
if (!shouldPower && currentState.getValue(POWERED) && worldIn.hasNeighborSignal(currentPos))
|
|
return;
|
|
if (currentState.getValue(POWERED) == shouldPower)
|
|
break;
|
|
toUpdate.add(currentPos);
|
|
currentPos = currentPos.relative(d);
|
|
}
|
|
}
|
|
|
|
toUpdate.add(pos);
|
|
for (BlockPos blockPos : toUpdate) {
|
|
BlockState blockState = worldIn.getBlockState(blockPos);
|
|
if (blockState.getBlock() instanceof GantryShaftBlock gsb) {
|
|
worldIn.setBlock(blockPos, blockState.setValue(POWERED, shouldPower), 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected boolean shouldBePowered(BlockState state, Level worldIn, BlockPos pos) {
|
|
boolean shouldPower = worldIn.hasNeighborSignal(pos);
|
|
|
|
Direction facing = state.getValue(FACING);
|
|
for (Direction d : Iterate.directionsInAxis(facing.getAxis())) {
|
|
BlockPos neighbourPos = pos.relative(d);
|
|
if (!worldIn.isLoaded(neighbourPos))
|
|
continue;
|
|
BlockState neighbourState = worldIn.getBlockState(neighbourPos);
|
|
if (!(neighbourState.getBlock() instanceof GantryShaftBlock))
|
|
continue;
|
|
if (neighbourState.getValue(FACING) != facing)
|
|
continue;
|
|
shouldPower |= neighbourState.getValue(POWERED);
|
|
}
|
|
|
|
return shouldPower;
|
|
}
|
|
|
|
@Override
|
|
public boolean hasShaftTowards(BlockState state, Direction face) {
|
|
return face.getAxis() == state.getValue(FACING).getAxis();
|
|
}
|
|
|
|
@Override
|
|
public Axis getRotationAxis(BlockState state) {
|
|
return state.getValue(FACING).getAxis();
|
|
}
|
|
|
|
@Override
|
|
public float getParticleTargetRadius() {
|
|
return .35f;
|
|
}
|
|
|
|
@Override
|
|
public float getParticleInitialRadius() {
|
|
return .25f;
|
|
}
|
|
|
|
@Override
|
|
public boolean isPathfindable(BlockState state, BlockGetter reader, BlockPos pos, PathComputationType type) {
|
|
return false;
|
|
}
|
|
|
|
public static class PlacementHelper extends PoleHelper<Direction> {
|
|
|
|
public PlacementHelper() {
|
|
super(AllBlocks.GANTRY_SHAFT::has, s -> s.getValue(FACING)
|
|
.getAxis(), FACING);
|
|
}
|
|
|
|
@Override
|
|
public Predicate<ItemStack> getItemPredicate() {
|
|
return AllBlocks.GANTRY_SHAFT::isIn;
|
|
}
|
|
|
|
@Override
|
|
public PlacementOffset getOffset(Player player, Level world, BlockState state, BlockPos pos,
|
|
BlockHitResult ray) {
|
|
PlacementOffset offset = super.getOffset(player, world, state, pos, ray);
|
|
offset.withTransform(offset.getTransform()
|
|
.andThen(s -> s.setValue(POWERED, state.getValue(POWERED))));
|
|
return offset;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public Class<GantryShaftTileEntity> getTileEntityClass() {
|
|
return GantryShaftTileEntity.class;
|
|
}
|
|
|
|
@Override
|
|
public BlockEntityType<? extends GantryShaftTileEntity> getTileEntityType() {
|
|
return AllTileEntities.GANTRY_SHAFT.get();
|
|
}
|
|
|
|
}
|