More ConfigurableItemHandler tests

This commit is contained in:
DBotThePony 2023-02-19 12:07:03 +07:00
parent 5db3d665f0
commit 32da00423e
Signed by: DBot
GPG Key ID: DCC23B5715498507
8 changed files with 101 additions and 66 deletions

View File

@ -80,12 +80,12 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
input: IItemHandler? = null,
output: IItemHandler? = null,
battery: IItemHandler? = null,
val frontDefault: ItemHandlerMode = determineDefaultMode(input, output),
val backDefault: ItemHandlerMode = determineDefaultMode(input, output),
val leftDefault: ItemHandlerMode = determineDefaultMode(input, output),
val rightDefault: ItemHandlerMode = determineDefaultMode(input, output),
val topDefault: ItemHandlerMode = determineDefaultMode(input, output),
val bottomDefault: ItemHandlerMode = determineDefaultMode(input, output),
val frontDefault: ItemHandlerMode = determineDefaultMode(input, output, battery, RelativeSide.FRONT),
val backDefault: ItemHandlerMode = determineDefaultMode(input, output, battery, RelativeSide.BACK),
val leftDefault: ItemHandlerMode = determineDefaultMode(input, output, battery, RelativeSide.LEFT),
val rightDefault: ItemHandlerMode = determineDefaultMode(input, output, battery, RelativeSide.RIGHT),
val topDefault: ItemHandlerMode = determineDefaultMode(input, output, battery, RelativeSide.TOP),
val bottomDefault: ItemHandlerMode = determineDefaultMode(input, output, battery, RelativeSide.BOTTOM),
) {
val sideless: IItemHandler
@ -281,15 +281,32 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
}
companion object {
private fun determineDefaultMode(input: IItemHandler?, output: IItemHandler?): ItemHandlerMode {
if (input == null && output == null)
private fun determineDefaultMode(input: IItemHandler?, output: IItemHandler?, battery: IItemHandler?, side: RelativeSide): ItemHandlerMode {
if (side == RelativeSide.BACK && battery != null) {
return ItemHandlerMode.BATTERY
}
if (input == null && output == null) {
return ItemHandlerMode.DISABLED
else if (input != null && output != null)
return ItemHandlerMode.INPUT_OUTPUT
else if (output != null)
return ItemHandlerMode.OUTPUT
else
return ItemHandlerMode.INPUT
} else if (input != null && output != null) {
return when (side) {
RelativeSide.FRONT, RelativeSide.BACK -> ItemHandlerMode.DISABLED
RelativeSide.RIGHT, RelativeSide.TOP -> ItemHandlerMode.INPUT
RelativeSide.LEFT, RelativeSide.BOTTOM -> ItemHandlerMode.OUTPUT
}
} else if (output != null) {
if (side == RelativeSide.TOP) {
return ItemHandlerMode.DISABLED
} else {
return ItemHandlerMode.OUTPUT
}
} else {
if (side == RelativeSide.BOTTOM) {
return ItemHandlerMode.DISABLED
} else {
return ItemHandlerMode.INPUT
}
}
}
}
}

View File

@ -18,6 +18,7 @@ import net.minecraftforge.common.util.LazyOptional
import ru.dbotthepony.mc.otm.capability.*
import ru.dbotthepony.mc.otm.capability.energy.BlockEnergyStorageImpl
import ru.dbotthepony.mc.otm.capability.energy.ItemEnergyStorageImpl
import ru.dbotthepony.mc.otm.container.HandlerFilter
import ru.dbotthepony.mc.otm.container.MatteryContainer
import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.core.nbt.ifHas
@ -28,6 +29,7 @@ import ru.dbotthepony.mc.otm.core.nbt.set
abstract class MatteryPoweredBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(p_155228_, p_155229_, p_155230_) {
val batteryContainer = MatteryContainer(::setChangedLight, 1).also(::addDroppableContainer)
val batteryItemHandler = batteryContainer.handler(HandlerFilter.Dischargeable)
init {
savetable(::batteryContainer, BATTERY_KEY)

View File

@ -31,33 +31,29 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDe
return ChemicalGeneratorMenu(containerID, inventory, this)
}
val container = MatteryContainer(this::setChangedLight, SLOTS).also(::addDroppableContainer)
val energy = GeneratorEnergyStorage(this::setChangedLight, CAPACITY, THROUGHPUT)
val batteryContainer = MatteryContainer(::setChangedLight, 1).also(::addDroppableContainer)
val residueContainer = MatteryContainer(::setChangedLight, 1).also(::addDroppableContainer)
val fuelContainer = MatteryContainer(::setChangedLight, 1).also(::addDroppableContainer)
val itemHandler = container.handler(object : HandlerFilter {
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
if (slot == SLOT_INPUT)
return ForgeHooks.getBurnTime(stack, null) > 0
val batteryItemHandler = batteryContainer.handler(HandlerFilter.Chargeable)
val residueItemHandler = batteryContainer.handler(HandlerFilter.OnlyOut)
val fuelItemHandler = batteryContainer.handler(HandlerFilter.ChemicalFuel)
if (slot == SLOT_RESIDUE)
return false
val energy = GeneratorEnergyStorage(::setChangedLight, CAPACITY, THROUGHPUT)
return stack.getCapability(ForgeCapabilities.ENERGY).isPresent
}
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
if (slot == SLOT_RESIDUE) return true
return slot == SLOT_BATTERY &&
(!stack.getCapability(ForgeCapabilities.ENERGY).isPresent || stack.getCapability(ForgeCapabilities.ENERGY).resolve().get().receiveEnergy(Int.MAX_VALUE, true) <= 0)
}
})
val itemConfig = ConfigurableItemHandler(
input = fuelItemHandler,
output = residueItemHandler,
battery = batteryItemHandler,
backDefault = ItemHandlerMode.BATTERY)
init {
savetable(::energy, ENERGY_KEY)
savetable(::container, INVENTORY_KEY)
savetable(::batteryContainer)
savetable(::residueContainer)
savetable(::fuelContainer)
exposeEnergyGlobally(energy)
exposeItemsGlobally(itemHandler)
savetables.int(::workTicks, WORK_TICKS_KEY)
savetables.int(::workTicksTotal, WORK_TICKS_TOTAL_KEY)
@ -107,25 +103,25 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDe
}
if (workTicks == 0 && !redstoneControl.isBlockedByRedstone && checkFuelSlot) {
if (!container[SLOT_INPUT].isEmpty) {
val ticks = ForgeHooks.getBurnTime(container[SLOT_INPUT], null)
val residue = container[SLOT_INPUT].item.getCraftingRemainingItem(container[SLOT_INPUT].copy().also { it.count = 1 })
val canPutResidue = residue.isEmpty || container[SLOT_RESIDUE].isEmpty || ItemStack.isSameItemSameTags(container[SLOT_RESIDUE], residue) && container[SLOT_RESIDUE].count < container[2].maxStackSize
if (!fuelContainer[0].isEmpty) {
val ticks = ForgeHooks.getBurnTime(fuelContainer[0], null)
val residue = fuelContainer[0].item.getCraftingRemainingItem(fuelContainer[0].copy().also { it.count = 1 })
val canPutResidue = residue.isEmpty || residueContainer[0].isEmpty || ItemStack.isSameItemSameTags(residueContainer[0], residue) && residueContainer[0].count < residueContainer[0].maxStackSize
if (canPutResidue && ticks >= 4 && (energy.batteryLevel < Decimal.ONE || GENERATION_SPEED * (ticks / 4) + energy.batteryLevel <= energy.maxBatteryLevel)) {
workTicksTotal = ticks / 4
workTicks = ticks / 4
container[SLOT_INPUT].shrink(1)
fuelContainer[0].shrink(1)
if (!residue.isEmpty) {
if (container[SLOT_RESIDUE].isEmpty) {
container[SLOT_RESIDUE] = residue
if (residueContainer[0].isEmpty) {
residueContainer[0] = residue
} else {
container[SLOT_RESIDUE].count++
residueContainer[0].count++
}
}
container.setChanged(SLOT_INPUT)
fuelContainer.setChanged(0)
}
}
@ -134,7 +130,7 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDe
if (energy.batteryLevel.isZero) return
val item = container[SLOT_BATTERY]
val item = batteryContainer[0]
if (!item.isEmpty) {
item.energy?.let(this::workWithPower)
@ -155,11 +151,6 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDe
private var _GENERATION_SPEED: DecimalConfigValue by WriteOnce()
private var _CAPACITY: DecimalConfigValue by WriteOnce()
const val SLOT_INPUT = 0
const val SLOT_BATTERY = 1
const val SLOT_RESIDUE = 2
const val SLOTS = 3
fun registerConfig(builder: ForgeConfigSpec.Builder) {
builder.push(MNames.CHEMICAL_GENERATOR)

View File

@ -63,16 +63,6 @@ class ChemicalGeneratorBlock : RotatableMatteryBlock(), EntityBlock {
) {
super.appendHoverText(itemStack, p_49817_, tooltips, p_49819_)
GeneratorEnergyStorage.appendHoverText(itemStack, p_49817_, tooltips, p_49819_)
val tag = itemStack.tag?.get(BlockItem.BLOCK_ENTITY_TAG) as? CompoundTag ?: return
val container = MatteryContainer(ChemicalGeneratorBlockEntity.SLOTS)
tag.map(MatteryBlockEntity.INVENTORY_KEY, container::deserializeNBT)
if (!container[ChemicalGeneratorBlockEntity.SLOT_BATTERY].isEmpty) {
tooltips.add(TranslatableComponent("otm.item.block.stored_battery", container[ChemicalGeneratorBlockEntity.SLOT_BATTERY].displayName).withStyle(ChatFormatting.GRAY))
ItemEnergyStorageImpl.appendHoverText(container[ChemicalGeneratorBlockEntity.SLOT_BATTERY], tooltips)
}
}
private val shapes = getShapeForEachState(rotationProperty) { BlockShapes.CHEMICAL_GENERATOR.rotateFromNorth(it[rotationProperty]).computeShape() }

View File

@ -34,7 +34,7 @@ class ChemicalGeneratorScreen(menu: ChemicalGeneratorMenu, inventory: Inventory,
SlotPanel(this, frame, menu.residueSlot, 56f, PROGRESS_SLOT_TOP)
SlotPanel(this, frame, menu.fuelSlot, 104f, PROGRESS_SLOT_TOP)
makeDeviceControls(this, frame, redstone = menu.redstone)
makeDeviceControls(this, frame, redstone = menu.redstone, itemConfig = menu.itemConfig)
return frame
}

View File

@ -1,6 +1,8 @@
package ru.dbotthepony.mc.otm.container
import net.minecraft.world.item.ItemStack
import net.minecraftforge.common.ForgeHooks
import net.minecraftforge.common.capabilities.ForgeCapabilities
interface HandlerFilter {
fun canInsert(slot: Int, stack: ItemStack): Boolean {
@ -35,4 +37,34 @@ interface HandlerFilter {
}
object Both : HandlerFilter
object Dischargeable : HandlerFilter {
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
return stack.getCapability(ForgeCapabilities.ENERGY).map { it.canExtract() && it.extractEnergy(Int.MAX_VALUE, true) > 0 }.orElse(false)
}
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
return stack.getCapability(ForgeCapabilities.ENERGY).map { !it.canExtract() || it.extractEnergy(Int.MAX_VALUE, true) <= 0 }.orElse(true)
}
}
object Chargeable : HandlerFilter {
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
return stack.getCapability(ForgeCapabilities.ENERGY).map { it.canReceive() && it.receiveEnergy(Int.MAX_VALUE, true) > 0 }.orElse(false)
}
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
return stack.getCapability(ForgeCapabilities.ENERGY).map { !it.canReceive() || it.receiveEnergy(Int.MAX_VALUE, true) <= 0 }.orElse(true)
}
}
object ChemicalFuel : HandlerFilter {
override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean {
return ForgeHooks.getBurnTime(stack, null) <= 0
}
override fun canInsert(slot: Int, stack: ItemStack): Boolean {
return ForgeHooks.getBurnTime(stack, null) > 0
}
}
}

View File

@ -5,6 +5,9 @@ import ru.dbotthepony.mc.otm.core.immutableMap
import ru.dbotthepony.mc.otm.core.math.RelativeSide
import ru.dbotthepony.mc.otm.menu.MatteryMenu
/**
* [allowPull] and [allowPush] controls whenever player is allowed to change these options
*/
class ItemHandlerPlayerInput(val menu: MatteryMenu, val allowPull: Boolean = true, val allowPush: Boolean = true) {
inner class Piece(val side: RelativeSide) {
private val allowedFlags = MatteryDeviceBlockEntity.ItemHandlerMode.values().map { menu.mSynchronizer.bool() to it }

View File

@ -11,6 +11,7 @@ import ru.dbotthepony.mc.otm.core.ifPresentK
import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback
import ru.dbotthepony.mc.otm.menu.input.ItemHandlerPlayerInput
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget
import ru.dbotthepony.mc.otm.registry.MMenus
@ -19,28 +20,28 @@ class ChemicalGeneratorMenu @JvmOverloads constructor(id: Int, inv: Inventory, t
: MatteryMenu(MMenus.CHEMICAL_GENERATOR, id, inv, tile) {
val redstone = EnumInputWithFeedback(this, RedstoneSetting::class.java)
val itemConfig = ItemHandlerPlayerInput(this, allowPull = false, allowPush = true)
init {
if (tile != null) {
redstone.with(tile.redstoneControl::redstoneSetting)
itemConfig.configure(tile.itemConfig)
}
}
val container = tile?.container ?: SimpleContainer(3)
val fuelSlot = object : MatterySlot(container, ChemicalGeneratorBlockEntity.SLOT_INPUT) {
val fuelSlot = object : MatterySlot(tile?.fuelContainer ?: SimpleContainer(1), 0) {
override fun mayPlace(itemStack: ItemStack): Boolean {
return ForgeHooks.getBurnTime(itemStack, null) > 0
}
}
val residueSlot = object : MatterySlot(container, ChemicalGeneratorBlockEntity.SLOT_RESIDUE) {
val residueSlot = object : MatterySlot(tile?.residueContainer ?: SimpleContainer(1), 0) {
override fun mayPlace(itemStack: ItemStack): Boolean {
return false
}
}
val batterySlot = object : MatterySlot(container, ChemicalGeneratorBlockEntity.SLOT_BATTERY) {
val batterySlot = object : MatterySlot(tile?.batteryContainer ?: SimpleContainer(1), 0) {
override fun mayPlace(itemStack: ItemStack): Boolean {
itemStack.getCapability(ForgeCapabilities.ENERGY).ifPresentK {
return it.canReceive()
@ -54,7 +55,6 @@ class ChemicalGeneratorMenu @JvmOverloads constructor(id: Int, inv: Inventory, t
val energy = LevelGaugeWidget(this, tile?.energy)
var burnTime by mSynchronizer.int()
override val storageSlots = listOf(
addSlot(fuelSlot),
addSlot(batterySlot),