MultiLoader 26.1+ · Part 4

Creating Blocks (MultiLoader 26.1+)

BEGINNER MULTILOADER 26.1-26.1.2 22 min read · Jun 12, 2026
MultiLoader 26.1+ · 17 parts
1 Getting Started with MultiLoader 26.1+ 2 Setting Up RegistrationUtils (MultiLoader 26.1+) 3 Creating Items (MultiLoader 26.1+) 4 Creating Blocks (MultiLoader 26.1+) 5 Data Generation: Block & Item Models (MultiLoader 26.1+) 6 Data Generation: Block Loot Tables (MultiLoader 26.1+) 7 Data Generation: Crafting Recipes (MultiLoader 26.1+) 8 Data Generation: Block & Item Tags (MultiLoader 26.1+) 9 Data Generation: Language Files (MultiLoader 26.1+) 10 Data Generation: Advancements (MultiLoader 26.1+) 11 Data Generation: Sound Definitions (MultiLoader 26.1+) 12 Data Generation: Particle Descriptions (MultiLoader 26.1+) 13 Data Generation: Enchantments (MultiLoader 26.1+) 14 Custom Food Items (MultiLoader 26.1+) 15 Custom Tools (MultiLoader 26.1+) 16 Custom Armour (MultiLoader 26.1+) 17 Block Entities (MultiLoader 26.1+)

Now that we have items working, it is time to create a custom block. Blocks in Minecraft are closely tied to their items (the BlockItem is what you hold in your inventory), so our registry helper will handle registering both at once.

NOTE
Make sure you have completed the Creating Items tutorial first. We rely on the ItemRegistry here to register the BlockItem automatically.

Creating the Block Registry

Create a new BlockRegistry class in your registry package. We will add a private helper method called registerBlock that simultaneously registers the block and its corresponding BlockItem. We will also create another helper method getBlockProperties to set the properties of the block itself, as well as setting the ID of the block:

java
public class BlockRegistry {
public static final RegistrationProvider<Block> BLOCKS =
RegistrationProvider.get(Registries.BLOCK, Constants.MOD_ID);
public static BlockBehaviour.Properties getBlockProperties(String name, BlockBehaviour.Properties base) {
return base.setId(ResourceKey.create(Registries.BLOCK, Identifier.fromNamespaceAndPath(Constants.MOD_ID, name)));
}
private static <T extends Block> RegistryObject<Block, T> registerBlock(String name, Supplier<T> supplier) {
var block = BLOCKS.register(name, supplier);
ItemRegistry.ITEMS.register(name, () -> new BlockItem(block.get(), ItemRegistry.getItemProperties(name)));
return block;
}
public static void init() {}
}

The registerBlock helper registers the block under your mod's namespace, then immediately registers a matching BlockItem so the block is obtainable as an item. Both share the same registry name, which is the standard Minecraft convention.

In 26.1, every block (just like items) must be given an explicit registry key via Block.Properties.setId(). Without it the game throws at startup when it tries to look up the block's key. The key is a ResourceKey<Block> built from your mod ID and the block's registry name, and it must match the name you pass to BLOCKS.register(). Passing the name as a parameter to the helper keeps them in sync automatically.

Defining a Block

Add a public static final field for your first block. We will create a simple dirt variant called New Dirt by copying all properties from vanilla dirt:

java
public static final RegistryObject<Block, Block> NEW_DIRT = registerBlock("new_dirt",
() -> new Block(BlockBehaviour.Properties.ofFullCopy(Blocks.DIRT)));

ofFullCopy copies every property from the target block, including hardness, blast resistance, sound, and tool requirement. You can also use the builder pattern (BlockBehaviour.Properties.of()...) to set properties manually.

Call BlockRegistry.init() from CommonClass.init():

java
public class CommonClass {
public static void init() {
ItemRegistry.init();
BlockRegistry.init();
CreativeTabRegistry.init();
}
}

Block Model and Texture

Create the block model JSON at src/main/resources/assets/examplemod/models/block/new_dirt.json:

json
{
"parent": "minecraft:block/cube_all",
"textures": {
"all": "examplemod:block/new_dirt"
}
}

The cube_all parent applies the same texture to every face. Create a 16x16 PNG texture at src/main/resources/assets/examplemod/textures/block/new_dirt.png.

As introduced in the Items tutorial, 26.1 uses an items/ definition file to control how the block looks in your inventory. Create src/main/resources/assets/examplemod/items/new_dirt.json:

json
{
"model": {
"type": "minecraft:model",
"model": "examplemod:block/new_dirt"
}
}

For blocks, the item definition points straight at the block model rather than a separate item model. The block model already describes the full cube geometry, so the inventory slot renders it directly without needing a dedicated models/item/ file.

Blockstate File

The blockstate file maps block property combinations to model variants. For a simple block with no properties, there is just one variant with an empty string key. Create src/main/resources/assets/examplemod/blockstates/new_dirt.json:

json
{
"variants": {
"": { "model": "examplemod:block/new_dirt" }
}
}
TIP
For more complex blocks (directional, powered, waterlogged, etc.) you add extra variants here. See the Minecraft Wiki on Block States for the full format.

Creative Tab for Blocks

Open CreativeTabRegistry and add a second tab for your blocks, or add the block to the existing items tab. Here we will keep them separate:

java
public static final RegistryObject<CreativeModeTab, CreativeModeTab> BLOCKS_TAB =
CREATIVE_MODE_TABS.register(Constants.MOD_ID + "_blocks_tab", () ->
CreativeModeTab.builder(CreativeModeTab.Row.TOP, 1)
.icon(() -> new ItemStack(BlockRegistry.NEW_DIRT.get()))
.displayItems((params, output) -> {
output.accept(BlockRegistry.NEW_DIRT.get());
})
.title(Component.translatable("itemGroup." + Constants.MOD_ID + ".blocks_tab"))
.build()
);

Language File

Add display names for the block, its item, and the new creative tab to your en_us.json language file:

json
{
"item.examplemod.iron_stick": "Iron Stick",
"item.examplemod.new_dirt": "New Dirt",
"block.examplemod.new_dirt": "New Dirt",
"itemGroup.examplemod.tab": "Example Mod Items",
"itemGroup.examplemod.blocks_tab": "Example Mod Blocks"
}

Testing In-Game

Run the Fabric Client or NeoForge Client. Open creative mode and you should see your new Blocks tab with New Dirt in it. Place the block and verify it renders correctly with your texture. You can also use:

shell
/give @s examplemod:new_dirt

Breaking the block will not drop anything yet, as that requires a loot table. We cover that in the Data Generation tutorials coming up next.

You can find the source for this tutorial here:

View Source on GitHub
NEXT IN SERIES

Data Generation: Block & Item Models (MultiLoader 26.1+)

Configure NeoForge datagen to write resources into the common project, create a ModelProvider using BlockModelGenerators, and hook it into GatherDataEvent.Client to auto-generate blockstate, model, and item definition files.

Continue →