package net.minecraft.world.level.block; import com.mojang.serialization.MapCodec; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.BlockTags; import net.minecraft.util.RandomSource; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.ScheduledTickAccess; 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.IntegerProperty; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.Fluids; import net.minecraft.world.level.pathfinder.PathComputationType; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.VoxelShape; import org.jetbrains.annotations.Nullable; public class SeaPickleBlock extends BushBlock implements BonemealableBlock, SimpleWaterloggedBlock { public static final MapCodec CODEC = simpleCodec(SeaPickleBlock::new); public static final int MAX_PICKLES = 4; public static final IntegerProperty PICKLES = BlockStateProperties.PICKLES; public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED; protected static final VoxelShape ONE_AABB = Block.box(6.0, 0.0, 6.0, 10.0, 6.0, 10.0); protected static final VoxelShape TWO_AABB = Block.box(3.0, 0.0, 3.0, 13.0, 6.0, 13.0); protected static final VoxelShape THREE_AABB = Block.box(2.0, 0.0, 2.0, 14.0, 6.0, 14.0); protected static final VoxelShape FOUR_AABB = Block.box(2.0, 0.0, 2.0, 14.0, 7.0, 14.0); @Override public MapCodec codec() { return CODEC; } protected SeaPickleBlock(BlockBehaviour.Properties properties) { super(properties); this.registerDefaultState(this.stateDefinition.any().setValue(PICKLES, 1).setValue(WATERLOGGED, true)); } @Nullable @Override public BlockState getStateForPlacement(BlockPlaceContext context) { BlockState blockState = context.getLevel().getBlockState(context.getClickedPos()); if (blockState.is(this)) { return blockState.setValue(PICKLES, Math.min(4, (Integer)blockState.getValue(PICKLES) + 1)); } else { FluidState fluidState = context.getLevel().getFluidState(context.getClickedPos()); boolean bl = fluidState.getType() == Fluids.WATER; return super.getStateForPlacement(context).setValue(WATERLOGGED, bl); } } public static boolean isDead(BlockState state) { return !(Boolean)state.getValue(WATERLOGGED); } @Override protected boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos) { return !state.getCollisionShape(level, pos).getFaceShape(Direction.UP).isEmpty() || state.isFaceSturdy(level, pos, Direction.UP); } @Override protected boolean canSurvive(BlockState state, LevelReader level, BlockPos pos) { BlockPos blockPos = pos.below(); return this.mayPlaceOn(level.getBlockState(blockPos), level, blockPos); } @Override protected BlockState updateShape( BlockState blockState, LevelReader levelReader, ScheduledTickAccess scheduledTickAccess, BlockPos blockPos, Direction direction, BlockPos blockPos2, BlockState blockState2, RandomSource randomSource ) { if (!blockState.canSurvive(levelReader, blockPos)) { return Blocks.AIR.defaultBlockState(); } else { if ((Boolean)blockState.getValue(WATERLOGGED)) { scheduledTickAccess.scheduleTick(blockPos, Fluids.WATER, Fluids.WATER.getTickDelay(levelReader)); } return super.updateShape(blockState, levelReader, scheduledTickAccess, blockPos, direction, blockPos2, blockState2, randomSource); } } @Override protected boolean canBeReplaced(BlockState state, BlockPlaceContext useContext) { return !useContext.isSecondaryUseActive() && useContext.getItemInHand().is(this.asItem()) && state.getValue(PICKLES) < 4 ? true : super.canBeReplaced(state, useContext); } @Override protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { switch (state.getValue(PICKLES)) { case 1: default: return ONE_AABB; case 2: return TWO_AABB; case 3: return THREE_AABB; case 4: return FOUR_AABB; } } @Override protected FluidState getFluidState(BlockState state) { return state.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(state); } @Override protected void createBlockStateDefinition(StateDefinition.Builder builder) { builder.add(PICKLES, WATERLOGGED); } @Override public boolean isValidBonemealTarget(LevelReader level, BlockPos pos, BlockState state) { return !isDead(state) && level.getBlockState(pos.below()).is(BlockTags.CORAL_BLOCKS); } @Override public boolean isBonemealSuccess(Level level, RandomSource random, BlockPos pos, BlockState state) { return true; } @Override public void performBonemeal(ServerLevel level, RandomSource random, BlockPos pos, BlockState state) { int i = 5; int j = 1; int k = 2; int l = 0; int m = pos.getX() - 2; int n = 0; for (int o = 0; o < 5; o++) { for (int p = 0; p < j; p++) { int q = 2 + pos.getY() - 1; for (int r = q - 2; r < q; r++) { BlockPos blockPos = new BlockPos(m + o, r, pos.getZ() - n + p); if (blockPos != pos && random.nextInt(6) == 0 && level.getBlockState(blockPos).is(Blocks.WATER)) { BlockState blockState = level.getBlockState(blockPos.below()); if (blockState.is(BlockTags.CORAL_BLOCKS)) { level.setBlock(blockPos, Blocks.SEA_PICKLE.defaultBlockState().setValue(PICKLES, random.nextInt(4) + 1), 3); } } } } if (l < 2) { j += 2; n++; } else { j -= 2; n--; } l++; } level.setBlock(pos, state.setValue(PICKLES, 4), 2); } @Override protected boolean isPathfindable(BlockState state, PathComputationType pathComputationType) { return false; } }