From a6eb0ca7f182d3474730b4c126c5cf3ad6223104 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 17 Aug 2023 00:23:36 +0700 Subject: [PATCH] Drive rack insert/extract controls, profiled energy, updated menu, make redstone control of drive rack actually do stuff --- .../entity/storage/DriveRackBlockEntity.kt | 22 +++++++-- .../client/screen/panels/button/Buttons.kt | 32 +++++++++++-- .../client/screen/panels/util/GridPanel.kt | 8 +++- .../client/screen/storage/DriveRackScreen.kt | 38 ++++++++++++--- .../client/screen/storage/StorageBusScreen.kt | 9 +--- .../mc/otm/graph/storage/StorageNode.kt | 19 +++++++- .../ru/dbotthepony/mc/otm/menu/MatteryMenu.kt | 4 ++ .../mc/otm/menu/storage/DriveRackMenu.kt | 26 +++++----- .../storage/optics/FlowControlComponent.kt | 47 +++++++++++++++++++ .../mc/otm/storage/optics/Optics.kt | 9 ++++ 10 files changed, 178 insertions(+), 36 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/storage/optics/FlowControlComponent.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt index 4b405990f..8e6c5f6d2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt @@ -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) { 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 3d18a1491..4bc9763ea 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 @@ -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>( return button } + fun addStorageMode(prop: GetterSetter) { + 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 > sortingButtons(ascending: GetterSetter, sorting: GetterSetter, default: T, configurator: LargeEnumRectangleButtonPanel.() -> Unit) { LargeBooleanRectangleButtonPanel( screen, @@ -415,18 +427,19 @@ class DeviceControls>( 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>( 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 > makeDeviceControls( diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/util/GridPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/util/GridPanel.kt index 782189a60..55a550420 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/util/GridPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/util/GridPanel.kt @@ -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( @@ -80,4 +80,10 @@ open class GridPanel( totalHeight += maxHeight } } + + companion object { + fun slots(screen: S, parent: EditablePanel<*>?, columns: Int, rows: Int): GridPanel { + return GridPanel(screen, parent, width = columns * AbstractSlotPanel.SIZE, height = rows * AbstractSlotPanel.SIZE, rows = rows, columns = columns) + } + } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/storage/DriveRackScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/storage/DriveRackScreen.kt index 171e9725c..a153f8e41 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/storage/DriveRackScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/storage/DriveRackScreen.kt @@ -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(menu, inventory, title) { @@ -15,14 +25,30 @@ class DriveRackScreen(menu: DriveRackMenu, inventory: Inventory, title: Componen override fun makeMainFrame(): FramePanel> { 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 } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/storage/StorageBusScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/storage/StorageBusScreen.kt index 9097f7aba..c504cb6a1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/storage/StorageBusScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/storage/StorageBusScreen.kt @@ -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 } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageNode.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageNode.kt index d00cf71db..a176a192c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageNode.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/graph/storage/StorageNode.kt @@ -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) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt index da8c260f3..5c20fd3fe 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt @@ -485,6 +485,10 @@ abstract class MatteryMenu( return super.addSlot(pSlot) } + fun addSlot(slots: Iterable) { + slots.forEach(::addSlot) + } + /** * Adds slot to "storage slots" list (utilized by quick move) and calls [addSlot] * diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveRackMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveRackMenu.kt index 580b7512f..4b46e738c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveRackMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveRackMenu.kt @@ -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 +) : 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() } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/storage/optics/FlowControlComponent.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/optics/FlowControlComponent.kt new file mode 100644 index 000000000..e5105985b --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/optics/FlowControlComponent.kt @@ -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>(private val parent: IStorageComponent, private val flow: Supplier) : IStorageComponent by parent { + override fun addListener(listener: IStorageEventConsumer): Boolean { + return parent.addListener(ListenerProxy(listener, this)) + } + + override fun removeListener(listener: IStorageEventConsumer): 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]" + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/storage/optics/Optics.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/optics/Optics.kt index b76371daf..ad5811e35 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/storage/optics/Optics.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/optics/Optics.kt @@ -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 > IVirtualStorageComponent.powered(energy: Supplier> IVirtualStorageComponent.powered(energy: IMatteryEnergyStorage): IVirtualStorageComponent { return PoweredVirtualComponent(this) { energy } } + +fun > IStorageComponent.flow(flow: Supplier): IStorageComponent { + return FlowControlComponent(this, flow) +} + +fun > IStorageComponent.flow(flow: FlowDirection): IStorageComponent { + return FlowControlComponent(this) { flow } +}