Configurable energy handler working
This commit is contained in:
parent
9959f72db3
commit
3b53d65b29
@ -613,6 +613,7 @@ private fun gui(provider: MatteryLanguageProvider) {
|
||||
gui("stored_amount", "Exact amount stored: %s")
|
||||
|
||||
gui("sides.item_config", "Item Configuration")
|
||||
gui("sides.energy_config", "Energy Configuration")
|
||||
|
||||
gui("sides.top", "Top")
|
||||
gui("sides.bottom", "Bottom")
|
||||
|
@ -618,6 +618,7 @@ private fun gui(provider: MatteryLanguageProvider) {
|
||||
gui("stored_amount", "Точное количество в хранилище: %s шт.")
|
||||
|
||||
gui("sides.item_config", "Настройка Предметов")
|
||||
gui("sides.energy_config", "Настройка Энергии")
|
||||
|
||||
gui("sides.top", "Верхняя сторона")
|
||||
gui("sides.bottom", "Нижняя сторона")
|
||||
|
@ -1,5 +1,6 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectFunction
|
||||
@ -52,7 +53,9 @@ import ru.dbotthepony.mc.otm.core.forValidRefs
|
||||
import ru.dbotthepony.mc.otm.core.get
|
||||
import ru.dbotthepony.mc.otm.core.getValue
|
||||
import ru.dbotthepony.mc.otm.core.ifPresentK
|
||||
import ru.dbotthepony.mc.otm.core.immutableList
|
||||
import ru.dbotthepony.mc.otm.core.immutableMap
|
||||
import ru.dbotthepony.mc.otm.core.immutableSet
|
||||
import ru.dbotthepony.mc.otm.core.math.BlockRotation
|
||||
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
||||
import ru.dbotthepony.mc.otm.core.math.minus
|
||||
@ -170,14 +173,16 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc
|
||||
}
|
||||
}
|
||||
|
||||
protected fun exposeEnergy(side: RelativeSide, value: IMatteryEnergyStorage) {
|
||||
protected fun exposeEnergy(side: RelativeSide, value: IMatteryEnergyStorage): ImmutableList<Side.Cap<*>> {
|
||||
return immutableList {
|
||||
val thisSide = _sides[side]!!
|
||||
|
||||
thisSide.Cap(ForgeCapabilities.ENERGY, value)
|
||||
thisSide.Cap(MatteryCapability.ENERGY, value)
|
||||
accept(thisSide.Cap(ForgeCapabilities.ENERGY, value))
|
||||
accept(thisSide.Cap(MatteryCapability.ENERGY, value))
|
||||
|
||||
if (isMekanismLoaded) {
|
||||
thisSide.Cap(MatteryCapability.MEKANISM_ENERGY, Mattery2MekanismEnergyWrapper(value))
|
||||
accept(thisSide.Cap(MatteryCapability.MEKANISM_ENERGY, Mattery2MekanismEnergyWrapper(value)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,12 +15,16 @@ import net.minecraftforge.common.capabilities.ForgeCapabilities
|
||||
import net.minecraftforge.items.IItemHandler
|
||||
import ru.dbotthepony.mc.otm.capability.CombinedItemHandler
|
||||
import ru.dbotthepony.mc.otm.capability.EmptyItemHandler
|
||||
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
||||
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.core.TextComponent
|
||||
import ru.dbotthepony.mc.otm.core.getValue
|
||||
import ru.dbotthepony.mc.otm.core.ifPresentK
|
||||
import ru.dbotthepony.mc.otm.core.immutableMap
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.math.RelativeSide
|
||||
import ru.dbotthepony.mc.otm.core.nbt.getJson
|
||||
import ru.dbotthepony.mc.otm.core.nbt.putJson
|
||||
@ -68,6 +72,135 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
|
||||
redstoneControl.deserializeNBT(nbt[REDSTONE_CONTROL_KEY] as? CompoundTag)
|
||||
}
|
||||
|
||||
inner class ConfigurableEnergy<T : IMatteryEnergyStorage>(
|
||||
val capability: T,
|
||||
|
||||
val possibleModes: FlowDirection = capability.energyFlow,
|
||||
|
||||
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 {
|
||||
exposeEnergySideless(capability)
|
||||
}
|
||||
|
||||
val front = Piece(RelativeSide.FRONT).also { it.energyFlow = frontDefault }
|
||||
val back = Piece(RelativeSide.BACK).also { it.energyFlow = backDefault }
|
||||
val left = Piece(RelativeSide.LEFT).also { it.energyFlow = leftDefault }
|
||||
val right = Piece(RelativeSide.RIGHT).also { it.energyFlow = rightDefault }
|
||||
val top = Piece(RelativeSide.TOP).also { it.energyFlow = topDefault }
|
||||
val bottom = Piece(RelativeSide.BOTTOM).also { it.energyFlow = 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) : IMatteryEnergyStorage, ITickable {
|
||||
private val capControllers = exposeEnergy(side, this@Piece)
|
||||
private val neighbour by sides[side]!!.track(ForgeCapabilities.ENERGY)
|
||||
|
||||
override fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
|
||||
return capability.extractEnergy(howMuch, simulate)
|
||||
}
|
||||
|
||||
override fun receiveEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
|
||||
return capability.receiveEnergy(howMuch, simulate)
|
||||
}
|
||||
|
||||
override fun extractEnergyChecked(howMuch: Decimal, simulate: Boolean): Decimal {
|
||||
if (energyFlow.output)
|
||||
return capability.extractEnergyChecked(howMuch, simulate)
|
||||
|
||||
return Decimal.ZERO
|
||||
}
|
||||
|
||||
override fun receiveEnergyChecked(howMuch: Decimal, simulate: Boolean): Decimal {
|
||||
if (energyFlow.input)
|
||||
return capability.receiveEnergyChecked(howMuch, simulate)
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
override fun fillBattery(): Boolean {
|
||||
return capability.fillBattery()
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
if (energyFlow == FlowDirection.NONE || !automatePull && !automatePush)
|
||||
return
|
||||
|
||||
neighbour.ifPresentK {
|
||||
if (energyFlow.input && automatePull) {
|
||||
moveEnergy(source = it, destination = capability, simulate = false)
|
||||
}
|
||||
|
||||
if (energyFlow.output && automatePush) {
|
||||
moveEnergy(source = capability, destination = it, simulate = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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})" }
|
||||
|
||||
if (access.read() != value) {
|
||||
access.write(value)
|
||||
|
||||
if (value == FlowDirection.NONE) {
|
||||
for (controller in capControllers)
|
||||
controller.close()
|
||||
} else {
|
||||
for (controller in capControllers) {
|
||||
controller.close()
|
||||
controller.expose()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
var automatePull by synchronizer.bool()
|
||||
var automatePush by synchronizer.bool()
|
||||
|
||||
init {
|
||||
savetables.enum(::energyFlow, "energy_${side}_flow", FlowDirection::valueOf)
|
||||
savetables.bool(::automatePull, "energy_${side}_pull")
|
||||
savetables.bool(::automatePush, "energy_${side}_push")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class ItemHandlerMode(val translationKey: String) {
|
||||
DISABLED("otm.gui.side_mode.disabled"),
|
||||
INPUT("otm.gui.side_mode.input"),
|
||||
@ -107,7 +240,7 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
|
||||
val top = Piece(RelativeSide.TOP, input, output, battery).also { it.mode = topDefault }
|
||||
val bottom = Piece(RelativeSide.BOTTOM, input, output, battery).also { it.mode = bottomDefault }
|
||||
|
||||
val sides = immutableMap {
|
||||
val pieces = immutableMap {
|
||||
put(RelativeSide.FRONT, front)
|
||||
put(RelativeSide.BACK, back)
|
||||
put(RelativeSide.LEFT, left)
|
||||
@ -126,14 +259,14 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
|
||||
}
|
||||
|
||||
inner class Piece(
|
||||
side: RelativeSide,
|
||||
val side: RelativeSide,
|
||||
val input: IItemHandler? = null,
|
||||
val output: IItemHandler? = null,
|
||||
val battery: IItemHandler? = null,
|
||||
) : IItemHandler, ITickable {
|
||||
private var currentHandler: IItemHandler = EmptyItemHandler
|
||||
val capController = this@MatteryDeviceBlockEntity.sides[side]!!.Cap(ForgeCapabilities.ITEM_HANDLER, this)
|
||||
private val neighbour by this@MatteryDeviceBlockEntity.sides[side]!!.track(ForgeCapabilities.ITEM_HANDLER)
|
||||
private val capController = sides[side]!!.Cap(ForgeCapabilities.ITEM_HANDLER, this)
|
||||
private val neighbour by sides[side]!!.track(ForgeCapabilities.ITEM_HANDLER)
|
||||
|
||||
val possibleViews: ImmutableSet<ItemHandlerMode>
|
||||
val inputOutput: IItemHandler?
|
||||
@ -184,29 +317,27 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo
|
||||
}
|
||||
})
|
||||
|
||||
var automatePull = false
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
field = value
|
||||
|
||||
if (value) {
|
||||
innerSlotPull = 0
|
||||
outerSlotPull = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var automatePush = false
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
field = value
|
||||
var automatePull by synchronizer.bool(setter = { value, access, _ ->
|
||||
if (access.read() != value) {
|
||||
access.write(value)
|
||||
|
||||
if (value) {
|
||||
innerSlotPush = 0
|
||||
outerSlotPush = 0
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
var automatePush by synchronizer.bool(setter = { value, access, _ ->
|
||||
if (access.read() != value) {
|
||||
access.write(value)
|
||||
|
||||
if (value) {
|
||||
innerSlotPush = 0
|
||||
outerSlotPush = 0
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
init {
|
||||
savetables.bool(::automatePull, "itemhandler_${side}_automatePull")
|
||||
|
@ -47,20 +47,21 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDe
|
||||
battery = batteryItemHandler,
|
||||
backDefault = ItemHandlerMode.BATTERY)
|
||||
|
||||
val energyConfig = ConfigurableEnergy(energy)
|
||||
|
||||
init {
|
||||
for (piece in energyConfig.pieces.values)
|
||||
piece.automatePush = true
|
||||
|
||||
savetable(::energy, ENERGY_KEY)
|
||||
savetable(::batteryContainer)
|
||||
savetable(::residueContainer)
|
||||
savetable(::fuelContainer)
|
||||
|
||||
exposeEnergyGlobally(energy)
|
||||
|
||||
savetables.int(::workTicks, WORK_TICKS_KEY)
|
||||
savetables.int(::workTicksTotal, WORK_TICKS_TOTAL_KEY)
|
||||
}
|
||||
|
||||
private val consumers = trackGlobally(ForgeCapabilities.ENERGY)
|
||||
|
||||
override fun setChangedLight() {
|
||||
super.setChangedLight()
|
||||
checkFuelSlot = true
|
||||
@ -74,15 +75,6 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDe
|
||||
|
||||
private var checkFuelSlot = true
|
||||
|
||||
private fun workWithPower(it: IEnergyStorage) {
|
||||
val extracted = energy.extractEnergy(THROUGHPUT, true)
|
||||
val received = it.receiveEnergy(extracted, false)
|
||||
|
||||
if (!received.isZero) {
|
||||
energy.extractEnergy(received, false)
|
||||
}
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
|
||||
@ -133,12 +125,9 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDe
|
||||
val item = batteryContainer[0]
|
||||
|
||||
if (!item.isEmpty) {
|
||||
item.energy?.let(this::workWithPower)
|
||||
if (energy.batteryLevel.isZero) return
|
||||
item.energy?.also {
|
||||
moveEnergy(energy, it, THROUGHPUT, simulate = false)
|
||||
}
|
||||
|
||||
for (consumer in consumers) {
|
||||
consumer.ifPresentK(::workWithPower)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package ru.dbotthepony.mc.otm.capability
|
||||
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import java.util.function.Predicate
|
||||
|
||||
/**
|
||||
@ -20,35 +21,84 @@ import java.util.function.Predicate
|
||||
* * `BI_DIRECTIONAL.test(OUTPUT)` = `false`
|
||||
* * `BI_DIRECTIONAL.test(INPUT)` = `false`
|
||||
*/
|
||||
enum class FlowDirection(val input: Boolean, val output: Boolean) : Predicate<FlowDirection> {
|
||||
enum class FlowDirection(val input: Boolean, val output: Boolean, val translationKey: String) : Predicate<FlowDirection> {
|
||||
/**
|
||||
* Can only be inputted (consumer)
|
||||
*/
|
||||
INPUT(true, false),
|
||||
INPUT(true, false, "otm.gui.side_mode.input"),
|
||||
|
||||
/**
|
||||
* Can only be outputted/transmitted (producer)
|
||||
*/
|
||||
OUTPUT(false, true),
|
||||
OUTPUT(false, true, "otm.gui.side_mode.output"),
|
||||
|
||||
/**
|
||||
* Can both consume and produce (capacitor)
|
||||
*/
|
||||
BI_DIRECTIONAL(true, true),
|
||||
BI_DIRECTIONAL(true, true, "otm.gui.side_mode.input_output"),
|
||||
|
||||
/**
|
||||
* Why would you want to use this
|
||||
*/
|
||||
NONE(false, false);
|
||||
NONE(false, false, "otm.gui.side_mode.disabled");
|
||||
|
||||
/**
|
||||
* All values that pass [isSupertype]
|
||||
*/
|
||||
val family: ImmutableSet<FlowDirection> by lazy {
|
||||
ImmutableSet.Builder<FlowDirection>().also {
|
||||
when (this) {
|
||||
INPUT -> it.add(INPUT)
|
||||
OUTPUT -> it.add(OUTPUT)
|
||||
BI_DIRECTIONAL -> {
|
||||
it.add(INPUT)
|
||||
it.add(OUTPUT)
|
||||
it.add(BI_DIRECTIONAL)
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
it.add(NONE)
|
||||
}.build()
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtype test (returns true if we can assign [t] to this, e.g. we can assign [BI_DIRECTIONAL] to [INPUT])
|
||||
*/
|
||||
override fun test(t: FlowDirection): Boolean {
|
||||
return t === this || (!input || t.input) && (!output || t.output)
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtype test (returns true if we can assign [value] to this, e.g. we can assign [BI_DIRECTIONAL] to [INPUT])
|
||||
*/
|
||||
fun isSubtype(value: FlowDirection) = test(value)
|
||||
|
||||
/**
|
||||
* Supertype test (e.g. [INPUT] is supertype to [BI_DIRECTIONAL], so if this is [BI_DIRECTIONAL] then calling [isSupertype] with [INPUT] will return `true`)
|
||||
*/
|
||||
fun isSupertype(value: FlowDirection): Boolean {
|
||||
return value === this || value in family
|
||||
}
|
||||
|
||||
fun intersect(other: FlowDirection): FlowDirection {
|
||||
return of(other.input && input, other.output && output)
|
||||
}
|
||||
|
||||
fun withInput(flag: Boolean): FlowDirection {
|
||||
if (flag == input)
|
||||
return this
|
||||
|
||||
return of(flag, output)
|
||||
}
|
||||
|
||||
fun withOutput(flag: Boolean): FlowDirection {
|
||||
if (flag == output)
|
||||
return this
|
||||
|
||||
return of(input, flag)
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun of(input: Boolean, output: Boolean): FlowDirection {
|
||||
|
@ -1,6 +1,8 @@
|
||||
package ru.dbotthepony.mc.otm.capability
|
||||
|
||||
import net.minecraftforge.energy.IEnergyStorage
|
||||
import net.minecraftforge.items.IItemHandler
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
|
||||
/**
|
||||
* Attempts to safely exchange/move item between slots of two handlers
|
||||
@ -41,3 +43,27 @@ fun moveBetweenSlots(source: IItemHandler, sourceSlot: Int, destination: IItemHa
|
||||
|
||||
return sourceSlot to destinationSlot
|
||||
}
|
||||
|
||||
@Suppress("name_shadowing")
|
||||
fun moveEnergy(source: IEnergyStorage, destination: IEnergyStorage, amount: Decimal = Decimal.LONG_MAX_VALUE, simulate: Boolean): Decimal {
|
||||
val extracted = source.extractEnergy(amount, true)
|
||||
|
||||
if (extracted.isPositive) {
|
||||
val received = destination.receiveEnergy(extracted, true)
|
||||
|
||||
if (received.isPositive) {
|
||||
val extracted = source.extractEnergy(received, true)
|
||||
|
||||
if (extracted.isPositive) {
|
||||
if (simulate) {
|
||||
return extracted
|
||||
}
|
||||
|
||||
val received = destination.receiveEnergy(extracted, false)
|
||||
return source.extractEnergy(received, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Decimal.ZERO
|
||||
}
|
||||
|
@ -68,4 +68,5 @@ object Widgets18 {
|
||||
val INPUT_OUTPUT = controlsGrid.next()
|
||||
val BATTERY_ONLY = controlsGrid.next()
|
||||
val ITEMS_CONFIGURATION = controlsGrid.next()
|
||||
val ENERGY_CONFIGURATION = controlsGrid.next()
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package ru.dbotthepony.mc.otm.client.screen.panels.button
|
||||
import com.mojang.blaze3d.platform.InputConstants
|
||||
import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity
|
||||
import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting
|
||||
import ru.dbotthepony.mc.otm.capability.FlowDirection
|
||||
import ru.dbotthepony.mc.otm.client.minecraft
|
||||
import ru.dbotthepony.mc.otm.client.render.Widgets18
|
||||
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
||||
@ -10,6 +11,8 @@ import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
|
||||
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.EnergyPlayerInput
|
||||
import ru.dbotthepony.mc.otm.menu.input.IPlayerInputWithFeedback
|
||||
import ru.dbotthepony.mc.otm.menu.input.ItemHandlerPlayerInput
|
||||
import java.util.function.Predicate
|
||||
@ -59,57 +62,33 @@ private fun <S : MatteryScreen<*>> makeItemModeButton(screen: S, parent: FramePa
|
||||
return button
|
||||
}
|
||||
|
||||
private fun <S : MatteryScreen<*>> makeItemHandlerControlPanel(
|
||||
screen: S,
|
||||
inputs: ItemHandlerPlayerInput
|
||||
): FramePanel<S> {
|
||||
val frame = object : FramePanel<S>(screen, 78f, 80f, TranslatableComponent("otm.gui.sides.item_config")) {
|
||||
override fun tickInner() {
|
||||
super.tickInner()
|
||||
private fun <S : MatteryScreen<*>> makeEnergyModeButton(screen: S, parent: FramePanel<S>, input: EnergyPlayerInput.Piece): LargeEnumRectangleButtonPanel<S, FlowDirection> {
|
||||
val button = LargeEnumRectangleButtonPanel(screen, parent, enum = FlowDirection::class.java, prop = input.input, defaultValue = input.default)
|
||||
|
||||
if (!isEverFocused()) {
|
||||
remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val front = makeItemModeButton(screen, frame, inputs.pieces[RelativeSide.FRONT]!!)
|
||||
val back = makeItemModeButton(screen, frame, inputs.pieces[RelativeSide.BACK]!!)
|
||||
val left = makeItemModeButton(screen, frame, inputs.pieces[RelativeSide.LEFT]!!)
|
||||
val right = makeItemModeButton(screen, frame, inputs.pieces[RelativeSide.RIGHT]!!)
|
||||
val top = makeItemModeButton(screen, frame, inputs.pieces[RelativeSide.TOP]!!)
|
||||
val bottom = makeItemModeButton(screen, frame, inputs.pieces[RelativeSide.BOTTOM]!!)
|
||||
|
||||
if (inputs.pull.test(minecraft.player)) {
|
||||
val pull = LargeBooleanRectangleButtonPanel(
|
||||
screen,
|
||||
frame,
|
||||
skinElementActive = Widgets18.PULL,
|
||||
skinElementInactive = Widgets18.PULL_DISABLED,
|
||||
prop = inputs.pull,
|
||||
val values = listOf(
|
||||
FlowDirection.NONE to Widgets18.DISABLED,
|
||||
FlowDirection.INPUT to Widgets18.INPUT_ONLY,
|
||||
FlowDirection.OUTPUT to Widgets18.OUTPUT_ONLY,
|
||||
FlowDirection.BI_DIRECTIONAL to Widgets18.INPUT_OUTPUT,
|
||||
)
|
||||
|
||||
pull.tooltip = TranslatableComponent("otm.gui.side_mode.pull")
|
||||
|
||||
pull.x = 30f - 20f
|
||||
pull.y = 14f
|
||||
for ((k, v) in values) {
|
||||
button.add(k, skinElement = v, tooltip = TranslatableComponent(k.translationKey))
|
||||
}
|
||||
|
||||
if (inputs.push.test(minecraft.player)) {
|
||||
val push = LargeBooleanRectangleButtonPanel(
|
||||
screen,
|
||||
frame,
|
||||
skinElementActive = Widgets18.PUSH,
|
||||
skinElementInactive = Widgets18.PUSH_DISABLED,
|
||||
prop = inputs.push,
|
||||
)
|
||||
button.finish()
|
||||
|
||||
push.tooltip = TranslatableComponent("otm.gui.side_mode.push")
|
||||
|
||||
push.x = 30f + 20f
|
||||
push.y = 14f
|
||||
return button
|
||||
}
|
||||
|
||||
private fun moveButtons(
|
||||
front: EditablePanel<*>,
|
||||
back: EditablePanel<*>,
|
||||
left: EditablePanel<*>,
|
||||
right: EditablePanel<*>,
|
||||
top: EditablePanel<*>,
|
||||
bottom: EditablePanel<*>,
|
||||
) {
|
||||
top.tooltip = TranslatableComponent("otm.gui.sides.top")
|
||||
bottom.tooltip = TranslatableComponent("otm.gui.sides.bottom")
|
||||
back.tooltip = TranslatableComponent("otm.gui.sides.back")
|
||||
@ -134,9 +113,94 @@ private fun <S : MatteryScreen<*>> makeItemHandlerControlPanel(
|
||||
|
||||
back.x = 30f - 20f
|
||||
back.y = 14f + 42f
|
||||
}
|
||||
|
||||
@Suppress("name_shadowing")
|
||||
private fun pullPush(frame: FramePanel<*>, pull: BooleanInputWithFeedback, push: BooleanInputWithFeedback) {
|
||||
if (pull.test(minecraft.player)) {
|
||||
val pull = LargeBooleanRectangleButtonPanel(
|
||||
frame.screen,
|
||||
frame,
|
||||
skinElementActive = Widgets18.PULL,
|
||||
skinElementInactive = Widgets18.PULL_DISABLED,
|
||||
prop = pull,
|
||||
)
|
||||
|
||||
pull.tooltip = TranslatableComponent("otm.gui.side_mode.pull")
|
||||
|
||||
pull.x = 30f - 20f
|
||||
pull.y = 14f
|
||||
}
|
||||
|
||||
if (push.test(minecraft.player)) {
|
||||
val push = LargeBooleanRectangleButtonPanel(
|
||||
frame.screen,
|
||||
frame,
|
||||
skinElementActive = Widgets18.PUSH,
|
||||
skinElementInactive = Widgets18.PUSH_DISABLED,
|
||||
prop = push,
|
||||
)
|
||||
|
||||
push.tooltip = TranslatableComponent("otm.gui.side_mode.push")
|
||||
|
||||
push.x = 30f + 20f
|
||||
push.y = 14f
|
||||
}
|
||||
}
|
||||
|
||||
private fun <S : MatteryScreen<*>> makeItemHandlerControlPanel(
|
||||
screen: S,
|
||||
inputs: ItemHandlerPlayerInput
|
||||
): FramePanel<S> {
|
||||
val frame = object : FramePanel<S>(screen, 78f, 80f, TranslatableComponent("otm.gui.sides.item_config")) {
|
||||
override fun tickInner() {
|
||||
super.tickInner()
|
||||
|
||||
if (!isEverFocused()) {
|
||||
remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val front = makeItemModeButton(screen, frame, inputs.pieces[RelativeSide.FRONT]!!)
|
||||
val back = makeItemModeButton(screen, frame, inputs.pieces[RelativeSide.BACK]!!)
|
||||
val left = makeItemModeButton(screen, frame, inputs.pieces[RelativeSide.LEFT]!!)
|
||||
val right = makeItemModeButton(screen, frame, inputs.pieces[RelativeSide.RIGHT]!!)
|
||||
val top = makeItemModeButton(screen, frame, inputs.pieces[RelativeSide.TOP]!!)
|
||||
val bottom = makeItemModeButton(screen, frame, inputs.pieces[RelativeSide.BOTTOM]!!)
|
||||
|
||||
pullPush(frame, inputs.pull, inputs.push)
|
||||
moveButtons(front, back, left, right, top, bottom)
|
||||
screen.addPanel(frame)
|
||||
frame.requestFocus()
|
||||
|
||||
return frame
|
||||
}
|
||||
|
||||
private fun <S : MatteryScreen<*>> makeEnergyConfigPanel(
|
||||
screen: S,
|
||||
inputs: EnergyPlayerInput
|
||||
): FramePanel<S> {
|
||||
val frame = object : FramePanel<S>(screen, 78f, 80f, TranslatableComponent("otm.gui.sides.energy_config")) {
|
||||
override fun tickInner() {
|
||||
super.tickInner()
|
||||
|
||||
if (!isEverFocused()) {
|
||||
remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val front = makeEnergyModeButton(screen, frame, inputs.pieces[RelativeSide.FRONT]!!).also { it.predicate = Predicate { inputs.possibleModes.isSupertype(it) } }
|
||||
val back = makeEnergyModeButton(screen, frame, inputs.pieces[RelativeSide.BACK]!!).also { it.predicate = Predicate { inputs.possibleModes.isSupertype(it) } }
|
||||
val left = makeEnergyModeButton(screen, frame, inputs.pieces[RelativeSide.LEFT]!!).also { it.predicate = Predicate { inputs.possibleModes.isSupertype(it) } }
|
||||
val right = makeEnergyModeButton(screen, frame, inputs.pieces[RelativeSide.RIGHT]!!).also { it.predicate = Predicate { inputs.possibleModes.isSupertype(it) } }
|
||||
val top = makeEnergyModeButton(screen, frame, inputs.pieces[RelativeSide.TOP]!!).also { it.predicate = Predicate { inputs.possibleModes.isSupertype(it) } }
|
||||
val bottom = makeEnergyModeButton(screen, frame, inputs.pieces[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
|
||||
@ -146,7 +210,8 @@ fun <S : MatteryScreen<*>> makeDeviceControls(
|
||||
screen: S,
|
||||
parent: FramePanel<S>,
|
||||
redstone: IPlayerInputWithFeedback<RedstoneSetting>? = null,
|
||||
itemConfig: ItemHandlerPlayerInput? = null
|
||||
itemConfig: ItemHandlerPlayerInput? = null,
|
||||
energyConfig: EnergyPlayerInput? = null,
|
||||
): EditablePanel<S> {
|
||||
val panel = object : EditablePanel<S>(screen, parent, width = LargeEnumRectangleButtonPanel.SIZE, height = 0f, x = parent.width + 3f) {
|
||||
override fun tickInner() {
|
||||
@ -179,6 +244,23 @@ fun <S : MatteryScreen<*>> makeDeviceControls(
|
||||
}.height + 2f
|
||||
}
|
||||
|
||||
if (energyConfig != null) {
|
||||
y += object : LargeRectangleButtonPanel<S>(screen, panel, y = y, skinElement = Widgets18.ENERGY_CONFIGURATION) {
|
||||
init {
|
||||
tooltip = TranslatableComponent("otm.gui.sides.energy_config")
|
||||
}
|
||||
|
||||
override fun onClick(mouseButton: Int) {
|
||||
if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) {
|
||||
val frame = makeEnergyConfigPanel(screen, energyConfig)
|
||||
|
||||
frame.x = absoluteX + width / 2f - frame.width / 2f
|
||||
frame.y = absoluteY + height + 8f
|
||||
}
|
||||
}
|
||||
}.height + 2f
|
||||
}
|
||||
|
||||
panel.height = (y - 2f).coerceAtLeast(0f)
|
||||
return panel
|
||||
}
|
||||
|
@ -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, itemConfig = menu.itemConfig)
|
||||
makeDeviceControls(this, frame, redstone = menu.redstone, itemConfig = menu.itemConfig, energyConfig = menu.energyConfig)
|
||||
|
||||
return frame
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ package ru.dbotthepony.mc.otm.core
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
import com.google.common.collect.ImmutableMap
|
||||
import com.google.common.collect.ImmutableSet
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonPrimitive
|
||||
@ -35,6 +36,7 @@ import java.math.BigInteger
|
||||
import java.util.Arrays
|
||||
import java.util.Spliterators
|
||||
import java.util.UUID
|
||||
import java.util.function.Consumer
|
||||
import java.util.stream.Stream
|
||||
import java.util.stream.StreamSupport
|
||||
import kotlin.reflect.KProperty
|
||||
@ -135,6 +137,18 @@ inline fun <K : Any, V : Any> immutableMap(initializer: ImmutableMap.Builder<K,
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
inline fun <V : Any> immutableSet(initializer: Consumer<V>.() -> Unit): ImmutableSet<V> {
|
||||
val builder = ImmutableSet.Builder<V>()
|
||||
initializer.invoke(builder::add)
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
inline fun <V : Any> immutableList(initializer: Consumer<V>.() -> Unit): ImmutableList<V> {
|
||||
val builder = ImmutableList.Builder<V>()
|
||||
initializer.invoke(builder::add)
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
fun <T> IForgeRegistry<T>.getID(value: T): Int {
|
||||
return (this as ForgeRegistry<T>).getID(value)
|
||||
}
|
||||
|
@ -0,0 +1,62 @@
|
||||
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 EnergyPlayerInput(val menu: MatteryMenu, val allowPull: Boolean = true, val allowPush: Boolean = true) {
|
||||
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<FlowDirection>(menu)
|
||||
|
||||
var default by menu.mSynchronizer.enum(FlowDirection.NONE)
|
||||
|
||||
init {
|
||||
pull.filter { allowPull }
|
||||
push.filter { allowPush }
|
||||
}
|
||||
|
||||
fun configure(config: MatteryDeviceBlockEntity.ConfigurableEnergy<*>.Piece, parent: MatteryDeviceBlockEntity.ConfigurableEnergy<*>) {
|
||||
pull.with(config::automatePull)
|
||||
push.with(config::automatePush)
|
||||
input.withSupplier { config.energyFlow }.withConsumer { if (parent.possibleModes.isSupertype(it)) config.energyFlow = 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 configure(config: MatteryDeviceBlockEntity.ConfigurableEnergy<*>) {
|
||||
possibleModes = config.possibleModes
|
||||
|
||||
for ((side, v) in config.pieces) {
|
||||
pieces[side]!!.configure(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) } }
|
||||
}
|
||||
}
|
@ -50,7 +50,7 @@ class ItemHandlerPlayerInput(val menu: MatteryMenu, val allowPull: Boolean = tru
|
||||
}
|
||||
|
||||
fun configure(config: MatteryDeviceBlockEntity.ConfigurableItemHandler) {
|
||||
for ((side, v) in config.sides) {
|
||||
for ((side, v) in config.pieces) {
|
||||
pieces[side]!!.configure(v)
|
||||
pieces[side]!!.default = config.defaults[side]!!
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import ru.dbotthepony.mc.otm.block.entity.tech.ChemicalGeneratorBlockEntity
|
||||
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.EnergyPlayerInput
|
||||
import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback
|
||||
import ru.dbotthepony.mc.otm.menu.input.ItemHandlerPlayerInput
|
||||
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
|
||||
@ -21,11 +22,13 @@ class ChemicalGeneratorMenu @JvmOverloads constructor(id: Int, inv: Inventory, t
|
||||
|
||||
val redstone = EnumInputWithFeedback(this, RedstoneSetting::class.java)
|
||||
val itemConfig = ItemHandlerPlayerInput(this, allowPull = false, allowPush = true)
|
||||
val energyConfig = EnergyPlayerInput(this, allowPull = false, allowPush = true)
|
||||
|
||||
init {
|
||||
if (tile != null) {
|
||||
redstone.with(tile.redstoneControl::redstoneSetting)
|
||||
itemConfig.configure(tile.itemConfig)
|
||||
energyConfig.configure(tile.energyConfig)
|
||||
}
|
||||
}
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
Loading…
Reference in New Issue
Block a user