package net.minecraft.world.level.block; import com.mojang.serialization.MapCodec; import java.util.List; import java.util.function.Predicate; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.RandomSource; import net.minecraft.world.Container; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntitySelector; import net.minecraft.world.entity.vehicle.AbstractMinecart; import net.minecraft.world.entity.vehicle.MinecartCommandBlock; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; 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.block.state.properties.RailShape; import net.minecraft.world.phys.AABB; public class DetectorRailBlock extends BaseRailBlock { public static final MapCodec CODEC = simpleCodec(DetectorRailBlock::new); public static final EnumProperty SHAPE = BlockStateProperties.RAIL_SHAPE_STRAIGHT; public static final BooleanProperty POWERED = BlockStateProperties.POWERED; private static final int PRESSED_CHECK_PERIOD = 20; @Override public MapCodec codec() { return CODEC; } public DetectorRailBlock(BlockBehaviour.Properties properties) { super(true, properties); this.registerDefaultState(this.stateDefinition.any().setValue(POWERED, false).setValue(SHAPE, RailShape.NORTH_SOUTH).setValue(WATERLOGGED, false)); } @Override protected boolean isSignalSource(BlockState state) { return true; } @Override protected void entityInside(BlockState state, Level level, BlockPos pos, Entity entity) { if (!level.isClientSide) { if (!(Boolean)state.getValue(POWERED)) { this.checkPressed(level, pos, state); } } } @Override protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { if ((Boolean)state.getValue(POWERED)) { this.checkPressed(level, pos, state); } } @Override protected int getSignal(BlockState state, BlockGetter level, BlockPos pos, Direction direction) { return state.getValue(POWERED) ? 15 : 0; } @Override protected int getDirectSignal(BlockState state, BlockGetter level, BlockPos pos, Direction direction) { if (!(Boolean)state.getValue(POWERED)) { return 0; } else { return direction == Direction.UP ? 15 : 0; } } private void checkPressed(Level level, BlockPos pos, BlockState state) { if (this.canSurvive(state, level, pos)) { boolean bl = (Boolean)state.getValue(POWERED); boolean bl2 = false; List list = this.getInteractingMinecartOfType(level, pos, AbstractMinecart.class, entity -> true); if (!list.isEmpty()) { bl2 = true; } if (bl2 && !bl) { BlockState blockState = state.setValue(POWERED, true); level.setBlock(pos, blockState, 3); this.updatePowerToConnected(level, pos, blockState, true); level.updateNeighborsAt(pos, this); level.updateNeighborsAt(pos.below(), this); level.setBlocksDirty(pos, state, blockState); } if (!bl2 && bl) { BlockState blockState = state.setValue(POWERED, false); level.setBlock(pos, blockState, 3); this.updatePowerToConnected(level, pos, blockState, false); level.updateNeighborsAt(pos, this); level.updateNeighborsAt(pos.below(), this); level.setBlocksDirty(pos, state, blockState); } if (bl2) { level.scheduleTick(pos, this, 20); } level.updateNeighbourForOutputSignal(pos, this); } } protected void updatePowerToConnected(Level level, BlockPos pos, BlockState state, boolean powered) { RailState railState = new RailState(level, pos, state); for (BlockPos blockPos : railState.getConnections()) { BlockState blockState = level.getBlockState(blockPos); level.neighborChanged(blockState, blockPos, blockState.getBlock(), null, false); } } @Override protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) { if (!oldState.is(state.getBlock())) { BlockState blockState = this.updateState(state, level, pos, movedByPiston); this.checkPressed(level, pos, blockState); } } @Override public Property getShapeProperty() { return SHAPE; } @Override protected boolean hasAnalogOutputSignal(BlockState state) { return true; } @Override protected int getAnalogOutputSignal(BlockState state, Level level, BlockPos pos) { if ((Boolean)state.getValue(POWERED)) { List list = this.getInteractingMinecartOfType(level, pos, MinecartCommandBlock.class, entity -> true); if (!list.isEmpty()) { return ((MinecartCommandBlock)list.get(0)).getCommandBlock().getSuccessCount(); } List list2 = this.getInteractingMinecartOfType(level, pos, AbstractMinecart.class, EntitySelector.CONTAINER_ENTITY_SELECTOR); if (!list2.isEmpty()) { return AbstractContainerMenu.getRedstoneSignalFromContainer((Container)list2.get(0)); } } return 0; } private List getInteractingMinecartOfType(Level level, BlockPos pos, Class cartType, Predicate filter) { return level.getEntitiesOfClass(cartType, this.getSearchBB(pos), filter); } private AABB getSearchBB(BlockPos pos) { double d = 0.2; return new AABB(pos.getX() + 0.2, pos.getY(), pos.getZ() + 0.2, pos.getX() + 1 - 0.2, pos.getY() + 1 - 0.2, pos.getZ() + 1 - 0.2); } @Override protected BlockState rotate(BlockState state, Rotation rotation) { switch (rotation) { case CLOCKWISE_180: switch ((RailShape)state.getValue(SHAPE)) { case ASCENDING_EAST: return state.setValue(SHAPE, RailShape.ASCENDING_WEST); case ASCENDING_WEST: return state.setValue(SHAPE, RailShape.ASCENDING_EAST); case ASCENDING_NORTH: return state.setValue(SHAPE, RailShape.ASCENDING_SOUTH); case ASCENDING_SOUTH: return state.setValue(SHAPE, RailShape.ASCENDING_NORTH); case SOUTH_EAST: return state.setValue(SHAPE, RailShape.NORTH_WEST); case SOUTH_WEST: return state.setValue(SHAPE, RailShape.NORTH_EAST); case NORTH_WEST: return state.setValue(SHAPE, RailShape.SOUTH_EAST); case NORTH_EAST: return state.setValue(SHAPE, RailShape.SOUTH_WEST); } case COUNTERCLOCKWISE_90: switch ((RailShape)state.getValue(SHAPE)) { case ASCENDING_EAST: return state.setValue(SHAPE, RailShape.ASCENDING_NORTH); case ASCENDING_WEST: return state.setValue(SHAPE, RailShape.ASCENDING_SOUTH); case ASCENDING_NORTH: return state.setValue(SHAPE, RailShape.ASCENDING_WEST); case ASCENDING_SOUTH: return state.setValue(SHAPE, RailShape.ASCENDING_EAST); case SOUTH_EAST: return state.setValue(SHAPE, RailShape.NORTH_EAST); case SOUTH_WEST: return state.setValue(SHAPE, RailShape.SOUTH_EAST); case NORTH_WEST: return state.setValue(SHAPE, RailShape.SOUTH_WEST); case NORTH_EAST: return state.setValue(SHAPE, RailShape.NORTH_WEST); case NORTH_SOUTH: return state.setValue(SHAPE, RailShape.EAST_WEST); case EAST_WEST: return state.setValue(SHAPE, RailShape.NORTH_SOUTH); } case CLOCKWISE_90: switch ((RailShape)state.getValue(SHAPE)) { case ASCENDING_EAST: return state.setValue(SHAPE, RailShape.ASCENDING_SOUTH); case ASCENDING_WEST: return state.setValue(SHAPE, RailShape.ASCENDING_NORTH); case ASCENDING_NORTH: return state.setValue(SHAPE, RailShape.ASCENDING_EAST); case ASCENDING_SOUTH: return state.setValue(SHAPE, RailShape.ASCENDING_WEST); case SOUTH_EAST: return state.setValue(SHAPE, RailShape.SOUTH_WEST); case SOUTH_WEST: return state.setValue(SHAPE, RailShape.NORTH_WEST); case NORTH_WEST: return state.setValue(SHAPE, RailShape.NORTH_EAST); case NORTH_EAST: return state.setValue(SHAPE, RailShape.SOUTH_EAST); case NORTH_SOUTH: return state.setValue(SHAPE, RailShape.EAST_WEST); case EAST_WEST: return state.setValue(SHAPE, RailShape.NORTH_SOUTH); } default: return state; } } @Override protected BlockState mirror(BlockState state, Mirror mirror) { RailShape railShape = state.getValue(SHAPE); switch (mirror) { case LEFT_RIGHT: switch (railShape) { case ASCENDING_NORTH: return state.setValue(SHAPE, RailShape.ASCENDING_SOUTH); case ASCENDING_SOUTH: return state.setValue(SHAPE, RailShape.ASCENDING_NORTH); case SOUTH_EAST: return state.setValue(SHAPE, RailShape.NORTH_EAST); case SOUTH_WEST: return state.setValue(SHAPE, RailShape.NORTH_WEST); case NORTH_WEST: return state.setValue(SHAPE, RailShape.SOUTH_WEST); case NORTH_EAST: return state.setValue(SHAPE, RailShape.SOUTH_EAST); default: return super.mirror(state, mirror); } case FRONT_BACK: switch (railShape) { case ASCENDING_EAST: return state.setValue(SHAPE, RailShape.ASCENDING_WEST); case ASCENDING_WEST: return state.setValue(SHAPE, RailShape.ASCENDING_EAST); case ASCENDING_NORTH: case ASCENDING_SOUTH: default: break; case SOUTH_EAST: return state.setValue(SHAPE, RailShape.SOUTH_WEST); case SOUTH_WEST: return state.setValue(SHAPE, RailShape.SOUTH_EAST); case NORTH_WEST: return state.setValue(SHAPE, RailShape.NORTH_EAST); case NORTH_EAST: return state.setValue(SHAPE, RailShape.NORTH_WEST); } } return super.mirror(state, mirror); } @Override protected void createBlockStateDefinition(StateDefinition.Builder builder) { builder.add(SHAPE, POWERED, WATERLOGGED); } }