User Tools

Site Tools


tutorial:blockstate

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
tutorial:blockstate [2019/08/28 21:53] – add new section header for JSON stuff b0undarybreakertutorial:blockstate [2023/11/18 08:13] (current) – [Adding models for your blockstates] update Minecraft Wiki link solidblock
Line 1: Line 1:
 ====== Giving a block state ====== ====== Giving a block state ======
-Every type of block in Minecraft is represented by a singular ''Block'' instance. +Every type of block in Minecraft is represented by a singular ''Block'' instance. This makes it impossible to change a specific block's state by simply changing the ''Block'' instance's state, as every other block of that type will be affected! But, what if you //do// want to give a singular block state, so it can change based on some condition? 
-This makes it impossible to change a specific block's state by simply changing the ''Block'' instance's state, + 
-as every other block of that type will be affected! +This is what ''BlockState''s are for. Say we wanted a block that can summon lightning, but only when charged up.   
-But, what if you //do// want to give a singular block state, so it can change based on some condition? +
-This is what ''BlockState''s are for.  +
-Say we wanted a block to have a hardness of ''0.5'' normally, but if we right click it before we try to break it, +
-it would become harder and gain a hardness of ''2''.   +
      
-First we define the boolean property of the block - whether or not it is hard:+First we define the boolean property of the block - whether or not it is charged (careful not to import the wrong ''BooleanProperty''), and register the block within the mod initializer. (If you directly register the block in the static field in the ''ChargeableBlock'' class, the mod initializer may totally ignore it if the class is not initialized.) 
 + 
 +In fact, you can also use existing properties defined in vanilla, which can be found in ''Properties'' (''net.minecraft.state.property.Properties''). If you intend to define other types of properties, you may use ''IntProperty'' or ''EnumProperty''.
 <code java> <code java>
-public class MyBlock extends Block { +public class ChargeableBlock extends Block { 
-    public static final BooleanProperty HARDENED = BooleanProperty.of("hardened");+    public static final BooleanProperty CHARGED = BooleanProperty.of("charged"); 
 +     
 +    // The block instance. You can place it anywhere. Make the class is initialized. 
 +    public static final ChargeableBlock CHARGEABLE_BLOCK = new ChargeableBlock(FabricBlockSettings.copyOf(Blocks.STONE)); 
 +
 +</code> 
 +<code java> 
 +public class ExampleMod implements ModInitializer { 
 +    @Override 
 +    public void onInitialize() { 
 +        Registry.register(Registries.BLOCK, new Identifier("tutorial", "chargeable_block"), ChargeableBlock.CHARGEABLE_BLOCK); 
 +        Registry.register(Registries.ITEM, new Identifier("tutorial", "chargeable_block"), new BlockItem(ChargeableBlock.CHARGEABLE_BLOCK, new FabricItemSettings()); 
 +    }
 } }
 </code> </code>
-Then we need to register the property by overriding ''appendProperties'':+Then we need to register the properties of the block by overriding ''appendProperties'', and then add the ''CHARGED'' property:
 <code java> <code java>
-public class MyBlock extends Block {+public class ChargeableBlock extends Block {
     [...]     [...]
     @Override     @Override
-    protected void appendProperties(StateFactory.Builder<Block, BlockState> stateFactory) { +    protected void appendProperties(StateManager.Builder<Block, BlockState> builder) { 
-        stateFactory.add(HARDENED);+        builder.add(CHARGED);
     }     }
          
 } }
 </code> </code>
-Then we need to set the default state of our property in the block constructor:+Then we need to set the default state of our property in the block constructor (To set multiple properties, chain ''with()'' calls):
 <code java> <code java>
-public class MyBlock extends Block {+public class ChargeableBlock extends Block {
     [...]     [...]
-    public MyBlock(Settings settings) {+    public ChargeableBlock(Settings settings) {
         super(settings);         super(settings);
-        setDefaultState(getStateFactory().getDefaultState().with(HARDENED, false));+        setDefaultState(getDefaultState().with(CHARGED, false));
     }     }
          
 } }
 </code> </code>
- +Now, we need to be able to charge the block, through the ''onUse'' method, with invoking the ''world.setBlockState()'' method inside of it (The ''playSound'' is completely optional, but it helps us know that the block is charged).
-Now, to set the property we need to call   +
- +
-''world.setBlockState(<block-position>, <block-instance>.getDefaultState().with(<property-name>, <new-value>)'':   +
-      +
-(Replace ''MyBlocks.MY_BLOCK_INSTANCE'' with your block's instance)+
 <code java> <code java>
-public class MyBlock extends Block {+public class ChargeableBlock extends Block {
     [...]     [...]
     @Override     @Override
-    public boolean activate(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult blockHitResult) { +    public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { 
-        world.setBlockState(pos, MyBlocks.MY_BLOCK_INSTANCE.getDefaultState().with(HARDENED, true)); +        player.playSound(SoundEvents.BLOCK_RESPAWN_ANCHOR_CHARGE, 1, 1); 
-        return true;+        world.setBlockState(pos, state.with(CHARGED, true)); 
 +        return ActionResult.SUCCESS;
     }     }
 } }
 </code> </code>
-And to use the property we call ''blockState.get(<our-property-name>)'':+ 
 +And finally, to use the ''CHARGED'' propertywe call ''onSteppedOn'', with ''world.getBlockState(pos).get(CHARGED)'' inside of it:
 <code java> <code java>
-public class MyBlock extends Block {+public class ChargeableBlock extends Block {
     [...]     [...]
     @Override     @Override
-    public float getHardness(BlockState blockState, BlockView blockView, BlockPos pos) { +    public void onSteppedOn(World world, BlockPos pos, BlockState state, Entity entity) { 
-        boolean hardened = blockState.get(HARDENED); +        if (world.getBlockState(pos).get(CHARGED)){ 
-        if(hardenedreturn 2.0f+            // Summoning the Lighting Bolt at the block 
-        else return 0.5f;+            LightningEntity lightningEntity = (LightningEntity) EntityType.LIGHTNING_BOLT.create(world); 
 +            lightningEntity.refreshPositionAfterTeleport(Vec3d.ofBottomCenter(pos)); 
 +            world.spawnEntity(lightningEntity)
 +        
 + 
 +        world.setBlockState(pos, state.with(CHARGED, false)); 
 +        super.onSteppedOn(world, pos, state, entity);
     }     }
 } }
Line 67: Line 80:
 ==== Adding models for your blockstates ==== ==== Adding models for your blockstates ====
  
-You can also make the texture and model of your block change based on the state. This is done through a JSON file called a Blockstate JSON. All blocks need a blockstate JSON, whether they have multiple states or not, but the contents of the JSON can be as simple or complex as you like. Let's say you register an instance of ''MyBlock'' to the ID ''mymod:my_block''. Minecraft would look for a file at the location ''src/main/resources/assets/mymod/blockstates/my_block.json'' to load the state from. If you don't want your block to change models between states, the blockstate JSON can be very simpleIt would look something like this:+You can also make the texture and model of your block change based on the state. This is done through a JSON file called a "blockstate JSON". All blocks need a blockstate JSON, whether they have multiple states or not, but the contents of the JSON can be as simple or complex as you like. If you want to change the textures of your block based on the state, you //will// need multiple models.
  
-<code json>+Let's say you register an instance of ''Chargeable'' to the ID ''tutorial:chargeable_block''. Minecraft would look for a file at the location ''src/main/resources/assets/tutorial/blockstates/chargeable_block.json'' to load the state from. If you don't want your block to change models between states, the blockstate JSON can be very simple. It would look something like this: 
 + 
 +<code JavaScript resources/assets/tutorial/blockstates/chargeable_block.json>
 { {
     "variants": {     "variants": {
-        "": { "model": "mymod:block/my_block" }+        "": { "model": "tutorial:block/chargeable_block" }
     }     }
 } }
Line 79: Line 94:
 Let's break this simple example down. There are a couple important parts to this JSON: Let's break this simple example down. There are a couple important parts to this JSON:
  
-The ''"variants"'' block will be where all possible variations for your blockstate go. We'll explore variants more in a little. +  * The ''%%"variants"%%'' defines what model should each possible blockstate use. We'll explore variants more in a little. 
-A variant named ''""'' will apply to //every// permutation of a blockstate. If you have a ''""'' variant, you shouldn't have any other variants in the JSON, or Minecraft will get upset. +  A variant named ''%%""%%'' (empty string) will apply to //every// permutation of a blockstate. If you have a ''%%""%%'' variant, you shouldn't have any other variants in the JSON, or Minecraft will get upset. 
-The object assigned to the ''""'' variant can have various properties added to it like rotation or texture manipulation. Check out the linked Model page below for more documentation on what properties can be added. All variants //must// contain a ''"model"'' property. +  The object assigned to the ''%%""%%'' variant can have various properties added to it like rotation or texture manipulation. Check out the linked Model page below for more documentation on what properties can be added. All variants //must// contain a ''%%"model"%%'' property. 
-The ''"model"'' property is always passed an ID of a model. In this case, the game will look at the location ''src/main/resources/assets/mymod/models/block/my_block.json''. The ID here can be anything. It doesn't //need// to be the same as your block's ID, but if you only have one variant, it probably should. Block models have their own setup, which is documented very well on the Minecraft wiki page linked below. You can either write the JSON by hand or use a program like [[https://blockbench.net|Blockbench]] to generate it more easily.+  The ''%%"model"%%'' property is always passed an ID of a model. In this case, the game will look at the location ''src/main/resources/assets/tutorial/models/block/chargeable_block.json''. The ID here can be anything. It doesn't //need// to be the same as your block's ID, but if you only have one variant, it probably should. Block models have their own setup, which is documented very well on the Minecraft wiki page linked below. You can either write the JSON by hand or use a program like [[https://blockbench.net|Blockbench]] to generate it more easily.
  
-If you //do// want to have different models for each blockstate, you'd want to add multiple variants. For the same ''src/main/resources/assets/mymod/blockstates/my_block.json'' location we used above, your could would probably look like such:+If you want to have different models for each blockstate, you should add multiple variants. For the same ''src/main/resources/assets/tutorial/blockstates/chargeable_block.json'' location we used above, your model file would probably look like such:
  
-<code json>+<code JavaScript resources/assets/tutorial/blockstates/chargeable_block.json>
 { {
     "variants": {     "variants": {
-        "hardened=false": { "model": "mymod:block/my_block" }, +        "charged=false": { "model": "tutorial:block/chargeable_block" }, 
-        "hardened=true": { "model": "mymod:block/my_block_hardened" }+        "charged=true": { "model": "tutorial:block/chargeable_block_charged" }
     }     }
 } }
 </code> </code>
  
-In this JSON, there are two variants, one for each possibility of the ''HARDENED'' property we defined above. Since we gave the property the string name of ''hardened'' in the Java, that's what we use here. Booleans only have two states, but if you use properties based on integers or enums, you'll have more variants. Variants are based on possible permutations of the properties added to your block. A property can be totally ignored in the blockstate JSON if you want, like in the first blockstate JSON where we ignored the ''hardened'' property, but if you want to include a property in one variant, it must be included in //all// variants. If ''mymod:my_block'' also had a boolean property called ''glowing'', and you wanted to change the model based on whether it was glowing and based on whether it was hardened, you would need four variants: hardened off and glowing off, hardened on and glowing off, hardened off and glowing on, and hardened on and glowing on. The same model can be assigned to multiple variants if you need it to be.+In this JSON, there are two variants, one for each possibility of the ''CHARGED'' property we defined above. Since we gave the property the string name of ''charged'' in the Java, that's what we use here. Booleans only have two states, but if you use properties based on integers or enums, you'll have more variants.  
 + 
 +Variants are based on possible permutations of the properties added to your block. A property can be totally ignored in the blockstate JSON if you want, like in the first blockstate JSON where we ignored the ''charged'' property, but if you want to include a property in one variant, it must be included in //all// variants. If ''tutorial:chargeable_block'' also had a boolean property called ''glowing'', and you wanted to change the model based on whether it was glowing and based on whether it was charged, you would need four variants: charged off and glowing off, charged on and glowing off, charged off and glowing on, and charged on and glowing on. The same model can be assigned to multiple variants if you need it to be. 
 + 
 +This is only a simple introduction to blockstate JSONs. All of the tricks you can do with blockstate and model JSONs are documented on the [[https://minecraft.wiki/Model|Minecraft wiki page]], along with examples of how the features are used in vanilla. Best of luck!
  
-This is only a simple introduction to blockstate JSONs. All of the tricks you can do with blockstate and model JSONs are documented on the [[https://minecraft.gamepedia.com/Model|Minecraft wiki]], along with examples of how the features are used in vanilla. Best of luck! 
 ==== A note about performance ==== ==== A note about performance ====
-Every possible state of a block is registered at the start of the game. This means that if you have 14 boolean properties, the block has 2^14 = 16384 different states and 2^14 states are registered. For this reason blocks should not contain too many blockstate properties. Rather, blockstates should be mostly reserved for visuals, and [[tutorial:blockentity|Block Entities]] should be used for more advanced state.+Every possible blockstate for a block is registered when the ''Block'' object is initialized. This means that if you have 14 boolean properties, the block has 2^14 = 16384 different states and 2^14 states are registered. For this reasonblocks should not contain too many blockstate properties. Rather, blockstates should be mostly reserved for visuals, and [[tutorial:blockentity|Block Entities]] should be used for more advanced state
 + 
 +As all possible states have been built, an equal state for a block is a same object, and the ''with'' method returns an existing object, instead of creating a new object - which means, for example, ''CHARGEABLE_BLOCK.getDefaultState().with(CHARGED, true) == CHARGEABLE_BLOCK.getDefaultState().with(CHARGED, true)'' returns ''true''.
tutorial/blockstate.1567029186.txt.gz · Last modified: 2019/08/28 21:53 by b0undarybreaker