From f8c2be4d4c05b6e4727860ca7798041860568ac5 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 12 Aug 2023 01:08:42 +0700 Subject: [PATCH] Storage bus insert/extract priorities configuration, operation mode, small refactorings --- .../mc/otm/datagen/lang/English.kt | 5 + .../mc/otm/datagen/lang/Russian.kt | 5 + .../mc/otm/block/entity/MatteryBlockEntity.kt | 27 ++- .../mc/otm/block/entity/RedstoneControl.kt | 18 +- .../entity/storage/StorageBusBlockEntity.kt | 37 +-- .../entity/tech/PlatePressBlockEntity.kt | 6 +- .../mc/otm/capability/FlowDirection.kt | 5 +- .../mc/otm/client/render/RenderGravity.kt | 53 +++++ .../mc/otm/client/render/WidgetLocation.kt | 2 +- .../mc/otm/client/render/Widgets18.kt | 5 +- .../mc/otm/client/screen/MatteryScreen.kt | 63 +++++ .../otm/client/screen/panels/ColorPicker.kt | 2 +- .../otm/client/screen/panels/EditablePanel.kt | 63 ++++- .../mc/otm/client/screen/panels/Label.kt | 4 +- .../screen/panels/button/ButtonPanel.kt | 4 +- .../panels/input/NetworkedStringInputPanel.kt | 7 +- .../screen/panels/input/NumberInputPanel.kt | 215 ++++++++++++++++++ .../screen/panels/input/TextInputPanel.kt | 8 +- .../client/screen/panels/util/GridPanel.kt | 79 ++++--- .../screen/panels/util/HeightControls.kt | 12 +- .../panels/util/HorizontalStripPanel.kt | 14 +- .../client/screen/storage/StorageBusScreen.kt | 71 +++--- .../mc/otm/container/UpgradeContainer.kt | 11 +- .../dbotthepony/mc/otm/core/ByteSupplier.kt | 5 + .../dbotthepony/mc/otm/core/ShortSupplier.kt | 5 + ...StreamyIterator.kt => StreamyIterators.kt} | 130 +++-------- .../otm/menu/input/EnumInputWithFeedback.kt | 24 +- .../mc/otm/menu/storage/ItemMonitorMenu.kt | 4 +- .../mc/otm/menu/storage/StorageBusMenu.kt | 19 +- .../textures/gui/widgets/storage_controls.png | Bin 847 -> 981 bytes .../textures/gui/widgets/storage_controls.xcf | Bin 5791 -> 7924 bytes 31 files changed, 638 insertions(+), 265 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/NumberInputPanel.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/core/ByteSupplier.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/core/ShortSupplier.kt rename src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/{StreamyIterator.kt => StreamyIterators.kt} (76%) 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 46d65a59f..447e72d02 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 @@ -709,6 +709,11 @@ private fun gui(provider: MatteryLanguageProvider) { with(provider.english) { gui("quicksearch", "Quick search...") + gui("insert_priority", "Insert priority") + gui("extract_priority", "Extract priority") + gui("increase", "Increase") + gui("decrease", "Decrease") + gui("color_picker", "Color Picker") gui("color.short.red", "R") 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 22f20e08a..206dc139c 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 @@ -711,6 +711,11 @@ private fun gui(provider: MatteryLanguageProvider) { with(provider.russian) { gui("quicksearch", "Быстрый поиск...") + gui("insert_priority", "Приоритет вставки") + gui("extract_priority", "Приоритет забора") + gui("increase", "Увеличить") + gui("decrease", "Уменьшить") + gui("color_picker", "Выбор цвета") gui("color.short.red", "К") diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryBlockEntity.kt index ec716f8fa..7c3b27a5a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryBlockEntity.kt @@ -44,6 +44,7 @@ import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage import ru.dbotthepony.mc.otm.capability.isMekanismLoaded import ru.dbotthepony.mc.otm.compat.mekanism.Mattery2MekanismEnergyWrapper import ru.dbotthepony.mc.otm.compat.mekanism.Mekanism2MatteryEnergyWrapper +import ru.dbotthepony.mc.otm.core.ISubscriptable import ru.dbotthepony.mc.otm.core.collect.WeakHashSet import ru.dbotthepony.mc.otm.core.forValidRefs import ru.dbotthepony.mc.otm.core.get @@ -175,9 +176,7 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc } } - interface SideListener : Supplier> { - fun addListener(listener: Consumer>) - } + interface SideListener : Supplier>, ISubscriptable> inner class Side(val side: RelativeSide) { init { @@ -194,17 +193,16 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc set(value) { if (value !== field) { field = value - - for (tracker in listeners) - tracker.accept(value) + listeners.accept(value) } } - private val listeners = ArrayList>>(0) + private val listeners = ISubscriptable.Impl>() - override fun addListener(listener: Consumer>) { - listeners.add(listener) + override fun addListener(listener: Consumer>): ISubscriptable.L { + val l = listeners.addListener(listener) listener.accept(value) + return l } override fun get(): LazyOptional { @@ -234,15 +232,16 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc private val mekanism: SubRef? private var actualMekanism: LazyOptional? = null - private val listeners = ArrayList>>() + private val listeners = ISubscriptable.Impl>() - override fun addListener(listener: Consumer>) { - listeners.add(listener) + override fun addListener(listener: Consumer>): ISubscriptable.L { + val l = listeners.addListener(listener) listener.accept(get()) + return l } init { - regular.addListener { a -> listeners.forEach { it.accept(a) } } + regular.addListener { listeners.accept(it) } if (isMekanismLoaded) { mekanism = track(MatteryCapability.MEKANISM_ENERGY) as SubRef @@ -256,7 +255,7 @@ abstract class MatteryBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: Bloc actualMekanism = null } - listeners.forEach { it.accept(get()) } + listeners.accept(get()) } } else { mekanism = null diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/RedstoneControl.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/RedstoneControl.kt index 4f311198a..04ff7785f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/RedstoneControl.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/RedstoneControl.kt @@ -3,6 +3,8 @@ package ru.dbotthepony.mc.otm.block.entity import it.unimi.dsi.fastutil.booleans.BooleanConsumer import net.minecraft.nbt.CompoundTag import net.minecraftforge.common.util.INBTSerializable +import ru.dbotthepony.mc.otm.core.IBooleanSubscriptable +import ru.dbotthepony.mc.otm.core.ISubscriptable import ru.dbotthepony.mc.otm.core.nbt.mapString import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.network.synchronizer.FieldSynchronizer @@ -11,15 +13,15 @@ interface IRedstoneControlled { val redstoneControl: AbstractRedstoneControl } -abstract class AbstractRedstoneControl : INBTSerializable { +abstract class AbstractRedstoneControl : INBTSerializable, IBooleanSubscriptable { abstract var redstoneSetting: RedstoneSetting abstract var redstoneSignal: Int - protected val listeners = ArrayList() + protected val listeners = IBooleanSubscriptable.Impl() val isBlockedByRedstone: Boolean get() = !redstoneSetting.test(redstoneSignal) - fun addListener(callback: BooleanConsumer) { - listeners.add(callback) + final override fun addListener(listener: BooleanConsumer): ISubscriptable.L { + return listeners.addListener(listener) } override fun serializeNBT(): CompoundTag { @@ -56,7 +58,7 @@ class RedstoneControl(private val valueChanges: (new: Boolean, old: Boolean) -> if (state != old) { valueChanges.invoke(state, old) - listeners.forEach { it.accept(state) } + listeners.accept(state) } } @@ -69,7 +71,7 @@ class RedstoneControl(private val valueChanges: (new: Boolean, old: Boolean) -> if (state != old) { valueChanges.invoke(state, old) - listeners.forEach { it.accept(state) } + listeners.accept(state) } } } @@ -89,7 +91,7 @@ class SynchronizedRedstoneControl( if (state != old) { valueChanges.invoke(state, old) - listeners.forEach { it.accept(state) } + listeners.accept(state) } } }) @@ -105,7 +107,7 @@ class SynchronizedRedstoneControl( if (state != old) { valueChanges.invoke(state, old) - listeners.forEach { it.accept(state) } + listeners.accept(state) } } }).property diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageBusBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageBusBlockEntity.kt index 3604c5111..45d3a1716 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageBusBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageBusBlockEntity.kt @@ -18,7 +18,9 @@ import ru.dbotthepony.mc.otm.* import ru.dbotthepony.mc.otm.block.CableBlock import ru.dbotthepony.mc.otm.block.entity.MatteryPoweredBlockEntity import ru.dbotthepony.mc.otm.block.entity.storage.AbstractStorageImportExport.Companion.FILTER_KEY +import ru.dbotthepony.mc.otm.capability.FlowDirection 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.ItemFilter @@ -45,20 +47,14 @@ private class TrackedTuple(override var stack: ItemStorageStack, override val id } } -private fun Long.clamp(): Int { - if (this > Int.MAX_VALUE) { - return Int.MAX_VALUE - } - - return this.toInt() -} - class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.STORAGE_BUS, blockPos, blockState) { override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { return StorageBusMenu(containerID, inventory, this) } - val energy = WorkerEnergyStorage(this::setChangedLight, MachinesConfig.STORAGE_INTERFACES) + val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::setChangedLight, MachinesConfig.STORAGE_INTERFACES)) + val energyConfig = ConfigurableEnergy(energy, modesFront = FlowDirection.NONE) + val cell: StorageNode = object : StorageNode(energy) { override fun onNeighbour(link: Link) { if (link is DirectionLink) { @@ -93,8 +89,13 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter setChangedLight() } + var mode: FlowDirection = FlowDirection.BI_DIRECTIONAL + set(value) { + field = value + setChangedLight() + } + init { - exposeEnergyGlobally(energy) savetable(::energy, ENERGY_KEY) savetables.int(::insertPriority) savetables.int(::extractPriority) @@ -103,11 +104,21 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter side(RelativeSide.FRONT).track(ForgeCapabilities.ITEM_HANDLER).addListener { component?.let(cell::removeStorageComponent) component = if (it.isPresent) { - ItemHandlerComponent(it.orThrow()).also(cell::addStorageComponent) + ItemHandlerComponent(it.orThrow()).also { if (!redstoneControl.isBlockedByRedstone) cell.addStorageComponent(it) } } else { null } } + + redstoneControl.addListener { + val component = component ?: return@addListener + + if (it) { + cell.removeStorageComponent(component) + } else { + cell.addStorageComponent(component) + } + } } val filter = ItemFilter(MAX_FILTERS) { _, _, _ -> @@ -359,7 +370,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter } override fun insertStack(stack: ItemStorageStack, simulate: Boolean): ItemStorageStack { - if (redstoneControl.isBlockedByRedstone || energy.batteryLevel.isZero || !filter.match(stack.toItemStack())) + if (redstoneControl.isBlockedByRedstone || energy.batteryLevel.isZero || !filter.match(stack.toItemStack()) || !mode.input) return stack val required = StorageStack.ITEMS.energyPerInsert(stack) @@ -390,7 +401,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter } override fun extractStack(id: UUID, amount: BigInteger, simulate: Boolean): ItemStorageStack { - if (redstoneControl.isBlockedByRedstone || !amount.isPositive || !energy.batteryLevel.isPositive) + if (redstoneControl.isBlockedByRedstone || !amount.isPositive || !energy.batteryLevel.isPositive || !mode.output) return ItemStorageStack.EMPTY var total = BigInteger.ZERO diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt index 484df1610..30b72f565 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt @@ -21,7 +21,8 @@ import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.UpgradeContainer import ru.dbotthepony.mc.otm.container.balance import ru.dbotthepony.mc.otm.core.collect.filter -import ru.dbotthepony.mc.otm.core.collect.findAny +import ru.dbotthepony.mc.otm.core.collect.find +import ru.dbotthepony.mc.otm.core.collect.maybe import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu import ru.dbotthepony.mc.otm.menu.tech.TwinPlatePressMenu import ru.dbotthepony.mc.otm.registry.MBlockEntities @@ -92,8 +93,7 @@ class PlatePressBlockEntity( .values .iterator() .filter { it.matches(inputContainer, id) } - .findAny() - .orElse(null) ?: return JobContainer.noItem() + .maybe() ?: return JobContainer.noItem() val toProcess = inputContainer[id].count.coerceAtMost(1 + upgrades.processingItems) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/FlowDirection.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/FlowDirection.kt index ae15a5428..d11df0163 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/FlowDirection.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/FlowDirection.kt @@ -64,7 +64,7 @@ enum class FlowDirection(val input: Boolean, val output: Boolean, val translatio }.build() } - val translation: Component + val title: Component get() = TranslatableComponent(translationKey) /** @@ -105,6 +105,9 @@ enum class FlowDirection(val input: Boolean, val output: Boolean, val translatio } companion object { + @JvmField + val WITHOUT_NONE: ImmutableSet = ImmutableSet.of(INPUT, OUTPUT, BI_DIRECTIONAL) + @JvmStatic fun of(input: Boolean, output: Boolean): FlowDirection { if (input && output) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/RenderGravity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/RenderGravity.kt index f67ee6051..33a72244a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/RenderGravity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/RenderGravity.kt @@ -30,6 +30,10 @@ enum class GravityRounding { return base - subtraction } } + + override fun round(base: Float): Float { + return base + } }, /** @@ -39,6 +43,10 @@ enum class GravityRounding { override fun round(base: Float, subtraction: Float): Float { return (base - subtraction).roundToInt().toFloat() } + + override fun round(base: Float): Float { + return base.roundToInt().toFloat() + } }, /** @@ -48,9 +56,14 @@ enum class GravityRounding { override fun round(base: Float, subtraction: Float): Float { return base - subtraction } + + override fun round(base: Float): Float { + return base + } }; abstract fun round(base: Float, subtraction: Float): Float + abstract fun round(base: Float): Float } interface IXGravity { @@ -60,6 +73,8 @@ interface IXGravity { fun x(x: Float, width: FloatSupplier): Float = x(x, width, 1f) fun x(x: Float, width: Float): Float = x(x, width, 1f) + fun repositionX(outer: Float, inner: Float, rounding: GravityRounding = GravityRounding.YES): Float + fun x(x: Float, font: Font, text: Component): Float = x(x, font, text, 1f) fun x(x: Float, font: Font, text: Component, scale: Float = 1f, rounding: GravityRounding = GravityRounding.DEFAULT): Float @@ -80,6 +95,8 @@ interface IYGravity { fun y(y: Float, height: Float, scale: Float = 1f, rounding: GravityRounding = GravityRounding.DEFAULT): Float fun y(y: Float, height: Float): Float = y(y, height, 1f) + fun repositionY(outer: Float, inner: Float, rounding: GravityRounding = GravityRounding.YES): Float + fun y(y: Float, height: Int, scale: Float = 1f): Float { return y(y, height.toFloat(), scale).roundToInt().toFloat() } @@ -106,6 +123,10 @@ enum class XGravity : IXGravity { override fun x(x: Float, font: Font, text: FormattedCharSequence, scale: Float, rounding: GravityRounding): Float { return x } + + override fun repositionX(outer: Float, inner: Float, rounding: GravityRounding): Float { + return 0f + } }, CENTER { override fun x(x: Float, width: FloatSupplier, scale: Float, rounding: GravityRounding): Float { @@ -127,6 +148,13 @@ enum class XGravity : IXGravity { override fun x(x: Float, font: Font, text: FormattedCharSequence, scale: Float, rounding: GravityRounding): Float { return rounding.round(x, font.width(text) / 2f * scale) } + + override fun repositionX(outer: Float, inner: Float, rounding: GravityRounding): Float { + if (outer <= inner) + return 0f + else + return rounding.round((outer - inner) / 2f, 0f) + } }, RIGHT { override fun x(x: Float, width: FloatSupplier, scale: Float, rounding: GravityRounding): Float { @@ -148,6 +176,13 @@ enum class XGravity : IXGravity { override fun x(x: Float, font: Font, text: FormattedCharSequence, scale: Float, rounding: GravityRounding): Float { return rounding.round(x, font.width(text) * scale) } + + override fun repositionX(outer: Float, inner: Float, rounding: GravityRounding): Float { + if (outer <= inner) + return 0f + else + return rounding.round(outer - inner, 0f) + } }; } @@ -160,6 +195,10 @@ enum class YGravity : IYGravity { override fun y(y: Float, height: Float, scale: Float, rounding: GravityRounding): Float { return y } + + override fun repositionY(outer: Float, inner: Float, rounding: GravityRounding): Float { + return 0f + } }, CENTER { @@ -170,6 +209,13 @@ enum class YGravity : IYGravity { override fun y(y: Float, height: Float, scale: Float, rounding: GravityRounding): Float { return rounding.round(y, height / 2f * scale) } + + override fun repositionY(outer: Float, inner: Float, rounding: GravityRounding): Float { + if (outer <= inner) + return 0f + else + return rounding.round((outer - inner) / 2f, 0f) + } }, BOTTOM { @@ -180,6 +226,13 @@ enum class YGravity : IYGravity { override fun y(y: Float, height: Float, scale: Float, rounding: GravityRounding): Float { return rounding.round(y, height * scale) } + + override fun repositionY(outer: Float, inner: Float, rounding: GravityRounding): Float { + if (outer <= inner) + return 0f + else + return rounding.round(outer - inner, 0f) + } }; } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/WidgetLocation.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/WidgetLocation.kt index 7c9ca1069..9da40a685 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/WidgetLocation.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/WidgetLocation.kt @@ -6,7 +6,7 @@ import ru.dbotthepony.mc.otm.client.render.sprites.MatteryAtlas object WidgetLocation { val LARGE_BUTTON = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/large_button.png"), 72f, 18f) - val STORAGE_CONTROLS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/storage_controls.png"), 90f, 36f) + val STORAGE_CONTROLS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/storage_controls.png"), 90f, 54f) val MISC_18 = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/misc18.png"), 72f, 72f) val SLOT_BACKGROUNDS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/slot_backgrounds.png"), 72f, 72f) 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 e6cea1252..82d7bb6eb 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 @@ -37,7 +37,7 @@ object Widgets18 { val BUTTON_DISABLED_STRETCHABLE = makeButton(buttonGrids) val BUTTON_DISABLED = buttonGrids.next() - private val storageGrid = WidgetLocation.STORAGE_CONTROLS.grid(rows = 2, columns = 5) + private val storageGrid = WidgetLocation.STORAGE_CONTROLS.grid(rows = 3, columns = 5) val ARROW_DOWN = storageGrid.next() val ARROW_UP = storageGrid.next() val SORT_DEFAULT = storageGrid.next() @@ -47,6 +47,9 @@ object Widgets18 { val SORT_ID = storageGrid.next() val SORT_MATTER_VALUE = storageGrid.next() val SORT_MATTER_COMPLEXITY = storageGrid.next() + val ONLY_STORE = storageGrid.next() + val ONLY_EXTRACT = storageGrid.next() + val STORE_EXTRACT = storageGrid.next() private val miscGrid = WidgetLocation.MISC_18.grid(4, 4) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt index ad038b27c..d55ed476c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt @@ -19,6 +19,7 @@ import net.minecraftforge.common.MinecraftForge import org.lwjgl.opengl.GL11 import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.client.moveMousePosScaled +import ru.dbotthepony.mc.otm.client.render.WidgetLocation import ru.dbotthepony.mc.otm.client.render.Widgets18 import ru.dbotthepony.mc.otm.client.render.translation import ru.dbotthepony.mc.otm.client.screen.panels.* @@ -31,14 +32,23 @@ import ru.dbotthepony.mc.otm.client.screen.panels.util.DiscreteScrollBarPanel import ru.dbotthepony.mc.otm.client.screen.panels.util.HeightControls import ru.dbotthepony.mc.otm.client.screen.panels.util.ScrollBarConstants import ru.dbotthepony.mc.otm.client.screen.widget.HorizontalPowerGaugePanel +import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel +import ru.dbotthepony.mc.otm.client.screen.widget.PatternGaugePanel +import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel +import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledPowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.TallHorizontalProfiledPowerGaugePanel +import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel +import ru.dbotthepony.mc.otm.client.screen.widget.WideProfiledPowerGaugePanel import ru.dbotthepony.mc.otm.config.ClientConfig import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.math.component1 import ru.dbotthepony.mc.otm.core.math.component2 import ru.dbotthepony.mc.otm.core.math.integerDivisionDown import ru.dbotthepony.mc.otm.menu.MatteryMenu +import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget +import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import java.util.* import kotlin.collections.ArrayDeque import kotlin.collections.List @@ -374,6 +384,59 @@ abstract class MatteryScreen(menu: T, inventory: Inventory, tit return true } + protected fun makeBars( + parent: EditablePanel<*>, + energy: LevelGaugeWidget? = null, + profiledEnergy: ProfiledLevelGaugeWidget<*>? = null, + matter: LevelGaugeWidget? = null, + profiledMatter: ProfiledLevelGaugeWidget<*>? = null, + patterns: LevelGaugeWidget? = null, + batterySlot: MatterySlot? = null, + ) { + var bars = 0 + if (energy != null) bars++ + if (profiledEnergy != null) bars++ + if (matter != null) bars++ + if (patterns != null) bars++ + if (profiledMatter != null) bars++ + + val canvas = EditablePanel(this, parent, width = AbstractSlotPanel.SIZE.coerceAtLeast(9f * bars)) + canvas.dock = Dock.LEFT + canvas.childrenOrder = -1000 + + val gauges = EditablePanel(this, canvas, height = WidgetLocation.VERTICAL_GAUGES.height) + gauges.dock = Dock.TOP + + if (profiledEnergy != null) { + if (bars == 1) { + WideProfiledPowerGaugePanel(this, gauges, profiledEnergy).dock = Dock.TOP + } else { + ProfiledPowerGaugePanel(this, gauges, profiledEnergy).dock = Dock.LEFT + } + } else if (energy != null) { + if (bars == 1) { + WidePowerGaugePanel(this, gauges, energy).dock = Dock.TOP + } else { + PowerGaugePanel(this, gauges, energy).dock = Dock.LEFT + } + } + + if (matter != null) { + MatterGaugePanel(this, gauges, matter).dock = Dock.LEFT + } + + if (patterns != null) { + PatternGaugePanel(this, gauges, patterns).dock = Dock.LEFT + } + + if (batterySlot != null) { + BatterySlotPanel(this, canvas, batterySlot).also { + it.dock = Dock.BOTTOM + it.dockResize = DockResizeMode.NONE + } + } + } + /** * Safely to be overriden. By default, creates well-known dimensions window * diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/ColorPicker.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/ColorPicker.kt index 97810e9d7..5bc85ec98 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/ColorPicker.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/ColorPicker.kt @@ -580,7 +580,7 @@ open class ColorPickerPanel( } } - override fun acceptsCharacter(codepoint: Char, mods: Int): Boolean { + override fun acceptsCharacter(codepoint: Char, mods: Int, index: Int): Boolean { return RGBAColor.isHexCharacter(codepoint) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt index cad6d06bb..d7d9673ae 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt @@ -33,6 +33,8 @@ data class ScreenPos(val x: Float, val y: Float) data class DockProperty(val left: Float = 0f, val top: Float = 0f, val right: Float = 0f, val bottom: Float = 0f) { val isEmpty get() = left == 0f && right == 0f && top == 0f && bottom == 0f + val horizontal get() = left + right + val vertical get() = top + bottom companion object { val EMPTY = DockProperty() @@ -73,7 +75,6 @@ open class EditablePanel @JvmOverloads constructor( height: Float = 10f, ) : Comparable> { // layout engine does not support navigation using keyboard - // fuck off val listener: GuiEventListener = object : GuiEventListener { override fun setFocused(p_265728_: Boolean) { if (p_265728_) { @@ -138,6 +139,9 @@ open class EditablePanel @JvmOverloads constructor( } } + /** + * Bigger values means lesser priority while docking + */ var childrenOrder = 0 set(value) { if (field != value) { @@ -235,17 +239,21 @@ open class EditablePanel @JvmOverloads constructor( } /** - * Width to be utilized in docking code. + * Width of this panel as considered by docking code, updated inside [performLayout] * - * Can only differ from [width] if [dockResize] is not [DockResizeMode.ALL] and not [DockResizeMode.WIDTH] + * If panel is not docked ([dock] is [Dock.NONE]), this value equals to [width] plus [DockProperty.horizontal] of [dockMargin] + * + * If panel is docked, this value will be equal to [width], if [dockResize] allows resizing [width], or could-have value, if [dockResize] doesn't */ var dockedWidth: Float = 0f private set /** - * Height to be utilized in docking code. + * Height of this panel as considered by docking code, updated inside [performLayout] * - * Can only differ from [height] if [dockResize] is not [DockResizeMode.ALL] and not [DockResizeMode.HEIGHT] + * If panel is not docked ([dock] is [Dock.NONE]), this value equals to [height] plus [DockProperty.vertical] of [dockMargin] + * + * If panel is docked, this value will be equal to [height], if [dockResize] allows resizing [height], or could-have value, if [dockResize] doesn't */ var dockedHeight: Float = 0f private set @@ -362,6 +370,38 @@ open class EditablePanel @JvmOverloads constructor( } } + var dockPaddingLeft: Float + get() = dockPadding.left + set(value) { + if (value != dockPadding.left) { + dockPadding = dockPadding.copy(left = value) + } + } + + var dockPaddingRight: Float + get() = dockPadding.right + set(value) { + if (value != dockPadding.right) { + dockPadding = dockPadding.copy(right = value) + } + } + + var dockPaddingTop: Float + get() = dockPadding.top + set(value) { + if (value != dockPadding.top) { + dockPadding = dockPadding.copy(top = value) + } + } + + var dockPaddingBottom: Float + get() = dockPadding.bottom + set(value) { + if (value != dockPadding.bottom) { + dockPadding = dockPadding.copy(bottom = value) + } + } + var acceptMouseInput = true var acceptKeyboardInput = true var grabMouseInput = false @@ -1060,7 +1100,11 @@ open class EditablePanel @JvmOverloads constructor( for (child in visibleChildrenInternal) { when (child.dock) { - Dock.NONE -> {} + Dock.NONE -> { + child.dockedWidth = child.width + child.dockMargin.horizontal + child.dockedHeight = child.height + child.dockMargin.vertical + } + Dock.FILL -> {} Dock.LEFT -> { @@ -1192,8 +1236,8 @@ open class EditablePanel @JvmOverloads constructor( * * Performs layout if required */ - open fun sizeToContents() { - if (layoutInvalidated) { + open fun sizeToContents(performLayout: Boolean = true) { + if (layoutInvalidated && performLayout) { performLayout() } @@ -1398,8 +1442,7 @@ open class EditablePanel @JvmOverloads constructor( } fun getChildren(index: Int): EditablePanel<*>? { - if (index < 0 || index >= childrenInternal.size) return null - return childrenInternal[index] + return childrenInternal.getOrNull(index) } fun isGrabbingMouseInput(): Boolean { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/Label.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/Label.kt index 797f88dd3..aa1cba389 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/Label.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/Label.kt @@ -61,8 +61,8 @@ open class Label @JvmOverloads constructor( } } - override fun sizeToContents() { - super.sizeToContents() + override fun sizeToContents(performLayout: Boolean) { + super.sizeToContents(performLayout) val w = font.width(text) val h = font.lineHeight + 2 diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/button/ButtonPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/button/ButtonPanel.kt index 53965c468..67a0c546f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/button/ButtonPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/button/ButtonPanel.kt @@ -56,8 +56,8 @@ open class ButtonPanel( graphics.draw(font, label, width / 2f, height / 2f, color = textColor, gravity = RenderGravity.CENTER_CENTER) } - override fun sizeToContents() { - super.sizeToContents() + override fun sizeToContents(performLayout: Boolean) { + super.sizeToContents(performLayout) height = height.coerceAtLeast(HEIGHT).coerceAtLeast(font.lineHeight.toFloat() + 2f) width = width.coerceAtLeast(HEIGHT).coerceAtLeast(font.width(label) + 4f) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/NetworkedStringInputPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/NetworkedStringInputPanel.kt index be566b427..c5ad5d7d8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/NetworkedStringInputPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/NetworkedStringInputPanel.kt @@ -4,12 +4,13 @@ import net.minecraft.client.gui.screens.Screen import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.menu.input.AbstractPlayerInputWithFeedback +import ru.dbotthepony.mc.otm.menu.input.IPlayerInputWithFeedback import ru.dbotthepony.mc.otm.milliTime open class NetworkedStringInputPanel( screen: S, parent: EditablePanel<*>?, - val backend: AbstractPlayerInputWithFeedback, + val backend: IPlayerInputWithFeedback, x: Float = 0f, y: Float = 0f, width: Float = 60f, @@ -29,7 +30,7 @@ open class NetworkedStringInputPanel( private var lastChanges = 0L - override fun onTextChanged(old: String, new: String) { + override fun onTextChanged(new: String, old: String) { lastChanges = milliTime + 1000L backend.accept(new) } @@ -38,7 +39,7 @@ open class NetworkedStringInputPanel( super.tickInner() if (milliTime >= lastChanges) { - text = backend.value + text = backend.get() } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/NumberInputPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/NumberInputPanel.kt new file mode 100644 index 000000000..b96963ee7 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/NumberInputPanel.kt @@ -0,0 +1,215 @@ +package ru.dbotthepony.mc.otm.client.screen.panels.input + +import com.mojang.blaze3d.platform.InputConstants +import net.minecraft.client.gui.screens.Screen +import ru.dbotthepony.mc.otm.client.render.Widgets +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.button.RectangleButtonPanel +import ru.dbotthepony.mc.otm.client.screen.panels.util.HeightControls +import ru.dbotthepony.mc.otm.core.GetterSetter +import ru.dbotthepony.mc.otm.core.TranslatableComponent +import ru.dbotthepony.mc.otm.core.math.Decimal + +abstract class NumberInputPanel( + screen: S, + parent: EditablePanel<*>, + val prop: GetterSetter, + x: Float = 0f, + y: Float = 0f, + width: Float = WIDTH, + height: Float = HeightControls.BUTTON_HEIGHT * 2f, + var min: N? = null, + var max: N? = null, +) : EditablePanel(screen, parent, x, y, width, height) { + abstract fun toNumber(input: String): N? + abstract fun increase(input: N): N + abstract fun decrease(input: N): N + abstract val isFractional: Boolean + + fun clamp(value: N): N { + val min = min + val max = max + if (min != null && (value as Comparable) < min) return min + if (max != null && (value as Comparable) > max) return max + return value + } + + fun increase() { + prop.accept(clamp(increase(prop.get()))) + } + + fun decrease() { + prop.accept(clamp(decrease(prop.get()))) + } + + val textInput = object : TextInputPanel(screen, this@NumberInputPanel) { + init { + allowNumbersAndSign() + dock = Dock.FILL + text = prop.get().toString() + } + + override fun acceptsCharacter(codepoint: Char, mods: Int, index: Int): Boolean { + if (!isFractional && codepoint == '.') return false + return super.acceptsCharacter(codepoint, mods, index) + } + + override fun tickInner() { + super.tickInner() + + if (!hasHierarchicalFocus()) { + text = prop.get().toString() + } + } + + override fun onTextChanged(new: String, old: String) { + if (hasHierarchicalFocus()) { + val i = toNumber(new) + if (i != null) prop.accept(i) + } + } + } + + val controls = EditablePanel(screen, this, width = HeightControls.BUTTON_WIDTH, height = HeightControls.BUTTON_HEIGHT) + val increaseControl = Control(true) + val decreaseControl = Control(false) + + init { + increaseControl.childrenOrder = 1 + decreaseControl.childrenOrder = 2 + textInput.dockRight = 2f + } + + init { + controls.dock = Dock.RIGHT + } + + inner class Control(val isIncrease: Boolean) : RectangleButtonPanel(screen, controls, width = HeightControls.BUTTON_WIDTH, height = HeightControls.BUTTON_HEIGHT) { + override val PRESSED = if (!isIncrease) Widgets.ARROW_DOWN_BUTTON_PRESSED else Widgets.ARROW_UP_BUTTON_PRESSED + override val HOVERED = if (!isIncrease) Widgets.ARROW_DOWN_BUTTON_HOVERED else Widgets.ARROW_UP_BUTTON_HOVERED + override val IDLE = if (!isIncrease) Widgets.ARROW_DOWN_BUTTON_IDLE else Widgets.ARROW_UP_BUTTON_IDLE + override val DISABLED = if (!isIncrease) Widgets.ARROW_DOWN_BUTTON_DISABLED else Widgets.ARROW_UP_BUTTON_DISABLED + + init { + dock = Dock.TOP + + if (isIncrease) + tooltips.add(TranslatableComponent("otm.gui.increase")) + else + tooltips.add(TranslatableComponent("otm.gui.decrease")) + } + + override fun test(value: Int): Boolean { + return value == InputConstants.MOUSE_BUTTON_LEFT || value == InputConstants.MOUSE_BUTTON_RIGHT + } + + override fun onClick(mouseButton: Int) { + if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) { + if (isIncrease) { + increase() + } else { + decrease() + } + } else if (mouseButton == InputConstants.MOUSE_BUTTON_RIGHT) { + if (isIncrease) { + decrease() + } else { + increase() + } + } + } + } + + companion object { + const val WIDTH = 50f + } +} + +abstract class LNumberInputPanel( + screen: S, + parent: EditablePanel<*>, + prop: GetterSetter, + x: Float = 0f, + y: Float = 0f, + width: Float = WIDTH, + height: Float = HeightControls.BUTTON_HEIGHT * 2f, + min: N? = null, + max: N? = null, + val toNumber: (String) -> N?, + val increase: (N) -> N, + val decrease: (N) -> N, + final override val isFractional: Boolean +) : NumberInputPanel(screen, parent, prop, x, y, width, height, min, max) { + final override fun toNumber(input: String): N? { + return toNumber.invoke(input) + } + + final override fun increase(input: N): N { + return increase.invoke(input) + } + + final override fun decrease(input: N): N { + return decrease.invoke(input) + } +} + +open class IntInputPanel( + screen: S, + parent: EditablePanel<*>, + prop: GetterSetter, + x: Float = 0f, + y: Float = 0f, + width: Float = WIDTH, + height: Float = HeightControls.BUTTON_HEIGHT * 2f, + var step: Int = 1, + min: Int? = null, + max: Int? = null, +) : NumberInputPanel(screen, parent, prop, x, y, width, height, min, max) { + final override fun toNumber(input: String): Int? { + return input.toIntOrNull() + } + + final override fun increase(input: Int): Int { + return input + step + } + + final override fun decrease(input: Int): Int { + return input - step + } + + final override val isFractional: Boolean + get() = false +} + +open class DecimalInputPanel( + screen: S, + parent: EditablePanel<*>, + prop: GetterSetter, + x: Float = 0f, + y: Float = 0f, + width: Float = WIDTH, + height: Float = HeightControls.BUTTON_HEIGHT * 2f, + var step: Decimal = Decimal.ONE, + min: Decimal? = null, + max: Decimal? = null, +) : NumberInputPanel(screen, parent, prop, x, y, width, height, min, max) { + final override fun toNumber(input: String): Decimal? { + return try { + Decimal(input) + } catch (err: NumberFormatException) { + null + } + } + + final override fun increase(input: Decimal): Decimal { + return input + step + } + + final override fun decrease(input: Decimal): Decimal { + return input - step + } + + final override val isFractional: Boolean + get() = true +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/TextInputPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/TextInputPanel.kt index c88a4eec4..328a0d943 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/TextInputPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/input/TextInputPanel.kt @@ -27,7 +27,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.DockProperty import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.addAll -import ru.dbotthepony.mc.otm.core.collect.mapToInt +import ru.dbotthepony.mc.otm.core.collect.map import ru.dbotthepony.mc.otm.core.collect.reduce import ru.dbotthepony.mc.otm.core.math.RGBAColor import ru.dbotthepony.mc.otm.milliTime @@ -904,7 +904,7 @@ open class TextInputPanel( pushbackSnapshot() if (multiLine) { - var index = cursorRow + (0 until cursorLine).iterator().mapToInt { this[it]?.length ?: 0 }.reduce(0, Int::plus) + var index = cursorRow + (0 until cursorLine).iterator().map { this[it]?.length ?: 0 }.reduce(0, Int::plus) val insert = minecraft.keyboardHandler.clipboard.replace("\t", " ").filter { acceptsCharacter(it, 0, index++) }.split(NEWLINES).toMutableList() val actualLastSize = insert.lastOrNull()?.length ?: 0 val line = this[cursorLine] @@ -944,7 +944,7 @@ open class TextInputPanel( cursorRow = actualLastSize } } else { - var index = cursorRow + (0 until cursorLine).iterator().mapToInt { this[it]?.length ?: 0 }.reduce(0, Int::plus) + var index = cursorRow + (0 until cursorLine).iterator().map { this[it]?.length ?: 0 }.reduce(0, Int::plus) val insert = minecraft.keyboardHandler.clipboard.replace("\t", " ").replace(NEWLINES, "").filter { acceptsCharacter(it, 0, index++) } val line = this[cursorLine] @@ -1462,7 +1462,7 @@ open class TextInputPanel( } private val NUMBERS = CharOpenHashSet().also { - for (char in "0123456789-+") + for (char in "0123456789.") it.add(char) } 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 a9de349d6..782189a60 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 @@ -1,8 +1,12 @@ package ru.dbotthepony.mc.otm.client.screen.panels.util 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.core.collect.filter +import ru.dbotthepony.mc.otm.core.collect.map +import ru.dbotthepony.mc.otm.core.collect.maybe open class GridPanel( screen: S, @@ -26,37 +30,54 @@ open class GridPanel( invalidateLayout() } - override fun performLayout() { - var currentX = 0f - var currentY = 0f - var lineY = 0f - var index = 0 - - for (row in 0 until rows) { - var column = 0 - - while (column < columns) { - val child = getChildren(index) ?: break - - if (child.visible && child.dock === Dock.NONE) { - lineY = lineY.coerceAtLeast(child.height + child.dockMargin.top + child.dockMargin.bottom) - child.setPos(currentX + child.dockMargin.left, currentY + child.dockMargin.top) - currentX += child.width + child.dockMargin.left + child.dockMargin.right - } else { - column-- - } - - index++ - column++ - } - - currentY += lineY - currentX = 0f - lineY = 0f - - getChildren(index) ?: break + var gravity: RenderGravity = RenderGravity.CENTER_CENTER + set(value) { + field = value + invalidateLayout() } + override fun performLayout() { super.performLayout() + var children = visibleChildren.iterator().filter { it.dock == Dock.NONE } + + var totalWidth = 0f + var totalHeight = 0f + + for (row in 0 until rows) { + var maxHeight = 0f + var width = 0f + + for (column in 0 until columns) { + val child = children.maybe() ?: break + width += child.dockedWidth + maxHeight = maxHeight.coerceAtLeast(child.dockedHeight) + } + + totalWidth = totalWidth.coerceAtLeast(width) + totalHeight += maxHeight + } + + val alignX = gravity.repositionX(width, totalWidth) + val alignY = gravity.repositionY(height, totalHeight) + children = visibleChildren.iterator().filter { it.dock == Dock.NONE } + + totalWidth = 0f + totalHeight = 0f + + for (row in 0 until rows) { + var maxHeight = 0f + var width = 0f + + for (column in 0 until columns) { + val child = children.maybe() ?: break + child.x = alignX + width + child.y = alignY + totalHeight + width += child.dockedWidth + maxHeight = maxHeight.coerceAtLeast(child.dockedHeight) + } + + totalWidth = totalWidth.coerceAtLeast(width) + totalHeight += maxHeight + } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/util/HeightControls.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/util/HeightControls.kt index 9eeaae48a..653bfe9f5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/util/HeightControls.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/util/HeightControls.kt @@ -46,7 +46,7 @@ open class HeightControls( decrease.isDisabled = !value.canDecrease } - open inner class Control(val isIncrease: Boolean) : RectangleButtonPanel(screen, this@HeightControls, width = BUTTON_WIDTH, height = BUTTON_HEIGHT) { + inner class Control(val isIncrease: Boolean) : RectangleButtonPanel(screen, this@HeightControls, width = BUTTON_WIDTH, height = BUTTON_HEIGHT) { override val PRESSED: AbstractMatterySprite = if (isIncrease) Widgets.ARROW_DOWN_BUTTON_PRESSED else Widgets.ARROW_UP_BUTTON_PRESSED override val HOVERED: AbstractMatterySprite = if (isIncrease) Widgets.ARROW_DOWN_BUTTON_HOVERED else Widgets.ARROW_UP_BUTTON_HOVERED override val IDLE: AbstractMatterySprite = if (isIncrease) Widgets.ARROW_DOWN_BUTTON_IDLE else Widgets.ARROW_UP_BUTTON_IDLE @@ -57,10 +57,14 @@ open class HeightControls( dockBottom = 2f } - override fun onClick(clickButton: Int) { - if (clickButton == InputConstants.MOUSE_BUTTON_LEFT) { + override fun test(value: Int): Boolean { + return value == InputConstants.MOUSE_BUTTON_LEFT || value == InputConstants.MOUSE_BUTTON_RIGHT + } + + override fun onClick(mouseButton: Int) { + if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) { this@HeightControls.onClick(isIncrease) - } else if (clickButton == InputConstants.MOUSE_BUTTON_RIGHT) { + } else if (mouseButton == InputConstants.MOUSE_BUTTON_RIGHT) { this@HeightControls.onClick(!isIncrease) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/util/HorizontalStripPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/util/HorizontalStripPanel.kt index 64c81c1fa..fa8b8e496 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/util/HorizontalStripPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/util/HorizontalStripPanel.kt @@ -13,13 +13,13 @@ class HorizontalStripPanel( width: Float = 0f, height: Float = 0f, ) : EditablePanel(screen, parent, x, y, width, height) { - override fun sizeToContents() { + override fun sizeToContents(performLayout: Boolean) { var w = 0f var h = 0f - for (child in children) { + for (child in visibleChildren) { if (child.dock == Dock.NONE) { - w += child.width + child.dockMargin.left + child.dockMargin.right + w += child.width + child.dockMargin.horizontal h = h.coerceAtLeast(child.height) } } @@ -33,19 +33,19 @@ class HorizontalStripPanel( var w = 0f - for (child in children) { + for (child in visibleChildren) { if (child.dock == Dock.NONE) { - w += child.width + child.dockMargin.left + child.dockMargin.right + w += child.width + child.dockMargin.horizontal } } w = width / 2f - w / 2f - for (child in children) { + for (child in visibleChildren) { if (child.dock == Dock.NONE) { child.y = (height / 2f - child.height / 2f).roundToInt().toFloat() child.x = (w + child.dockMargin.left).roundToInt().toFloat() - w += child.dockMargin.left + child.width + child.dockMargin.right + w += child.dockMargin.horizontal + child.width } } } 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 8cfff6a10..2e52a31b3 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 @@ -2,57 +2,64 @@ package ru.dbotthepony.mc.otm.client.screen.storage import net.minecraft.network.chat.Component 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.core.TranslatableComponent import ru.dbotthepony.mc.otm.client.screen.panels.* import ru.dbotthepony.mc.otm.client.screen.panels.button.CheckBoxLabelInputPanel -import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls -import ru.dbotthepony.mc.otm.client.screen.panels.input.TextInputPanel -import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel +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.FilterSlotPanel -import ru.dbotthepony.mc.otm.client.screen.widget.WidePowerGaugePanel +import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel import ru.dbotthepony.mc.otm.menu.storage.StorageBusMenu class StorageBusScreen(menu: StorageBusMenu, inventory: Inventory, title: Component) : MatteryScreen(menu, inventory, title) { override fun makeMainFrame(): FramePanel> { - val frame = super.makeMainFrame()!! + val frame = FramePanel(this, 150f, 126f, title) - 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) + val right = EditablePanel(this, frame, width = AbstractSlotPanel.SIZE * 6f) + right.dock = Dock.RIGHT + val grid = GridPanel(this, right, columns = 6, rows = 3, height = AbstractSlotPanel.SIZE * 3f) + grid.dock = Dock.TOP + grid.dockBottom = 2f - for (row in 0 .. 2) { - for (column in 0 .. 5) { - FilterSlotPanel(this, frame, menu.busFilterSlots[row + column * 3], 55f + 18f * column, 17f + 18f * row) - } + for (slot in menu.busFilterSlots) + FilterSlotPanel(this, grid, slot) + + IntInputPanel(this, right, menu.insertPriority).also { + it.dock = Dock.BOTTOM + it.dockBottom = 2f + it.tooltips.add(TranslatableComponent("otm.gui.insert_priority")) + it.childrenOrder = -1 } - CheckBoxLabelInputPanel(this, frame, menu.busFilterState, TranslatableComponent("otm.gui.filter.is_whitelist"), 59f, 78f, width = 170f) + IntInputPanel(this, right, menu.extractPriority).also { + it.dock = Dock.BOTTOM + it.dockBottom = 2f + it.tooltips.add(TranslatableComponent("otm.gui.extract_priority")) + it.childrenOrder = -2 + } - makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig) + CheckBoxLabelInputPanel(this, right, menu.busFilterState, TranslatableComponent("otm.gui.filter.is_whitelist")).also { + it.dock = Dock.BOTTOM + it.childrenOrder = -3 + } - /*object : TextInputPanel(this@StorageBusScreen, frame) { - init { - allowNumbersAndSign() - dock = Dock.BOTTOM - } + val controls = DeviceControls(this, frame, redstoneConfig = menu.redstoneConfig) + val mode = LargeEnumRectangleButtonPanel(this, frame, prop = menu.mode, defaultValue = FlowDirection.BI_DIRECTIONAL, enum = FlowDirection::class.java) - override fun tickInner() { - super.tickInner() + 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() - if (!hasHierarchicalFocus()) { - text = menu.insertPriority.value.toString() - } - } - - override fun onTextChanged(new: String, old: String) { - if (hasHierarchicalFocus()) { - val i = new.toIntOrNull() - if (i != null) menu.insertPriority.accept(i) - } - } - }*/ + controls.addButton(mode) return frame } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt index db3e843ec..a8fa5095e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt @@ -5,13 +5,8 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.UpgradeType import ru.dbotthepony.mc.otm.config.EnergyBalanceValues import ru.dbotthepony.mc.otm.config.VerboseEnergyBalanceValues -import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.collect.map -import ru.dbotthepony.mc.otm.core.collect.mapToDouble -import ru.dbotthepony.mc.otm.core.collect.mapToInt import ru.dbotthepony.mc.otm.core.collect.reduce -import ru.dbotthepony.mc.otm.core.collect.sum -import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.math.Decimal import kotlin.math.pow @@ -28,9 +23,9 @@ open class UpgradeContainer(slotCount: Int, open val allowedUpgrades: Set a + b } override val processingItems: Int - get() = iterator().mapToInt { it.getCapability(MatteryCapability.UPGRADE).map { it.processingItems }.orElse(0).coerceAtLeast(0) * it.count }.reduce(0) { a, b -> a + b } + get() = iterator().map { it.getCapability(MatteryCapability.UPGRADE).map { it.processingItems }.orElse(0).coerceAtLeast(0) * it.count }.reduce(0) { a, b -> a + b } override val energyStorageFlat: Decimal get() = decimals(IMatteryUpgrade::energyStorageFlat, Decimal::plus) override val energyStorage: Decimal @@ -42,7 +37,7 @@ open class UpgradeContainer(slotCount: Int, open val allowedUpgrades: Set a * b } + get() = iterator().map { it.getCapability(MatteryCapability.UPGRADE).map { it.failureMultiplier }.orElse(1.0).coerceAtLeast(0.0).pow(it.count.toDouble()) }.reduce(1.0) { a, b -> a * b } override val energyThroughputFlat: Decimal get() = decimals(IMatteryUpgrade::energyThroughputFlat, Decimal::plus) override val energyThroughput: Decimal diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/ByteSupplier.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/ByteSupplier.kt new file mode 100644 index 000000000..77714b552 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/ByteSupplier.kt @@ -0,0 +1,5 @@ +package ru.dbotthepony.mc.otm.core + +interface ByteSupplier { + fun getAsByte(): Byte +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/ShortSupplier.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/ShortSupplier.kt new file mode 100644 index 000000000..e8952d63a --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/ShortSupplier.kt @@ -0,0 +1,5 @@ +package ru.dbotthepony.mc.otm.core + +interface ShortSupplier { + fun getAsShort(): Short +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/StreamyIterator.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/StreamyIterators.kt similarity index 76% rename from src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/StreamyIterator.kt rename to src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/StreamyIterators.kt index 4b11f9329..8580dbb75 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/StreamyIterator.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/StreamyIterators.kt @@ -21,7 +21,7 @@ import java.util.stream.Collector * * Resulting [Iterator] is [MutableIterator] if [parent] is */ -class FilteredIterator(private val parent: Iterator, private val predicate: Predicate) : MutableIterator { +class FilteringIterator(private val parent: Iterator, private val predicate: Predicate) : MutableIterator { private var foundValue: Any? = Companion override fun hasNext(): Boolean { @@ -124,18 +124,6 @@ class FlatMappingIterator(private val parent: Iterator, private val map } } -fun concatIterators(): MutableIterator { - return ObjectIterators.EMPTY_ITERATOR as MutableIterator -} - -fun concatIterators(a: Iterator): MutableIterator { - return a as MutableIterator -} - -fun concatIterators(vararg iterators: Iterator): MutableIterator { - return iterators.iterator().flatMap { it } -} - /** * Limits amount of values returned by [parent] iterator to return at most [limit] values * @@ -201,12 +189,24 @@ class SkippingIterator(private val parent: Iterator, skip: Long) : Mutable } } +fun concatIterators(): MutableIterator { + return ObjectIterators.EMPTY_ITERATOR as MutableIterator +} + +fun concatIterators(a: Iterator): MutableIterator { + return a as MutableIterator +} + +fun concatIterators(vararg iterators: Iterator): MutableIterator { + return iterators.iterator().flatMap { it } +} + /** * Filters elements of [this] iterator * * Resulting [Iterator] is [MutableIterator] if [this] is */ -fun Iterator.filter(condition: Predicate) = FilteredIterator(this, condition) +fun Iterator.filter(condition: Predicate) = FilteringIterator(this, condition) /** * Maps elements of [this] iterator from values of [T] to [R] using function [mapper] @@ -236,92 +236,16 @@ fun Iterator.flatMap(mapper: (T) -> Iterator) = FlatMappingIterator */ fun Iterator.flatMap(mapper: java.util.function.Function>) = FlatMappingIterator(this, mapper::apply) -fun interface O2DFunction { - fun apply(value: T): Double -} - -fun interface O2IFunction { - fun apply(value: T): Int -} - -fun Iterator.mapToDouble(mapper: O2DFunction): it.unimi.dsi.fastutil.doubles.DoubleIterator { - return object : it.unimi.dsi.fastutil.doubles.DoubleIterator { - override fun hasNext(): Boolean { - return this@mapToDouble.hasNext() - } - - override fun remove() { - (this@mapToDouble as MutableIterator).remove() - } - - override fun nextDouble(): Double { - return mapper.apply(this@mapToDouble.next()) - } - } -} - -fun Iterator.mapToInt(mapper: O2IFunction): it.unimi.dsi.fastutil.ints.IntIterator { - return object : it.unimi.dsi.fastutil.ints.IntIterator { - override fun hasNext(): Boolean { - return this@mapToInt.hasNext() - } - - override fun remove() { - (this@mapToInt as MutableIterator).remove() - } - - override fun nextInt(): Int { - return mapper.apply(this@mapToInt.next()) - } - } -} - -fun it.unimi.dsi.fastutil.doubles.DoubleIterator.sum(): Double { - var value = 0.0 - while (hasNext()) value += nextDouble() - return value -} - -fun it.unimi.dsi.fastutil.ints.IntIterator.sum(): Int { - var value = 0 - while (hasNext()) value += nextInt() - return value -} - -fun interface DD2DFunction { - fun apply(a: Double, b: Double): Double -} - -fun interface II2IFunction { - fun apply(a: Int, b: Int): Int -} - -fun it.unimi.dsi.fastutil.doubles.DoubleIterator.reduce(identity: Double, reducer: DD2DFunction): Double { - var result = identity - while (hasNext()) result = reducer.apply(result, nextDouble()) - return result -} - -fun it.unimi.dsi.fastutil.ints.IntIterator.reduce(identity: Int, reducer: II2IFunction): Int { - var result = identity - while (hasNext()) result = reducer.apply(result, nextInt()) - return result -} - fun Iterator.reduce(identity: T, reducer: (T, T) -> T): T { var result = identity - - for (value in this) { - result = reducer.invoke(result, value) - } - + for (value in this) result = reducer.invoke(result, value) return result } fun Iterator.reduce(identity: T, reducer: BinaryOperator): T = reduce(identity, reducer::apply) fun Iterator.filterNotNull(): Iterator = filter { it != null } as Iterator -fun Iterator.anyMatch(predicate: Predicate): Boolean { +fun Iterator.any(predicate: Predicate): Boolean { for (value in this) { if (predicate.test(value)) { return true @@ -331,7 +255,7 @@ fun Iterator.anyMatch(predicate: Predicate): Boolean { return false } -fun Iterator.allMatch(predicate: Predicate): Boolean { +fun Iterator.all(predicate: Predicate): Boolean { for (value in this) { if (!predicate.test(value)) { return false @@ -341,7 +265,7 @@ fun Iterator.allMatch(predicate: Predicate): Boolean { return true } -fun Iterator.noneMatch(predicate: Predicate): Boolean { +fun Iterator.none(predicate: Predicate): Boolean { for (value in this) { if (predicate.test(value)) { return false @@ -368,7 +292,7 @@ fun Iterator.toList(): MutableList { return result } -fun Iterator.findFirst(): Optional { +fun Iterator.find(): Optional { if (hasNext()) { return Optional.of(next()) } @@ -376,7 +300,6 @@ fun Iterator.findFirst(): Optional { return Optional.empty() } -fun Iterator.findAny() = findFirst() fun Iterator.limit(limit: Long) = LimitingIterator(this, limit) fun Iterator.skip(skip: Long) = if (skip == 0L) this else SkippingIterator(this, skip) @@ -418,8 +341,8 @@ fun Iterator.max(comparator: Comparator): Optional { return Optional.of(max) } -fun Iterator.peek(peeker: (T) -> Unit): Iterator { - return object : Iterator { +fun Iterator.peek(peeker: (T) -> Unit): MutableIterator { + return object : MutableIterator { override fun hasNext(): Boolean { return this@peek.hasNext() } @@ -427,5 +350,16 @@ fun Iterator.peek(peeker: (T) -> Unit): Iterator { override fun next(): T { return this@peek.next().also(peeker) } + + override fun remove() { + (this@peek as MutableIterator).remove() + } } } + +fun Iterator.maybe(): T? { + return if (hasNext()) + next() + else + null +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/input/EnumInputWithFeedback.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/input/EnumInputWithFeedback.kt index 4c5877a1a..8d26f352e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/input/EnumInputWithFeedback.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/input/EnumInputWithFeedback.kt @@ -5,40 +5,40 @@ import ru.dbotthepony.mc.otm.core.util.EnumValueCodec import ru.dbotthepony.mc.otm.menu.MatteryMenu import kotlin.reflect.KMutableProperty0 -inline fun > EnumInputWithFeedback(menu: MatteryMenu) = EnumInputWithFeedback(menu, E::class.java) -inline fun > EnumInputWithFeedback(menu: MatteryMenu, state: KMutableProperty0?) = EnumInputWithFeedback(menu, E::class.java, state) -inline fun > EnumInputWithFeedback(menu: MatteryMenu, state: GetterSetter) = EnumInputWithFeedback(menu, E::class.java, state) +inline fun > EnumInputWithFeedback(menu: MatteryMenu, allowedValues: Set? = null) = EnumInputWithFeedback(menu, E::class.java, allowedValues = allowedValues) +inline fun > EnumInputWithFeedback(menu: MatteryMenu, state: KMutableProperty0?, allowedValues: Set? = null) = EnumInputWithFeedback(menu, E::class.java, state, allowedValues = allowedValues) +inline fun > EnumInputWithFeedback(menu: MatteryMenu, state: GetterSetter?, allowedValues: Set? = null) = EnumInputWithFeedback(menu, E::class.java, state, allowedValues = allowedValues) -inline fun > EnumInputWithFeedback(menu: MatteryMenu, allowSpectators: Boolean) = EnumInputWithFeedback(menu, E::class.java, allowSpectators) -inline fun > EnumInputWithFeedback(menu: MatteryMenu, allowSpectators: Boolean, state: KMutableProperty0?) = EnumInputWithFeedback(menu, E::class.java, allowSpectators, state) -inline fun > EnumInputWithFeedback(menu: MatteryMenu, allowSpectators: Boolean, state: GetterSetter) = EnumInputWithFeedback(menu, E::class.java, allowSpectators, state) +inline fun > EnumInputWithFeedback(menu: MatteryMenu, allowSpectators: Boolean, allowedValues: Set? = null) = EnumInputWithFeedback(menu, E::class.java, allowSpectators, allowedValues = allowedValues) +inline fun > EnumInputWithFeedback(menu: MatteryMenu, allowSpectators: Boolean, state: KMutableProperty0?, allowedValues: Set? = null) = EnumInputWithFeedback(menu, E::class.java, allowSpectators, state, allowedValues = allowedValues) +inline fun > EnumInputWithFeedback(menu: MatteryMenu, allowSpectators: Boolean, state: GetterSetter?, allowedValues: Set? = null) = EnumInputWithFeedback(menu, E::class.java, allowSpectators, state, allowedValues = allowedValues) -class EnumInputWithFeedback>(menu: MatteryMenu, clazz: Class, allowSpectators: Boolean = false) : AbstractPlayerInputWithFeedback() { +class EnumInputWithFeedback>(menu: MatteryMenu, clazz: Class, allowSpectators: Boolean = false, val allowedValues: Set? = null) : AbstractPlayerInputWithFeedback() { val codec = EnumValueCodec(clazz) private val default = codec.values.first() - override val input = menu.PlayerInput(codec, allowSpectators) { consumer?.invoke(it) } + override val input = menu.PlayerInput(codec, allowSpectators) { if (allowedValues == null || it in allowedValues) consumer?.invoke(it) } override val field = menu.mSynchronizer.ComputedField(getter = { supplier?.invoke() ?: default }, codec) - constructor(menu: MatteryMenu, clazz: Class, state: KMutableProperty0?) : this(menu, clazz) { + constructor(menu: MatteryMenu, clazz: Class, state: KMutableProperty0?, allowedValues: Set? = null) : this(menu, clazz, allowedValues = allowedValues) { if (state != null) { with(state) } } - constructor(menu: MatteryMenu, clazz: Class, state: GetterSetter?) : this(menu, clazz) { + constructor(menu: MatteryMenu, clazz: Class, state: GetterSetter?, allowedValues: Set? = null) : this(menu, clazz, allowedValues = allowedValues) { if (state != null) { with(state) } } - constructor(menu: MatteryMenu, clazz: Class, allowSpectators: Boolean, state: KMutableProperty0?) : this(menu, clazz, allowSpectators) { + constructor(menu: MatteryMenu, clazz: Class, allowSpectators: Boolean, state: KMutableProperty0?, allowedValues: Set? = null) : this(menu, clazz, allowSpectators, allowedValues = allowedValues) { if (state != null) { with(state) } } - constructor(menu: MatteryMenu, clazz: Class, allowSpectators: Boolean, state: GetterSetter?) : this(menu, clazz, allowSpectators) { + constructor(menu: MatteryMenu, clazz: Class, allowSpectators: Boolean, state: GetterSetter?, allowedValues: Set? = null) : this(menu, clazz, allowSpectators, allowedValues = allowedValues) { if (state != null) { with(state) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/ItemMonitorMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/ItemMonitorMenu.kt index 373f7390e..3cebf19d1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/ItemMonitorMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/ItemMonitorMenu.kt @@ -10,7 +10,7 @@ import ru.dbotthepony.mc.otm.block.entity.storage.IItemMonitorPlayerSettings import ru.dbotthepony.mc.otm.block.entity.storage.ItemMonitorBlockEntity import ru.dbotthepony.mc.otm.block.entity.storage.ItemMonitorPlayerSettings import ru.dbotthepony.mc.otm.container.get -import ru.dbotthepony.mc.otm.core.collect.mapToInt +import ru.dbotthepony.mc.otm.core.collect.map import ru.dbotthepony.mc.otm.core.collect.reduce import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu @@ -206,7 +206,7 @@ class ItemMonitorMenu( return ItemStack.EMPTY } } else { - if (crafted > 0 && crafted >= tile.craftingGrid.iterator().mapToInt { it.maxStackSize }.reduce(Int.MAX_VALUE, Int::coerceAtMost)) { + if (crafted > 0 && crafted >= tile.craftingGrid.iterator().map { it.maxStackSize }.reduce(Int.MAX_VALUE, Int::coerceAtMost)) { return ItemStack.EMPTY } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/StorageBusMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/StorageBusMenu.kt index e35fa3867..f4efb96b0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/StorageBusMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/StorageBusMenu.kt @@ -2,33 +2,32 @@ package ru.dbotthepony.mc.otm.menu.storage import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.block.entity.storage.StorageBusBlockEntity +import ru.dbotthepony.mc.otm.capability.FlowDirection import ru.dbotthepony.mc.otm.container.ItemFilterNetworkSlot import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback +import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.IntInputWithFeedback +import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.registry.MMenus -class StorageBusMenu @JvmOverloads constructor( +class StorageBusMenu( containerId: Int, inventory: Inventory, tile: StorageBusBlockEntity? = null ) : MatteryPoweredMenu(MMenus.STORAGE_BUS, containerId, inventory, tile) { val busFilterSlots: List - val busFilterState: BooleanInputWithFeedback - val insertPriority: IntInputWithFeedback - val extractPriority: IntInputWithFeedback + val busFilterState = BooleanInputWithFeedback(this, tile?.let { it.filter::isWhitelist }) + val insertPriority = IntInputWithFeedback(this, tile?.let { it::insertPriority }) + val extractPriority = IntInputWithFeedback(this, tile?.let { it::extractPriority }) + val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget) + val mode = EnumInputWithFeedback(this, tile?.let { it::mode }, FlowDirection.WITHOUT_NONE) init { if (tile != null) { busFilterSlots = addFilterSlots(tile.filter) - busFilterState = BooleanInputWithFeedback(this, tile.filter::isWhitelist) - insertPriority = IntInputWithFeedback(this, tile::insertPriority) - extractPriority = IntInputWithFeedback(this, tile::extractPriority) } else { busFilterSlots = addFilterSlots(StorageBusBlockEntity.MAX_FILTERS) - busFilterState = BooleanInputWithFeedback(this) - insertPriority = IntInputWithFeedback(this) - extractPriority = IntInputWithFeedback(this) } addStorageSlot(batterySlot) diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/storage_controls.png b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/storage_controls.png index 5955c8eff8e2a38ed3a539a9918b665f847bfee1..d12fd2d82aeeed5f03e5e0b35b1ae681c3cb7ba2 100644 GIT binary patch delta 972 zcmV;-12g>32Gs|U7k@Sg1^@s6N1l!&0004nX+uL$Nkc;*aB^>EX>4Tx04R}tkv&Mm zKp2MKri!JsIM_kNAxL$yi;6gwDi*;)X)CnqU~=gnG-*guTpR`0f`dPcRRY3ZEzi6g8cDa7Z*lLlRo z_>t?f%Ws^^4huXpV&pRO#1Ue#+{1DYvx=b-&k#oyRik_%@3O*qi?dp5u+BaC3qwV1 zCChc1qex;2DSxCPLPi5s)Lo3{OZY}@Sg;(sB85bAY75CqvP#`we-pRd^YSGiT4RXPUfNsy(m(b4lg}e>30tN*5?-F{QjvEM@CxfxYQm$ z)1zAesAp+9vGsu5up#O6{Jy1QmPd1L$T^48=zkG!9`$H?9`(f0wx~i!>&Clf4I_|E zLPslpa);>bSa02q9F}AxNTw5A}gDX7zHv?W!oolkpoUT7ZypYNh@K-SLV*wH#wPo4|Q8a}tC zO@Ftaq?I}YptFc})Bb&?L4IvMT+u@?U5HMP;;S2UQ$Kg-y! z+2pO+;qJ0n*6X3p$mV|UfzWoc9!~EdS^UNl9D*PSf~@n$x9t3@95Z#klN$9jAM?$LepB7!5(tj`{)j{VM{B6#yLo0000EX>4Tx04R}tkv&Mm zP!xqvQ>7v;9qb??n4vmZ5EXHhDi*;)X)CnqVDi#GXws0RxHt-~1qXi?s}3&Cx;nTD zg5VE`tBaGOi(b z_>t?f%Ws@Z4huXpVr0|v#1Ue#)Wvcav$CNQPZLKKRik_%=d!|ii?dp-vv!~Sg~5Wh zlHoelFcMfo5`QU(kWohkRal78u90FQP3LhB|B&NPkxM351&kaEs6mC~_`(0+_iWAL z)TEmfj03$dw*4^*1a^T|!?wSVZM$^>_@99*t>dpXf!R;e8yzir1cbMNi|dXi?*W%P zz~GZE8ImLUsf1z?ct4|W$^!$pK>wOMxAr+sAAl^)YJd3#I5-5xN|e3s@$SCvx&3>m zJ-;6`5^|0*NWB37000JJOGiWi000000Qp0^e*gdg32;bRa{vGf6951U69E94oEQKA z00(qQO+^Ri0}TTg8~^{%v;Y7BOi4sRRA}DqnqdyZAP9xqrpMy=+^hR#Vu%_*aCUoN zvZPro$bS>a)Ex%^0K~)04>Lcz*m*10s>NzOL+B)ttzwrdh+G_LtM*~_Wl5lGg~&v7 zmhZ~5HXtH8iRdijr63l8nE9z~)%MFLON)D@$aQc<98Yla9gU6JSMe|3)6S=t$)lL> z%#0pQT4vVFB8~#owk*q{*M3{is*Kh+)Qr(g+J9TBo{W~`WF}^|jc!Jd9RJ#{29L-g ztz*!ar(lSf;vmez4v`S{lvq`l@MOZ}Xi8H#&8rh7pvvo#C zRz5|qN;2$Zoa{v%NujdPKt%PlK4TFsTp0?an4BDcXZh> zs>?&4>$3S-UAFw9%eJe!e0WorN6d4&W^%3+i8gBsu7vLeE5WsVu#^uL!ppkGmRuU9 z8W5L5f*vLR+#GT&8HjRrQ)_q>;xUIm;_!72pLh6-!)F~n=kN{S`92Q23zP!!-R%FU z;ZZ1ELLz~GoN~ikNF8RQQu1z>c-1%iXTL~sQ>uzJ8RdMZN>7QHUoYZ*RwVs8@Tq&e+k6_t4!E&&& z4c65JXO6oIR4JU>*+D5KZEcW4;;?^ryr++GJJr950I;XEWYpo z3dKM&!QHTp_5|kE?O;~^nyXe#P(F$A&`VYdJl+u?<{B|g(zlzX7l)i4|gfeWt zgYJtj-gh1EfFI$QEg_U>G`Ot;jI;2#X^8gVZNG+>4KD^a;dHMDKLsn{#qd(F#MP)K zh%#)w7l<-Wby7xcJ4Rpw1mkTpFE|aY4x-GfR(?t(RCpi}3nT#51j-HJBP!6rLZ+;g zB8z&$m!gKP{5Qpee_l$@*{730OhT-}`QhWqHHM3T5F6bki*HRt?T*oHHD0Fx0gxQ0 zrL5_=sW%6NS#T?u2e=l)xnQaKAjZx7ULeM2os|2)saRVWh~>VI&_R^DW#y-YL?|g0 z%m|u#>FbaRD3*t4LJpDcZaP0{#SwO&O<+Afa8IER~gJf(TqDn%1-6`a(x>{h_jN(N0$zeVWS zb{=+X&)*dOq}WG&;v}OE-v(uvyTYP!fS9|g zXaH_gm9_J5miOeQkdrj4i_&_#gX6v_e3#m4LZTgQrAXv+PHH*fRIC*Y5?cl$bP%=7 zTKS+ky}aa{Vg|(?r7G}852~DI*LEEA8He?1;D!W&`%?HmVk(C13)QzWJX@QrII@sPK=H z0glejhU?p?*LMjK^CC8csyvQy%$2UHSuu9O)P7BuDz|npZQ6qf9iO>v<)`sG^Kii8 zbu4aZv1j-=(I~IaXt)N8takw3)JojkQireuFd(<-qMcq5~i>mA> z>PnPXN|>4=jmDTlA*QDGCtgaq)K61cyAplf!FR!r;bnxe`wMq=$t%TO+;*VL&M%$1 zwU5DFr*iT}Z*{14ZuvjLB??Fxb$-`iOF1AUAkF_;+~{yO2-wDajk~Jrs0=_BOqd#g Uroo1(ZGn)0+;;7WsmXrvH-lyp`~Uy| delta 410 zcmexjJ70H#sFVr=1WW@`fHP6R^gIiVFHRwz9=|h@)<6FCZ;o!A23NVF};}FARxxX z%&<9-TbGH6RUa(M>J1iUP2RkPcO4TGhcH-_Lmw>4;l6o>fCLj0S0Y%Hs}>~6$u$*X zAH!rv;We9Q3NK`2;(0x}fmfQ59juF2esh6n3L_I=D_9rbLa->`&dprn3mBOMqQRm9 zw!#{S6eL^z(||9>V1mjCPwfB!T52de$gHu