Skip to main content

Basic Blocks

In this tutorial we will register a simple block with a texture and a loot table. It will be a similar process to basic items.

Concepts

Blocks are very similar to items. They must be registered so the game knows about them. Each type block is an instance of the Block class (not each physical block in the world). Basic traits of your block can be set with a properties object but more complex behavior will require your own class that extends Block.

New Block

In your init package make a new class called BlockInit. The code here is mostly the same as in ItemInit. Just make sure to say Block instead of Item everywhere. The string you pass the register function is the block's registry name which will be used for naming asset files later.

public class BlockInit {
public static final DeferredRegister<Block> BLOCKS = DeferredRegister.create(ForgeRegistries.BLOCKS, FirstModMain.MOD_ID);

public static final RegistryObject<Block> SMILE_BLOCK = BLOCKS.register("smile_block",
() -> new Block());
}

The Block constructor in the supplier takes a Block.Properties object made by calling the Block.Properties.of  method. This takes a Material which sets a few characteristics about your block like whether its flammable, how it reacts to pistons, default sounds, whether it blocks player motion, and what tools can mine it by default. Vanilla has many options to chose from, just let your IDE autocomplete from Material.

Then your Properties object has many other methods you can call to set different traits, just like we did with items. strength lets you pass in how long it takes to break and how resistant to explosions it is. You have to call requiresCorrectToolForDrops if it should be like stone and drop nothing without the tool (which tool is set by tags in the next section).  If you want it to be a light source you can use lightLevel with a lambda expression that maps a blockstate to a value from 1 to 16. There are many more like friction (used by ice), speedFactor (used by soul sand) and jumpFactor (used by honey). So that supplier might looks something like this:

() -> new Block(Block.Properties.of(Material.STONE).strength(4f, 1200f).requiresCorrectToolForDrops().lightLevel((state) -> 15))

You can also use Block.Properties.copy(ANOTHER_BLOCK) to avoid writing things out repeatedly. All vanilla blocks can be accessed with Blocks.INSERT_NAME_HERE so you can copy properties from one of them if you feel like it. Or avoid redundancy by referencing YOUR_BLOCK.get()

Tags

To make your block require a certain type and level of tool, you must add it to a tag. Tags are how minecraft catagories blocks/items behavior in a way accessible to datapacks. For example, there is a tag for sapplings and one for crops.

Vanilla adds tags for each tool type: mineable/pickaxe, mineable/axe, mineable/shovel, mineable/hoe and for each harvest level: needs_stone_tool, needs_iron_tool, needs_diamond_tool. You can add your block to some of these tags to make certain tools mine it quickly and respect the requiresCorrectToolForDrops() call on the Block.Properties.

Create the folders src/main/resources/data/minecraft/tags/blocks, in that directory create files for each tag you want to add your block to. They should be named tag_name.json. If the tag name has a / in it, that part before it is the name of the folder (ie, the shovel.json file goes in the mineable folder). These files will contain a json object with the replace key set to false (so you don't remove vanilla behavior) and the values key set to a list of registry names for the blocks you want to behave as described by the tag.

For example, I'll make the file needs_iron_tool.json. The mineable folder will contain the file pickaxe.json. Both will contain the following text:

{
"replace": false,
"values": [
"firstmod:smile_block"
]
}

This will make my block mine quickly with a pickaxe and only drop when using a pickaxe of iron or higher. Remember you must also call requiresCorrectToolForDrops() on your block properties object for this to work.

More info about this system: https://gist.github.com/gigaherz/691f528a61f631af90c9426c076a298a

Block Item

You need a BlockItem to place your block. You can register it manually like your other items but that's tedious so lets make it automatic. We will use the events system to run some code when the game registers all the other items. You can just copy this code for now or read the events tutorial for a more detailed explanation of how events work.

At the top of your class add this line to allow it to subscribe to events.

@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
public class BlockInit {
// ...previous code here...
}

Then make a static function with the SubscribeEvent annotation. Its argument will be the RegisterEvent so it fires when things are supposed to be registered. Each registry is processed severalty so we make sure that this event fired for items.

In that function get the Item registry and loop through all the blocks. For each block, we make an Item.Properties that puts it in our creative tab. Then we make a BlockItem with those properties to place our block. We register the BlockItem with the same registry name as the block.

@SubscribeEvent
public static void onRegisterItems(final RegisterEvent event) {
if (event.getRegistryKey().equals(ForgeRegistries.Keys.ITEMS)){
BLOCKS.getEntries().forEach( (blockRegistryObject) -> {
Block block = blockRegistryObject.get();
Item.Properties properties = new Item.Properties().tab(ItemInit.ModCreativeTab.instance);
Supplier<Item> blockItemFactory = () -> new BlockItem(block, properties);
event.register(ForgeRegistries.Keys.ITEMS, blockRegistryObject.getId(), blockItemFactory);
});
}
}

Instead of doing it this way you could manually register a BlockItem for each of your blocks in your ItemInit class but that's really tedious so I'd advise doing it this way. There might be some blocks you make later where you'll what a unique block item. All you'd have to do is add an if statement to check for that block and create the new BlockItem differently.

Main Class

In the constructor of your main class add this line to call the register method of your DeferredRegister (same as for items).

BlockInit.BLOCKS.register(modEventBus);

Assets

In your project folder go to src/main/resources/assets/mod_id. Make a new folder called blockstates and in your models folder make a new folder called block. In textures make a new folder called blocks and put the png image you want to use for your block's texture. Then go out to src/main/resources/data/mod_id and make a folder called loot_tables and in that make a folder called blocks.

In blockstates make a file called block_name.json (replace block_name with whatever string you passed in as your registry name). Since this is a simple block, we just need one varient that points to a model. Make sure you change firstmod to your mod id and smile_block to the registry name of your block.

{
"variants": {
"": {
"model": "firstmod:block/smile_block"
}
}
}

This is the simplest possible blockstate definition. More complex blocks can have different sides (like grass), rotation (like furnaces and chests), age (like crops or ice) and you can define your own custom properties. The possibilities are endless and will likely be discussed more in depth in another tutorial.

In models/block make a file called block_name.json. This is the file you'd change if you want different sides of the block to look different (like a grass block) but since I don't, I'll just point to one texture (make sure to change smile_block to the name of your image file).

{
"parent": "block/cube_all",
"textures": {
"all": "firstmod:blocks/smile_block"
}
}

In models/item make a block_name.json file that just parents off your block model

{
"parent": "firstmod:block/smile_block"
}

In lang/en_us.json add a line that gives your block a name. Remember to change the mod id and block registry name.

"block.firstmod.smile_block": "Smiley Block"

In loot_tables/blocks make block_name.json. This sets what drops when you break the block. This is a simple loot table that just drops the block's item but it could be anything.

{
"type": "minecraft:block",
"pools": [
{
"rolls": 1.0,
"entries": [
{
"type": "minecraft:item",
"name": "firstmod:smile_block"
}
]
}
]
}

Loot tables are also how drops from entities are determined and what you find in chests. They deserve a tutorial of their own but in the mean time, take a look at vanilla's loot tables and the wiki for inspiration.

You should end up with a file structure like this:

- src/main/resources/
- assets/modid/
- blockstates/
- block_name.json
- models/block/
- block_name.json
- textures/blocks/
- block_name.png
- data/modid/
- loot_tables/blocks
- block_name.json

Data Generators

If your mod has a lot of blocks that just use their own basic texture, it can be tedious (and error prone) to repeatedly copy the model/blockstate/loot_table json file, just changing a single line each time. Luckily, Minecraft provides a way to generate these files from code. This will be covered in detail in a future tutorial. Join the discord server to be notified when it is released.

Run the game

If we run the game, we can see that the block shows up in our creative tab. We can place it and break it with an iron pickaxe

Later versions

This tutorial is for 1.19.2, NOT 1.19.3 or 1.19.4. Mojang changed how they deal with breaking changes in minor versions so some stuff will be different. I'll probably update it at some point but for now see these resources for an overview of changes.