How to tell the game to use a corner hitbox for a stair-like block mode?

hitboxes

public class MoldingBlock extends StairsBlock {
    /*
    NE -> Northeast
    NW -> Northwest
    SE -> Southeast
    SW -> Southwest
     */
    protected static final VoxelShape NE_CORNER_FIRST = Block.createCuboidShape(0.0, 8.0, 0.0, 16.0, 16.0, 8.0);
    protected static final VoxelShape NE_CORNER_SECOND = Block.createCuboidShape(8.0, 8.0, 8.0, 16.0, 16.0, 16.0);

    protected static final VoxelShape SE_CORNER_FIRST = Block.createCuboidShape(8.0, 8.0, 0.0, 16.0, 16.0, 16.0);
    protected static final VoxelShape SE_CORNER_SECOND = Block.createCuboidShape(0.0, 8.0, 8.0, 8.0, 16.0, 16.0);

    private static final VoxelShape northEast = VoxelShapes.union(NE_CORNER_FIRST, NE_CORNER_SECOND);
    private static final VoxelShape southEast = VoxelShapes.union(SE_CORNER_FIRST, SE_CORNER_SECOND);

    public MoldingBlock(BlockState blockState, Settings settings) {
        super(blockState, settings);
    }

    // Both of the following blocks of code below deals with block collision.
    @Override
    public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, ShapeContext context) {
        Direction cardinalDir = state.get(FACING);
        BlockHalf upOrDown = state.get(HALF);
        StairShape whichCorner = state.get(SHAPE);
        return switch (upOrDown) {
            case TOP -> switch (cardinalDir) {
                case NORTH -> northEast; //VoxelShapes.cuboid(0f, 0.5f, 0f, 1f, 1f, 0.5f);
                case SOUTH -> southEast; //VoxelShapes.cuboid(0f, 0.5f, 0.5f, 1f, 1f, 1f);
                case EAST -> VoxelShapes.cuboid(0.5f, 0.5f, 0f, 1f, 1f, 1f);
                case WEST -> VoxelShapes.cuboid(0f, 0.5f, 0f, 0.5f, 1f, 1f);
                default -> VoxelShapes.fullCube();
            };
            case BOTTOM -> switch (cardinalDir) {
                case NORTH -> VoxelShapes.cuboid(0f, 0f, 0f, 1f, 0.5f, 0.5f);
                case SOUTH -> VoxelShapes.cuboid(0f, 0f, 0.5f, 1f, 0.5f, 1f);
                case EAST -> VoxelShapes.cuboid(0.5f, 0f, 0f, 1f, 0.5f, 1f);
                case WEST -> VoxelShapes.cuboid(0f, 0f, 0f, 0.5f, 0.5f, 1f);
                default -> VoxelShapes.fullCube();
            };
            //throw new IllegalStateException("Unexpected value: " + upOrDown);
        };
    }
}

The above code handles telling the game to use a different hitbox depending on which cardinal direction the block faces and which part of the Y-axis the block was placed on.

What I want to do is to tell the game to use straight hitboxes (8x8x16) for the cardinal directions and to place the hitbox in accordance to which half of the full blockspace and when the molding block has an inner 90-degree corner (pictured below w/ red outline), it should use a corner hitbox.
corner hitbox

When the molding block has an outside corner, it should just use a cube hitbox (8x8x8).
outside corner

The “oak_crown_molding.json” file for reference: oak_crown_molding.json

I believe you’d want to move the big switch case into a getStraightShapeFor(BlockHalf half, Direction dir), then in getOutlineShape you could have something like:

var straightShape = this.getStraightShapeFor(upOrDown, cardinalDir);

return switch (stairShape) {
    case STRAIGHT -> straightShape;
    case INNER_LEFT -> VoxelShapes.union(straightShape, this.getStraightShapeFor(upOrDown, cardinalDir.rotateYClockwise())); // might be anticlockwise?
    case OUTER_LEFT -> VoxelShapes.combineAndSimplify(straightShape, this.getStraightShapeFor(upOrDown, cardinalDir.rotateYClockwise()), BooleanBiFunction.AND); // might be anticlockwise?
    // etc. for other cases
}

Note that it is best to cache these union VoxelShapes. For best performance, you could instead do what the vanilla StairsBlock does, but that’s a bit confusing.

If this has been solved, please mark the solution.

This is a fairly hacky solution I arrived at quite a while ago:

@Override
    public VoxelShape getOutlineShape(BlockState state, BlockView view, BlockPos pos, ShapeContext context) {
        Direction cardinalDir = state.get(FACING);
        BlockHalf upOrDown = state.get(HALF);
        StairShape moldingShape = state.get(SHAPE);

        var straightShape = this.getStraightShapeFor(upOrDown, cardinalDir);
        return switch (moldingShape) {
            case STRAIGHT -> straightShape;
            case INNER_LEFT -> VoxelShapes.union(straightShape, this.getStraightShapeFor(upOrDown, cardinalDir.rotateYCounterclockwise()));
            case OUTER_LEFT -> VoxelShapes.combineAndSimplify(straightShape, this.getStraightShapeFor(upOrDown, cardinalDir.rotateYCounterclockwise()), BooleanBiFunction.AND);
            default -> VoxelShapes.combineAndSimplify(straightShape, this.getStraightShapeFor(upOrDown, cardinalDir.rotateYClockwise()), BooleanBiFunction.AND);
        };
    }

Those shape probably should be cached in a static final Map, combining VoxelShapes can be quite resource-intensive.

At least for collision those shapes are cached by the block state.

That’s already been done here: architecture-extensions/MoldingBlock.java at 1.18 · woodiertexas/architecture-extensions · GitHub

What I meant is cache all the possible final shapes. Not the basic parts of the shapes.

Essentially taking the following bits…

VoxelShapes.union(straightShape, this.getStraightShapeFor(upOrDown, cardinalDir.rotateYCounterclockwise()));
VoxelShapes.combineAndSimplify(straightShape, this.getStraightShapeFor(upOrDown, cardinalDir.rotateYCounterclockwise()), BooleanBiFunction.AND);

…and putting them into a final variable?