-
Notifications
You must be signed in to change notification settings - Fork 94
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: modmuss <[email protected]>
- Loading branch information
Showing
36 changed files
with
573 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
--- | ||
title: Block States | ||
description: Learn why blockstates are a great way to add visual functionality to your blocks. | ||
authors: | ||
- IMB11 | ||
--- | ||
|
||
# Block States {#block-states} | ||
|
||
A block state is a piece of data attached to a singular block in the Minecraft world containing information on the block in the form of properties - some examples of properties vanilla stores in block states: | ||
|
||
- Rotation: Mostly used for logs and other natural blocks. | ||
- Activated: Heavily used in redstone devices, and blocks such as the furnace or smoker. | ||
- Age: Used in crops, plants, saplings, kelp etc. | ||
|
||
You can probably see why they are useful - they avoid the need to store NBT data in a block entity - reducing the world size, and preventing TPS issues! | ||
|
||
Blockstate definitions are found in the `assets/<mod id here>/blockstates` folder. | ||
|
||
## Example: Pillar Block {#pillar-block} | ||
|
||
<!-- Note: This example could be used for a custom recipe types guide, a condensor machine block with a custom "Condensing" recipe? --> | ||
|
||
Minecraft has some custom classes already that allow you quickly create certain types of blocks - this example goes through the creation of a block with the `axis` property by creating a "Condensed Oak Log" block. | ||
|
||
The vanilla `PillarBlock` class allows the block to be placed in the X, Y or Z axis. | ||
|
||
@[code transcludeWith=:::3](@/reference/latest/src/main/java/com/example/docs/block/ModBlocks.java) | ||
|
||
Pillar blocks have two textures, top and side - they use the `block/cube_column` model. | ||
|
||
As always, with all block textures, the texture files can be found in `assets/<mod id here>/textures/block` | ||
|
||
<DownloadEntry type="Textures" visualURL="/assets/develop/blocks/blockstates_0_large.png" downloadURL="/assets/develop/blocks/condensed_oak_log_textures.zip" /> | ||
|
||
Since the pillar block has two positions, horizontal and vertical, we'll need to make two separate model files: | ||
|
||
- `condensed_oak_log_horizontal.json` which extends the `block/cube_column_horizontal` model. | ||
- `condensed_oak_log.json` which extends the `block/cube_column` model. | ||
|
||
An example of the `condensed_oak_log_horizontal.json` file: | ||
|
||
@[code](@/reference/latest/src/main/resources/assets/fabric-docs-reference/models/block/condensed_oak_log_horizontal.json) | ||
|
||
--- | ||
|
||
::: info | ||
Remember, blockstate files can be found in the `assets/<mod id here>/blockstates` folder, the name of the blockstate file should match the block ID used when registering your block in the `ModBlocks` class. For instance, if the block ID is `condensed_oak_log`, the file should be named `condensed_oak_log.json`. | ||
|
||
For a more in-depth look at all the modifiers available in the blockstate files, check out the [Minecraft Wiki - Models (Block States)](https://minecraft.wiki/w/Tutorials/Models#Block_states) page. | ||
::: | ||
|
||
Next, we need to create a blockstate file. The blockstate file is where the magic happens—pillar blocks have three axes, so we'll use specific models for the following situations: | ||
|
||
- `axis=x` - When the block is placed along the X axis, we will rotate the model to face the positive X direction. | ||
- `axis=y` - When the block is placed along the Y axis, we will use the normal vertical model. | ||
- `axis=z` - When the block is placed along the Z axis, we will rotate the model to face the positive X direction. | ||
|
||
@[code](@/reference/latest/src/main/resources/assets/fabric-docs-reference/blockstates/condensed_oak_log.json) | ||
|
||
As always, you'll need to create a translation for your block, and an item model which parents either of the two models. | ||
|
||
![Example of Pillar block in-game](/assets/develop/blocks/blockstates_1.png) | ||
|
||
## Custom Block States {#custom-block-states} | ||
|
||
Custom block states are great if your block has unique properties - sometimes you may find that your block can re-use vanilla properties. | ||
|
||
This example will create a unique boolean property called `activated` - when a player right-clicks on the block, the block will go from `activated=false` to `activated=true` - changing its texture accordingly. | ||
|
||
### Creating The Property {#creating-the-property} | ||
|
||
Firstly, you'll need to create the property itself - since this is a boolean, we'll use the `BooleanProperty.of` method. | ||
|
||
@[code transcludeWith=:::1](@/reference/latest/src/main/java/com/example/docs/block/custom/PrismarineLampBlock.java) | ||
|
||
Next, we have to append the property to the blockstate manager in the `appendProperties` method. You'll need to override the method to access the builder: | ||
|
||
@[code transcludeWith=:::2](@/reference/latest/src/main/java/com/example/docs/block/custom/PrismarineLampBlock.java) | ||
|
||
You'll also have to set a default state for the `activated` property in the constructor of your custom block. | ||
|
||
@[code transcludeWith=:::3](@/reference/latest/src/main/java/com/example/docs/block/custom/PrismarineLampBlock.java) | ||
|
||
::: warning | ||
Don't forget to register your block using the custom class instead of `Block`! | ||
::: | ||
|
||
### Using The Property {#using-the-property} | ||
|
||
This example flips the boolean `activated` property when the player interacts with the block. We can override the `onUse` method for this: | ||
|
||
@[code transcludeWith=:::4](@/reference/latest/src/main/java/com/example/docs/block/custom/PrismarineLampBlock.java) | ||
|
||
### Visualizing The Property {#visualizing-the-property} | ||
|
||
Before creating the blockstate file, you will need to provide textures for both the activated and deactivated states of the block, as well as the block model. | ||
|
||
<DownloadEntry type="Textures" visualURL="/assets/develop/blocks/blockstates_2_large.png" downloadURL="/assets/develop/blocks/prismarine_lamp_textures.zip" /> | ||
|
||
Use your knowledge of block models to create two models for the block: one for the activated state and one for the deactivated state. Once you've done that, you can begin creating the blockstate file. | ||
|
||
Since you created a new property, you will need to update the blockstate file for the block to account for that property. | ||
|
||
If you have multiple properties on a block, you'll need to account for all possible combinations. For example, `activated` and `axis` would lead to 6 combinations (two possible values for `activated` and three possible values for `axis`). | ||
|
||
Since this block only has two possible variants, as it only has one property (`activated`), the blockstate JSON will look something like this: | ||
|
||
@[code](@/reference/latest/src/main/resources/assets/fabric-docs-reference/blockstates/prismarine_lamp.json) | ||
|
||
--- | ||
|
||
Since the example block is a lamp, we also need to make it emit light when the `activated` property is true. This can be done through the block settings passed to the constructor when registering the block. | ||
|
||
You can use the `luminance` method to set the light level emitted by the block, we can create a static method in the `PrismarineLampBlock` class to return the light level based on the `activated` property, and pass it as a method reference to the `luminance` method: | ||
|
||
@[code transcludeWith=:::5](@/reference/latest/src/main/java/com/example/docs/block/custom/PrismarineLampBlock.java) | ||
|
||
@[code transcludeWith=:::4](@/reference/latest/src/main/java/com/example/docs/block/ModBlocks.java) | ||
|
||
--- | ||
|
||
<!-- Note: This block can be a great starter for a redstone block interactivity page, maybe triggering the blockstate based on redstone input? --> | ||
|
||
Once you've completed everything, the final result should look something like the following: | ||
|
||
<VideoPlayer src="/assets/develop/blocks/blockstates_3.webm" title="Prismarine Lamp Block in-game" /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
--- | ||
title: Creating Your First Block | ||
description: Learn how to create your first custom block in Minecraft. | ||
authors: | ||
- IMB11 | ||
--- | ||
|
||
# Creating Your First Block {#creating-your-first-block} | ||
|
||
Blocks are the building blocks of Minecraft (no pun intended) - just like everything else in Minecraft, they're stored in registries. | ||
|
||
## Preparing Your Blocks Class {#preparing-your-blocks-class} | ||
|
||
If you've completed the [Creating Your First Item](../items/first-item) page, this process will feel extremely familiar - you will need to create a method that registers your block, and it's block item. | ||
|
||
You should put this method in a class called `ModBlocks` (or whatever you want to name it). | ||
|
||
Mojang does something extremely similar like this with vanilla blocks; you can refer to the `Blocks` class to see how they do it. | ||
|
||
@[code transcludeWith=:::1](@/reference/latest/src/main/java/com/example/docs/block/ModBlocks.java) | ||
|
||
--- | ||
|
||
Just like with items, you need to ensure that the class is loaded so that all static fields containing your block instances are initialized. | ||
|
||
You can do this by creating a dummy `initialize` method, which can be called in your mod initializer to trigger the static initialization. | ||
|
||
::: info | ||
If you are unaware of what static initialization is, it is the process of initializing static fields in a class. This is done when the class is loaded by the JVM, and is done before any instances of the class are created. | ||
::: | ||
|
||
```java | ||
public class ModBlocks { | ||
// ... | ||
|
||
public static void initialize() {} | ||
} | ||
``` | ||
|
||
@[code transcludeWith=:::1](@/reference/latest/src/main/java/com/example/docs/block/FabricDocsReferenceBlocks.java) | ||
|
||
## Creating And Registering Your Block {#creating-and-registering-your-block} | ||
|
||
Similarly to items, blocks take a `Blocks.Settings` class in their constructor, which specifies properties about the block, such as its sound effects and mining level. | ||
|
||
We will not cover all the options here—you can view the class yourself to see the various options, which should be self-explanatory. | ||
|
||
For example purposes, we will be creating a simple block that has the properties of dirt, but is a different material. | ||
|
||
::: tip | ||
You can also use `AbstractBlock.Settings.copy(AbstractBlock block)` to copy the settings of an existing block, in this case, we could have used `Blocks.DIRT` to copy the settings of dirt, but for example purposes we'll use the builder. | ||
::: | ||
|
||
@[code transcludeWith=:::2](@/reference/latest/src/main/java/com/example/docs/block/ModBlocks.java) | ||
|
||
To automatically create the block item, we can pass `true` to the `shouldRegisterItem` parameter of the `register` method we created in the previous step. | ||
|
||
### Adding Your Block to an Item Group {#adding-your-block-to-an-item-group} | ||
|
||
Since the `BlockItem` is automatically created and registered, to add it to an item group, you must use the `Block.asItem()` method to get the `BlockItem` instance. | ||
|
||
For this example, we'll use a custom item group created in the [Custom Item Groups](../items/custom-item-groups) page. | ||
|
||
@[code transcludeWith=:::3](@/reference/latest/src/main/java/com/example/docs/block/ModBlocks.java) | ||
|
||
--- | ||
|
||
You should now notice that your block is in the creative inventory, and can be placed in the world! | ||
|
||
![Block in world without suitable model or texture](/assets/develop/blocks/first_block_0.png). | ||
|
||
There are a few issues though - the block item is not named, and the block has no texture, block model or item model. | ||
|
||
## Adding Block Translations {#adding-block-translations} | ||
|
||
To add a translation, you must create a translation key in your translation file - `assets/<mod id here>/lang/en_us.json`. | ||
|
||
Minecraft will use this translation in the creative inventory and other places where the block name is displayed, such as command feedback. | ||
|
||
```json | ||
{ | ||
"block.mod_id.condensed_dirt": "Condensed Dirt" | ||
} | ||
``` | ||
|
||
You can either restart the game or build your mod and press <kbd>F3</kbd> + <kbd>T</kbd> to apply changes - and you should see that the block has a name in the creative inventory and other places such as the statistics screen. | ||
|
||
## Models and Textures {#models-and-textures} | ||
|
||
All block textures can be found in the `assets/<mod id here>/textures/block` folder - an example texture for the "Condensed Dirt" block is free to use. | ||
|
||
<DownloadEntry type="Texture" visualURL="/assets/develop/blocks/first_block_1.png" downloadURL="/assets/develop/blocks/first_block_1_small.png" /> | ||
|
||
To make the texture show up in-game, you must create a block and item model which can be found in the respective locations for the "Condensed Dirt" block: | ||
|
||
- `assets/<mod id here>/models/block/condensed_dirt.json` | ||
- `assets/<mod id here>/models/item/condensed_dirt.json` | ||
|
||
The item model is pretty simple, it can just use the block model as a parent - since most block models have support for being rendered in a GUI: | ||
|
||
@[code](@/reference/latest/src/main/resources/assets/fabric-docs-reference/models/item/condensed_dirt.json) | ||
|
||
The block model however, in our case, must parent the `block/cube_all` model: | ||
|
||
@[code](@/reference/latest/src/main/resources/assets/fabric-docs-reference/models/block/condensed_dirt.json) | ||
|
||
When you load into the game, you may notice that the texture is still missing. This is because you need to add a blockstate definition. | ||
|
||
## Creating the Block State Definition {#creating-the-block-state-definition} | ||
|
||
The blockstate definition is used to instruct the game on which model to render based on the current state of the block. | ||
|
||
For the example block, which doesn't have a complex blockstate, only one entry is needed in the definition. | ||
|
||
This file should be located in the `assets/mod_id/blockstates` folder, and its name should match the block ID used when registering your block in the `ModBlocks` class. For instance, if the block ID is `condensed_dirt`, the file should be named `condensed_dirt.json`. | ||
|
||
@[code](@/reference/latest/src/main/resources/assets/fabric-docs-reference/blockstates/condensed_dirt.json) | ||
|
||
Blockstates are really complex, which is why they are addressed in an upcoming page: [Block States](./blockstates) | ||
|
||
Restarting the game, or reloading via <kbd>F3</kbd> + <kbd>T</kbd> to apply changes - you should be able to see the block texture in the inventory and physically in the world: | ||
|
||
![Block in world with suitable texture and model](/assets/develop/blocks/first_block_4.png) | ||
|
||
## Adding Block Drops {#adding-block-drops} | ||
|
||
When breaking the block in survival, you may see that the block does not drop - you might want this functionality, however to make your block drop as an item on break you must implement its loot table - the loot table file should be placed in the `data/<mod id here>/loot_tables/blocks/` folder. | ||
|
||
::: info | ||
For a greater understanding of loot tables, you can refer to the [Minecraft Wiki - Loot Tables](https://minecraft.wiki/w/Loot_table) page. | ||
::: | ||
|
||
@[code](@/reference/latest/src/main/resources/data/fabric-docs-reference/loot_tables/blocks/condensed_dirt.json) | ||
|
||
This loot table provides a single item drop of the block item when the block is broken, and when it is blown up by an explosion. | ||
|
||
## Recommending a Harvesting Tool {#recommending-a-harvesting-tool} | ||
|
||
You may also want your block to be harvestable only by a specific tool - for example, you may want to make your block faster to harvest with a shovel. | ||
|
||
All the tool tags should be placed in the `data/minecraft/tags/mineable/` folder - where the name of the file depends on the type of tool used, one of the following: | ||
|
||
- `hoe.json` | ||
- `axe.json` | ||
- `pickaxe.json` | ||
- `shovel.json` | ||
|
||
The contents of the file are quite simple - it is a list of items that should be added to the tag. | ||
|
||
This example adds the "Condensed Dirt" block to the `shovel` tag. | ||
|
||
@[code](@/reference/latest/src/main/resources/data/minecraft/tags/mineable/shovel.json) | ||
|
||
## Mining Levels {#mining-levels} | ||
|
||
Similarly, the mining level tag can be found in the same folder, and respects the following format: | ||
|
||
- `needs_stone_tool.json` - A minimum level of stone tools | ||
- `needs_iron_tool.json` - A minimum level of iron tools | ||
- `needs_diamond_tool.json` - A minimum level of diamond tools. | ||
|
||
The file has the same format as the harvesting tool file - a list of items to be added to the tag. | ||
|
||
## Extra Notes {#extra-notes} | ||
|
||
If you're adding multiple blocks to your mod, you may want to consider using [Data Generation](https://fabricmc.net/wiki/tutorial:datagen_setup) to automate the process of creating block and item models, blockstate definitions, and loot tables. |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
12 changes: 12 additions & 0 deletions
12
reference/latest/src/main/java/com/example/docs/block/FabricDocsReferenceBlocks.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.example.docs.block; | ||
|
||
import net.fabricmc.api.ModInitializer; | ||
|
||
// :::1 | ||
public class FabricDocsReferenceBlocks implements ModInitializer { | ||
@Override | ||
public void onInitialize() { | ||
ModBlocks.initialize(); | ||
} | ||
} | ||
// :::1 |
Oops, something went wrong.