/* * @file VariantSlabBlock.java * @author Stefan Wilhelm (wile) * @copyright (C) 2020 Stefan Wilhelm * @license MIT (see https://opensource.org/licenses/MIT) * * Standard half block horizontal slab characteristics class. */ package dev.zontreck.libzontreck.edlibmc; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; import net.minecraft.sounds.SoundSource; import net.minecraft.util.Mth; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.SpawnPlacements; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.item.context.BlockPlaceContext; 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.Mirror; import net.minecraft.world.level.block.Rotation; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntity; 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.EnumProperty; import net.minecraft.world.level.block.state.properties.IntegerProperty; import net.minecraft.world.level.block.state.properties.SlabType; import net.minecraft.world.level.material.Fluid; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class VariantSlabBlock extends StandardBlocks.WaterLoggable implements StandardBlocks.IStandardBlock { public static final EnumProperty TYPE = BlockStateProperties.SLAB_TYPE; public static final IntegerProperty TEXTURE_VARIANT = IntegerProperty.create("tvariant", 0, 3); protected static final VoxelShape[] AABBs = { Shapes.create(new AABB(0, 8. / 16, 0, 1, 16. / 16, 1)), // top slab Shapes.create(new AABB(0, 0. / 16, 0, 1, 8. / 16, 1)), // bottom slab Shapes.create(new AABB(0, 0. / 16, 0, 1, 16. / 16, 1)), // both slabs Shapes.create(new AABB(0, 0. / 16, 0, 1, 16. / 16, 1)) // << 2bit fill }; protected static final int[] num_slabs_contained_in_parts_ = {1, 1, 2, 2}; private static boolean with_pickup = false; public static void on_config(boolean direct_slab_pickup) { with_pickup = direct_slab_pickup; } protected boolean is_cube(BlockState state) { return state.getValue(TYPE) == SlabType.DOUBLE; } public VariantSlabBlock(long config, BlockBehaviour.Properties builder) { super(config, builder); registerDefaultState(defaultBlockState().setValue(TYPE, SlabType.BOTTOM)); } @Override public RenderTypeHint getRenderTypeHint() { return (((config & StandardBlocks.CFG_TRANSLUCENT) != 0) ? (RenderTypeHint.TRANSLUCENT) : (RenderTypeHint.CUTOUT)); } @Override @OnlyIn(Dist.CLIENT) public void appendHoverText(ItemStack stack, @Nullable BlockGetter world, List tooltip, TooltipFlag flag) { if (!Auxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true)) return; if (with_pickup && Auxiliaries.Tooltip.helpCondition()) Auxiliaries.Tooltip.addInformation("engineersdecor.tooltip.slabpickup", "engineersdecor.tooltip.slabpickup", tooltip, flag, true); } @Override @OnlyIn(Dist.CLIENT) @SuppressWarnings("deprecation") public boolean skipRendering(BlockState state, BlockState adjacentBlockState, Direction side) { return (adjacentBlockState == state) || (super.skipRendering(state, adjacentBlockState, side)); } @Override public boolean isPossibleToRespawnInThis(BlockState state) { return false; } @Override public boolean isValidSpawn(BlockState state, BlockGetter world, BlockPos pos, SpawnPlacements.Type type, @Nullable EntityType entityType) { return false; } @Override public VoxelShape getShape(BlockState state, BlockGetter source, BlockPos pos, CollisionContext selectionContext) { return AABBs[state.getValue(TYPE).ordinal() & 0x3]; } @Override public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) { return getShape(state, world, pos, selectionContext); } @Override protected void createBlockStateDefinition(StateDefinition.Builder builder) { super.createBlockStateDefinition(builder); builder.add(TYPE, TEXTURE_VARIANT); } @Override @Nullable public BlockState getStateForPlacement(BlockPlaceContext context) { BlockPos pos = context.getClickedPos(); if (context.getLevel().getBlockState(pos).getBlock() == this) return context.getLevel().getBlockState(pos).setValue(TYPE, SlabType.DOUBLE).setValue(WATERLOGGED, false); final int rnd = Mth.clamp((int) (Mth.getSeed(context.getClickedPos()) & 0x3), 0, 3); final Direction face = context.getClickedFace(); final BlockState placement_state = super.getStateForPlacement(context).setValue(TEXTURE_VARIANT, rnd); // fluid state if (face == Direction.UP) return placement_state.setValue(TYPE, SlabType.BOTTOM); if (face == Direction.DOWN) return placement_state.setValue(TYPE, SlabType.TOP); if (!face.getAxis().isHorizontal()) return placement_state; final boolean isupper = ((context.getClickLocation().y() - context.getClickedPos().getY()) > 0.5); return placement_state.setValue(TYPE, isupper ? SlabType.TOP : SlabType.BOTTOM); } @Override @SuppressWarnings("deprecation") public boolean canBeReplaced(BlockState state, BlockPlaceContext context) { if (context.getItemInHand().getItem() != this.asItem()) return false; if (!context.replacingClickedOnBlock()) return true; final Direction face = context.getClickedFace(); final SlabType type = state.getValue(TYPE); if ((face == Direction.UP) && (type == SlabType.BOTTOM)) return true; if ((face == Direction.DOWN) && (type == SlabType.TOP)) return true; if (!face.getAxis().isHorizontal()) return false; final boolean isupper = ((context.getClickLocation().y() - context.getClickedPos().getY()) > 0.5); return isupper ? (type == SlabType.BOTTOM) : (type == SlabType.TOP); } @Override @SuppressWarnings("deprecation") public BlockState rotate(BlockState state, Rotation rot) { return state; } @Override @SuppressWarnings("deprecation") public BlockState mirror(BlockState state, Mirror mirrorIn) { return state; } @Override public boolean hasDynamicDropList() { return true; } @Override public List dropList(BlockState state, Level world, BlockEntity te, boolean explosion) { return new ArrayList<>(Collections.singletonList(new ItemStack(this.asItem(), num_slabs_contained_in_parts_[state.getValue(TYPE).ordinal() & 0x3]))); } @Override @SuppressWarnings("deprecation") public void attack(BlockState state, Level world, BlockPos pos, Player player) { if ((world.isClientSide) || (!with_pickup)) return; final ItemStack stack = player.getMainHandItem(); if (stack.isEmpty() || (Block.byItem(stack.getItem()) != this)) return; if (stack.getCount() >= stack.getMaxStackSize()) return; Vec3 lv = player.getLookAngle(); Direction facing = Direction.getNearest((float) lv.x, (float) lv.y, (float) lv.z); if ((facing != Direction.UP) && (facing != Direction.DOWN)) return; if (state.getBlock() != this) return; SlabType type = state.getValue(TYPE); if (facing == Direction.DOWN) { if (type == SlabType.DOUBLE) { world.setBlock(pos, state.setValue(TYPE, SlabType.BOTTOM), 3); } else { world.removeBlock(pos, false); } } else if (facing == Direction.UP) { if (type == SlabType.DOUBLE) { world.setBlock(pos, state.setValue(TYPE, SlabType.TOP), 3); } else { world.removeBlock(pos, false); } } if (!player.isCreative()) { stack.grow(1); if (player.getInventory() != null) player.getInventory().setChanged(); } SoundType st = this.getSoundType(state, world, pos, null); world.playSound(player, pos, st.getPlaceSound(), SoundSource.BLOCKS, (st.getVolume() + 1f) / 2.5f, 0.9f * st.getPitch()); } @Override public boolean placeLiquid(LevelAccessor world, BlockPos pos, BlockState state, FluidState fluidState) { return (state.getValue(TYPE) != SlabType.DOUBLE) && super.placeLiquid(world, pos, state, fluidState); } @Override public boolean canPlaceLiquid(BlockGetter world, BlockPos pos, BlockState state, Fluid fluid) { return (state.getValue(TYPE) != SlabType.DOUBLE) && super.canPlaceLiquid(world, pos, state, fluid); } }