Table of Contents
Syncing BlockEntity data with ItemStack
Introduction
When you create a Block
with BlockEntity
, you might want to place the block with predefined Nbt data from an ItemStack
(of your BlockItem
), or save the BlockEntity
data in the ItemStack
after breaking the block.
Before proceeding, you will need a Block (with BlockItem), a BlockEntity and a way to modify the BlockEntity's data for testing purposes.
Block Drops with data
For a block to drop an ItemStack
with the Nbt from the BlockEntity
of the broken block, we only need to change the loot table:
- src/main/resources/data/tutorial/loot_tables/blocks/demo_block.json
{ "type": "minecraft:block", "pools": [ { "rolls": 1.0, "entries": [ { "type": "minecraft:item", "name": "tutorial:demo_block", "functions": [ { "function": "minecraft:copy_nbt", "source": "block_entity", "ops": [ { "source": "number", "target": "BlockEntityTag.number", "op": "replace" } ] } ] } ] } ] }
Where:
- source is the Tag key String we used in the
writeNbt
andreadNbt
methods in ourDemoBlockEntity
class – “number” - target is the Tag key hierarchy in the dropped
ItemStack
(source prefixed with the “BlockEntityTag” key, which is needed for placing the block back with the saved data) – “BlockEntityTag.number”
To save more fields, just add more replace operations (with source, target and op) to the “ops” array.
Reading saved data from ItemStack
To get the BlockEntity's Nbt, we can use the helper BlockItem.getBlockEntityNbt(stack)
method, which just calls stack.getSubNbt(BLOCK_ENTITY_TAG_KEY)
internally. (BLOCK_ENTITY_TAG_KEY being “BlockEntityTag”, already mentioned in the loot table).
public class DemoBlock extends Block implements BlockEntityProvider { [...] @Override public void appendTooltip(ItemStack stack, BlockView world, List<Text> tooltip, TooltipContext context) { NbtCompound nbt = BlockItem.getBlockEntityNbt(stack); if (nbt == null) return; tooltip.add(Text.literal("Number: "+nbt.getInt("number")) } }
Changing ItemStack's BlockEntity data
We can change our tooltip to always display some default value even if the stack does not have any BlockEntity data.
public class DemoBlock extends Block implements BlockEntityProvider { [...] @Override public void appendTooltip(ItemStack stack, BlockView world, List<Text> tooltip, TooltipContext context) { NbtCompound nbt = BlockItem.getBlockEntityNbt(stack); if (nbt == null){ NbtCompound nbt = new NbtCompound(); nbt.putInt("number", 0); BlockItem.setBlockEntityNbt(stack, ExampleMod.DEMO_BLOCK_ENTITY, nbt); } tooltip.add(Text.literal("Number: "+nbt.getInt("number")) } }
Placing Block with data
Is automatic! As long as the data is in the “BlockEntityTag” subNbt (e.g. by using the BlockItem.getBlockEntityNbt
and BlockItem.setBlockEntityNbt
helper methods) under tag keys recognized by the readNbt
method of the BlockEntity
.
Helpful Reference
If something still isn't clear or you want more examples, I highly recommend looking at the Minecraft implementation of ShulkerBoxBlock
and ShulkerBoxBlockEntity
. That for example also implements Nameable
interface and has code to save custom names through ItemStack
and BlockEntity
.
Loot Tables
More info on Loot tables on Minecraft Wiki.
Vanilla loot tables: .minecraft\versions\[version]\[version].jar\data\minecraft\loot_tables\
Also, this Loot Table Generator might be useful.