Jump to content

[1.19.2] Saving BlockState properties in ItemStack and other way around

Adil Yilan

Recommended Posts

I want to have a cask that can be filled with oil up until the certain level.

public final class OilCaskBlock extends Block {

	public static final int MAX_LEVEL = 16;
	public static final IntegerProperty LEVEL = IntegerProperty.create("level", 1, MAX_LEVEL);

	public OilCaskBlock() {
	private static Properties createProperties() {

		Properties properties = Properties.of(Material.METAL, MaterialColor.COLOR_LIGHT_GRAY);

		properties.strength(5, 5);


		return properties;
	protected void createBlockStateDefinition(Builder<Block, BlockState> builder) {


I have also created a BlockItem for this block:

public final class OilCaskBlockItem extends BlockItem {
	public OilCaskBlockItem() {
		super(FluidBlocks.OIL_CASK.get(), createProperties());	
	private static Properties createProperties()
		Properties properties = new Properties();
		return properties;


So what happens now is:

  • I fill cask to level 8
  • Mine it and get item in inventory
  • When I place item back, it is no longer level 8 but level 1 instead - so it's original BlockState was not preserved in ItemStack

I have managed to find this net.minecraft.world.level.storage.loot.functions.CopyBlockState class that apparently saves BlockState in CompoundTag named "BlockStateTag" and it says it is checked when block is placed.

However I do not know how to leverage this class or is it the right approach to use it.

This is how my loot table is defined in datagen:

public final class FluidBlockLoot extends BlockLoot {

	protected void addTables() {

	protected Iterable<Block> getKnownBlocks() {
		return FluidBlocks.REGISTRY.getEntries().stream().map(RegistryObject::get)::iterator;

Should I read this tag manually in getPlacementState method of BlockItem class?

Is there something I need to add in datagen to trigger this BlockState copying to happen automatically?

What is the missing link here? :D



Link to comment
Share on other sites

You can do some similar like the ShulkerBoxBlock does in #playerWillDestroy. Create a new ItemStack there of your OilCask Item.
Then call ItemStack#getOrCreateTagElement with your Mod Id store in the returned CompoundTag,
the BlockState using NbtUtils#writeBlockState (use a new CompoundTag as parameter). Add the ItemStack using a ItemEntity to the world (level).

Override #getPlacementState in your BlockItem, get the CompoundTag from the ItemStack (which you can get from the given BlockPlaceContext) via ItemStack#getTagElement.
Check for not null and if the CompoundTag contains the stored BlockState using the key you used to store it in the CompoundTag.
If both checks are false return the default BlockState of your OilCask, else read the BlockState via NbtUtils#readBlockState.

Note: There are many ways to do this, this is the way i would use.

Link to comment
Share on other sites

You don't need to write code in your block for this.

You can use the CopyBlockState loot item function.


See the vanilla code in BlockLoot.createBeeNestDrop() for how it remembers the honey level


That code is more probably more complicated than you need since it;

* Also copies some block entity nbt for the bees

* Only drops the block when the player has silk touch.


If you don't post your logs/debug.log we can't help you. For curseforge you need to enable the forge debug.log in its minecraft settings. You should also post your crash report if you have one.

If there is no error in the log file and you don't have a crash report then post the launcher_log.txt from the minecraft folder. Again for curseforge this will be in your curseforge/minecraft/Install

Large files should be posted to a file sharing site like https://gist.github.com  You should also read the support forum sticky post.

Link to comment
Share on other sites

Thanks @warjort (and @Luis_ST), I have managed to make this work as expected. :)

I have broken dropSelf method to pieces and added BlockState related code from createBeeNestDrop method, and wrapped all that in new helper method:

	protected void dropSelfWithBlockState(Block block, Property<?>[] properties) {

		CopyBlockState.Builder blockStateCopyBuilder = CopyBlockState.copyState(block);
		for(Property<?> property : properties) {

		LootPoolSingletonContainer.Builder<?> itemLootTableBuilder = LootItem.lootTableItem(block);
		LootPool.Builder lootPoolBuilder = LootPool.lootPool();
		lootPoolBuilder = applyExplosionCondition(block, lootPoolBuilder);
		LootTable.Builder lootTableBuilder = LootTable.lootTable();
		this.add(block, lootTableBuilder);


So I can now call this for all other scenarios like this:

		dropSelfWithBlockState(FluidBlocks.OIL_CASK.get(), new Property<?>[] { 


Hope others will find this useful.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Create New...

Important Information

By using this site, you agree to our Terms of Use.