Adil Yilan Posted September 3, 2022 Share Posted September 3, 2022 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() { super(createProperties()); } private static Properties createProperties() { Properties properties = Properties.of(Material.METAL, MaterialColor.COLOR_LIGHT_GRAY); properties.requiresCorrectToolForDrops(); properties.strength(5, 5); properties.sound(SoundType.METAL); properties.noOcclusion(); return properties; } @Override protected void createBlockStateDefinition(Builder<Block, BlockState> builder) { builder.add(LEVEL); } } 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(); properties.tab(CreativeModeTab.TAB_MISC); properties.stacksTo(1); 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 { @Override protected void addTables() { dropSelf(FluidBlocks.EMPTY_CASK.get()); dropSelf(FluidBlocks.OIL_CASK.get()); } @Override 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? Quote Link to comment Share on other sites More sharing options...
Luis_ST Posted September 3, 2022 Share Posted September 3, 2022 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. Quote Link to comment Share on other sites More sharing options...
warjort Posted September 3, 2022 Share Posted September 3, 2022 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. Quote Boilerplate: 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 More sharing options...
Adil Yilan Posted September 3, 2022 Author Share Posted September 3, 2022 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) { blockStateCopyBuilder.copy(property); } LootPoolSingletonContainer.Builder<?> itemLootTableBuilder = LootItem.lootTableItem(block); itemLootTableBuilder.apply(blockStateCopyBuilder); LootPool.Builder lootPoolBuilder = LootPool.lootPool(); lootPoolBuilder.setRolls(ConstantValue.exactly(1.0F)); lootPoolBuilder.add(itemLootTableBuilder); lootPoolBuilder = applyExplosionCondition(block, lootPoolBuilder); LootTable.Builder lootTableBuilder = LootTable.lootTable(); lootTableBuilder.withPool(lootPoolBuilder); this.add(block, lootTableBuilder); } So I can now call this for all other scenarios like this: dropSelfWithBlockState(FluidBlocks.OIL_CASK.get(), new Property<?>[] { OilCaskBlock.LEVEL }); Hope others will find this useful. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.