From 75ffae542dee0f5fd49a22ae37d972e9ed38fbd1 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 8 Oct 2022 17:35:07 +0700 Subject: [PATCH] Loot tables for cargo crates? --- .../mc/otm/block/CargoCrateBlock.kt | 4 +- .../otm/block/entity/CargoCrateBlockEntity.kt | 74 +++++++++++++++++-- .../otm/container/MatteryContainerHandler.kt | 23 ++++-- 3 files changed, 87 insertions(+), 14 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/CargoCrateBlock.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/CargoCrateBlock.kt index 476a82294..7f2364c4b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/CargoCrateBlock.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/CargoCrateBlock.kt @@ -32,10 +32,12 @@ class CargoCrateBlock(val color: DyeColor?) : RotatableMatteryBlock( return super.getStateForPlacement(context)?.setValue(IS_OPEN, false) } + @Suppress("OVERRIDE_DEPRECATION") override fun hasAnalogOutputSignal(p_60457_: BlockState): Boolean { return true } + @Suppress("OVERRIDE_DEPRECATION") override fun getAnalogOutputSignal(p_60487_: BlockState, level: Level, p_60489_: BlockPos): Int { val tile = level.getBlockEntity(p_60489_) as? CargoCrateBlockEntity ?: return 0 return AbstractContainerMenu.getRedstoneSignalFromContainer(tile.container) @@ -45,4 +47,4 @@ class CargoCrateBlock(val color: DyeColor?) : RotatableMatteryBlock( @JvmField val IS_OPEN: BooleanProperty = BooleanProperty.create("open") } -} \ No newline at end of file +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/CargoCrateBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/CargoCrateBlockEntity.kt index f3d9bf49f..37c3b16b7 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/CargoCrateBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/CargoCrateBlockEntity.kt @@ -1,28 +1,41 @@ package ru.dbotthepony.mc.otm.block.entity +import net.minecraft.advancements.CriteriaTriggers import net.minecraft.core.BlockPos import net.minecraft.core.Direction import net.minecraft.nbt.CompoundTag +import net.minecraft.nbt.LongTag +import net.minecraft.nbt.StringTag import net.minecraft.network.chat.Component +import net.minecraft.resources.ResourceLocation +import net.minecraft.server.level.ServerLevel +import net.minecraft.server.level.ServerPlayer import net.minecraft.sounds.SoundSource import net.minecraft.world.Container +import net.minecraft.world.Containers import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player import net.minecraft.world.inventory.AbstractContainerMenu +import net.minecraft.world.item.ItemStack import net.minecraft.world.level.block.Block import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.gameevent.GameEvent +import net.minecraft.world.level.storage.loot.LootContext +import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets +import net.minecraft.world.level.storage.loot.parameters.LootContextParams +import net.minecraft.world.phys.Vec3 import net.minecraftforge.common.capabilities.Capability import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.util.LazyOptional -import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.block.CargoCrateBlock import ru.dbotthepony.mc.otm.block.IDroppableContainer import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.MatteryContainerFilter +import ru.dbotthepony.mc.otm.core.TranslatableComponent +import ru.dbotthepony.mc.otm.core.map +import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.menu.CargoCrateMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities -import ru.dbotthepony.mc.otm.container.set -import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.registry.MSoundEvents class CargoCrateBlockEntity( @@ -31,7 +44,18 @@ class CargoCrateBlockEntity( ) : MatteryBlockEntity(MBlockEntities.CARGO_CRATE, p_155229_, p_155230_), IDroppableContainer { val container = MatteryContainer(this::setChanged, CAPACITY) private var interactingPlayers = 0 - val handler = container.handler() + val handler = container.handler(object : MatteryContainerFilter { + override fun preInsert(slot: Int, stack: ItemStack, simulate: Boolean) { + unpackLootTable() + } + + override fun preExtract(slot: Int, amount: Int, simulate: Boolean) { + unpackLootTable() + } + }) + + var lootTable: ResourceLocation? = null + var lootTableSeed: Long? = null override val droppableContainer: Container get() = container @@ -72,20 +96,56 @@ class CargoCrateBlockEntity( return super.getCapability(cap, side) } - public override fun saveAdditional(nbt: CompoundTag) { + override fun saveAdditional(nbt: CompoundTag) { super.saveAdditional(nbt) nbt[INVENTORY_KEY] = container.serializeNBT() + + lootTable?.let { nbt[LOOT_TABLE_KEY] = it.toString() } + lootTableSeed?.let { nbt[LOOT_TABLE_SEED_KEY] = it } } override fun load(nbt: CompoundTag) { super.load(nbt) container.deserializeNBT(nbt[INVENTORY_KEY]) + + lootTable = nbt.map(LOOT_TABLE_KEY) { it: StringTag -> ResourceLocation.tryParse(it.asString) } + lootTableSeed = (nbt[LOOT_TABLE_SEED_KEY] as LongTag?)?.asLong + } + + fun unpackLootTable(ply: Player? = null) { + val lootTable = lootTable ?: return + val lootTableSeed = lootTableSeed ?: 0L + val server = level?.server ?: return + + val loot = server.lootTables.get(lootTable) + + if (ply is ServerPlayer) { + CriteriaTriggers.GENERATE_LOOT.trigger(ply, lootTable) + } + + this.lootTable = null + this.lootTableSeed = null + + val context = LootContext.Builder(level as ServerLevel) + .withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(this.worldPosition)) + .withOptionalRandomSeed(lootTableSeed) + + if (ply != null) { + context.withLuck(ply.luck).withParameter(LootContextParams.THIS_ENTITY, ply) + } + + Containers.dropContents(level as ServerLevel, blockPos, container) + loot.fill(container, context.create(LootContextParamSets.CHEST)) } override val defaultDisplayName: Component get() = MACHINE_NAME - override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { + override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu? { + if (lootTable != null && ply.isSpectator) + return null + + unpackLootTable(ply) return CargoCrateMenu(containerID, inventory, this) } @@ -93,4 +153,4 @@ class CargoCrateBlockEntity( private val MACHINE_NAME = TranslatableComponent("block.overdrive_that_matters.cargo_crate") const val CAPACITY = 9 * 6 } -} \ No newline at end of file +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainerHandler.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainerHandler.kt index 4d624392c..2d8172003 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainerHandler.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainerHandler.kt @@ -5,8 +5,16 @@ import net.minecraftforge.common.util.LazyOptional import net.minecraftforge.items.IItemHandler interface MatteryContainerFilter { - fun canInsert(slot: Int, stack: ItemStack): Boolean - fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean + fun canInsert(slot: Int, stack: ItemStack): Boolean { + return true + } + + fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { + return true + } + + fun preInsert(slot: Int, stack: ItemStack, simulate: Boolean) {} + fun preExtract(slot: Int, amount: Int, simulate: Boolean) {} } object MatteryContainerFilterOnlyIn : MatteryContainerFilter { @@ -41,7 +49,7 @@ object MatteryContainerFilterBoth : MatteryContainerFilter { class MatteryContainerHandler @JvmOverloads internal constructor( private val container: MatteryContainer, - private val filter: MatteryContainerFilter = MatteryContainerFilterBoth, + private val hooks: MatteryContainerFilter = MatteryContainerFilterBoth, ) : IItemHandler { private var handler = LazyOptional.of { this } @@ -61,9 +69,10 @@ class MatteryContainerHandler @JvmOverloads internal constructor( override fun getStackInSlot(slot: Int) = container[slot] override fun insertItem(slot: Int, stack: ItemStack, simulate: Boolean): ItemStack { - if (!filter.canInsert(slot, stack)) + if (!hooks.canInsert(slot, stack)) return stack + hooks.preInsert(slot, stack, simulate) val localStack = container[slot] if (localStack.isEmpty) { @@ -100,9 +109,11 @@ class MatteryContainerHandler @JvmOverloads internal constructor( require(amount >= 0) { "Can not extract negative amount of items" } + hooks.preExtract(slot, amount, simulate) + val localStack = container.getItem(slot) if (localStack.isEmpty) return ItemStack.EMPTY - if (!filter.canExtract(slot, amount, localStack)) return ItemStack.EMPTY + if (!hooks.canExtract(slot, amount, localStack)) return ItemStack.EMPTY val minimal = Math.min(amount, localStack.count) val copy = localStack.copy() @@ -122,6 +133,6 @@ class MatteryContainerHandler @JvmOverloads internal constructor( } override fun isItemValid(slot: Int, stack: ItemStack): Boolean { - return filter.canInsert(slot, stack) + return hooks.canInsert(slot, stack) } }