Make A Pillar Style Block

Started by nanoxiphias on Sun, 04/04/2021 - 08:01

Topic category: User side tutorials

Last seen on 03:49, 1. May 2021
Joined Mar 2021
Points:

User statistics:

  • Modifications:
  • Forum topics:
  • Wiki pages:
  • Tracker tickets:
  • MCreator plugins:
  • Comments:
Make A Pillar Style Block
Sun, 04/04/2021 - 09:02 (edited)

How To Make A Pillar Style Block.

Make a block that changes its states when placed above or below a block of the same type. (will work with 1.16 too)

demo

Feel free to make a video tutorial based on this tutorial

Project Files

The workspace I have created is called pillars.


Import images

You will need 2 textures, a texture for the sides and a texture for the ends.pillar side texture pillar end texture

 

To import your textures goto Resources -> 

Choose: import block texture(s)...

navigate to the location of you textures and import them.

 

Import the models

Note: you can use Blockbench which is a free program used to make models

 

You will need 4 models. 

Here are some models you can use to get you started.

Copy the code into a text editor and save them as the name above the code block.

 

📜 pillar_block.json

{
    "elements": [
        {
            "from": [0, 12, 0],
            "to": [16, 16, 16],
            "faces": {
                "north": {"uv": [0, 0, 16, 4], "texture": "#side"},
                "east": {"uv": [0, 0, 16, 4], "texture": "#side"},
                "south": {"uv": [0, 0, 16, 4], "texture": "#side"},
                "west": {"uv": [0, 0, 16, 4], "texture": "#side"},
                "up": {"uv": [0, 0, 16, 16], "texture": "#end"},
                "down": {"uv": [0, 0, 16, 16], "texture": "#end"}
            }
        },
        {
            "from": [2, 4, 2],
            "to": [14, 12, 14],
            "faces": {
                "north": {"uv": [0, 0, 16, 16], "texture": "#side"},
                "east": {"uv": [0, 0, 16, 16], "texture": "#side"},
                "south": {"uv": [0, 0, 16, 16], "texture": "#side"},
                "west": {"uv": [0, 0, 16, 16], "texture": "#side"}
            }
        },
        {
            "from": [0, 0, 0],
            "to": [16, 4, 16],
            "faces": {
                "north": {"uv": [0, 0, 16, 4], "texture": "#side"},
                "east": {"uv": [0, 0, 16, 4], "texture": "#side"},
                "south": {"uv": [0, 0, 16, 4], "texture": "#side"},
                "west": {"uv": [0, 0, 16, 4], "texture": "#side"},
                "up": {"uv": [0, 0, 16, 16], "texture": "#end"},
                "down": {"uv": [0, 0, 16, 16], "texture": "#end"}
            }
        }
    ],
    "display": {
        "thirdperson_righthand": {
            "rotation": [75, 45, 0],
            "translation": [0, 2.5, 0],
            "scale": [0.375, 0.375, 0.375]
        },
        "thirdperson_lefthand": {
            "rotation": [75, 45, 0],
            "translation": [0, 2.5, 0],
            "scale": [0.375, 0.375, 0.375]
        },
        "firstperson_righthand": {
            "rotation": [0, 45, 0],
            "scale": [0.4, 0.4, 0.4]
        },
        "firstperson_lefthand": {
            "rotation": [0, 45, 0],
            "scale": [0.4, 0.4, 0.4]
        },
        "ground": {
            "translation": [0, 3, 0],
            "scale": [0.25, 0.25, 0.25]
        },
        "gui": {
            "rotation": [30, 225, 0],
            "scale": [0.625, 0.625, 0.625]
        },
        "fixed": {
            "scale": [0.5, 0.5, 0.5]
        }
    }
}

📜 pillar_block_top.json

{
    "elements": [
        {
            "from": [0, 12, 0],
            "to": [16, 16, 16],
            "faces": {
                "north": {"uv": [0, 0, 16, 4], "texture": "#side"},
                "east": {"uv": [0, 0, 16, 4], "texture": "#side"},
                "south": {"uv": [0, 0, 16, 4], "texture": "#side"},
                "west": {"uv": [0, 0, 16, 4], "texture": "#side"},
                "up": {"uv": [0, 0, 16, 16], "texture": "#end"},
                "down": {"uv": [0, 0, 16, 16], "texture": "#end"}
            }
        },
        {
            "from": [2, 0, 2],
            "to": [14, 12, 14],
            "faces": {
                "north": {"uv": [0, 0, 16, 16], "texture": "#side"},
                "east": {"uv": [0, 0, 16, 16], "texture": "#side"},
                "south": {"uv": [0, 0, 16, 16], "texture": "#side"},
                "west": {"uv": [0, 0, 16, 16], "texture": "#side"}
            }
        }
    ],
    "display": {
        "thirdperson_righthand": {
            "rotation": [75, 45, 0],
            "translation": [0, 2.5, 0],
            "scale": [0.375, 0.375, 0.375]
        },
        "thirdperson_lefthand": {
            "rotation": [75, 45, 0],
            "translation": [0, 2.5, 0],
            "scale": [0.375, 0.375, 0.375]
        },
        "firstperson_righthand": {
            "rotation": [0, 45, 0],
            "scale": [0.4, 0.4, 0.4]
        },
        "firstperson_lefthand": {
            "rotation": [0, 45, 0],
            "scale": [0.4, 0.4, 0.4]
        },
        "ground": {
            "translation": [0, 3, 0],
            "scale": [0.25, 0.25, 0.25]
        },
        "gui": {
            "rotation": [30, 225, 0],
            "scale": [0.625, 0.625, 0.625]
        },
        "fixed": {
            "scale": [0.5, 0.5, 0.5]
        }
    }
}

📜 pillar_block_middle.json

{
    "elements": [
        {
            "from": [2, 0, 2],
            "to": [14, 16, 14],
            "faces": {
                "north": {"uv": [0, 0, 16, 16], "texture": "side"},
                "east": {"uv": [0, 0, 16, 16], "texture": "side"},
                "south": {"uv": [0, 0, 16, 16], "texture": "side"},
                "west": {"uv": [0, 0, 16, 16], "texture": "side"}
            }
        }
    ],
    "display": {
        "thirdperson_righthand": {
            "rotation": [75, 45, 0],
            "translation": [0, 2.5, 0],
            "scale": [0.375, 0.375, 0.375]
        },
        "thirdperson_lefthand": {
            "rotation": [75, 45, 0],
            "translation": [0, 2.5, 0],
            "scale": [0.375, 0.375, 0.375]
        },
        "firstperson_righthand": {
            "rotation": [0, 45, 0],
            "scale": [0.4, 0.4, 0.4]
        },
        "firstperson_lefthand": {
            "rotation": [0, 45, 0],
            "scale": [0.4, 0.4, 0.4]
        },
        "ground": {
            "translation": [0, 3, 0],
            "scale": [0.25, 0.25, 0.25]
        },
        "gui": {
            "rotation": [30, 225, 0],
            "scale": [0.625, 0.625, 0.625]
        },
        "fixed": {
            "scale": [0.5, 0.5, 0.5]
        }
    }
}

📜 pillar_block_bottom.json

{
    "elements": [
        {
            "from": [2, 4, 2],
            "to": [14, 16, 14],
            "faces": {
                "north": {"uv": [0, 0, 16, 16], "texture": "#side"},
                "east": {"uv": [0, 0, 16, 16], "texture": "#side"},
                "south": {"uv": [0, 0, 16, 16], "texture": "#side"},
                "west": {"uv": [0, 0, 16, 16], "texture": "#side"}
            }
        },
        {
            "from": [0, 0, 0],
            "to": [16, 4, 16],
            "faces": {
                "north": {"uv": [0, 0, 16, 4], "texture": "#side"},
                "east": {"uv": [0, 0, 16, 4], "texture": "#side"},
                "south": {"uv": [0, 0, 16, 4], "texture": "#side"},
                "west": {"uv": [0, 0, 16, 4], "texture": "#side"},
                "up": {"uv": [0, 0, 16, 16], "texture": "#end"},
                "down": {"uv": [0, 0, 16, 16], "texture": "#end"}
            }
        }
    ],
    "display": {
        "thirdperson_righthand": {
            "rotation": [75, 45, 0],
            "translation": [0, 2.5, 0],
            "scale": [0.375, 0.375, 0.375]
        },
        "thirdperson_lefthand": {
            "rotation": [75, 45, 0],
            "translation": [0, 2.5, 0],
            "scale": [0.375, 0.375, 0.375]
        },
        "firstperson_righthand": {
            "rotation": [0, 45, 0],
            "scale": [0.4, 0.4, 0.4]
        },
        "firstperson_lefthand": {
            "rotation": [0, 45, 0],
            "scale": [0.4, 0.4, 0.4]
        },
        "ground": {
            "translation": [0, 3, 0],
            "scale": [0.25, 0.25, 0.25]
        },
        "gui": {
            "rotation": [30, 225, 0],
            "scale": [0.625, 0.625, 0.625]
        },
        "fixed": {
            "scale": [0.5, 0.5, 0.5]
        }
    }
}

To import your models. 

Goto Resources ->

  • Choose "import JSON 3D model..."

navigate to the folder where your model files are located and import them.


Once this is done you can create a new block.

Give the Block a name I named mine Pillar

 

In the Block textures section 

  • Bottom / main: select a texture - this is used for the particle when landed upon or destroyed.

In the Render type and rotation section

  • Block model: Select pillar_block (assuming you named the model files the same as the tutorial).

In the Transparency section

  •  Transparency type:  CUTOUT

Now you can save the block.

Of course you can make any changes you like in the "Properties" section such as hardness, material and more.


In the side panel - navigate to the pillar blockstate file

📁 Pillars - This is your workspaces name
┣ 📂 Source (Gradle)
┣ 📂 Resources (Gradle)
┃  ┣ 📂 assets
┃  ┃  ┣ 📂 pillars
┃  ┃  ┃  ┣ 📂 blockstates
┃  ┃  ┃  ┃  ┣ 📜 pillar.json

Remove the current text 

Copy paste the code below into the file.

{
  "variants": {
    "section=default": {
      "model": "pillars:block/pillar"
    },
    "section=top": {
      "model": "pillars:block/pillar_top"
    },
    "section=middle": {
      "model": "pillars:block/pillar_middle"
    },
    "section=bottom": {
      "model": "pillars:block/pillar_bottom"
    }
  }
}

Change "pillars" to whatever your modname is.

save and lock the code from mcreator


Now you need to add the model files to your mod

 

In the menu bar.

goto: Workspace -> Open workspace folder

📁 src
┣ 📂 main
┃  ┣ 📂 resources
┃  ┃  ┣ 📂 assets
┃  ┃  ┃  ┣ 📂 pillars
┃  ┃  ┃  ┃  ┣ 📂 models
┃  ┃  ┃  ┃  ┃  ┣ 📂 block
┃  ┃  ┃  ┃  ┃  ┃  ┣ 📜 pillar.json

copy and paste the pillar.json file 3 times and rename each as such.

📜 pillar_top.json

📜 pillar_middle.json

📜 pillar_bottom.json

Close the folder.


Now you can edit the files.

Go back to mcreator and find the "models\block" folder

📁 Pillars - This is your workspaces name
┣ 📂 Source (Gradle)
┣ 📂 Resources
┃  ┣ 📂 assets
┃  ┃  ┣ 📂 pillars
┃  ┃  ┃  ┣ 📂 blockstates
┃  ┃  ┃  ┃  ┣ 📜 pillar.json
┃  ┃  ┃  ┣ 📂 models
┃  ┃  ┃  ┃  ┣ 📂 block
┃  ┃  ┃  ┃  ┃  ┣ 📜 pillar.json
┃  ┃  ┃  ┃  ┃  ┣ 📜 pillar_bottom.json
┃  ┃  ┃  ┃  ┃  ┣ 📜 pillar_middle.json
┃  ┃  ┃  ┃  ┃  ┣ 📜 pillar_top.json

 

Open pillar_top.json

Append _top to the value of the "parent" key

{
  "parent": "pillars:custom/pillar_block_top",
  "textures": {
    "particle": "pillars:blocks/pillar_end",
    "side": "pillars:blocks/pillar_side",
    "end": "pillars:blocks/pillar_end"
  }
}

do the same for bottom and middle model files

"parent": "pillars:custom/pillar_block_bottom",
"parent": "pillars:custom/pillar_block_middle",

If you test your mod now, you will see that the item appears to be correct, but when you place it in the world, you get a missing texture.


Now you need to do a little Java coding.

First you need to create a custom element and name it AbstractPillarBlock

You are creating this element so that you can reuse it to make other pillar like blocks should you want them.

 

Remove all code from the file and copy and paste this commented code below.

package net.mcreator.pillars;
/**
 * Imports tell the java runtime which classes are depended upon and where they are located.
 */
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.IWaterLoggable;
import net.minecraft.fluid.Fluids;
import net.minecraft.fluid.IFluidState;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.EnumProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.Direction;
import net.minecraft.util.IStringSerializable;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.IBooleanFunction;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;

import java.util.List;
import java.util.Locale;

import java.util.Locale;

public abstract class AbstractPillarBlock extends Block implements IWaterLoggable {

    public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
    //This field creates the blockstates you need.
    public static final EnumProperty<PillarSection> PILLAR_TYPE = EnumProperty.create("section", PillarSection.class);

    /**
     * The constructor is called when this class is created (instantiated) to initialize it.
     */
    public AbstractPillarBlock(Properties props) {
        super(props);
        // Sets the state of this block when only this block exists.
        this.setDefaultState(this.getStateContainer().getBaseState().with(PILLAR_TYPE, PillarSection.DEFAULT));
    }

    /**
     * Adds properties to the state container builder, so that the system knows this block supports the properties provided
     */
    @Override
    protected void fillStateContainer(StateContainer.Builder<Block, BlockState> builder) {
        super.fillStateContainer(builder);
        builder.add(PILLAR_TYPE, WATERLOGGED);
    }

    /**
     * Updates the state based on the provided neighbours face and state after placed, returning a new state.
     */
    @Override
    public BlockState updatePostPlacement(BlockState thisState, Direction otherBlockFacing, BlockState neighboursBlockState, IWorld world, BlockPos thisPos, BlockPos neighbourBlockPos) {
        return this.getThisState(world, thisPos).with(WATERLOGGED, thisState.get(WATERLOGGED));
    }

    /**
     * Check what state this block should use when placing the BlockItem.
     */
    @Override
    public BlockState getStateForPlacement(BlockItemUseContext ctx) {
        BlockPos blockpos = ctx.getPos();
        World world = ctx.getWorld();
        IFluidState fluidstate = world.getFluidState(blockpos);
        return this.getThisState(world, blockpos).with(WATERLOGGED, fluidstate.getFluid() == Fluids.WATER);
    }

    /**
     * The shape used to draw the BoundingBox "outline" of the block when a player is looking at it.
     */
    @Override
    public VoxelShape getShape(BlockState state, IBlockReader world, BlockPos pos, ISelectionContext ctx) {
        switch (state.get(PILLAR_TYPE)) {
            case TOP:
                return this.getTopShape();
            case MIDDLE:
                return this.getMiddleShape();
            case BOTTOM:
                return this.getBottomShape();
            default:
            case DEFAULT:
                return this.getDefaultShape();
        }
    }

    /**
     * Helper method used to combine voxel shapes to get the correct bounding box
     */
    public static VoxelShape combineAll(IBooleanFunction fct, List<VoxelShape> shapes) {
        if (shapes.isEmpty()) {
            return VoxelShapes.empty();
        }
        VoxelShape shape = shapes.get(0);
        for (int i = 1; i < shapes.size(); i++) {
            shape = VoxelShapes.combine(shape, shapes.get(i), fct);
        }
        return shape;
    }

    /**
     * you will set these methods in our blocks class so that the `getShape` methods can use them.
     */
    protected abstract VoxelShape getTopShape();
    protected abstract VoxelShape getMiddleShape();
    protected abstract VoxelShape getBottomShape();
    protected abstract VoxelShape getDefaultShape();
    /**
     * you do not want each block you create to connect to others using this class.
     * So you use this method to create unique states for each new block extending this class.
     */
    protected abstract BlockState getThisState(IBlockReader world, BlockPos pos);

    /**
     * A set of named constants you can use to say what section our `PillarBlock` can have
     */
    public enum PillarSection implements IStringSerializable {
        DEFAULT,
        TOP,
        MIDDLE,
        BOTTOM;

        @Override
        public String getName() {
            return name().toLowerCase(Locale.ROOT);
        }

        @Override
        public String toString() {
            return this.getName();
        }
    }
}

 

Now you need to edit the block class.

You should be careful to only edit what is needed in this class.

📁 Pillars - This is your workspaces name
┣ 📂 Source (Gradle)
┃  ┣ 📂 net
┃  ┃  ┣ 📂 mcreator
┃  ┃  ┃  ┣ 📂 block
┃  ┃  ┃  ┃  ┣ 📜 PillarBlock.java
┣ 📂 Resources (Gradle)

Find this line below.

public static class CustomBlock extends Block

and change Block to AbstractPillarBlock so it should now look like

public static class CustomBlock extends AbstractPillarBlock

Remove code such that your file will look like this.

package net.mcreator.pillars.block;

import net.minecraftforge.registries.ObjectHolder;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.api.distmarker.Dist;

import net.minecraft.item.ItemGroup;
import net.minecraft.item.Item;
import net.minecraft.item.BlockItem;
import net.minecraft.client.renderer.RenderTypeLookup;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.block.Block;

import net.mcreator.pillars.PillarsModElements;

@PillarsModElements.ModElement.Tag
public class PillarBlock extends PillarsModElements.ModElement {
    @ObjectHolder("pillars:pillar")
    public static final Block block = null;
    public PillarBlock(PillarsModElements instance) {
        super(instance, 1);
    }

    @Override
    public void initElements() {
        elements.blocks.add(() -> new CustomBlock());
        elements.items
                .add(() -> new BlockItem(block, new Item.Properties().group(ItemGroup.BUILDING_BLOCKS)).setRegistryName(block.getRegistryName()));
    }

    @Override
    @OnlyIn(Dist.CLIENT)
    public void clientLoad(FMLClientSetupEvent event) {
        RenderTypeLookup.setRenderLayer(block, RenderType.getCutout());
    }
    public static class CustomBlock extends AbstractPillarBlock {
        // remove every thing between here ---

        // ...

        // and here ---
    }
}

Add these constants fields above the CustomBlock constructor

private static final VoxelShape[] DEFAULT = {Block.makeCuboidShape(0, 0, 0, 16, 4, 16), Block.makeCuboidShape(2, 4, 2, 14, 12, 14), Block.makeCuboidShape(0, 12, 0, 16, 16, 16)};
private static final VoxelShape[] TOP = {Block.makeCuboidShape(0, 12, 0, 16, 16, 16), Block.makeCuboidShape(2, 0, 2, 14, 12, 14)};
private static final VoxelShape[] MIDDLE = {Block.makeCuboidShape(2, 0, 2, 14, 16, 14)};
private static final VoxelShape[] BOTTOM = {Block.makeCuboidShape(0, 0, 0, 16, 4, 16), Block.makeCuboidShape(2, 4, 2, 14, 16, 14)};

These constants say what our blocks Bounding box will be. 

When creating new blocks that extend AbstractPillarBlock these are all that you would need to edit.

Note: You can use the from and to part of the model file to get the bounding box.


You are using some classes ArraysVoxelShapeIBooleanFunction and AbstractPillarBlock that are not used by mcreator in this class so you will need to import them.

 

At the top of the class in the import section. after.

package net.mcreator.pillars.block;

add this code

import net.mcreator.pillars.AbstractPillarBlock;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.IBooleanFunction;
import java.util.Arrays;

 

Because you have extended the AbstractPillarBlock class you need to add some methods that are not part of this blocks class.

In the constructor remove this.setsetDefaultState(...) if it exists as this is handled by the AbstractPillarBlock class.

public CustomBlock() {
    //Make sure to keep this `super(...)` the same as it was do not copy paste this as it may be different to your properties.
    super(Block.Properties.create(Material.ROCK).sound(SoundType.GROUND).hardnessAndResistance(1f, 10f).lightValue(0).notSolid());
    setRegistryName("pillar");
}

After the closing bracket } of the constructor paste in the code below.

What this does is explained in the AbstractPillarBlock class.

@Override
protected VoxelShape getTopShape() {
    return combineAll(IBooleanFunction.OR, Arrays.asList(TOP));
}

@Override
protected VoxelShape getMiddleShape() {
    return combineAll(IBooleanFunction.OR, Arrays.asList(MIDDLE));
}

@Override
protected VoxelShape getBottomShape() {
    return combineAll(IBooleanFunction.OR, Arrays.asList(BOTTOM));
}

@Override
protected VoxelShape getDefaultShape() {
    return combineAll(IBooleanFunction.OR, Arrays.asList(DEFAULT));
}

The last method you need to add, says what block this block should connect to, which in this case is this block PillarBlock.CustomBlock

If you create another pillar block change PillarBlock to the name of the block class name.

@Override
public BlockState getThisState(IBlockReader world, BlockPos pos) {
    boolean shouldConnectAbove = world.getBlockState(pos.up()).getBlock() instanceof PillarBlock.CustonBlock;
    boolean shouldConnectBelow = world.getBlockState(pos.down()).getBlock() instanceof PillarBlock.Customblock;
    if (shouldConnectAbove) {
        if (shouldConnectBelow) {
            return this.getDefaultState().with(PILLAR_TYPE, PillarSection.MIDDLE);
        }
        return this.getDefaultState().with(PILLAR_TYPE, PillarSection.BOTTOM);
    } else if (shouldConnectBelow) {
        return this.getDefaultState().with(PILLAR_TYPE, PillarSection.TOP);
    }
    return this.getDefaultState().with(PILLAR_TYPE, PillarSection.DEFAULT);
}

Your finished class should look similar to this

assuming you used the same project naming as I have.

package net.mcreator.pillars.block;
import net.mcreator.pillars.AbstractPillarBlock;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.IBooleanFunction;
import java.util.Arrays;
// do not edit below this line ------------------------------------------
import net.minecraft.block.BlockState;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.util.math.BlockPos;


import net.minecraft.world.IBlockReader;
import net.minecraftforge.registries.ObjectHolder;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.api.distmarker.Dist;

import net.minecraft.item.ItemGroup;
import net.minecraft.item.Item;
import net.minecraft.item.BlockItem;
import net.minecraft.client.renderer.RenderTypeLookup;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.block.Block;

import net.mcreator.pillars.PillarsModElements;

@PillarsModElements.ModElement.Tag
public class PillarBlock extends PillarsModElements.ModElement {
    @ObjectHolder("pillars:pillar")
    public static final Block block = null;
    public PillarBlock(PillarsModElements instance) {
        super(instance, 1);
    }

    @Override
    public void initElements() {
        elements.blocks.add(() -> new CustomBlock());
        elements.items
                .add(() -> new BlockItem(block, new Item.Properties().group(ItemGroup.BUILDING_BLOCKS)).setRegistryName(block.getRegistryName()));
    }

    @Override
    @OnlyIn(Dist.CLIENT)
    public void clientLoad(FMLClientSetupEvent event) {
        RenderTypeLookup.setRenderLayer(block, RenderType.getCutout());
    }
// do not edit above this line ------------------------------------------
    public static class CustomBlock extends AbstractPillarBlock {
        private static final VoxelShape[] DEFAULT = {Block.makeCuboidShape(0, 0, 0, 16, 4, 16), Block.makeCuboidShape(2, 4, 2, 14, 12, 14), Block.makeCuboidShape(0, 12, 0, 16, 16, 16)};
        private static final VoxelShape[] TOP = {Block.makeCuboidShape(0, 12, 0, 16, 16, 16), Block.makeCuboidShape(2, 0, 2, 14, 12, 14)};
        private static final VoxelShape[] MIDDLE = {Block.makeCuboidShape(2, 0, 2, 14, 16, 14)};
        private static final VoxelShape[] BOTTOM = {Block.makeCuboidShape(0, 0, 0, 16, 4, 16), Block.makeCuboidShape(2, 4, 2, 14, 16, 14)};


        public CustomBlock() {
            super(Block.Properties.create(Material.ROCK).sound(SoundType.STONE).hardnessAndResistance(2f, 10f).lightValue(0).notSolid());
            setRegistryName("pillar");
        }

        @Override
        protected VoxelShape getTopShape() {
            return combineAll(IBooleanFunction.OR, Arrays.asList(TOP));
        }

        @Override
        protected VoxelShape getMiddleShape() {
            return combineAll(IBooleanFunction.OR, Arrays.asList(MIDDLE));
        }

        @Override
        protected VoxelShape getBottomShape() {
            return combineAll(IBooleanFunction.OR, Arrays.asList(BOTTOM));
        }

        @Override
        protected VoxelShape getDefaultShape() {
            return combineAll(IBooleanFunction.OR, Arrays.asList(DEFAULT));
        }

        @Override
        public BlockState getThisState(IBlockReader world, BlockPos pos) {
            boolean shouldConnectAbove = world.getBlockState(pos.up()).getBlock() instanceof PillarBlock.CustomBlock;
            boolean shouldConnectBelow = world.getBlockState(pos.down()).getBlock() instanceof PillarBlock.CustomBlock;
            if (shouldConnectAbove) {
                if (shouldConnectBelow) {
                    return this.getDefaultState().with(PILLAR_TYPE, PillarSection.MIDDLE);
                }
                return this.getDefaultState().with(PILLAR_TYPE, PillarSection.BOTTOM);
            } else if (shouldConnectBelow) {
                return this.getDefaultState().with(PILLAR_TYPE, PillarSection.TOP);
            }
            return this.getDefaultState().with(PILLAR_TYPE, PillarSection.DEFAULT);
        }
    }
}

Test your mod... and you should have something similar to the demo gif at the top of this post.


Any problems let me know.


If you see any errors please let me know this is my first time writing a tutorial on a forum.

I have many other tutorial ideas 

Edited by nanoxiphias on Sun, 04/04/2021 - 09:02
Last seen on 16:12, 5. May 2021
Joined Nov 2018
Points:

User statistics:

  • Modifications:
  • Forum topics:
  • Wiki pages:
  • Tracker tickets:
  • MCreator plugins:
  • Comments:
Nice tutorial!
Sun, 04/04/2021 - 09:07

Nice tutorial!

Wow, nice idea, and also the…
Sun, 04/04/2021 - 09:12

Wow, nice idea, and also the tutorial is very very well written. Nice work!

Last seen on 01:21, 7. May 2021
Joined Aug 2020
Points:

User statistics:

  • Modifications:
  • Forum topics:
  • Wiki pages:
  • Tracker tickets:
  • MCreator plugins:
  • Comments:
this looks like a great…
Sun, 04/04/2021 - 09:27

this looks like a great tutorial! adding blockstates instead of making separate block variants w/ different models. I was curious about blockstates too, so this one might help me a bit.

if only there's a way that MCreator gets blockstates support, stuff like this would be way easier to make, and users will no longer need to create an alternate block or 2 (or more) and pretend they're "blockstates", but this can suffice for now!