From 9cfe30e82a7fdfd5cac31be7180a75df6cd90a24 Mon Sep 17 00:00:00 2001 From: GamerDuck123 Date: Tue, 24 Jun 2025 02:48:01 -0400 Subject: [PATCH] - Added BarrelRules.kt which adds the proper storing of inventories for barrels, as well as the proper breaking procedure (items falling to the ground) Just like my chest block handler, this should work with any world format that retains block NBT data, I only tested on Polar and can confirm it to work on polar *NOTE* My code for BarrelRules.kt was translated from Java code, so it might not be the prettiest looking thing, I tried to clean it up a bit, but I might have missed a few things, it is functional though. --- .../blocks/behavior/BarrelRules.kt | 136 ++++++++++++++++++ .../blocks/group/VanillaBlockBehaviour.kt | 5 + 2 files changed, 141 insertions(+) create mode 100644 blocksandstuff-blocks/src/main/kotlin/org/everbuild/blocksandstuff/blocks/behavior/BarrelRules.kt diff --git a/blocksandstuff-blocks/src/main/kotlin/org/everbuild/blocksandstuff/blocks/behavior/BarrelRules.kt b/blocksandstuff-blocks/src/main/kotlin/org/everbuild/blocksandstuff/blocks/behavior/BarrelRules.kt new file mode 100644 index 0000000..a83163d --- /dev/null +++ b/blocksandstuff-blocks/src/main/kotlin/org/everbuild/blocksandstuff/blocks/behavior/BarrelRules.kt @@ -0,0 +1,136 @@ +package org.everbuild.blocksandstuff.blocks.behavior + +import net.kyori.adventure.key.Key +import net.kyori.adventure.nbt.CompoundBinaryTag +import net.kyori.adventure.text.Component +import net.minestom.server.MinecraftServer +import net.minestom.server.codec.Transcoder +import net.minestom.server.coordinate.Point +import net.minestom.server.coordinate.Vec +import net.minestom.server.entity.ItemEntity +import net.minestom.server.event.EventListener +import net.minestom.server.event.inventory.InventoryCloseEvent +import net.minestom.server.instance.Instance +import net.minestom.server.instance.block.Block +import net.minestom.server.instance.block.BlockHandler +import net.minestom.server.instance.block.BlockHandler.Destroy +import net.minestom.server.inventory.Inventory +import net.minestom.server.inventory.InventoryType +import net.minestom.server.item.ItemStack +import net.minestom.server.utils.time.TimeUnit +import java.util.* +import java.util.concurrent.ThreadLocalRandom +import java.util.concurrent.atomic.AtomicInteger +import java.util.function.Consumer + +class BarrelRules(private val block: Block) : BlockHandler { + override fun getKey(): Key { + return block.key() + } + + override fun onInteract(interaction: BlockHandler.Interaction): Boolean { + val p = interaction.player; + if (p.isSneaking && !p.itemInMainHand.isAir) return onInteract(interaction) + + val clickedBlock = interaction.block + val blockPos = interaction.blockPosition + val instance = interaction.instance + + val inv = getBlockInventory(clickedBlock, blockPos, instance) + + p.openInventory(inv) + instance.setBlock(blockPos, clickedBlock.withProperty("open", "true")) + + MinecraftServer.getGlobalEventHandler().addListener( + EventListener.builder(InventoryCloseEvent::class.java) + .expireCount(1) + .handler({ event: InventoryCloseEvent? -> + if (event != null) { + instance.setBlock(blockPos, clickedBlock.withProperty("open", "false")) + updateBlockInventory(inv, clickedBlock, blockPos, instance) + } + }) + .build() + ) + + return false + } + + override fun onDestroy(destroy: Destroy) { + val block = destroy.block + if (destroy.instance.getBlock(destroy.getBlockPosition()) === Block.AIR && block.nbt() != null) { + if (block.nbt()!!.get("Inventory") != null) { + val tag = block.nbt()!!.get("Inventory") + val inventory = ITEMSTACK_CODEC.decode(Transcoder.NBT, tag!!).orElse( + listOf( + ItemStack.AIR + ) + ) + inventory.forEach(Consumer { itemStack: ItemStack? -> + val entity = ItemEntity(itemStack!!) + entity.setPickupDelay(1, TimeUnit.SECOND) // 1s for natural drop + entity.scheduleRemove(5, TimeUnit.MINUTE) + entity.setVelocity( + Vec( + RANDOM.nextDouble() * 2 - 1, + 2.0, + RANDOM.nextDouble() * 2 - 1 + ) + ) + entity.setInstance(destroy.instance, destroy.blockPosition.add(0.5, 0.5, 0.5)) + }) + } + } + } + + private fun updateBlockInventory(inv: Inventory, block: Block, blockPos: Point, instance: Instance) { + instance.setBlock( + blockPos, + block.withNbt( + CompoundBinaryTag.builder().put( + "Inventory", + ITEMSTACK_CODEC.encode(Transcoder.NBT, listOf(*inv.getItemStacks())) + .orElseThrow() + ).build() + ) + ) + } + + private fun getBlockInventory(block: Block, blockPos: Point, instance: Instance): Inventory { + val inv = Inventory(InventoryType.CHEST_3_ROW, Component.text("Barrel")) + + if (block.nbt() != null) { + if (block.nbt()!!.get("Inventory") != null) { + val tag = block.nbt()!!.get("Inventory") + val inventory = ITEMSTACK_CODEC.decode(Transcoder.NBT, tag!!).orElse( + listOf( + ItemStack.AIR + ) + ) + val slot = AtomicInteger(0) + inventory.forEach(Consumer { i: ItemStack? -> inv.setItemStack(slot.getAndIncrement(), i!!) }) + } + } else { + instance.setBlock( + blockPos, + block.withNbt( + CompoundBinaryTag.builder().put( + "Inventory", + ITEMSTACK_CODEC.encode( + Transcoder.NBT, + listOf(ItemStack.AIR) + ).orElseThrow() + ).build() + ) + ) + } + + + return inv + } + + companion object { + private val ITEMSTACK_CODEC = ItemStack.CODEC.list() + private val RANDOM = ThreadLocalRandom.current(); + } +} \ No newline at end of file diff --git a/blocksandstuff-blocks/src/main/kotlin/org/everbuild/blocksandstuff/blocks/group/VanillaBlockBehaviour.kt b/blocksandstuff-blocks/src/main/kotlin/org/everbuild/blocksandstuff/blocks/group/VanillaBlockBehaviour.kt index f34928a..41960eb 100644 --- a/blocksandstuff-blocks/src/main/kotlin/org/everbuild/blocksandstuff/blocks/group/VanillaBlockBehaviour.kt +++ b/blocksandstuff-blocks/src/main/kotlin/org/everbuild/blocksandstuff/blocks/group/VanillaBlockBehaviour.kt @@ -134,6 +134,11 @@ object VanillaBlockBehaviour : VanillaRuleset BlockHa ::StrippingBehaviorRule ) + val BARREL = group( + byBlock(Block.BARREL), + ::BarrelRules + ) + override fun createGroup( blockGroup: BlockGroup, valueFunction: (Block) -> BlockHandler