User Tools

Site Tools


tutorial:blockentity_sync_itemstack

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 and readNbt methods in our DemoBlockEntity 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.

tutorial/blockentity_sync_itemstack.txt · Last modified: 2023/09/24 18:54 by mattidragon