Topic category: User side tutorials
Making a non-cuboid Shaped Block
You need some Java knowledge for this tutorial.
Before starting this tutorial keep in mind that this tutorial will require you to lock your block element and you can't change any of your block properties without coding after locking the element. So make sure before adding a custom shape to your block, your block is complete.
Also give your block a cubiod shape other than a full cube to save some work and all of the things here must be done under CustomBlock class so find the line below and do the things here under it.
public static class CustomBlock extends Block {...
Block can be something else if your block is horizontal.
If you are using Fabric Generator, it must look something like below:
public class [YourBlock]Block extends block {...
Classes could be implementing things so this might change.
For Forge 1.15.x/1.16.x (and probably 1.14.x):
First lets see how a cuboid shape is done in Forge.
Block.makeCuboidShape(x1, y1, z1, x2, y2, z2)
This is how you make a cuboid collision box. xyz1 are the start coords of your box and xyz2 are the end coords. Game will automatically create a cube from xyz1 to xyz2.
Now lets create a weird shape using multiple collision boxes:
private static final VoxelShape SHAPE = VoxelShapes.or(Block.makeCuboidShape(6, 0, 6, 10, 13, 10), Block.makeCuboidShape(0, 13, 0, 16, 16, 16)).simplify();
This shape looks like a table with a centered leg. You can also do this like below for better understanding:
private static final VoxelShape SHAPE = VoxelShapes.or(
Block.makeCuboidShape(6, 0, 6, 10, 13, 10),
Block.makeCuboidShape(0, 13, 0, 16, 16, 16)
).simplify();
This is a VoxelShape/collision box named SHAPE. You can name your shape anything you want but SHAPE is what most people use.
Now we need to bind this shape to our block. This part is very simple just find the override below:
@Override
public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
return [Your Current Shape];
}
And replace your current shape with your shapes name. In our case it must be like below:
@Override
public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) {
return SHAPE;
}
And thats it, if you copy pasted the code you'll also need add the imports below:
import net.minecraft.util.math.shapes.VoxelShapes;
What if my block is Horizontal?
If your shape is symetrical, you dont need to do anything, if your shape is not symetrical, then read below.
First make voxelshapes for every direction like below:
private static final VoxelShape SHAPE_NORTH = VoxelShapes.or(Your blocks shape from north);
private static final VoxelShape SHAPE_SOUTH = VoxelShapes.or(Your blocks shape from south);
private static final VoxelShape SHAPE_WEST = VoxelShapes.or(Your blocks shape from west);
private static final VoxelShape SHAPE_EAST = VoxelShapes.or(Your blocks shape from east);
Then again find the override but this time it must look something like below:
@Override
public VoxelShape getShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context) {
switch ((Direction) state.get(FACING)) {
case UP :
case DOWN :
case SOUTH :
default :
return [Your Current South Shape];
case NORTH :
return [Your Current North Shape];
case WEST :
return [Your Current West Shape];
case EAST :
return [Your Current East Shape];
}
}
And replace the shapes accordingly like below:
@Override
public VoxelShape getShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext context) {
switch ((Direction) state.get(FACING)) {
case UP :
case DOWN :
case SOUTH :
default :
return SHAPE_SOUTH;
case NORTH :
return SHAPE_NORTH;
case WEST :
return SHAPE_WEST;
case EAST :
return SHAPE_EAST;
}
}
And thats it!
For Fabric 1.16.x:
First lets see how a cuboid shape is done in Fabric.
Block.createCuboidShape(x1, y1, z1, x2, y2, z2)
As you can see its very similar with forge.
Now lets recreate the table shape we created above using Fabric.
private static final VoxelShape SHAPE = VoxelShapes.union(Block.createCuboidShape(6, 0, 6, 10, 13, 10), Block.createCuboidShape(0, 13, 0, 16, 16, 16));
Again you can do this like below for simplicity:
private static final VoxelShape SHAPE = VoxelShapes.union(
Block.createCuboidShape(6, 0, 6, 10, 13, 10),
Block.createCuboidShape(0, 13, 0, 16, 16, 16)
);
Now again find the override, which must look something like below:
@Override
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
return [Your Current Shape];
}
And again replace your curent shape with your shape. It must look something like below:
@Override
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
return SHAPE;
}
You dont need to import extra classes in Fabric.
What if my block is Horizontal?
If your shape is symetrical, you dont need to do anything, if your shape is not symetrical, then read below.
Again make multiple voxelshapes for your block, one for every direction like below:
private static final VoxelShape SHAPE_NORTH = VoxelShapes.union(Your blocks shape from north);
private static final VoxelShape SHAPE_SOUTH = VoxelShapes.union(Your blocks shape from south);
private static final VoxelShape SHAPE_WEST = VoxelShapes.union(Your blocks shape from west);
private static final VoxelShape SHAPE_EAST = VoxelShapes.union(Your blocks shape from east);
Then again find the override which must look something like below:
@Override
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
switch ((Direction) state.get(FACING)) {
case UP :
case DOWN :
case SOUTH :
default :
return [Your Current South Shape];
case NORTH :
return [Your Current North Shape];
case WEST :
return [Your Current West Shape];
case EAST :
return [Your Current East Shape];
}
}
And again replace the shapes accordingly like below:
@Override
public VoxelShape getOutlineShape(BlockState state, BlockView world, BlockPos pos, ShapeContext context) {
switch ((Direction) state.get(FACING)) {
case UP :
case DOWN :
case SOUTH :
default :
return SHAPE_SOUTH;
case NORTH :
return SHAPE_NORTH;
case WEST :
return SHAPE_WEST;
case EAST :
return SHAPE_EAST;
}
}
And you're done! Enjoy your non-cuboid collision boxed blocks. 😀
If you come across with any issues, you can post them below. Also don't forgot to give your log and code using a website like pastebin, etc..
(Please don't just copy paste the whole log 😢☹️👿)
Awesome tutorial! :D
Thanks
Amazing tutorial! I think it will help a lot of users(like me, when I will continue to make mods). I'm glad to see you also want to make the tutorial for an unofficial plugin! :D
Thanks, I'm glad I can help you and other users. I'll add Fabric once I finish it, their isn't much diffrence between them anyway.
(Finally) 🙃 added Fabric
Marry me! <3
O_o (replying to chrishiss)
Hi! I'm trying to make a block with a custom collision box using this tutorial. It all mostly makes sense to me, except for this part:
I'm not entirely sure what I should be putting in the parentheses? I've had experience with coding in the past before, but I can't find any documentation on VoxelShapes and I don't really know what to do here. Please help!
Sorry for the late reply, you need to put one or more shapes in parentheses
A shape:
After each line, put a comma (,) to seperate the each shape, except the last one
Example:
minX, minY, minZ, maxX, maxY, maxZ must be numbers (min 0, max 16)
A proper example:
Thanks so much! Wouldn't have figured that out on my own, this helps a lot!
How do I do on with this?
Stream.of(
Block.makeCuboidShape(1, 0, 1, 15, 1, 15),
Block.makeCuboidShape(4, 1, 4, 12, 16, 12),
Block.makeCuboidShape(10, 1, 2, 14, 12, 6),
Block.makeCuboidShape(2, 1, 2, 5, 8, 6),
Block.makeCuboidShape(9, 1, 10, 13, 9, 14),
Block.makeCuboidShape(3, 1, 9, 7, 6, 13)
).reduce((v1, v2) -> {return VoxelShapes.combineAndSimplify(v1, v2, IBooleanFunction.OR);});