Adopt and update functions from an abandoned library

This commit is contained in:
Zontreck 2024-02-27 16:06:12 -07:00
parent d9113f357c
commit 5214d31d21
24 changed files with 6615 additions and 1 deletions

View file

@ -0,0 +1,698 @@
/*
* @file StandardBlocks.java
* @author Stefan Wilhelm (wile)
* @copyright (C) 2020 Stefan Wilhelm
* @license MIT (see https://opensource.org/licenses/MIT)
*
* Common functionality class for decor blocks.
*/
package dev.zontreck.libzontreck.edlibmc;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.SpawnPlacements;
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.SimpleWaterloggedBlock;
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.BooleanProperty;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.level.material.PushReaction;
import net.minecraft.world.level.pathfinder.PathComputationType;
import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.level.storage.loot.LootParams;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.shapes.BooleanOp;
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.*;
import java.util.function.Function;
import java.util.function.Supplier;
@SuppressWarnings("deprecation")
public class StandardBlocks {
public static final long CFG_DEFAULT = 0x0000000000000000L; // no special config
public static final long CFG_CUTOUT = 0x0000000000000001L; // cutout rendering
public static final long CFG_MIPPED = 0x0000000000000002L; // cutout mipped rendering
public static final long CFG_TRANSLUCENT = 0x0000000000000004L; // indicates a block/pane is glass like (transparent, etc)
public static final long CFG_WATERLOGGABLE = 0x0000000000000008L; // The derived block extends IWaterLoggable
public static final long CFG_HORIZIONTAL = 0x0000000000000010L; // horizontal block, affects bounding box calculation at construction time and placement
public static final long CFG_LOOK_PLACEMENT = 0x0000000000000020L; // placed in direction the player is looking when placing.
public static final long CFG_FACING_PLACEMENT = 0x0000000000000040L; // placed on the facing the player has clicked.
public static final long CFG_OPPOSITE_PLACEMENT = 0x0000000000000080L; // placed placed in the opposite direction of the face the player clicked.
public static final long CFG_FLIP_PLACEMENT_IF_SAME = 0x0000000000000100L; // placement direction flipped if an instance of the same class was clicked
public static final long CFG_FLIP_PLACEMENT_SHIFTCLICK = 0x0000000000000200L; // placement direction flipped if player is sneaking
public static final long CFG_STRICT_CONNECTIONS = 0x0000000000000400L; // blocks do not connect to similar blocks around (implementation details may vary a bit)
public static final long CFG_AI_PASSABLE = 0x0000000000000800L; // does not block movement path for AI, needed for non-opaque blocks with collision shapes not thin at the bottom or one side.
public interface IStandardBlock {
default long config() {
return 0;
}
default boolean hasDynamicDropList() {
return false;
}
default List<ItemStack> dropList(BlockState state, Level world, @Nullable BlockEntity te, boolean explosion) {
return Collections.singletonList((!world.isClientSide()) ? (new ItemStack(state.getBlock().asItem())) : (ItemStack.EMPTY));
}
enum RenderTypeHint {SOLID, CUTOUT, CUTOUT_MIPPED, TRANSLUCENT, TRANSLUCENT_NO_CRUMBLING}
default RenderTypeHint getRenderTypeHint() {
return getRenderTypeHint(config());
}
default RenderTypeHint getRenderTypeHint(long config) {
if ((config & CFG_CUTOUT) != 0) return RenderTypeHint.CUTOUT;
if ((config & CFG_MIPPED) != 0) return RenderTypeHint.CUTOUT_MIPPED;
if ((config & CFG_TRANSLUCENT) != 0) return RenderTypeHint.TRANSLUCENT;
return RenderTypeHint.SOLID;
}
}
public static class BaseBlock extends Block implements IStandardBlock, SimpleWaterloggedBlock {
public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
public final long config;
public BaseBlock(long conf, BlockBehaviour.Properties properties) {
super(properties);
config = conf;
BlockState state = getStateDefinition().any();
if ((conf & CFG_WATERLOGGABLE) != 0) state = state.setValue(WATERLOGGED, false);
registerDefaultState(state);
}
@Override
public long config() {
return config;
}
@Override
@OnlyIn(Dist.CLIENT)
public void appendHoverText(ItemStack stack, @Nullable BlockGetter world, List<Component> tooltip, TooltipFlag flag) {
Auxiliaries.Tooltip.addInformation(stack, world, tooltip, flag, true);
}
@Override
public RenderTypeHint getRenderTypeHint() {
return getRenderTypeHint(config);
}
@Override
@SuppressWarnings("deprecation")
public boolean isPathfindable(BlockState state, BlockGetter world, BlockPos pos, PathComputationType type) {
return ((config & CFG_AI_PASSABLE) != 0) && (super.isPathfindable(state, world, pos, type));
}
public boolean hasSignalConnector(BlockState state, BlockGetter world, BlockPos pos, @Nullable Direction side) {
return state.isSignalSource();
}
@Override
@SuppressWarnings("deprecation")
public void onRemove(BlockState state, Level world, BlockPos pos, BlockState newState, boolean isMoving) {
final boolean rsup = (state.hasBlockEntity() && (state.getBlock() != newState.getBlock()));
super.onRemove(state, world, pos, newState, isMoving);
if (rsup) world.updateNeighbourForOutputSignal(pos, this);
}
@Override
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos) {
return (((config & CFG_WATERLOGGABLE) == 0) || (!state.getValue(WATERLOGGED))) && super.propagatesSkylightDown(state, reader, pos);
}
@Override
@SuppressWarnings("deprecation")
public FluidState getFluidState(BlockState state) {
return (((config & CFG_WATERLOGGABLE) != 0) && state.getValue(WATERLOGGED)) ? Fluids.WATER.getSource(false) : super.getFluidState(state);
}
@Override
@SuppressWarnings("deprecation")
public BlockState updateShape(BlockState state, Direction facing, BlockState facingState, LevelAccessor world, BlockPos pos, BlockPos facingPos) {
if (((config & CFG_WATERLOGGABLE) != 0) && (state.getValue(WATERLOGGED)))
world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world));
return state;
}
@Override // SimpleWaterloggedBlock
public boolean canPlaceLiquid(BlockGetter world, BlockPos pos, BlockState state, Fluid fluid) {
return ((config & CFG_WATERLOGGABLE) != 0) && SimpleWaterloggedBlock.super.canPlaceLiquid(world, pos, state, fluid);
}
@Override // SimpleWaterloggedBlock
public boolean placeLiquid(LevelAccessor world, BlockPos pos, BlockState state, FluidState fluidState) {
return ((config & CFG_WATERLOGGABLE) != 0) && SimpleWaterloggedBlock.super.placeLiquid(world, pos, state, fluidState);
}
@Override // SimpleWaterloggedBlock
public ItemStack pickupBlock(LevelAccessor world, BlockPos pos, BlockState state) {
return ((config & CFG_WATERLOGGABLE) != 0) ? (SimpleWaterloggedBlock.super.pickupBlock(world, pos, state)) : (ItemStack.EMPTY);
}
@Override // SimpleWaterloggedBlock
public Optional<SoundEvent> getPickupSound() {
return ((config & CFG_WATERLOGGABLE) != 0) ? (SimpleWaterloggedBlock.super.getPickupSound()) : Optional.empty();
}
}
public static class Cutout extends BaseBlock implements IStandardBlock {
private final VoxelShape vshape;
public Cutout(long conf, BlockBehaviour.Properties properties) {
this(conf, properties, Auxiliaries.getPixeledAABB(0, 0, 0, 16, 16, 16));
}
public Cutout(long conf, BlockBehaviour.Properties properties, AABB aabb) {
this(conf, properties, Shapes.create(aabb));
}
public Cutout(long conf, BlockBehaviour.Properties properties, AABB[] aabbs) {
this(conf, properties, Arrays.stream(aabbs).map(Shapes::create).reduce(Shapes.empty(), (shape, aabb) -> Shapes.joinUnoptimized(shape, aabb, BooleanOp.OR)));
}
public Cutout(long conf, BlockBehaviour.Properties properties, VoxelShape voxel_shape) {
super(conf, properties);
vshape = voxel_shape;
}
@Override
@SuppressWarnings("deprecation")
public VoxelShape getShape(BlockState state, BlockGetter source, BlockPos pos, CollisionContext selectionContext) {
return vshape;
}
@Override
@SuppressWarnings("deprecation")
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
return vshape;
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockState state = super.getStateForPlacement(context);
if ((config & CFG_WATERLOGGABLE) != 0) {
FluidState fs = context.getLevel().getFluidState(context.getClickedPos());
state = state.setValue(WATERLOGGED, fs.getType() == Fluids.WATER);
}
return state;
}
@Override
public boolean isPossibleToRespawnInThis(BlockState p_279289_) {
return false;
}
@Override
@SuppressWarnings("deprecation")
public PushReaction getPistonPushReaction(BlockState state) {
return PushReaction.NORMAL;
}
@Override
public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos) {
if ((config & CFG_WATERLOGGABLE) != 0) {
if (state.getValue(WATERLOGGED)) return false;
}
return super.propagatesSkylightDown(state, reader, pos);
}
@Override
@SuppressWarnings("deprecation")
public FluidState getFluidState(BlockState state) {
if ((config & CFG_WATERLOGGABLE) != 0) {
return state.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(state);
}
return super.getFluidState(state);
}
@Override
@SuppressWarnings("deprecation")
public BlockState updateShape(BlockState state, Direction facing, BlockState facingState, LevelAccessor world, BlockPos pos, BlockPos facingPos) {
if ((config & CFG_WATERLOGGABLE) != 0) {
if (state.getValue(WATERLOGGED))
world.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickDelay(world));
}
return state;
}
}
public static class WaterLoggable extends Cutout implements IStandardBlock {
public WaterLoggable(long config, BlockBehaviour.Properties properties) {
super(config | CFG_WATERLOGGABLE, properties);
}
public WaterLoggable(long config, BlockBehaviour.Properties properties, AABB aabb) {
super(config | CFG_WATERLOGGABLE, properties, aabb);
}
public WaterLoggable(long config, BlockBehaviour.Properties properties, VoxelShape voxel_shape) {
super(config | CFG_WATERLOGGABLE, properties, voxel_shape);
}
public WaterLoggable(long config, BlockBehaviour.Properties properties, AABB[] aabbs) {
super(config | CFG_WATERLOGGABLE, properties, aabbs);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(WATERLOGGED);
}
}
public static class Directed extends Cutout implements IStandardBlock {
public static final DirectionProperty FACING = BlockStateProperties.FACING;
protected final Map<BlockState, VoxelShape> vshapes;
public Directed(long config, BlockBehaviour.Properties properties, final Function<List<BlockState>, Map<BlockState, VoxelShape>> shape_supplier) {
super(config, properties);
registerDefaultState(super.defaultBlockState().setValue(FACING, Direction.UP));
vshapes = shape_supplier.apply(getStateDefinition().getPossibleStates());
}
public Directed(long config, BlockBehaviour.Properties properties, final Supplier<ArrayList<VoxelShape>> shape_supplier) {
this(config, properties, (states) -> {
final Map<BlockState, VoxelShape> vshapes = new HashMap<>();
final ArrayList<VoxelShape> indexed_shapes = shape_supplier.get();
for (BlockState state : states)
vshapes.put(state, indexed_shapes.get(state.getValue(FACING).get3DDataValue()));
return vshapes;
});
}
public Directed(long config, BlockBehaviour.Properties properties, final AABB[] unrotatedAABBs) {
this(config, properties, (states) -> {
final boolean is_horizontal = ((config & CFG_HORIZIONTAL) != 0);
Map<BlockState, VoxelShape> vshapes = new HashMap<>();
for (BlockState state : states) {
vshapes.put(state, Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(unrotatedAABBs, state.getValue(FACING), is_horizontal)));
}
return vshapes;
});
}
public Directed(long config, BlockBehaviour.Properties properties, final AABB unrotatedAABB) {
this(config, properties, new AABB[]{unrotatedAABB});
}
@Override
public boolean isPossibleToRespawnInThis(BlockState p_279289_) {
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 vshapes.get(state);
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
return getShape(state, world, pos, selectionContext);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(FACING);
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockState state = super.getStateForPlacement(context);
if (state == null) return null;
Direction facing = context.getClickedFace();
if ((config & (CFG_HORIZIONTAL | CFG_LOOK_PLACEMENT)) == (CFG_HORIZIONTAL | CFG_LOOK_PLACEMENT)) {
// horizontal placement in direction the player is looking
facing = context.getHorizontalDirection();
} else if ((config & (CFG_HORIZIONTAL | CFG_LOOK_PLACEMENT)) == (CFG_HORIZIONTAL)) {
// horizontal placement on a face
if (((facing == Direction.UP) || (facing == Direction.DOWN))) return null;
} else if ((config & CFG_LOOK_PLACEMENT) != 0) {
// placement in direction the player is looking, with up and down
facing = context.getNearestLookingDirection();
}
if ((config & CFG_OPPOSITE_PLACEMENT) != 0) facing = facing.getOpposite();
if (((config & CFG_FLIP_PLACEMENT_SHIFTCLICK) != 0) && (context.getPlayer() != null) && (context.getPlayer().isShiftKeyDown()))
facing = facing.getOpposite();
return state.setValue(FACING, facing);
}
}
public static class AxisAligned extends Cutout implements IStandardBlock {
public static final EnumProperty<Direction.Axis> AXIS = BlockStateProperties.AXIS;
protected final ArrayList<VoxelShape> vshapes;
public AxisAligned(long config, BlockBehaviour.Properties properties, final Supplier<ArrayList<VoxelShape>> shape_supplier) {
super(config, properties);
registerDefaultState(super.defaultBlockState().setValue(AXIS, Direction.Axis.X));
vshapes = shape_supplier.get();
}
public AxisAligned(long config, BlockBehaviour.Properties properties, final AABB[] unrotatedAABBs) {
this(config, properties, () -> new ArrayList<>(Arrays.asList(
Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(unrotatedAABBs, Direction.EAST, false)),
Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(unrotatedAABBs, Direction.UP, false)),
Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(unrotatedAABBs, Direction.SOUTH, false)),
Shapes.block()
)));
}
public AxisAligned(long config, BlockBehaviour.Properties properties, final AABB unrotatedAABB) {
this(config, properties, new AABB[]{unrotatedAABB});
}
@Override
public boolean isPossibleToRespawnInThis(BlockState p_279289_) {
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 vshapes.get((state.getValue(AXIS)).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<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(AXIS);
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context) {
Direction facing;
if ((config & CFG_LOOK_PLACEMENT) != 0) {
facing = context.getNearestLookingDirection();
} else {
facing = context.getClickedFace();
}
return super.getStateForPlacement(context).setValue(AXIS, facing.getAxis());
}
@Override
@SuppressWarnings("deprecation")
public BlockState rotate(BlockState state, Rotation rotation) {
switch (rotation) {
case CLOCKWISE_90:
case COUNTERCLOCKWISE_90:
switch (state.getValue(AXIS)) {
case X:
return state.setValue(AXIS, Direction.Axis.Z);
case Z:
return state.setValue(AXIS, Direction.Axis.X);
}
}
return state;
}
}
public static class Horizontal extends Cutout implements IStandardBlock {
public static final DirectionProperty HORIZONTAL_FACING = BlockStateProperties.HORIZONTAL_FACING;
protected final Map<BlockState, VoxelShape> vshapes;
protected final Map<BlockState, VoxelShape> cshapes;
public Horizontal(long config, BlockBehaviour.Properties properties, final Function<List<BlockState>, Map<BlockState, VoxelShape>> shape_supplier) {
super(config | CFG_HORIZIONTAL, properties);
registerDefaultState(super.defaultBlockState().setValue(HORIZONTAL_FACING, Direction.NORTH));
vshapes = shape_supplier.apply(getStateDefinition().getPossibleStates());
cshapes = shape_supplier.apply(getStateDefinition().getPossibleStates());
}
public Horizontal(long config, BlockBehaviour.Properties properties, final Supplier<ArrayList<VoxelShape>> shape_supplier) {
this(config, properties, (states) -> {
final Map<BlockState, VoxelShape> vshapes = new HashMap<>();
final ArrayList<VoxelShape> indexed_shapes = shape_supplier.get();
for (BlockState state : states)
vshapes.put(state, indexed_shapes.get(state.getValue(HORIZONTAL_FACING).get3DDataValue()));
return vshapes;
});
}
public Horizontal(long config, BlockBehaviour.Properties properties, final AABB unrotatedAABB) {
this(config, properties, new AABB[]{unrotatedAABB});
}
public Horizontal(long config, BlockBehaviour.Properties properties, final AABB[] unrotatedAABBs) {
this(config, properties, (states) -> {
Map<BlockState, VoxelShape> vshapes = new HashMap<>();
for (BlockState state : states) {
vshapes.put(state, Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(unrotatedAABBs, state.getValue(HORIZONTAL_FACING), true)));
}
return vshapes;
});
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(HORIZONTAL_FACING);
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter source, BlockPos pos, CollisionContext selectionContext) {
return vshapes.get(state);
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext selectionContext) {
return cshapes.get(state);
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context) {
BlockState state = super.getStateForPlacement(context);
if (state == null) return null;
Direction facing = context.getClickedFace();
if ((config & CFG_LOOK_PLACEMENT) != 0) {
// horizontal placement in direction the player is looking
facing = context.getHorizontalDirection();
} else {
// horizontal placement on a face
facing = ((facing == Direction.UP) || (facing == Direction.DOWN)) ? (context.getHorizontalDirection()) : facing;
}
if ((config & CFG_OPPOSITE_PLACEMENT) != 0) facing = facing.getOpposite();
if (((config & CFG_FLIP_PLACEMENT_SHIFTCLICK) != 0) && (context.getPlayer() != null) && (context.getPlayer().isShiftKeyDown()))
facing = facing.getOpposite();
return state.setValue(HORIZONTAL_FACING, facing);
}
@Override
@SuppressWarnings("deprecation")
public BlockState rotate(BlockState state, Rotation rot) {
return state.setValue(HORIZONTAL_FACING, rot.rotate(state.getValue(HORIZONTAL_FACING)));
}
@Override
@SuppressWarnings("deprecation")
public BlockState mirror(BlockState state, Mirror mirrorIn) {
return state.rotate(mirrorIn.getRotation(state.getValue(HORIZONTAL_FACING)));
}
}
public static class DirectedWaterLoggable extends Directed implements IStandardBlock {
public DirectedWaterLoggable(long config, BlockBehaviour.Properties properties, AABB aabb) {
super(config | CFG_WATERLOGGABLE, properties, aabb);
}
public DirectedWaterLoggable(long config, BlockBehaviour.Properties properties, AABB[] aabbs) {
super(config | CFG_WATERLOGGABLE, properties, aabbs);
}
public DirectedWaterLoggable(long config, BlockBehaviour.Properties properties, final Function<List<BlockState>, Map<BlockState, VoxelShape>> shape_supplier) {
super(config | CFG_WATERLOGGABLE, properties, shape_supplier);
}
public DirectedWaterLoggable(long config, BlockBehaviour.Properties properties, final Supplier<ArrayList<VoxelShape>> shape_supplier) {
super(config | CFG_WATERLOGGABLE, properties, shape_supplier);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(WATERLOGGED);
}
}
public static class AxisAlignedWaterLoggable extends AxisAligned implements IStandardBlock {
public AxisAlignedWaterLoggable(long config, BlockBehaviour.Properties properties, AABB aabb) {
super(config | CFG_WATERLOGGABLE, properties, aabb);
}
public AxisAlignedWaterLoggable(long config, BlockBehaviour.Properties properties, AABB[] aabbs) {
super(config | CFG_WATERLOGGABLE, properties, aabbs);
}
public AxisAlignedWaterLoggable(long config, BlockBehaviour.Properties properties, final Supplier<ArrayList<VoxelShape>> shape_supplier) {
super(config | CFG_WATERLOGGABLE, properties, shape_supplier);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(WATERLOGGED);
}
}
public static class HorizontalWaterLoggable extends Horizontal implements IStandardBlock {
public HorizontalWaterLoggable(long config, BlockBehaviour.Properties properties, AABB aabb) {
super(config | CFG_WATERLOGGABLE | CFG_HORIZIONTAL, properties, aabb);
}
public HorizontalWaterLoggable(long config, BlockBehaviour.Properties properties, AABB[] aabbs) {
super(config | CFG_WATERLOGGABLE | CFG_HORIZIONTAL, properties, aabbs);
}
public HorizontalWaterLoggable(long config, BlockBehaviour.Properties properties, final Supplier<ArrayList<VoxelShape>> shape_supplier) {
super(config | CFG_WATERLOGGABLE | CFG_HORIZIONTAL, properties, shape_supplier);
}
public HorizontalWaterLoggable(long config, BlockBehaviour.Properties properties, final Function<List<BlockState>, Map<BlockState, VoxelShape>> shape_supplier) {
super(config | CFG_WATERLOGGABLE | CFG_HORIZIONTAL, properties, shape_supplier);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(WATERLOGGED);
}
}
static public class HorizontalFourWayWaterLoggable extends WaterLoggable implements IStandardBlock {
public static final BooleanProperty NORTH = BlockStateProperties.NORTH;
public static final BooleanProperty EAST = BlockStateProperties.EAST;
public static final BooleanProperty SOUTH = BlockStateProperties.SOUTH;
public static final BooleanProperty WEST = BlockStateProperties.WEST;
protected final Map<BlockState, VoxelShape> shapes;
protected final Map<BlockState, VoxelShape> collision_shapes;
public HorizontalFourWayWaterLoggable(long config, BlockBehaviour.Properties properties, AABB base_aabb, final AABB[] side_aabb, int railing_height_extension) {
super(config, properties, base_aabb);
Map<BlockState, VoxelShape> build_shapes = new HashMap<>();
Map<BlockState, VoxelShape> build_collision_shapes = new HashMap<>();
for (BlockState state : getStateDefinition().getPossibleStates()) {
{
VoxelShape shape = ((base_aabb.getXsize() == 0) || (base_aabb.getYsize() == 0) || (base_aabb.getZsize() == 0)) ? Shapes.empty() : Shapes.create(base_aabb);
if (state.getValue(NORTH))
shape = Shapes.joinUnoptimized(shape, Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(side_aabb, Direction.NORTH, true)), BooleanOp.OR);
if (state.getValue(EAST))
shape = Shapes.joinUnoptimized(shape, Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(side_aabb, Direction.EAST, true)), BooleanOp.OR);
if (state.getValue(SOUTH))
shape = Shapes.joinUnoptimized(shape, Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(side_aabb, Direction.SOUTH, true)), BooleanOp.OR);
if (state.getValue(WEST))
shape = Shapes.joinUnoptimized(shape, Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(side_aabb, Direction.WEST, true)), BooleanOp.OR);
if (shape.isEmpty()) shape = Shapes.block();
build_shapes.put(state.setValue(WATERLOGGED, false), shape);
build_shapes.put(state.setValue(WATERLOGGED, true), shape);
}
{
// how the hack to extend a shape, these are the above with y+4px.
VoxelShape shape = ((base_aabb.getXsize() == 0) || (base_aabb.getYsize() == 0) || (base_aabb.getZsize() == 0)) ? Shapes.empty() : Shapes.create(base_aabb);
if (state.getValue(NORTH))
shape = Shapes.joinUnoptimized(shape, Auxiliaries.getUnionShape(Auxiliaries.getMappedAABB(Auxiliaries.getRotatedAABB(side_aabb,
Direction.NORTH, true), bb -> bb.expandTowards(0, railing_height_extension, 0))), BooleanOp.OR);
if (state.getValue(EAST))
shape = Shapes.joinUnoptimized(shape, Auxiliaries.getUnionShape(Auxiliaries.getMappedAABB(Auxiliaries.getRotatedAABB(side_aabb,
Direction.EAST, true), bb -> bb.expandTowards(0, railing_height_extension, 0))), BooleanOp.OR);
if (state.getValue(SOUTH))
shape = Shapes.joinUnoptimized(shape, Auxiliaries.getUnionShape(Auxiliaries.getMappedAABB(Auxiliaries.getRotatedAABB(side_aabb,
Direction.SOUTH, true), bb -> bb.expandTowards(0, railing_height_extension, 0))), BooleanOp.OR);
if (state.getValue(WEST))
shape = Shapes.joinUnoptimized(shape, Auxiliaries.getUnionShape(Auxiliaries.getMappedAABB(Auxiliaries.getRotatedAABB(side_aabb,
Direction.WEST, true), bb -> bb.expandTowards(0, railing_height_extension, 0))), BooleanOp.OR);
if (shape.isEmpty()) shape = Shapes.block();
build_collision_shapes.put(state.setValue(WATERLOGGED, false), shape);
build_collision_shapes.put(state.setValue(WATERLOGGED, true), shape);
}
}
shapes = build_shapes;
collision_shapes = build_collision_shapes;
registerDefaultState(super.defaultBlockState().setValue(NORTH, false).setValue(EAST, false).setValue(SOUTH, false).setValue(WEST, false).setValue(WATERLOGGED, false));
}
public HorizontalFourWayWaterLoggable(long config, BlockBehaviour.Properties properties, AABB base_aabb, final AABB side_aabb, int railing_height_extension) {
this(config, properties, base_aabb, new AABB[]{side_aabb}, railing_height_extension);
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder);
builder.add(NORTH, EAST, SOUTH, WEST);
}
@Override
@Nullable
public BlockState getStateForPlacement(BlockPlaceContext context) {
return super.getStateForPlacement(context).setValue(NORTH, false).setValue(EAST, false).setValue(SOUTH, false).setValue(WEST, false);
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) {
return shapes.getOrDefault(state, Shapes.block());
}
@Override
public VoxelShape getCollisionShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) {
return collision_shapes.getOrDefault(state, Shapes.block());
}
public static BooleanProperty getDirectionProperty(Direction face) {
return switch (face) {
case EAST -> HorizontalFourWayWaterLoggable.EAST;
case SOUTH -> HorizontalFourWayWaterLoggable.SOUTH;
case WEST -> HorizontalFourWayWaterLoggable.WEST;
default -> HorizontalFourWayWaterLoggable.NORTH;
};
}
}
}