Drive rack insert/extract controls, profiled energy, updated menu, make redstone control of drive rack actually do stuff

This commit is contained in:
DBotThePony 2023-08-17 00:23:36 +07:00
parent 10de6eb864
commit a6eb0ca7f1
Signed by: DBot
GPG Key ID: DCC23B5715498507
10 changed files with 178 additions and 36 deletions

View File

@ -8,8 +8,10 @@ import net.minecraft.world.item.ItemStack
import net.minecraft.world.level.Level
import net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.graph.storage.StorageNode
import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage
import ru.dbotthepony.mc.otm.config.MachinesConfig
import ru.dbotthepony.mc.otm.container.MatteryContainer
@ -18,10 +20,12 @@ import ru.dbotthepony.mc.otm.menu.storage.DriveRackMenu
import ru.dbotthepony.mc.otm.registry.MBlockEntities
import ru.dbotthepony.mc.otm.storage.optics.priority
import ru.dbotthepony.mc.otm.storage.optics.powered
import ru.dbotthepony.mc.otm.storage.optics.flow
class DriveRackBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.DRIVE_RACK, blockPos, blockState) {
val energy = WorkerEnergyStorage(this::setChangedLight, MachinesConfig.DRIVE_RACK)
val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::setChangedLight, MachinesConfig.DRIVE_RACK))
val cell = StorageNode(energy)
val energyConfig = ConfigurableEnergy(energy)
var insertPriority = 0
set(value) {
@ -35,16 +39,22 @@ class DriveRackBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery
setChangedLight()
}
var mode = FlowDirection.BI_DIRECTIONAL
set(value) {
field = value
setChangedLight()
}
val container: MatteryContainer = object : MatteryContainer(this::setChanged, 4) {
override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {
super.setChanged(slot, new, old)
old.getCapability(MatteryCapability.DRIVE).ifPresentK {
cell.removeStorageComponent(it.priority(::insertPriority, ::extractPriority).powered(energy))
cell.removeStorageComponent(it.priority(::insertPriority, ::extractPriority).powered(energy).flow(::mode))
}
new.getCapability(MatteryCapability.DRIVE).ifPresentK {
cell.addStorageComponent(it.priority(::insertPriority, ::extractPriority).powered(energy))
cell.addStorageComponent(it.priority(::insertPriority, ::extractPriority).powered(energy).flow(::mode))
}
}
}.also(::addDroppableContainer)
@ -52,10 +62,14 @@ class DriveRackBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery
init {
savetable(::energy, ENERGY_KEY)
savetable(::container, INVENTORY_KEY)
exposeEnergyGlobally(energy)
exposeGlobally(MatteryCapability.STORAGE_NODE, cell)
savetables.int(::insertPriority)
savetables.int(::extractPriority)
savetables.enum(::mode, map = FlowDirection::valueOf)
redstoneControl.addListener {
cell.isDetached = it
}
}
override fun setLevel(level: Level) {

View File

@ -28,6 +28,7 @@ import ru.dbotthepony.mc.otm.config.ClientConfig
import ru.dbotthepony.mc.otm.core.GetterSetter
import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent
import ru.dbotthepony.mc.otm.core.immutableList
import ru.dbotthepony.mc.otm.core.math.RelativeSide
import ru.dbotthepony.mc.otm.core.util.ItemSorter
import ru.dbotthepony.mc.otm.core.value
@ -342,6 +343,17 @@ class DeviceControls<out S : MatteryScreen<*>>(
return button
}
fun addStorageMode(prop: GetterSetter<FlowDirection>) {
val mode = LargeEnumRectangleButtonPanel(screen, this, prop = prop, defaultValue = FlowDirection.BI_DIRECTIONAL, enum = FlowDirection::class.java)
mode.add(FlowDirection.INPUT, Widgets18.ONLY_STORE, FlowDirection.INPUT.title)
mode.add(FlowDirection.OUTPUT, Widgets18.ONLY_EXTRACT, FlowDirection.OUTPUT.title)
mode.add(FlowDirection.BI_DIRECTIONAL, Widgets18.STORE_EXTRACT, FlowDirection.BI_DIRECTIONAL.title)
mode.finish()
addButton(mode)
}
inline fun <reified T : Enum<T>> sortingButtons(ascending: GetterSetter<Boolean>, sorting: GetterSetter<T>, default: T, configurator: LargeEnumRectangleButtonPanel<S, T>.() -> Unit) {
LargeBooleanRectangleButtonPanel(
screen,
@ -415,18 +427,19 @@ class DeviceControls<out S : MatteryScreen<*>>(
upgradeWindow!!.toScreenCenter()
upgradeWindow!!.popup()
} else {
val square = ceil(upgrades.slots.size.toDouble().pow(0.5)).toInt()
val size = square * AbstractSlotPanel.SIZE
val (columns, rows) = SPECIAL_UPGRADE_CASES.getOrElse(upgrades.slots.size - 1) {
val square = ceil(it.toDouble().pow(0.5)).toInt()
square to square
}
upgradeWindow = FramePanel(screen, (size + 40f).coerceAtLeast(120f), 30f + size, TranslatableComponent("otm.gui.upgrades")).also { frame ->
val grid = GridPanel(screen, frame, width = AbstractSlotPanel.SIZE * square, height = AbstractSlotPanel.SIZE * square, columns = square, rows = square)
upgradeWindow = FramePanel(screen, (columns * AbstractSlotPanel.SIZE + 40f).coerceAtLeast(120f), 30f + rows * AbstractSlotPanel.SIZE, TranslatableComponent("otm.gui.upgrades")).also { frame ->
val grid = GridPanel(screen, frame, columns = columns, rows = rows)
for (slot in upgrades.slots) {
SlotPanel(screen, grid, slot)
}
grid.dock = Dock.FILL
grid.dockResize = DockResizeMode.NONE
screen.addPanel(frame)
@ -524,6 +537,15 @@ class DeviceControls<out S : MatteryScreen<*>>(
x = (parent?.width ?: 0f) + 3f
y = 0f
}
companion object {
val SPECIAL_UPGRADE_CASES = immutableList {
accept(1 to 1)
accept(2 to 1)
accept(3 to 1)
accept(2 to 2)
}
}
}
fun <S : MatteryScreen<*>> makeDeviceControls(

View File

@ -4,8 +4,8 @@ import net.minecraft.client.gui.screens.Screen
import ru.dbotthepony.mc.otm.client.render.RenderGravity
import ru.dbotthepony.mc.otm.client.screen.panels.Dock
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
import ru.dbotthepony.mc.otm.core.collect.filter
import ru.dbotthepony.mc.otm.core.collect.map
import ru.dbotthepony.mc.otm.core.collect.maybe
open class GridPanel<out S : Screen>(
@ -80,4 +80,10 @@ open class GridPanel<out S : Screen>(
totalHeight += maxHeight
}
}
companion object {
fun <S : Screen> slots(screen: S, parent: EditablePanel<*>?, columns: Int, rows: Int): GridPanel<S> {
return GridPanel(screen, parent, width = columns * AbstractSlotPanel.SIZE, height = rows * AbstractSlotPanel.SIZE, rows = rows, columns = columns)
}
}
}

View File

@ -3,11 +3,21 @@ package ru.dbotthepony.mc.otm.client.screen.storage
import net.minecraft.network.chat.Component
import ru.dbotthepony.mc.otm.menu.storage.DriveRackMenu
import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.client.render.Widgets18
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import ru.dbotthepony.mc.otm.client.screen.panels.Dock
import ru.dbotthepony.mc.otm.client.screen.panels.DockProperty
import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls
import ru.dbotthepony.mc.otm.client.screen.panels.button.LargeEnumRectangleButtonPanel
import ru.dbotthepony.mc.otm.client.screen.panels.input.IntInputPanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel
import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel
import ru.dbotthepony.mc.otm.core.TranslatableComponent
class DriveRackScreen(menu: DriveRackMenu, inventory: Inventory, title: Component) :
MatteryScreen<DriveRackMenu>(menu, inventory, title) {
@ -15,14 +25,30 @@ class DriveRackScreen(menu: DriveRackMenu, inventory: Inventory, title: Componen
override fun makeMainFrame(): FramePanel<MatteryScreen<*>> {
val frame = super.makeMainFrame()!!
WidePowerGaugePanel(this, frame, menu.energyWidget, LEFT_MARGIN, GAUGE_TOP_WITH_SLOT)
BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE)
makeBars(frame, profiledEnergy = menu.profiledEnergy, batterySlot = menu.batterySlot)
SlotPanel(this, frame, menu.storageSlots[0], 71f, 32f)
SlotPanel(this, frame, menu.storageSlots[1], 71f + 18f, 32f)
val grid = GridPanel.slots(this, frame, 2, 2)
grid.dock = Dock.FILL
SlotPanel(this, frame, menu.storageSlots[2], 71f, 32f + 18f)
SlotPanel(this, frame, menu.storageSlots[3], 71f + 18f, 32f + 18f)
for (slot in menu.storageSlots)
SlotPanel(this, grid, slot)
IntInputPanel(this, frame, menu.insertPriority).also {
it.dock = Dock.BOTTOM
it.tooltips.add(TranslatableComponent("otm.gui.insert_priority"))
it.childrenOrder = -1
it.dockMargin = DockProperty(left = 20f, right = 10f, bottom = 2f)
}
IntInputPanel(this, frame, menu.extractPriority).also {
it.dock = Dock.BOTTOM
it.tooltips.add(TranslatableComponent("otm.gui.extract_priority"))
it.childrenOrder = -2
it.dockMargin = DockProperty(left = 20f, right = 10f, bottom = 2f)
}
val controls = DeviceControls(this, frame, energyConfig = menu.energyConfig, redstoneConfig = menu.redstoneConfig)
controls.addStorageMode(menu.mode)
return frame
}

View File

@ -52,14 +52,7 @@ class StorageBusScreen(menu: StorageBusMenu, inventory: Inventory, title: Compon
}
val controls = DeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig)
val mode = LargeEnumRectangleButtonPanel(this, frame, prop = menu.mode, defaultValue = FlowDirection.BI_DIRECTIONAL, enum = FlowDirection::class.java)
mode.add(FlowDirection.INPUT, Widgets18.ONLY_STORE, FlowDirection.INPUT.title)
mode.add(FlowDirection.OUTPUT, Widgets18.ONLY_EXTRACT, FlowDirection.OUTPUT.title)
mode.add(FlowDirection.BI_DIRECTIONAL, Widgets18.STORE_EXTRACT, FlowDirection.BI_DIRECTIONAL.title)
mode.finish()
controls.addButton(mode)
controls.addStorageMode(menu.mode)
return frame
}

View File

@ -77,7 +77,7 @@ open class StorageNode(private val energyDemander: IMatteryEnergyStorage? = null
fun addStorageComponent(component: IStorage<*>) {
if (components.add(component))
if (isValid && !manualAttaching)
if (isValid && !manualAttaching && !isDetached)
graph.add(component)
}
@ -86,6 +86,23 @@ open class StorageNode(private val energyDemander: IMatteryEnergyStorage? = null
graph.remove(component)
}
var isDetached = false
set(value) {
if (field != value) {
field = value
if (value) {
for (component in components) {
graph.remove(component)
}
} else if (!manualAttaching) {
for (component in components) {
graph.add(component)
}
}
}
}
override fun invalidate() {
for (component in components) {
graph.remove(component)

View File

@ -485,6 +485,10 @@ abstract class MatteryMenu(
return super.addSlot(pSlot)
}
fun addSlot(slots: Iterable<Slot>) {
slots.forEach(::addSlot)
}
/**
* Adds slot to "storage slots" list (utilized by quick move) and calls [addSlot]
*

View File

@ -2,27 +2,31 @@ package ru.dbotthepony.mc.otm.menu.storage
import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.core.immutableList
import ru.dbotthepony.mc.otm.block.entity.storage.DriveRackBlockEntity
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.menu.DriveSlot
import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu
import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback
import ru.dbotthepony.mc.otm.menu.input.IntInputWithFeedback
import ru.dbotthepony.mc.otm.menu.makeSlots
import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.registry.MMenus
class DriveRackMenu @JvmOverloads constructor(
p_38852_: Int,
containerId: Int,
inventory: Inventory,
tile: DriveRackBlockEntity? = null
) : MatteryPoweredMenu(MMenus.DRIVE_RACK, p_38852_, inventory, tile) {
val storageSlots: List<MatterySlot>
) : MatteryPoweredMenu(MMenus.DRIVE_RACK, containerId, inventory, tile) {
val storageSlots = makeSlots(tile?.container ?: SimpleContainer(4), ::DriveSlot)
val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig)
val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget)
val insertPriority = IntInputWithFeedback(this, tile?.let { it::insertPriority })
val extractPriority = IntInputWithFeedback(this, tile?.let { it::extractPriority })
val mode = EnumInputWithFeedback(this, tile?.let { it::mode }, FlowDirection.WITHOUT_NONE)
init {
val container = tile?.container ?: SimpleContainer(4)
storageSlots = immutableList(4) {
addStorageSlot(DriveSlot(container, it))
}
addStorageSlot(storageSlots)
addInventorySlots()
}
}

View File

@ -0,0 +1,47 @@
package ru.dbotthepony.mc.otm.storage.optics
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.storage.IStorageComponent
import ru.dbotthepony.mc.otm.storage.IStorageEventConsumer
import ru.dbotthepony.mc.otm.storage.StorageStack
import java.math.BigInteger
import java.util.*
import java.util.function.Supplier
class FlowControlComponent<S : StorageStack<S>>(private val parent: IStorageComponent<S>, private val flow: Supplier<FlowDirection>) : IStorageComponent<S> by parent {
override fun addListener(listener: IStorageEventConsumer<S>): Boolean {
return parent.addListener(ListenerProxy(listener, this))
}
override fun removeListener(listener: IStorageEventConsumer<S>): Boolean {
return parent.removeListener(ListenerProxy(listener, this))
}
override fun insertStack(stack: S, simulate: Boolean): S {
if (!flow.get().input) {
return storageType.empty
}
return parent.insertStack(stack, simulate)
}
override fun extractStack(id: UUID, amount: BigInteger, simulate: Boolean): S {
if (!flow.get().output) {
return storageType.empty
}
return parent.extractStack(id, amount, simulate)
}
override fun equals(other: Any?): Boolean {
return other is FlowControlComponent<*> && parent == other.parent
}
override fun hashCode(): Int {
return parent.hashCode()
}
override fun toString(): String {
return "FlowControlComponent[flow=${flow.get()}, $parent]"
}
}

View File

@ -1,5 +1,6 @@
package ru.dbotthepony.mc.otm.storage.optics
import ru.dbotthepony.mc.otm.capability.FlowDirection
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
import ru.dbotthepony.mc.otm.storage.IStorageAcceptor
import ru.dbotthepony.mc.otm.storage.IStorageComponent
@ -76,3 +77,11 @@ fun <S : StorageStack<S>> IVirtualStorageComponent<S>.powered(energy: Supplier<I
fun <S : StorageStack<S>> IVirtualStorageComponent<S>.powered(energy: IMatteryEnergyStorage): IVirtualStorageComponent<S> {
return PoweredVirtualComponent(this) { energy }
}
fun <S : StorageStack<S>> IStorageComponent<S>.flow(flow: Supplier<FlowDirection>): IStorageComponent<S> {
return FlowControlComponent(this, flow)
}
fun <S : StorageStack<S>> IStorageComponent<S>.flow(flow: FlowDirection): IStorageComponent<S> {
return FlowControlComponent(this) { flow }
}