Input balancing
This commit is contained in:
parent
2e37ff5de4
commit
4f7c9ea176
@ -680,6 +680,8 @@ private fun gui(provider: MatteryLanguageProvider) {
|
|||||||
gui("side_mode.pull", "Pull")
|
gui("side_mode.pull", "Pull")
|
||||||
gui("side_mode.push", "Push")
|
gui("side_mode.push", "Push")
|
||||||
|
|
||||||
|
gui("balance_inputs", "Balance input slots")
|
||||||
|
|
||||||
gui("sorting.default", "Default sorting")
|
gui("sorting.default", "Default sorting")
|
||||||
gui("sorting.name", "Sort by name")
|
gui("sorting.name", "Sort by name")
|
||||||
gui("sorting.id", "Sort by ID")
|
gui("sorting.id", "Sort by ID")
|
||||||
|
@ -685,6 +685,8 @@ private fun gui(provider: MatteryLanguageProvider) {
|
|||||||
gui("side_mode.pull", "Автоматическое вытягивание")
|
gui("side_mode.pull", "Автоматическое вытягивание")
|
||||||
gui("side_mode.push", "Автоматическое выталкивание")
|
gui("side_mode.push", "Автоматическое выталкивание")
|
||||||
|
|
||||||
|
gui("balance_inputs", "Балансировать входные слоты")
|
||||||
|
|
||||||
gui("sorting.default", "Сортировка по умолчанию")
|
gui("sorting.default", "Сортировка по умолчанию")
|
||||||
gui("sorting.name", "Сортировка по имени")
|
gui("sorting.name", "Сортировка по имени")
|
||||||
gui("sorting.id", "Сортировка по ID")
|
gui("sorting.id", "Сортировка по ID")
|
||||||
|
@ -7,13 +7,10 @@ import net.minecraft.data.recipes.FinishedRecipe
|
|||||||
import net.minecraft.resources.ResourceLocation
|
import net.minecraft.resources.ResourceLocation
|
||||||
import net.minecraft.util.valueproviders.ConstantFloat
|
import net.minecraft.util.valueproviders.ConstantFloat
|
||||||
import net.minecraft.util.valueproviders.FloatProvider
|
import net.minecraft.util.valueproviders.FloatProvider
|
||||||
import net.minecraft.util.valueproviders.UniformFloat
|
|
||||||
import net.minecraft.world.item.crafting.RecipeSerializer
|
import net.minecraft.world.item.crafting.RecipeSerializer
|
||||||
import ru.dbotthepony.mc.otm.recipe.PlatePressRecipe
|
import ru.dbotthepony.mc.otm.recipe.PlatePressRecipe
|
||||||
import ru.dbotthepony.mc.otm.recipe.PlatePressRecipeFactory
|
|
||||||
import ru.dbotthepony.mc.otm.core.set
|
import ru.dbotthepony.mc.otm.core.set
|
||||||
import ru.dbotthepony.mc.otm.core.toJsonStrict
|
import ru.dbotthepony.mc.otm.core.toJsonStrict
|
||||||
import ru.dbotthepony.mc.otm.data.getOrNull
|
|
||||||
|
|
||||||
class PlatePressFinishedRecipe(private val recipe: PlatePressRecipe) : FinishedRecipe {
|
class PlatePressFinishedRecipe(private val recipe: PlatePressRecipe) : FinishedRecipe {
|
||||||
override fun serializeRecipeData(it: JsonObject) {
|
override fun serializeRecipeData(it: JsonObject) {
|
||||||
@ -33,7 +30,7 @@ class PlatePressFinishedRecipe(private val recipe: PlatePressRecipe) : FinishedR
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getType(): RecipeSerializer<*> {
|
override fun getType(): RecipeSerializer<*> {
|
||||||
return PlatePressRecipeFactory
|
return PlatePressRecipe.Companion
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun serializeAdvancement(): JsonObject? {
|
override fun serializeAdvancement(): JsonObject? {
|
||||||
@ -74,7 +71,7 @@ class PlatePressShallowFinishedRecipe(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getType(): RecipeSerializer<*> {
|
override fun getType(): RecipeSerializer<*> {
|
||||||
return PlatePressRecipeFactory
|
return PlatePressRecipe.Companion
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun serializeAdvancement(): JsonObject? {
|
override fun serializeAdvancement(): JsonObject? {
|
||||||
|
@ -61,6 +61,12 @@ abstract class MatteryWorkerBlockEntity<JobType : IMachineJob>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var balanceInputs = false
|
||||||
|
|
||||||
|
init {
|
||||||
|
savetables.bool(::balanceInputs)
|
||||||
|
}
|
||||||
|
|
||||||
protected open fun jobUpdated(new: JobType?, old: JobType?, id: Int) {}
|
protected open fun jobUpdated(new: JobType?, old: JobType?, id: Int) {}
|
||||||
protected abstract fun onJobFinish(job: JobType, id: Int): JobStatus
|
protected abstract fun onJobFinish(job: JobType, id: Int): JobStatus
|
||||||
protected abstract fun computeNextJob(id: Int): JobContainer<JobType>
|
protected abstract fun computeNextJob(id: Int): JobContainer<JobType>
|
||||||
|
@ -17,6 +17,7 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
|
|||||||
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
import ru.dbotthepony.mc.otm.config.MachinesConfig
|
||||||
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
import ru.dbotthepony.mc.otm.container.MatteryContainer
|
||||||
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
import ru.dbotthepony.mc.otm.container.HandlerFilter
|
||||||
|
import ru.dbotthepony.mc.otm.container.balance
|
||||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||||
import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu
|
import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu
|
||||||
import ru.dbotthepony.mc.otm.menu.tech.TwinPlatePressMenu
|
import ru.dbotthepony.mc.otm.menu.tech.TwinPlatePressMenu
|
||||||
@ -87,6 +88,14 @@ class PlatePressBlockEntity(
|
|||||||
return JobContainer.success(MachineItemJob(recipe.getResultItem(level.registryAccess()), recipe.workTime.toDouble(), BASELINE_CONSUMPTION, experience = recipe.experience.sample(level.random)))
|
return JobContainer.success(MachineItemJob(recipe.getResultItem(level.registryAccess()), recipe.workTime.toDouble(), BASELINE_CONSUMPTION, experience = recipe.experience.sample(level.random)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun tick() {
|
||||||
|
if (isTwin && balanceInputs) {
|
||||||
|
inputContainer.balance()
|
||||||
|
}
|
||||||
|
|
||||||
|
super.tick()
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val BASELINE_CONSUMPTION = Decimal(15)
|
private val BASELINE_CONSUMPTION = Decimal(15)
|
||||||
}
|
}
|
||||||
|
@ -70,9 +70,8 @@ object Widgets18 {
|
|||||||
val REDSTONE_LOW = controlsGrid.next()
|
val REDSTONE_LOW = controlsGrid.next()
|
||||||
val REDSTONE_HIGH = controlsGrid.next()
|
val REDSTONE_HIGH = controlsGrid.next()
|
||||||
|
|
||||||
init {
|
val BALANCING_DISABLED = controlsGrid.next()
|
||||||
controlsGrid.jump()
|
val BALANCING_ENABLED = controlsGrid.next()
|
||||||
}
|
|
||||||
|
|
||||||
class SideControls {
|
class SideControls {
|
||||||
val disabled = controlsGrid.next()
|
val disabled = controlsGrid.next()
|
||||||
|
@ -274,11 +274,13 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
|||||||
val itemConfig: ItemConfigPlayerInput? = null,
|
val itemConfig: ItemConfigPlayerInput? = null,
|
||||||
val energyConfig: EnergyConfigPlayerInput? = null,
|
val energyConfig: EnergyConfigPlayerInput? = null,
|
||||||
val fluidConfig: FluidConfigPlayerInput? = null,
|
val fluidConfig: FluidConfigPlayerInput? = null,
|
||||||
|
val balanceInputs: BooleanInputWithFeedback? = null,
|
||||||
) : EditablePanel<S>(screen, parent, x = parent.width + 3f, height = 0f, width = 0f) {
|
) : EditablePanel<S>(screen, parent, x = parent.width + 3f, height = 0f, width = 0f) {
|
||||||
val itemConfigButton: LargeRectangleButtonPanel<S>?
|
val itemConfigButton: LargeRectangleButtonPanel<S>?
|
||||||
val energyConfigButton: LargeRectangleButtonPanel<S>?
|
val energyConfigButton: LargeRectangleButtonPanel<S>?
|
||||||
val fluidConfigButton: LargeRectangleButtonPanel<S>?
|
val fluidConfigButton: LargeRectangleButtonPanel<S>?
|
||||||
val redstoneControlsButton: LargeEnumRectangleButtonPanel<S, RedstoneSetting>?
|
val redstoneControlsButton: LargeEnumRectangleButtonPanel<S, RedstoneSetting>?
|
||||||
|
val balanceInputsButton: LargeBooleanRectangleButtonPanel<S>?
|
||||||
private var nextY = 0f
|
private var nextY = 0f
|
||||||
|
|
||||||
fun <P : EditablePanel<@UnsafeVariance S>> addButton(button: P): P {
|
fun <P : EditablePanel<@UnsafeVariance S>> addButton(button: P): P {
|
||||||
@ -302,6 +304,18 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
|||||||
redstoneControlsButton = null
|
redstoneControlsButton = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (balanceInputs != null) {
|
||||||
|
balanceInputsButton = addButton(LargeBooleanRectangleButtonPanel(
|
||||||
|
screen, this,
|
||||||
|
prop = balanceInputs,
|
||||||
|
skinElementActive = Widgets18.BALANCING_ENABLED,
|
||||||
|
skinElementInactive = Widgets18.BALANCING_DISABLED).also {
|
||||||
|
it.tooltip = TranslatableComponent("otm.gui.balance_inputs")
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
balanceInputsButton = null
|
||||||
|
}
|
||||||
|
|
||||||
if (itemConfig != null) {
|
if (itemConfig != null) {
|
||||||
itemConfigButton = addButton(object : LargeRectangleButtonPanel<S>(screen, this@DeviceControls, skinElement = Widgets18.ITEMS_CONFIGURATION) {
|
itemConfigButton = addButton(object : LargeRectangleButtonPanel<S>(screen, this@DeviceControls, skinElement = Widgets18.ITEMS_CONFIGURATION) {
|
||||||
init {
|
init {
|
||||||
@ -375,6 +389,9 @@ fun <S : MatteryScreen<*>> makeDeviceControls(
|
|||||||
itemConfig: ItemConfigPlayerInput? = null,
|
itemConfig: ItemConfigPlayerInput? = null,
|
||||||
energyConfig: EnergyConfigPlayerInput? = null,
|
energyConfig: EnergyConfigPlayerInput? = null,
|
||||||
fluidConfig: FluidConfigPlayerInput? = null,
|
fluidConfig: FluidConfigPlayerInput? = null,
|
||||||
|
balanceInputs: BooleanInputWithFeedback? = null,
|
||||||
): DeviceControls<S> {
|
): DeviceControls<S> {
|
||||||
return DeviceControls(screen, parent, extra = extra, redstoneConfig = redstoneConfig, itemConfig = itemConfig, energyConfig = energyConfig, fluidConfig = fluidConfig)
|
return DeviceControls(screen, parent, extra = extra, redstoneConfig = redstoneConfig,
|
||||||
|
itemConfig = itemConfig, energyConfig = energyConfig, fluidConfig = fluidConfig,
|
||||||
|
balanceInputs = balanceInputs)
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ class TwinPlatePressScreen(menu: TwinPlatePressMenu, inventory: Inventory, title
|
|||||||
ProgressGaugePanel(this, frame, menu.progressGauge1, 78f, PROGRESS_ARROW_TOP + 10f)
|
ProgressGaugePanel(this, frame, menu.progressGauge1, 78f, PROGRESS_ARROW_TOP + 10f)
|
||||||
SlotPanel(this, frame, menu.outputSlots[1], 104f, PROGRESS_SLOT_TOP + 10f)
|
SlotPanel(this, frame, menu.outputSlots[1], 104f, PROGRESS_SLOT_TOP + 10f)
|
||||||
|
|
||||||
makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig, itemConfig = menu.itemConfig)
|
makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig, itemConfig = menu.itemConfig, balanceInputs = menu.balanceInputs)
|
||||||
|
|
||||||
return frame
|
return frame
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,19 @@
|
|||||||
package ru.dbotthepony.mc.otm.container
|
package ru.dbotthepony.mc.otm.container
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntArrayList
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntArraySet
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntSet
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap
|
||||||
import net.minecraft.world.Container
|
import net.minecraft.world.Container
|
||||||
import net.minecraft.world.item.ItemStack
|
import net.minecraft.world.item.ItemStack
|
||||||
import net.minecraftforge.common.capabilities.Capability
|
import net.minecraftforge.common.capabilities.Capability
|
||||||
import net.minecraftforge.fluids.capability.IFluidHandler
|
import net.minecraftforge.fluids.capability.IFluidHandler
|
||||||
|
import ru.dbotthepony.mc.otm.core.addAll
|
||||||
import ru.dbotthepony.mc.otm.core.collect.iterator
|
import ru.dbotthepony.mc.otm.core.collect.iterator
|
||||||
import ru.dbotthepony.mc.otm.core.collect.nonEmpty
|
import ru.dbotthepony.mc.otm.core.collect.nonEmpty
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
operator fun Container.set(index: Int, value: ItemStack) = setItem(index, value)
|
operator fun Container.set(index: Int, value: ItemStack) = setItem(index, value)
|
||||||
operator fun Container.get(index: Int): ItemStack = getItem(index)
|
operator fun Container.get(index: Int): ItemStack = getItem(index)
|
||||||
@ -109,3 +117,133 @@ inline fun Container.forEachNonEmpty(lambda: (ItemStack) -> Unit) {
|
|||||||
lambda(value)
|
lambda(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Container.balance(slots: IntSet) {
|
||||||
|
if (slots.isEmpty()) return
|
||||||
|
|
||||||
|
val empty = IntArrayList()
|
||||||
|
val itemTypes = Object2ObjectOpenCustomHashMap<ItemStack, IntAVLTreeSet>(ItemStackHashStrategy)
|
||||||
|
|
||||||
|
for (i in slots.intIterator()) {
|
||||||
|
val item = getItem(i)
|
||||||
|
|
||||||
|
if (item.isEmpty) {
|
||||||
|
empty.add(i)
|
||||||
|
} else {
|
||||||
|
itemTypes.computeIfAbsent(item, Object2ObjectFunction { IntAVLTreeSet() }).add(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemTypes.isEmpty())
|
||||||
|
return
|
||||||
|
|
||||||
|
// только один вид предмета, просто балансируем его во все слоты
|
||||||
|
if (itemTypes.size == 1) {
|
||||||
|
val (item, list) = itemTypes.entries.first()
|
||||||
|
var count = list.stream().mapToInt { getItem(it).count }.sum()
|
||||||
|
|
||||||
|
// всего предметов меньше, чем слотов
|
||||||
|
if (count < slots.size) {
|
||||||
|
for (slot in list.intIterator()) {
|
||||||
|
getItem(slot).count = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
count -= list.size
|
||||||
|
|
||||||
|
while (count > 0 && empty.isNotEmpty()) {
|
||||||
|
setItem(empty.removeInt(0), item.copyWithCount(1))
|
||||||
|
count--
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
getItem(list.firstInt()).count += count
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// всего предметов больше, чем слотов
|
||||||
|
val perSlot = count / slots.size
|
||||||
|
var leftover = count - perSlot * slots.size
|
||||||
|
|
||||||
|
for (i in slots.intIterator()) {
|
||||||
|
setItem(i, item.copyWithCount(perSlot))
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in slots.intIterator()) {
|
||||||
|
if (leftover <= 0) break
|
||||||
|
getItem(i).count++
|
||||||
|
leftover--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setChanged()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// а вот тут уже проблемы
|
||||||
|
// для упрощения задачи, выполним рекурсивное разбитие задачи на более простые,
|
||||||
|
// где балансировка будет происходить только между пустыми слотами и предметами одного типа
|
||||||
|
|
||||||
|
// если у нас нет пустых слотов, просто балансируем между заполненными слотами
|
||||||
|
if (empty.isEmpty) {
|
||||||
|
for (set in itemTypes.values) {
|
||||||
|
balance(set)
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
} else if (empty.size == 1) {
|
||||||
|
// только один пустой слот, отдадим самому "жирному" предмету
|
||||||
|
val type = itemTypes.entries.stream().max { a, b -> b.value.intStream().sum().compareTo(a.value.intStream().sum()) }.orElseThrow()
|
||||||
|
type.value.add(empty.getInt(0))
|
||||||
|
balance(type.value)
|
||||||
|
|
||||||
|
for ((a, set) in itemTypes) {
|
||||||
|
if (a !== type.key) {
|
||||||
|
balance(set)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// определяем общее количество предметов
|
||||||
|
val totalCount = itemTypes.values.stream().mapToInt { it.stream().mapToInt { getItem(it).count }.sum() }.sum().toDouble()
|
||||||
|
val totalEmpty = empty.size
|
||||||
|
|
||||||
|
// определяем доли предметов по их количеству к общему количеству,
|
||||||
|
// что позволит нам выделить претендентов на пустые слоты
|
||||||
|
for (list in itemTypes.values) {
|
||||||
|
if (empty.isEmpty) break // ошибка округления
|
||||||
|
|
||||||
|
val perc = list.stream().mapToInt { getItem(it).count }.sum() / totalCount
|
||||||
|
|
||||||
|
for (i in 0 until (perc * totalEmpty).roundToInt()) {
|
||||||
|
list.add(empty.removeInt(0))
|
||||||
|
if (empty.isEmpty) break // ошибка округления
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty.isNotEmpty()) {
|
||||||
|
// ошибка округления
|
||||||
|
itemTypes.values.stream().max { a, b -> b.intStream().sum().compareTo(a.intStream().sum()) }.orElseThrow().add(empty.removeInt(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
for (list in itemTypes.values) {
|
||||||
|
balance(list)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Container.balance(slots: Iterator<Int>) {
|
||||||
|
balance(IntArraySet().also { it.addAll(slots) })
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Container.balance(slots: Iterable<Int>) {
|
||||||
|
balance(IntArraySet().also { it.addAll(slots) })
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Container.balance(slots: IntRange) {
|
||||||
|
balance(IntArraySet().also { it.addAll(slots) })
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Container.balance(startSlot: Int = 0, endSlot: Int = containerSize - 1) {
|
||||||
|
require(startSlot <= endSlot) { "Invalid slot range: $startSlot .. $endSlot" }
|
||||||
|
balance(IntArrayList(endSlot - startSlot + 1).also { for (i in startSlot .. endSlot) it.add(i) })
|
||||||
|
}
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.container
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.Hash
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
|
||||||
|
object ItemStackHashStrategy : Hash.Strategy<ItemStack> {
|
||||||
|
override fun equals(a: ItemStack?, b: ItemStack?): Boolean {
|
||||||
|
return a === b || a != null && b != null && ItemStack.isSameItemSameTags(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(o: ItemStack?): Int {
|
||||||
|
o ?: return 0
|
||||||
|
return o.item.hashCode().xor(o.tag.hashCode())
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,7 @@ import kotlin.reflect.KMutableProperty0
|
|||||||
|
|
||||||
class BooleanInputWithFeedback(menu: MatteryMenu) : AbstractPlayerInputWithFeedback<Boolean>() {
|
class BooleanInputWithFeedback(menu: MatteryMenu) : AbstractPlayerInputWithFeedback<Boolean>() {
|
||||||
override val input = menu.booleanInput { consumer?.invoke(it) }
|
override val input = menu.booleanInput { consumer?.invoke(it) }
|
||||||
override val value by menu.mSynchronizer.computedBool(BooleanSupplier { supplier?.invoke() ?: false })
|
override val value by menu.mSynchronizer.computedBool(BooleanSupplier { supplier?.invoke() ?: false }).property
|
||||||
|
|
||||||
constructor(menu: MatteryMenu, state: KMutableProperty0<Boolean>) : this(menu) {
|
constructor(menu: MatteryMenu, state: KMutableProperty0<Boolean>) : this(menu) {
|
||||||
with(state)
|
with(state)
|
||||||
|
@ -7,6 +7,7 @@ import ru.dbotthepony.mc.otm.block.entity.tech.PlatePressBlockEntity
|
|||||||
import ru.dbotthepony.mc.otm.menu.MachineOutputSlot
|
import ru.dbotthepony.mc.otm.menu.MachineOutputSlot
|
||||||
import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
|
import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
|
||||||
import ru.dbotthepony.mc.otm.menu.MatterySlot
|
import ru.dbotthepony.mc.otm.menu.MatterySlot
|
||||||
|
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
|
||||||
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
|
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
|
||||||
import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput
|
import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput
|
||||||
import ru.dbotthepony.mc.otm.menu.makeSlots
|
import ru.dbotthepony.mc.otm.menu.makeSlots
|
||||||
@ -28,6 +29,14 @@ class TwinPlatePressMenu @JvmOverloads constructor(
|
|||||||
val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig, allowPull = true)
|
val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig, allowPull = true)
|
||||||
val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget)
|
val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget)
|
||||||
|
|
||||||
|
val balanceInputs = BooleanInputWithFeedback(this)
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (tile != null) {
|
||||||
|
balanceInputs.with(tile::balanceInputs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
addStorageSlot(inputSlots)
|
addStorageSlot(inputSlots)
|
||||||
addStorageSlot(outputSlots)
|
addStorageSlot(outputSlots)
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.7 KiB |
Binary file not shown.
Loading…
Reference in New Issue
Block a user