User Tools

Site Tools


tutorial:blockentity

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
Next revisionBoth sides next revision
tutorial:blockentity [2020/03/30 20:40] draylartutorial:blockentity [2021/06/11 02:17] – Update BE ffrann
Line 11: Line 11:
 <code java> <code java>
 public class DemoBlockEntity extends BlockEntity { public class DemoBlockEntity extends BlockEntity {
-   public DemoBlockEntity() { +   public DemoBlockEntity(BlockPos pos, BlockState state) { 
-      super(ExampleMod.DEMO_BLOCK_ENTITY);+      super(ExampleMod.DEMO_BLOCK_ENTITY, pos, state);
    }    }
 } }
 </code> </code>
  
-Bellow will show you how to create the ''ExampleMod.DEMO_BLOCK_ENTITY'' field.+Below will show you how to create the ''ExampleMod.DEMO_BLOCK_ENTITY'' field.
  
 You can simply add variables to this barebone class or implement interfaces such as ''Tickable'' and ''Inventory'' to add more functionality. ''Tickable'' provides a single ''tick()'' method, which is called once per tick for every loaded instance of your Block in the world., while ''Inventory'' allows your BlockEntity to interact with automation such as hoppers - there will likely be a separate tutorial dedicated entirely to this interface later. You can simply add variables to this barebone class or implement interfaces such as ''Tickable'' and ''Inventory'' to add more functionality. ''Tickable'' provides a single ''tick()'' method, which is called once per tick for every loaded instance of your Block in the world., while ''Inventory'' allows your BlockEntity to interact with automation such as hoppers - there will likely be a separate tutorial dedicated entirely to this interface later.
  
-===== Registring your BlockEntity =====+===== Registering your BlockEntity =====
  
-Once you have created the ''BlockEntity'' class, you will need to register it for it to function. The first step of this process is to create a ''BlockEntityType'', which links your ''Block'' and ''BlockEntity'' together. Assuming your ''Block'' has been created and saved to a local variable ''DEMO_BLOCK'', you would create the matching ''BlockEntityType'' with the line below. ''modid:demo'' should be replaced by your Mod ID and the name you want your ''BlockEntity'' to be registered under.+Once you have created the ''BlockEntity'' class, you will need to register it for it to function. The first step of this process is to create a ''BlockEntityType'', which links your ''Block'' and ''BlockEntity'' together. Assuming your ''Block'' has been created and saved to a local variable ''DEMO_BLOCK'', you would create the matching ''BlockEntityType'' with the line below. In this tutorial, the ID of the block entity is ''tutorial:demo_block_entity''.
  
 The ''BlockEntityType'' should be registered in your ''onInitialize'' method, this is to ensure it gets registered at the correct time. The ''BlockEntityType'' should be registered in your ''onInitialize'' method, this is to ensure it gets registered at the correct time.
Line 32: Line 32:
 @Override @Override
 public void onInitialize() { public void onInitialize() {
-   DEMO_BLOCK_ENTITY = Registry.register(Registry.BLOCK_ENTITY_TYPE, "modid:demo", BlockEntityType.Builder.create(DemoBlockEntity::new, DEMO_BLOCK).build(null));+   DEMO_BLOCK_ENTITY = Registry.register(Registry.BLOCK_ENTITY_TYPE, "tutorial:demo_block_entity", FabricBlockEntityTypeBuilder.create(DemoBlockEntity::new, DEMO_BLOCK).build(null));
 } }
 </code> </code>
Line 38: Line 38:
 ==== Connecting a Block Entity to a Block ==== ==== Connecting a Block Entity to a Block ====
  
-Once your ''BlockEntityType'' has been created and registered as seen above, you can simply implement ''BlockEntityProvider'' in your ''Block'' class:+Once your ''BlockEntityType'' has been created and registered, you'll need a block that is associated with it. You can do this by implementing ''BlockEntityProvider'' and overriding ''createBlockEntity''. Each time your block is placed, your Block Entity will spawn alongside it.
  
 <code java> <code java>
-@Override +public class DemoBlock extends Block implements BlockEntityProvider { 
-public BlockEntity createBlockEntity(BlockView blockView) { + 
-   return new DemoBlockEntity();+   [...] 
 + 
 +   @Override 
 +   public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { 
 +      return new DemoBlockEntity(pos, state); 
 +   }
 } }
 </code> </code>
Line 49: Line 54:
 ===== Serializing Data ===== ===== Serializing Data =====
  
-If you want to store any data in your ''BlockEntity'', you will need to save and load it, or it will only be held while the ''BlockEntity'' is loaded, and the data will reset whenever you come back to it. Luckily, saving and loading is quite simple - you only need to override ''toTag()'' and ''fromTag()''+If you want to store any data in your ''BlockEntity'', you will need to save and load it, or it will only be held while the ''BlockEntity'' is loaded, and the data will reset whenever you come back to it. Luckily, saving and loading is quite simple - you only need to override ''writeNbt()'' and ''readNbt()''
  
-''toTag()'' returns a ''CompoundTag'', which should contain all of the data in your ''BlockEntity''. This data is saved to the disk and also send through packets if you need to sync your ''BlockEntity'' data with clients. It is very important to call the default implementation of ''toTag'', as it saves "Identifying Data" (position and ID) to the tag. Without this, any further data you try and save will be lost as it is not associated with a position and ''BlockEntityType''. Knowing this, the example below demonstrates saving an integer from your ''BlockEntity'' to the tag. In the example, the integer is saved under the key ''"number"'' - you can replace this with any string, but you can only have one entry for each key in your tag, and you will need to remember the key in order to retrieve the data later.+''writeNbt()'' returns a ''NBTCompound'', which should contain all of the data in your ''BlockEntity''. This data is saved to the disk and also send through packets if you need to sync your ''BlockEntity'' data with clients. It is very important to call the default implementation of ''writeNbt'', as it saves "Identifying Data" (position and ID) to the tag. Without this, any further data you try and save will be lost as it is not associated with a position and ''BlockEntityType''. Knowing this, the example below demonstrates saving an integer from your ''BlockEntity'' to the tag. In the example, the integer is saved under the key ''"number"'' - you can replace this with any string, but you can only have one entry for each key in your tag, and you will need to remember the key in order to retrieve the data later.
  
 <code java> <code java>
Line 64: Line 69:
        
    // Serialize the BlockEntity    // Serialize the BlockEntity
-   public CompoundTag toTag(CompoundTag tag) { +   @Override 
-      super.toTag(tag);+    public NbtCompound writeNbt(NbtCompound tag) { 
 +      super.writeNbt(tag);
              
       // Save the current value of the number to the tag       // Save the current value of the number to the tag
Line 75: Line 81:
 </code> </code>
  
-In order to retrieve the data later, you will also need to override ''fromTag''. This method is the opposite of ''toTag'' - instead of saving your data to a ''CompoundTag'', you are given the tag which you saved earlier, enabling you to retrieve any data that you need. As with ''toTag'', it is essential that you call ''super.fromTag'', and you will need to use the same keys to retrieve data that you saved. To retrieve, the number we saved earlier, see the example below.+In order to retrieve the data later, you will also need to override ''readNbt''. This method is the opposite of ''writeNbt'' - instead of saving your data to a ''NBTCompound'', you are given the tag which you saved earlier, enabling you to retrieve any data that you need. As with ''writeNbt'', it is essential that you call ''super.readNbt'', and you will need to use the same keys to retrieve data that you saved. To retrieve, the number we saved earlier, see the example below.
  
 <code java> <code java>
 // Deserialize the BlockEntity // Deserialize the BlockEntity
-public void fromTag(CompoundTag tag) { +@Override 
-   super.fromTag(tag);+public void readNbt(NbtCompound tag) { 
 +   super.readNbt(tag);
    number = tag.getInt("number");    number = tag.getInt("number");
 } }
 </code> </code>
  
-Once you have implemented the ''toTag'' and ''fromTag'' methods, you simply need to ensure that they are called at the right time. Whenever your ''BlockEntity'' data changes and needs to be saved, call ''markDirty()''. This will force the ''toTag'' method to be called when the world is next saved by marking the chunk which your block is in as dirty. As a general rule of thumb, simply call ''markDirty()'' whenever you change any custom variable in your ''BlockEntity'' class.+Once you have implemented the ''writeNbt'' and ''readNbt'' methods, you simply need to ensure that they are called at the right time. Whenever your ''BlockEntity'' data changes and needs to be saved, call ''markDirty()''. This will force the ''writeNbt'' method to be called when the world is next saved by marking the chunk which your block is in as dirty. As a general rule of thumb, simply call ''markDirty()'' whenever you change any custom variable in your ''BlockEntity'' class.
  
-If you need to sync some of your ''BlockEntity'' data to the client, for purposes such as rendering, you should implement ''BlockEntityClientSerializable'' from the Fabric API. This class provides the ''fromClientTag'' and ''toClientTag'' methods, which work much the same as the previously discussed ''fromTag'' and ''toTag'' methods, except that they are used specifically for sending to and receiving data on the client. +If you need to sync some of your ''BlockEntity'' data to the client, for purposes such as rendering, you should implement ''BlockEntityClientSerializable'' from the Fabric API. This class provides the ''fromClientTag'' and ''toClientTag'' methods, which work much the same as the previously discussed ''readNbt'' and ''writeNbt'' methods, except that they are used specifically for sending to and receiving data on the client. 
  
 ===== Overview ===== ===== Overview =====
  
 You should now have your very own ''BlockEntity'', which you can expand in various ways to suit your needs. You registered a ''BlockEntityType'', and used it to connect your ''Block'' and ''BlockEntity'' classes together. Then, you implemented ''BlockEntityProvider'' in your ''Block'' class, and used the interface to provide an instance of your new ''BlockEntity''. Finally, you learned how to save data to your ''BlockEntity'', and how to retrieve for use later. You should now have your very own ''BlockEntity'', which you can expand in various ways to suit your needs. You registered a ''BlockEntityType'', and used it to connect your ''Block'' and ''BlockEntity'' classes together. Then, you implemented ''BlockEntityProvider'' in your ''Block'' class, and used the interface to provide an instance of your new ''BlockEntity''. Finally, you learned how to save data to your ''BlockEntity'', and how to retrieve for use later.
tutorial/blockentity.txt · Last modified: 2023/09/20 19:18 by haykam