Loot tables for cargo crates?

This commit is contained in:
DBotThePony 2022-10-08 17:35:07 +07:00
parent c0364736f4
commit 75ffae542d
Signed by: DBot
GPG Key ID: DCC23B5715498507
3 changed files with 87 additions and 14 deletions

View File

@ -32,10 +32,12 @@ class CargoCrateBlock(val color: DyeColor?) : RotatableMatteryBlock(
return super.getStateForPlacement(context)?.setValue(IS_OPEN, false) return super.getStateForPlacement(context)?.setValue(IS_OPEN, false)
} }
@Suppress("OVERRIDE_DEPRECATION")
override fun hasAnalogOutputSignal(p_60457_: BlockState): Boolean { override fun hasAnalogOutputSignal(p_60457_: BlockState): Boolean {
return true return true
} }
@Suppress("OVERRIDE_DEPRECATION")
override fun getAnalogOutputSignal(p_60487_: BlockState, level: Level, p_60489_: BlockPos): Int { override fun getAnalogOutputSignal(p_60487_: BlockState, level: Level, p_60489_: BlockPos): Int {
val tile = level.getBlockEntity(p_60489_) as? CargoCrateBlockEntity ?: return 0 val tile = level.getBlockEntity(p_60489_) as? CargoCrateBlockEntity ?: return 0
return AbstractContainerMenu.getRedstoneSignalFromContainer(tile.container) return AbstractContainerMenu.getRedstoneSignalFromContainer(tile.container)

View File

@ -1,28 +1,41 @@
package ru.dbotthepony.mc.otm.block.entity package ru.dbotthepony.mc.otm.block.entity
import net.minecraft.advancements.CriteriaTriggers
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.LongTag
import net.minecraft.nbt.StringTag
import net.minecraft.network.chat.Component 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.sounds.SoundSource
import net.minecraft.world.Container import net.minecraft.world.Container
import net.minecraft.world.Containers
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu 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.Block
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import net.minecraft.world.level.gameevent.GameEvent 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.Capability
import net.minecraftforge.common.capabilities.ForgeCapabilities import net.minecraftforge.common.capabilities.ForgeCapabilities
import net.minecraftforge.common.util.LazyOptional 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.CargoCrateBlock
import ru.dbotthepony.mc.otm.block.IDroppableContainer import ru.dbotthepony.mc.otm.block.IDroppableContainer
import ru.dbotthepony.mc.otm.container.MatteryContainer 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.menu.CargoCrateMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities 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 import ru.dbotthepony.mc.otm.registry.MSoundEvents
class CargoCrateBlockEntity( class CargoCrateBlockEntity(
@ -31,7 +44,18 @@ class CargoCrateBlockEntity(
) : MatteryBlockEntity(MBlockEntities.CARGO_CRATE, p_155229_, p_155230_), IDroppableContainer { ) : MatteryBlockEntity(MBlockEntities.CARGO_CRATE, p_155229_, p_155230_), IDroppableContainer {
val container = MatteryContainer(this::setChanged, CAPACITY) val container = MatteryContainer(this::setChanged, CAPACITY)
private var interactingPlayers = 0 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 override val droppableContainer: Container
get() = container get() = container
@ -72,20 +96,56 @@ class CargoCrateBlockEntity(
return super.getCapability(cap, side) return super.getCapability(cap, side)
} }
public override fun saveAdditional(nbt: CompoundTag) { override fun saveAdditional(nbt: CompoundTag) {
super.saveAdditional(nbt) super.saveAdditional(nbt)
nbt[INVENTORY_KEY] = container.serializeNBT() 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) { override fun load(nbt: CompoundTag) {
super.load(nbt) super.load(nbt)
container.deserializeNBT(nbt[INVENTORY_KEY]) 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 override val defaultDisplayName: Component
get() = MACHINE_NAME 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) return CargoCrateMenu(containerID, inventory, this)
} }

View File

@ -5,8 +5,16 @@ import net.minecraftforge.common.util.LazyOptional
import net.minecraftforge.items.IItemHandler import net.minecraftforge.items.IItemHandler
interface MatteryContainerFilter { interface MatteryContainerFilter {
fun canInsert(slot: Int, stack: ItemStack): Boolean fun canInsert(slot: Int, stack: ItemStack): Boolean {
fun canExtract(slot: Int, amount: 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 { object MatteryContainerFilterOnlyIn : MatteryContainerFilter {
@ -41,7 +49,7 @@ object MatteryContainerFilterBoth : MatteryContainerFilter {
class MatteryContainerHandler @JvmOverloads internal constructor( class MatteryContainerHandler @JvmOverloads internal constructor(
private val container: MatteryContainer, private val container: MatteryContainer,
private val filter: MatteryContainerFilter = MatteryContainerFilterBoth, private val hooks: MatteryContainerFilter = MatteryContainerFilterBoth,
) : IItemHandler { ) : IItemHandler {
private var handler = LazyOptional.of<IItemHandler> { this } private var handler = LazyOptional.of<IItemHandler> { this }
@ -61,9 +69,10 @@ class MatteryContainerHandler @JvmOverloads internal constructor(
override fun getStackInSlot(slot: Int) = container[slot] override fun getStackInSlot(slot: Int) = container[slot]
override fun insertItem(slot: Int, stack: ItemStack, simulate: Boolean): ItemStack { override fun insertItem(slot: Int, stack: ItemStack, simulate: Boolean): ItemStack {
if (!filter.canInsert(slot, stack)) if (!hooks.canInsert(slot, stack))
return stack return stack
hooks.preInsert(slot, stack, simulate)
val localStack = container[slot] val localStack = container[slot]
if (localStack.isEmpty) { if (localStack.isEmpty) {
@ -100,9 +109,11 @@ class MatteryContainerHandler @JvmOverloads internal constructor(
require(amount >= 0) { "Can not extract negative amount of items" } require(amount >= 0) { "Can not extract negative amount of items" }
hooks.preExtract(slot, amount, simulate)
val localStack = container.getItem(slot) val localStack = container.getItem(slot)
if (localStack.isEmpty) return ItemStack.EMPTY 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 minimal = Math.min(amount, localStack.count)
val copy = localStack.copy() val copy = localStack.copy()
@ -122,6 +133,6 @@ class MatteryContainerHandler @JvmOverloads internal constructor(
} }
override fun isItemValid(slot: Int, stack: ItemStack): Boolean { override fun isItemValid(slot: Int, stack: ItemStack): Boolean {
return filter.canInsert(slot, stack) return hooks.canInsert(slot, stack)
} }
} }