From 3e086dcacf9d6c268135db60a74e3be9c8e7ae6f Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 22:56:26 +0700 Subject: [PATCH] Switch Powered furnaces to SlottedContainer, make them reject items which are not used in any recipe (in automation) --- .../tech/AbstractPoweredFurnaceBlockEntity.kt | 90 ++++++++++++++----- .../mc/otm/menu/tech/PoweredFurnaceMenu.kt | 14 ++- 2 files changed, 81 insertions(+), 23 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt index 6defd22b6..8afae2f5c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt @@ -29,33 +29,60 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.config.WorkerBalanceValues import ru.dbotthepony.mc.otm.container.CombinedContainer -import ru.dbotthepony.mc.otm.container.HandlerFilter -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.balance -import ru.dbotthepony.mc.otm.core.collect.filter -import ru.dbotthepony.mc.otm.core.collect.maybe +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters +import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer +import ru.dbotthepony.mc.otm.core.SimpleCache import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.otmRandom +import ru.dbotthepony.mc.otm.core.util.ItemStackKey +import ru.dbotthepony.mc.otm.core.util.asKey import ru.dbotthepony.mc.otm.menu.tech.PoweredFurnaceMenu import ru.dbotthepony.mc.otm.recipe.MatteryCookingRecipe import ru.dbotthepony.mc.otm.recipe.MicrowaveRecipe import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import ru.dbotthepony.mc.otm.registry.game.MRecipes +import java.time.Duration sealed class AbstractPoweredFurnaceBlockEntity

( type: BlockEntityType<*>, blockPos: BlockPos, blockState: BlockState, - val recipeType: RecipeType

, - val secondaryRecipeType: RecipeType?, - val config: WorkerBalanceValues, maxJobs: Int = 2 ) : MatteryWorkerBlockEntity(type, blockPos, blockState, ItemJob.CODEC, maxJobs) { + abstract val recipeType: RecipeType

+ abstract val secondaryRecipeType: RecipeType? + abstract val config: WorkerBalanceValues + final override val upgrades = makeUpgrades(2, UpgradeType.BASIC_PROCESSING) final override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyLevelUpdated, upgrades.transform(config))) - val inputs = MatteryContainer(this::itemContainerUpdated, maxJobs) - val outputs = MatteryContainer(this::itemContainerUpdated, maxJobs) + private inner class InputSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) { + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + if (!super.canAutomationPlaceItem(itemStack)) + return false + + val level = level ?: return true + + return acceptableItems.get(itemStack.asKey()) { + val input = SingleRecipeInput(itemStack) + val secondaryRecipeType = secondaryRecipeType + + if (secondaryRecipeType != null && level.recipeManager.byType(secondaryRecipeType).any { it.value.matches(input, level) }) + return@get true + + return@get level.recipeManager.byType(recipeType).any { it.value.matches(input, level) } + } + } + + override fun canAutomationTakeItem(desired: Int): Boolean { + return false + } + } + + val inputs = SlottedContainer.simple(maxJobs, ::InputSlot, ::itemContainerUpdated) + val outputs = SlottedContainer.simple(maxJobs, AutomationFilters.ONLY_OUT.simpleProvider, ::itemContainerUpdated) init { addDroppableContainer(inputs) @@ -76,8 +103,8 @@ sealed class AbstractPoweredFurnaceBlockEntity

(16384L, Duration.ofMinutes(1)) + } } -class PoweredFurnaceBlockEntity(blockPos: BlockPos, blockState: BlockState) : AbstractPoweredFurnaceBlockEntity( - MBlockEntities.POWERED_FURNACE, blockPos, blockState, RecipeType.SMELTING, null, MachinesConfig.POWERED_FURNACE) { +class PoweredFurnaceBlockEntity(blockPos: BlockPos, blockState: BlockState) : AbstractPoweredFurnaceBlockEntity(MBlockEntities.POWERED_FURNACE, blockPos, blockState) { + override val recipeType: RecipeType + get() = RecipeType.SMELTING + override val secondaryRecipeType: RecipeType? + get() = null + override val config: WorkerBalanceValues + get() = MachinesConfig.POWERED_FURNACE + override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { return PoweredFurnaceMenu.furnace(containerID, inventory, this) } } -class PoweredBlastFurnaceBlockEntity(blockPos: BlockPos, blockState: BlockState) : AbstractPoweredFurnaceBlockEntity( - MBlockEntities.POWERED_BLAST_FURNACE, blockPos, blockState, RecipeType.BLASTING, null, MachinesConfig.POWERED_FURNACE) { +class PoweredBlastFurnaceBlockEntity(blockPos: BlockPos, blockState: BlockState) : AbstractPoweredFurnaceBlockEntity(MBlockEntities.POWERED_BLAST_FURNACE, blockPos, blockState) { + override val recipeType: RecipeType + get() = RecipeType.BLASTING + override val secondaryRecipeType: RecipeType? + get() = null + override val config: WorkerBalanceValues + get() = MachinesConfig.POWERED_FURNACE + override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { return PoweredFurnaceMenu.blasting(containerID, inventory, this) } } -class PoweredSmokerBlockEntity(blockPos: BlockPos, blockState: BlockState) : AbstractPoweredFurnaceBlockEntity( - MBlockEntities.POWERED_SMOKER, blockPos, blockState, RecipeType.SMOKING, MRecipes.MICROWAVE, MachinesConfig.POWERED_FURNACE) { +class PoweredSmokerBlockEntity(blockPos: BlockPos, blockState: BlockState) : AbstractPoweredFurnaceBlockEntity(MBlockEntities.POWERED_SMOKER, blockPos, blockState) { + override val recipeType: RecipeType + get() = RecipeType.SMOKING + override val secondaryRecipeType: RecipeType + get() = MRecipes.MICROWAVE + override val config: WorkerBalanceValues + get() = MachinesConfig.POWERED_FURNACE + override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { return PoweredFurnaceMenu.smoking(containerID, inventory, this) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PoweredFurnaceMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PoweredFurnaceMenu.kt index 85739a185..f66e42b08 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PoweredFurnaceMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PoweredFurnaceMenu.kt @@ -1,19 +1,24 @@ package ru.dbotthepony.mc.otm.menu.tech +import com.google.common.collect.ImmutableList import mezz.jei.api.constants.RecipeTypes import mezz.jei.api.recipe.RecipeType import net.minecraft.server.level.ServerPlayer -import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory import net.minecraft.world.inventory.MenuType +import net.minecraft.world.item.crafting.Recipe +import net.minecraft.world.item.crafting.SingleRecipeInput import ru.dbotthepony.mc.otm.block.entity.tech.AbstractPoweredFurnaceBlockEntity import ru.dbotthepony.mc.otm.block.entity.tech.PoweredBlastFurnaceBlockEntity import ru.dbotthepony.mc.otm.block.entity.tech.PoweredFurnaceBlockEntity import ru.dbotthepony.mc.otm.block.entity.tech.PoweredSmokerBlockEntity import ru.dbotthepony.mc.otm.compat.jei.MicrowaveRecipeCategory +import ru.dbotthepony.mc.otm.container.EnhancedContainer +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.menu.OutputMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput @@ -23,6 +28,7 @@ import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.TakeExperienceWidget import ru.dbotthepony.mc.otm.registry.game.MMenus +import ru.dbotthepony.mc.otm.registry.game.MRecipes import java.util.function.Supplier class PoweredFurnaceMenu( @@ -31,8 +37,10 @@ class PoweredFurnaceMenu( inventory: Inventory, tile: AbstractPoweredFurnaceBlockEntity<*, *>? = null ) : AbstractProcessingMachineMenu(type, containerID, inventory, tile) { - val inputSlots = makeSlots(tile?.inputs ?: SimpleContainer(2), ::MatteryMenuSlot) - val outputSlots = makeSlots(tile?.outputs ?: SimpleContainer(2)) { c, s -> OutputMenuSlot(c, s) { tile?.experience?.popExperience(player as ServerPlayer) } } + // we can't make these slots to reject non-smeltable items + // since mods may add obscure recipes/ingredients which never test true on client + val inputSlots = makeSlots(tile?.inputs ?: SlottedContainer.filtered(2), ::UserFilteredMenuSlot) + val outputSlots = makeSlots(tile?.outputs ?: EnhancedContainer(2)) { c, s -> OutputMenuSlot(c, s) { tile?.experience?.popExperience(player as ServerPlayer) } } val progressGauge = immutableList(2) { ProgressGaugeWidget(this, tile?.jobEventLoops?.get(it)) } override val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig, allowPush = true)