diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt index 1817ae2ee..2f178dfb4 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt @@ -659,6 +659,7 @@ private fun gui(provider: MatteryLanguageProvider) { gui("sides.item_config", "Item Configuration") gui("sides.energy_config", "Energy Configuration") + gui("sides.fluid_config", "Fluid Configuration") gui("sides.top", "Top") gui("sides.bottom", "Bottom") diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt index 1b957ba61..c450a4a45 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt @@ -664,6 +664,7 @@ private fun gui(provider: MatteryLanguageProvider) { gui("sides.item_config", "Настройка предметов") gui("sides.energy_config", "Настройка энергии") + gui("sides.fluid_config", "Настройка жидкости") gui("sides.top", "Верхняя сторона") gui("sides.bottom", "Нижняя сторона") diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt index dcef9b156..44ed68d03 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt @@ -13,6 +13,8 @@ import net.minecraft.network.chat.Component import net.minecraft.world.item.ItemStack import net.minecraft.world.level.Level import net.minecraftforge.common.capabilities.ForgeCapabilities +import net.minecraftforge.fluids.FluidStack +import net.minecraftforge.fluids.capability.IFluidHandler import net.minecraftforge.items.IItemHandler import ru.dbotthepony.mc.otm.capability.CombinedItemHandler import ru.dbotthepony.mc.otm.capability.EmptyItemHandler @@ -21,6 +23,7 @@ import ru.dbotthepony.mc.otm.capability.UnmodifiableItemHandler import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage import ru.dbotthepony.mc.otm.capability.moveBetweenSlots import ru.dbotthepony.mc.otm.capability.moveEnergy +import ru.dbotthepony.mc.otm.capability.moveFluid import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.getValue import ru.dbotthepony.mc.otm.core.ifPresentK @@ -84,6 +87,153 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo } } + inner class ConfigurableFluidHandler( + val capability: T, + + val possibleModes: FlowDirection = FlowDirection.BI_DIRECTIONAL, + + val frontDefault: FlowDirection = possibleModes, + val backDefault: FlowDirection = possibleModes, + val leftDefault: FlowDirection = possibleModes, + val rightDefault: FlowDirection = possibleModes, + val topDefault: FlowDirection = possibleModes, + val bottomDefault: FlowDirection = possibleModes, + ) { + init { + exposeSideless(ForgeCapabilities.FLUID_HANDLER, capability) + } + + val front = Piece(RelativeSide.FRONT).also { it.flow = frontDefault } + val back = Piece(RelativeSide.BACK).also { it.flow = backDefault } + val left = Piece(RelativeSide.LEFT).also { it.flow = leftDefault } + val right = Piece(RelativeSide.RIGHT).also { it.flow = rightDefault } + val top = Piece(RelativeSide.TOP).also { it.flow = topDefault } + val bottom = Piece(RelativeSide.BOTTOM).also { it.flow = bottomDefault } + + val pieces = immutableMap { + put(RelativeSide.FRONT, front) + put(RelativeSide.BACK, back) + put(RelativeSide.LEFT, left) + put(RelativeSide.RIGHT, right) + put(RelativeSide.TOP, top) + put(RelativeSide.BOTTOM, bottom) + } + + val defaults = immutableMap { + put(RelativeSide.FRONT, frontDefault) + put(RelativeSide.BACK, backDefault) + put(RelativeSide.LEFT, leftDefault) + put(RelativeSide.RIGHT, rightDefault) + put(RelativeSide.TOP, topDefault) + put(RelativeSide.BOTTOM, bottomDefault) + } + + inner class Piece(val side: RelativeSide) : IFluidHandler, ITickable { + init { + tickList.always(this) + + // https://tenor.com/view/simp-metal-gear-liquid-snake-running-gif-16717852 + savetables.enum(::flow, "fluid_${side}_flow", FlowDirection::valueOf) + savetables.bool(::automatePull, "fluid_${side}_pull") + savetables.bool(::automatePush, "fluid_${side}_push") + } + + private val controller = sides[side]!!.Cap(ForgeCapabilities.FLUID_HANDLER, this) + private val neighbour by sides[side]!!.track(ForgeCapabilities.FLUID_HANDLER) + + var flow by synchronizer.enum(possibleModes, setter = { value, access, setByRemote -> + require(possibleModes.isSupertype(value)) { "Energy mode $value is not allowed (allowed modes: ${possibleModes.family})" } + + if (access.read() != value) { + access.write(value) + + if (value == FlowDirection.NONE) { + controller.close() + } else { + controller.close() + controller.expose() + } + } + }) + + // var automatePull by synchronizer.bool().property + var automatePull = false + // var automatePush by synchronizer.bool().property + var automatePush = false + + override fun tick() { + if (flow == FlowDirection.NONE || !automatePull && !automatePush || redstoneControl.isBlockedByRedstone) + return + + neighbour.ifPresentK { + if (flow.input && automatePull) { + moveFluid(source = it, destination = capability) + } + + if (flow.output && automatePush) { + moveFluid(source = capability, destination = it) + } + } + } + + override fun getTanks(): Int { + if (flow == FlowDirection.NONE) { + return 0 + } else { + return capability.getTanks() + } + } + + override fun getFluidInTank(tank: Int): FluidStack { + if (flow == FlowDirection.NONE) { + return FluidStack.EMPTY + } else { + return capability.getFluidInTank(tank) + } + } + + override fun getTankCapacity(tank: Int): Int { + if (flow == FlowDirection.NONE) { + return 0 + } else { + return capability.getTankCapacity(tank) + } + } + + override fun isFluidValid(tank: Int, stack: FluidStack): Boolean { + if (flow.input) { + return capability.isFluidValid(tank, stack) + } else { + return false + } + } + + override fun fill(resource: FluidStack, action: IFluidHandler.FluidAction): Int { + if (flow.input) { + return capability.fill(resource, action) + } else { + return 0 + } + } + + override fun drain(resource: FluidStack, action: IFluidHandler.FluidAction): FluidStack { + if (flow.output) { + return capability.drain(resource, action) + } else { + return FluidStack.EMPTY + } + } + + override fun drain(maxDrain: Int, action: IFluidHandler.FluidAction): FluidStack { + if (flow.output) { + return capability.drain(maxDrain, action) + } else { + return FluidStack.EMPTY + } + } + } + } + inner class ConfigurableEnergy( val capability: T, @@ -129,6 +279,25 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo private val capControllers = exposeEnergy(side, this@Piece) private val neighbour by sides[side]!!.track(ForgeCapabilities.ENERGY) + override var batteryLevel: Decimal by capability::batteryLevel + override val maxBatteryLevel: Decimal by capability::maxBatteryLevel + override val missingPower: Decimal by capability::missingPower + + override val canSetBatteryLevel: Boolean by capability::canSetBatteryLevel + + // var automatePull by synchronizer.bool().property + var automatePull = false + // var automatePush by synchronizer.bool().property + var automatePush = false + + init { + tickList.always(this) + + savetables.enum(::energyFlow, "energy_${side}_flow", FlowDirection::valueOf) + savetables.bool(::automatePull, "energy_${side}_pull") + savetables.bool(::automatePush, "energy_${side}_push") + } + override fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal { return capability.extractEnergy(howMuch, simulate) } @@ -151,12 +320,6 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo return Decimal.ZERO } - override var batteryLevel: Decimal by capability::batteryLevel - override val maxBatteryLevel: Decimal by capability::maxBatteryLevel - override val missingPower: Decimal by capability::missingPower - - override val canSetBatteryLevel: Boolean by capability::canSetBatteryLevel - override fun drainBattery(): Boolean { return capability.drainBattery() } @@ -180,10 +343,6 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo } } - init { - tickList.always(this) - } - override var energyFlow by synchronizer.enum(possibleModes, setter = { value, access, setByRemote -> require(possibleModes.isSupertype(value)) { "Energy mode $value is not allowed (allowed modes: ${possibleModes.family})" } @@ -201,15 +360,6 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo } } }) - - var automatePull by synchronizer.bool().property - var automatePush by synchronizer.bool().property - - init { - savetables.enum(::energyFlow, "energy_${side}_flow", FlowDirection::valueOf) - savetables.bool(::automatePull, "energy_${side}_pull") - savetables.bool(::automatePush, "energy_${side}_push") - } } } @@ -311,9 +461,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo put(RelativeSide.BOTTOM, bottomDefault) } - inner class Piece( - val side: RelativeSide, - ) : IItemHandler, ITickable { + inner class Piece(val side: RelativeSide) : IItemHandler, ITickable { private var currentHandler: IItemHandler = EmptyItemHandler private val capController = sides[side]!!.Cap(ForgeCapabilities.ITEM_HANDLER, this) private val neighbour by sides[side]!!.track(ForgeCapabilities.ITEM_HANDLER) @@ -346,7 +494,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo } }) - var automatePull by synchronizer.bool(setter = { value, access, _ -> + /*var automatePull by synchronizer.bool(setter = { value, access, _ -> if (access.readBoolean() != value) { access.write(value) @@ -366,7 +514,31 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo outerSlotPush = 0 } } - }).property + }).property*/ + + var automatePull = false + set(value) { + if (field != value) { + field = value + + if (value) { + innerSlotPush = 0 + outerSlotPush = 0 + } + } + } + + var automatePush = false + set(value) { + if (field != value) { + field = value + + if (value) { + innerSlotPush = 0 + outerSlotPush = 0 + } + } + } init { savetables.bool(::automatePull, "itemhandler_${side}_automatePull") diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/FluidTankBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/FluidTankBlockEntity.kt index f10dc1c0a..5b184133e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/FluidTankBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/FluidTankBlockEntity.kt @@ -62,8 +62,9 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery bottomDefault = ItemHandlerMode.INPUT_OUTPUT, ) + val fluidConfig = ConfigurableFluidHandler(fluid) + init { - exposeGlobally(ForgeCapabilities.FLUID_HANDLER, fluid) savetables.stateful(::fluid, FLUID_KEY) savetables.stateful(::fillInput) savetables.stateful(::drainInput) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt index 75194029f..a34697f1c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt @@ -106,6 +106,7 @@ object Widgets18 { val BATTERY_ONLY = controlsGrid.next() val ITEMS_CONFIGURATION = controlsGrid.next() val ENERGY_CONFIGURATION = controlsGrid.next() + val FLUID_CONFIGURATION = controlsGrid.next() val LEFT_CONTROLS_ITEMS = controls2(LEFT_CONTROLS) val RIGHT_CONTROLS_ITEMS = controls2(RIGHT_CONTROLS) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/FluidTankScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/FluidTankScreen.kt index 4f9f9f00e..9edcc6387 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/FluidTankScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/FluidTankScreen.kt @@ -30,7 +30,7 @@ class FluidTankScreen(menu: FluidTankMenu, inventory: Inventory, title: Componen SlotPanel(this, frame, menu.output, x = 30f + s.width + 4f + 20f, y = 53f) - makeDeviceControls(this, frame, itemConfig = menu.itemConfig, redstoneConfig = menu.redstoneConfig) + makeDeviceControls(this, frame, itemConfig = menu.itemConfig, redstoneConfig = menu.redstoneConfig, fluidConfig = menu.fluidConfig) makeCuriosPanel(this, frame, menu.equipment.curiosSlots, autoAlign = true) PlayerEquipmentPanel(this, frame, armorSlots = menu.equipment.armorSlots).also { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/button/Buttons.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/button/Buttons.kt index 0d9c8f7f2..d89dbc847 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/button/Buttons.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/button/Buttons.kt @@ -13,6 +13,7 @@ import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.math.RelativeSide import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput +import ru.dbotthepony.mc.otm.menu.input.FluidConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.IPlayerInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import java.util.function.Predicate @@ -66,6 +67,18 @@ private fun > makeEnergyModeButton(screen: S, parent: Frame return button } +private fun > makeFluidModeButton(screen: S, parent: FramePanel, input: FluidConfigPlayerInput.Piece, side: RelativeSide): LargeEnumRectangleButtonPanel { + val button = LargeEnumRectangleButtonPanel(screen, parent, enum = FlowDirection::class.java, prop = input.input, defaultValue = input.default) + + for (v in FlowDirection.values()) { + button.add(v, skinElement = Widgets18.CONTROLS[side]!![v]!!, tooltip = TranslatableComponent(v.translationKey)) + } + + button.finish() + + return button +} + private fun moveButtons( front: EditablePanel<*>, back: EditablePanel<*>, @@ -191,6 +204,35 @@ private fun > makeEnergyConfigPanel( return frame } +private fun > makeFluidConfigPanel( + screen: S, + inputs: FluidConfigPlayerInput +): FramePanel { + val frame = object : FramePanel(screen, 78f, 80f, TranslatableComponent("otm.gui.sides.fluid_config")) { + override fun tickInner() { + super.tickInner() + + if (!isEverFocused()) { + remove() + } + } + } + + val front = makeFluidModeButton(screen, frame, inputs.pieces[RelativeSide.FRONT]!!, RelativeSide.FRONT).also { it.predicate = Predicate { inputs.possibleModes.isSupertype(it) } } + val back = makeFluidModeButton(screen, frame, inputs.pieces[RelativeSide.BACK]!!, RelativeSide.BACK).also { it.predicate = Predicate { inputs.possibleModes.isSupertype(it) } } + val left = makeFluidModeButton(screen, frame, inputs.pieces[RelativeSide.LEFT]!!, RelativeSide.LEFT).also { it.predicate = Predicate { inputs.possibleModes.isSupertype(it) } } + val right = makeFluidModeButton(screen, frame, inputs.pieces[RelativeSide.RIGHT]!!, RelativeSide.RIGHT).also { it.predicate = Predicate { inputs.possibleModes.isSupertype(it) } } + val top = makeFluidModeButton(screen, frame, inputs.pieces[RelativeSide.TOP]!!, RelativeSide.TOP).also { it.predicate = Predicate { inputs.possibleModes.isSupertype(it) } } + val bottom = makeFluidModeButton(screen, frame, inputs.pieces[RelativeSide.BOTTOM]!!, RelativeSide.BOTTOM).also { it.predicate = Predicate { inputs.possibleModes.isSupertype(it) } } + + pullPush(frame, inputs.pull, inputs.push) + moveButtons(front, back, left, right, top, bottom) + screen.addPanel(frame) + frame.requestFocus() + + return frame +} + class DeviceControls>( screen: S, parent: FramePanel, @@ -198,9 +240,11 @@ class DeviceControls>( val redstoneConfig: IPlayerInputWithFeedback? = null, val itemConfig: ItemConfigPlayerInput? = null, val energyConfig: EnergyConfigPlayerInput? = null, + val fluidConfig: FluidConfigPlayerInput? = null, ) : EditablePanel(screen, parent, x = parent.width + 3f, height = 0f, width = 0f) { val itemConfigButton: LargeRectangleButtonPanel? val energyConfigButton: LargeRectangleButtonPanel? + val fluidConfigButton: LargeRectangleButtonPanel? val redstoneControlsButton: LargeEnumRectangleButtonPanel? private var nextY = 0f @@ -262,6 +306,25 @@ class DeviceControls>( } else { energyConfigButton = null } + + if (fluidConfig != null) { + fluidConfigButton = addButton(object : LargeRectangleButtonPanel(screen, this@DeviceControls, y = nextY, skinElement = Widgets18.FLUID_CONFIGURATION) { + init { + tooltip = TranslatableComponent("otm.gui.sides.fluid_config") + } + + override fun onClick(mouseButton: Int) { + if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) { + val frame = makeFluidConfigPanel(screen, fluidConfig) + + frame.x = absoluteX + width / 2f - frame.width / 2f + frame.y = absoluteY + height + 8f + } + } + }) + } else { + fluidConfigButton = null + } } override fun tickInner() { @@ -278,6 +341,7 @@ fun > makeDeviceControls( redstoneConfig: IPlayerInputWithFeedback? = null, itemConfig: ItemConfigPlayerInput? = null, energyConfig: EnergyConfigPlayerInput? = null, + fluidConfig: FluidConfigPlayerInput? = null, ): DeviceControls { - return DeviceControls(screen, parent, extra = extra, redstoneConfig = redstoneConfig, itemConfig = itemConfig, energyConfig = energyConfig) + return DeviceControls(screen, parent, extra = extra, redstoneConfig = redstoneConfig, itemConfig = itemConfig, energyConfig = energyConfig, fluidConfig = fluidConfig) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Savetables.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Savetables.kt index 670a2a580..ce92d4f66 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Savetables.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Savetables.kt @@ -27,7 +27,7 @@ import kotlin.reflect.KProperty0 class Savetables : INBTSerializable { private val entries = ArrayList>() - interface Entry : INBTSerializable { + sealed interface Entry : INBTSerializable { val name: String val type: Class fun validate() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/FluidTankMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/FluidTankMenu.kt index e7e1b4693..cce696644 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/FluidTankMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/FluidTankMenu.kt @@ -13,6 +13,7 @@ import ru.dbotthepony.mc.otm.menu.MachineOutputSlot 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.FluidConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.widget.FluidGaugeWidget import ru.dbotthepony.mc.otm.registry.MMenus @@ -22,6 +23,7 @@ class FluidTankMenu(containerId: Int, inventory: Inventory, tile: FluidTankBlock val equipment = makeEquipmentSlots(true) val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig) val redstoneConfig = EnumInputWithFeedback(this) + val fluidConfig = FluidConfigPlayerInput(this, tile?.fluidConfig) val drainInput = object : MatterySlot(tile?.drainInput ?: SimpleContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/input/FluidConfigPlayerInput.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/input/FluidConfigPlayerInput.kt new file mode 100644 index 000000000..aa0afad4e --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/input/FluidConfigPlayerInput.kt @@ -0,0 +1,68 @@ +package ru.dbotthepony.mc.otm.menu.input + +import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity +import ru.dbotthepony.mc.otm.capability.FlowDirection +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 FluidConfigPlayerInput(val menu: MatteryMenu, config: MatteryDeviceBlockEntity.ConfigurableFluidHandler<*>? = null, val allowPull: Boolean = false, val allowPush: Boolean = false) { + var possibleModes by menu.mSynchronizer.enum(FlowDirection::class.java) + private set + + inner class Piece(val side: RelativeSide) { + val pull = BooleanInputWithFeedback(menu) + val push = BooleanInputWithFeedback(menu) + val input = EnumInputWithFeedback(menu) + + var default by menu.mSynchronizer.enum(FlowDirection.NONE) + + init { + pull.filter { allowPull } + push.filter { allowPush } + } + + fun with(config: MatteryDeviceBlockEntity.ConfigurableFluidHandler<*>.Piece, parent: MatteryDeviceBlockEntity.ConfigurableFluidHandler<*>) { + pull.with(config::automatePull) + push.with(config::automatePush) + input.withSupplier { config.flow }.withConsumer { if (parent.possibleModes.isSupertype(it)) config.flow = it } + } + } + + val pieces = immutableMap { for (side in RelativeSide.values()) put(side, Piece(side)) } + + // TODO + val pull = BooleanInputWithFeedback(menu) + + // TODO + val push = BooleanInputWithFeedback(menu) + + init { + pull.filter { allowPull } + push.filter { allowPush } + } + + fun with(config: MatteryDeviceBlockEntity.ConfigurableFluidHandler<*>) { + possibleModes = config.possibleModes + + for ((side, v) in config.pieces) { + pieces[side]!!.with(v, config) + pieces[side]!!.default = config.defaults[side]!! + } + + pull.withSupplier { pieces.values.all { it.pull.value } } + push.withSupplier { pieces.values.all { it.push.value } } + + pull.withConsumer { v -> pieces.values.forEach { it.pull.input.invoke(v) } } + push.withConsumer { v -> pieces.values.forEach { it.push.input.invoke(v) } } + } + + init { + if (config != null) { + with(config) + } + } +} diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/side_controls.png b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/side_controls.png index 30dfc45a7..b9553b67f 100644 Binary files a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/side_controls.png and b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/side_controls.png differ diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/side_controls.xcf b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/side_controls.xcf index 4011dd829..119df61fc 100644 Binary files a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/side_controls.xcf and b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/side_controls.xcf differ