Создание блока заполняемым водой

Чтобы сделать блоки заполняемыми водой, реализуйте интерфейс Waterloggable и переопределите некоторые методы.

public class VerticalSlabBlock extends HorizontalFacingBlock implements Waterloggable {
    [...]
}

В этом случае мы сохраняем Properties.WATERLOGGED как статическое поле в этом классе, и вы можете использовать WATERLOGGED для доступа к полю. (Как бы ненужно это ни выглядело, большинство классов блоков ванильного Майнкрафта делают это, поэтому мы делаем то же самое. Конечно, вы можете отказаться от этого и использовать Properties.WATERLOGGED каждый раз, чтобы получить к нему доступ, или просто напрямую импортировать статическое поле.) Мы должны вручную заставить блок распознавать свойство, так как это не делается для вас с помощью интерфейса Waterloggable.

    // Обратите внимание, что ''Properties'' - это net.minecraft.state.property.Properties. Не импортируйте неправильный файл.
    public static final BooleanProperty WATERLOGGED = Properties.WATERLOGGED;
 
    // Пусть значение свойства WATERLOGGED по умолчанию станет ``false``
    public VerticalSlabBlock(Settings settings) {
        super(settings);
        setDefaultState(this.stateManager.getDefaultState()
            .with(Properties.HORIZONTAL_FACING, Direction.NORTH)
            .with(WATERLOGGED, false);
    }
 
    // Заставьте блок распознавать свойство, в противном случае установка свойства приведет к ошибкам.
    @Override
    protected void appendProperties(StateManager.Builder<Block, BlockState> stateManager) {
        stateManager.add(Properties.HORIZONTAL_FACING, WATERLOGGED);
    }

Мы также должны переопределить getPlacementState, чтобы блок, помещенный в воду, изначально был заполненным.

    @Override
    public BlockState getPlacementState(ItemPlacementContext ctx) {
        return (BlockState)this.getDefaultState()
            .with(Properties.HORIZONTAL_FACING, ctx.getPlayerFacing().getOpposite())
            .with(WATERLOGGED, ctx.getWorld().getFluidState(ctx.getBlockPos()).getFluid() == Fluids.WATER);
    }

Переопределите getFluidState, чтобы при затоплении блока отображалась вода.

    @Override
    public FluidState getFluidState(BlockState state) {
        return state.get(WATERLOGGED) ? Fluids.WATER.getStill(false) : super.getFluidState(state);
    }

Переопределите getStateForNeighborUpdate, чтобы он правильно обрабатывал поток воды.

    @Override
    public BlockState getStateForNeighborUpdate(BlockState state, Direction direction, BlockState neighborState, WorldAccess world, BlockPos pos, BlockPos neighborPos) {
        if (state.get(WATERLOGGED)) {
            // Это для 1.17 и ниже: world.getFluidTickScheduler().schedule(pos, Fluids.WATER, Fluids.WATER.getTickRate(world));
            world.createAndScheduleFluidTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world));
        }
 
        return super.getStateForNeighborUpdate(state, direction, neighborState, world, pos, neighborPos);
    }

Теперь блок становится заполняемым и корректно работает с водой.