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 980212cbc..9c54129d6 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 @@ -806,6 +806,7 @@ private fun gui(provider: MatteryLanguageProvider) { gui("balance_inputs", "Balance input slots") gui("sorting.sort_now", "Sort") + gui("sorting.sort_settings", "Right click to show settings") gui("sorting.default", "Default sorting") gui("sorting.name", "Sort by name") gui("sorting.id", "Sort by ID") 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 f9711bcfb..f786f55dd 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 @@ -806,6 +806,7 @@ private fun gui(provider: MatteryLanguageProvider) { gui("balance_inputs", "Балансировать входные слоты") gui("sorting.sort_now", "Отсортировать") + gui("sorting.sort_settings", "Нажмите правую кнопку мыши для настроек") gui("sorting.default", "Сортировка по умолчанию") gui("sorting.name", "Сортировка по имени") gui("sorting.id", "Сортировка по ID") diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterPanelBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterPanelBlockEntity.kt index 1c2bcda70..ae73612fd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterPanelBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterPanelBlockEntity.kt @@ -23,35 +23,24 @@ import ru.dbotthepony.mc.otm.core.nbt.mapString import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.util.ItemSorter import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode +import ru.dbotthepony.mc.otm.menu.IItemSortingSettings import ru.dbotthepony.mc.otm.registry.MBlockEntities import java.util.* import java.util.stream.Stream class MatterPanelBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.MATTER_PANEL, blockPos, blockState), IReplicationTaskProvider { - inner class PlayerSettings : INBTSerializable { - var sorter: ItemSorter = ItemSorter.DEFAULT + inner class PlayerSettings : IItemSortingSettings { + override var sorting: ItemSorter = ItemSorter.DEFAULT set(value) { field = value markDirtyFast() } - var ascending: Boolean = true + override var isAscending: Boolean = true set(value) { field = value markDirtyFast() } - - override fun serializeNBT(): CompoundTag { - return CompoundTag().also { - it["sorter"] = sorter.name - it["ascending"] = ascending - } - } - - override fun deserializeNBT(nbt: CompoundTag) { - sorter = nbt.mapString("sorter", ItemSorter::valueOf, ItemSorter.DEFAULT) - ascending = nbt.getBoolean("ascending", true) - } } var isProvidingTasks = true diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt index 423738677..157a5b1ea 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayerCapability.kt @@ -98,6 +98,7 @@ import ru.dbotthepony.mc.otm.core.nbt.getIntList import ru.dbotthepony.mc.otm.core.nbt.getStringList import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.util.IntValueCodec +import ru.dbotthepony.mc.otm.core.util.ItemStackSorter import ru.dbotthepony.mc.otm.core.util.ItemValueCodec import ru.dbotthepony.mc.otm.core.util.RGBCodec import ru.dbotthepony.mc.otm.core.util.Savetables @@ -105,6 +106,7 @@ import ru.dbotthepony.mc.otm.core.util.TickList import ru.dbotthepony.mc.otm.core.util.UUIDValueCodec import ru.dbotthepony.mc.otm.core.util.VarIntValueCodec import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu +import ru.dbotthepony.mc.otm.menu.IItemStackSortingSettings import ru.dbotthepony.mc.otm.network.* import ru.dbotthepony.mc.otm.network.SmokeParticlesPacket.Companion.makeSmoke import ru.dbotthepony.mc.otm.network.synchronizer.FieldSynchronizer @@ -402,6 +404,11 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial return _exoPackMenu!! } + val sortingSettings = object : IItemStackSortingSettings { + override var isAscending: Boolean = true + override var sorting: ItemStackSorter = ItemStackSorter.DEFAULT + } + fun recreateExoPackMenu() { _exoPackMenu = ExopackInventoryMenu(this) } @@ -591,6 +598,8 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial savetables.codecNullable(::exopackColor, RGBAColor.CODECRGB) savetables.bool(::exopackGlows) + + savetables.stateful(::sortingSettings) } fun invalidateNetworkState() { 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 60849bf3a..8999e8f91 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 @@ -38,8 +38,8 @@ object Widgets18 { val BUTTON_DISABLED = buttonGrids.next() private val storageGrid = WidgetLocation.STORAGE_CONTROLS.grid(rows = 4, columns = 5) - val ARROW_DOWN = storageGrid.next() - val ARROW_UP = storageGrid.next() + val SORT_DESCENDING = storageGrid.next() + val SORT_ASCENDING = storageGrid.next() val SORT_DEFAULT = storageGrid.next() val SORT_ALPHABET = storageGrid.next() val SORT_COUNT = storageGrid.next() 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 df07050f1..ef2495a9f 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 @@ -308,12 +308,7 @@ abstract class MatteryScreen(menu: T, inventory: Inventory, tit } if (menu.sortInventoryInput != null) { - deviceControls.addButton(LargeRectangleButtonPanel.input( - this, - deviceControls, - menu.sortInventoryInput!!, - icon = Widgets18.SORT_NOW - ).also { it.tooltips.add(TranslatableComponent("otm.gui.sorting.sort_now")) }) + deviceControls.customSortingButtons(menu.playerSortSettings, menu.sortInventoryInput!!) } if (menu.exopackChargeSlots.isNotEmpty()) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/CargoCrateScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/CargoCrateScreen.kt index 99d4e560d..55967a4c6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/CargoCrateScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/CargoCrateScreen.kt @@ -28,7 +28,7 @@ class CargoCrateScreen(menu: CargoCrateMenu, inventory: Inventory, title: Compon val controls = DeviceControls(this, frame) - controls.addButton(LargeRectangleButtonPanel.input(this, frame, menu.sort, icon = Widgets18.SORT_NOW).also { it.tooltips.add(TranslatableComponent("otm.gui.sorting.sort_now")) }) + controls.customSortingButtons(menu.playerSortSettings, menu.sort) return frame } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/MinecartCargoCrateScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/MinecartCargoCrateScreen.kt index c274f233a..30b8af8cd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/MinecartCargoCrateScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/MinecartCargoCrateScreen.kt @@ -4,6 +4,7 @@ import net.minecraft.network.chat.Component import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.client.screen.MatteryScreen 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.util.GridPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel import ru.dbotthepony.mc.otm.menu.decorative.MinecartCargoCrateMenu @@ -20,6 +21,10 @@ class MinecartCargoCrateScreen(menu: MinecartCargoCrateMenu, inventory: Inventor for (slot in menu.storageSlots) SlotPanel(this, grid, slot) + val controls = DeviceControls(this, frame) + + controls.customSortingButtons(menu.playerSortSettings, menu.sort) + return frame } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/matter/MatterPanelScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/matter/MatterPanelScreen.kt index 334ab37ff..ee098227c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/matter/MatterPanelScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/matter/MatterPanelScreen.kt @@ -55,7 +55,7 @@ class MatterPanelScreen( val controls = DeviceControls(this, frame) - controls.sortingButtons(menu::isAscending.asGetterSetter(), menu::sorting.asGetterSetter(), ItemSorter.DEFAULT) { + controls.sortingButtons(menu.settings::isAscending.asGetterSetter(), menu.settings::sorting.asGetterSetter(), ItemSorter.DEFAULT) { for (v in ItemSorter.entries) { add(v, skinElement = v.icon, tooltip = v.title) } 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 c09da8d5c..3742af760 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 @@ -140,7 +140,7 @@ open class EditablePanel @JvmOverloads constructor( } /** - * Bigger values means lesser priority while docking + * Bigger values means lesser priority while docking, rendering and processing inputs. */ var childrenOrder = 0 set(value) { @@ -881,7 +881,7 @@ open class EditablePanel @JvmOverloads constructor( poseStack.popPose() } - for (child in visibleChildrenInternal) { + for (child in visibleChildrenInternal.asReversed()) { child.absoluteX = absoluteX + child.x + xOffset child.absoluteY = absoluteY + child.y + yOffset 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 853c876a1..4abe11ac9 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 @@ -27,9 +27,13 @@ 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.asGetterSetter import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.math.RelativeSide +import ru.dbotthepony.mc.otm.core.util.ItemStackSorter import ru.dbotthepony.mc.otm.core.value +import ru.dbotthepony.mc.otm.menu.IItemStackSortingSettings +import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.UpgradeSlots import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput @@ -314,33 +318,61 @@ class DeviceControls>( val balanceInputsButton: LargeBooleanRectangleButtonPanel? val upgradesButton: LargeRectangleButtonPanel? + init { + childrenOrder = -1000 + } + private var upgradeWindow: FramePanel? = null - private var nextY = 0f + + private val buttons = ArrayList>() + + fun alignButtons() { + buttons.removeIf { it.isRemoved || it.parent != this } + + var y = 0f + + for (button in buttons) { + button.setPos(button.dockLeft, y + button.dockTop) + y += button.height + button.dockMargin.vertical + 2f + width = width.coerceAtLeast(button.width + button.dockMargin.horizontal) + } + + height = height.coerceAtLeast(y - 2f) + } + + fun removeButton(button: EditablePanel<*>) { + buttons.remove(button) + alignButtons() + } fun

> addButton(button: P): P { + buttons.add(button) button.parent = this - button.x = 0f - button.y = nextY - nextY += button.height + 2f - height = nextY - 2f - width = button.width.coerceAtLeast(width) + alignButtons() + return button + } + + fun

> addButton(button: P, after: EditablePanel<*>): P { + val index = buttons.indexOf(after) + if (index == -1) throw NoSuchElementException("Unknown panel to add button after: $after") + buttons.add(index + 1, button) + button.parent = this + alignButtons() return button } fun

> prependButton(button: P): P { - for (child in children) { - child.y += button.height + 2f - } - + buttons.add(0, button) button.parent = this - button.x = 0f - button.y = 0f - nextY += button.height + 2f - height = nextY - 2f - width = button.width.coerceAtLeast(width) + alignButtons() return button } + override fun performLayout() { + super.performLayout() + alignButtons() + } + fun addStorageMode(prop: GetterSetter) { val mode = LargeEnumRectangleButtonPanel(screen, this, prop = prop, defaultValue = FlowDirection.BI_DIRECTIONAL, enum = FlowDirection::class.java) @@ -352,24 +384,74 @@ class DeviceControls>( addButton(mode) } - inline fun > sortingButtons(ascending: GetterSetter, sorting: GetterSetter, default: T, configurator: LargeEnumRectangleButtonPanel.() -> Unit) { + inline fun > sortingButtons(ascending: GetterSetter, sorting: GetterSetter, default: T, configurator: LargeEnumRectangleButtonPanel.() -> Unit): List> { + val result = ArrayList>() + LargeBooleanRectangleButtonPanel( screen, this, prop = ascending, - iconActive = Widgets18.ARROW_UP, - iconInactive = Widgets18.ARROW_DOWN, + iconActive = Widgets18.SORT_ASCENDING, + iconInactive = Widgets18.SORT_DESCENDING, tooltipActive = TranslatableComponent("otm.gui.sorting.ascending"), tooltipInactive = TranslatableComponent("otm.gui.sorting.descending"), ).also { prependButton(it) + result.add(it) } LargeEnumRectangleButtonPanel(screen, this, enum = T::class.java, prop = sorting, defaultValue = default).also { prependButton(it) configurator.invoke(it) it.finish() + result.add(it) } + + return result + } + + fun customSortingButtons(settings: IItemStackSortingSettings, input: MatteryMenu.PlayerInput) { + addButton(object : LargeRectangleButtonPanel(screen, this@DeviceControls) { + var buttons: List>? = null + + init { + tooltips.add(TranslatableComponent("otm.gui.sorting.sort_now")) + tooltips.add(TextComponent("")) + tooltips.add(TranslatableComponent("otm.gui.sorting.sort_settings").withStyle(ChatFormatting.GRAY)) + + icon = Widgets18.SORT_NOW + } + + override fun test(value: Int): Boolean { + return value == InputConstants.MOUSE_BUTTON_LEFT || value == InputConstants.MOUSE_BUTTON_RIGHT + } + + override var isDisabled: Boolean + get() = !input.test(minecraft.player) + set(value) {} + + override fun onClick(mouseButton: Int) { + if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) { + input.accept(null) + } else { + if (buttons == null) { + buttons = sortingButtons(settings::isAscending.asGetterSetter(), settings::sorting.asGetterSetter(), ItemStackSorter.DEFAULT) { + for (v in ItemStackSorter.entries) { + add(v, v.icon, v.title) + } + + finish() + } + + buttons!!.forEach { removeButton(it) } + buttons!!.forEach { addButton(it as EditablePanel, this) } + } else { + buttons!!.forEach { it.remove() } + buttons = null + } + } + } + }) } init { @@ -492,7 +574,7 @@ class DeviceControls>( } if (energyConfig != null) { - energyConfigButton = addButton(object : LargeRectangleButtonPanel(screen, this@DeviceControls, y = nextY, icon = Widgets18.ENERGY_CONFIGURATION) { + energyConfigButton = addButton(object : LargeRectangleButtonPanel(screen, this@DeviceControls, icon = Widgets18.ENERGY_CONFIGURATION) { init { tooltips.add(TranslatableComponent("otm.gui.sides.energy_config")) } @@ -511,7 +593,7 @@ class DeviceControls>( } if (fluidConfig != null) { - fluidConfigButton = addButton(object : LargeRectangleButtonPanel(screen, this@DeviceControls, y = nextY, icon = Widgets18.FLUID_CONFIGURATION) { + fluidConfigButton = addButton(object : LargeRectangleButtonPanel(screen, this@DeviceControls, icon = Widgets18.FLUID_CONFIGURATION) { init { tooltips.add(TranslatableComponent("otm.gui.sides.fluid_config")) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerHelpers.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerHelpers.kt index 9a2a0e79e..627492193 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerHelpers.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerHelpers.kt @@ -8,6 +8,7 @@ import it.unimi.dsi.fastutil.ints.IntIterator import it.unimi.dsi.fastutil.ints.IntSet import it.unimi.dsi.fastutil.objects.Object2ObjectFunction import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap +import it.unimi.dsi.fastutil.objects.ObjectArrayList import net.minecraft.world.Container import net.minecraft.world.inventory.CraftingContainer import net.minecraft.world.item.ItemStack @@ -18,6 +19,8 @@ import ru.dbotthepony.mc.otm.container.util.ItemStackHashStrategy import ru.dbotthepony.mc.otm.container.util.slotIterator import ru.dbotthepony.mc.otm.core.addAll import ru.dbotthepony.mc.otm.core.collect.filter +import ru.dbotthepony.mc.otm.core.collect.map +import ru.dbotthepony.mc.otm.core.collect.max import ru.dbotthepony.mc.otm.core.collect.toList import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.map @@ -288,19 +291,6 @@ operator fun CraftingContainer.get(column: Int, row: Int, flop: Boolean): ItemSt get(column, row) } -private object FilteredFirst : Comparator { - override fun compare(o1: IContainerSlot, o2: IContainerSlot): Int { - if (o1.hasFilter && o2.hasFilter) - return 0 - else if (o2.hasFilter) - return -1 - else if (o1.hasFilter) - return 1 - else - return 0 - } -} - fun Container.sort(comparator: Comparator = ItemStackSorter.DEFAULT) { if (isEmpty) return @@ -310,8 +300,21 @@ fun Container.sort(comparator: Comparator = ItemStackSorter.DEFAULT) if (slots.isEmpty()) return - slots.sortWith(FilteredFirst.thenComparing(comparator.map(IContainerSlot::item))) - val items = slots.map { it.item.copy() } + val items = Object2ObjectOpenCustomHashMap(ItemStackHashStrategy) + + slots.forEach { + val get = items[it.item] + + if (get == null) { + items[it.item] = it.item.copy() + } else { + get.count += it.item.count + } + } + + val sortedItems = ObjectArrayList(items.values) + sortedItems.sortWith(comparator) + slots.forEach { it.remove() } - items.forEach { addItem(it, false) } + sortedItems.forEach { addItem(it, false) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ISortingSettings.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ISortingSettings.kt new file mode 100644 index 000000000..fa9a9552d --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ISortingSettings.kt @@ -0,0 +1,114 @@ +package ru.dbotthepony.mc.otm.menu + +import net.minecraft.nbt.CompoundTag +import net.minecraft.world.item.Item +import net.minecraft.world.item.ItemStack +import net.minecraftforge.common.util.INBTSerializable +import ru.dbotthepony.mc.otm.core.nbt.getBoolean +import ru.dbotthepony.mc.otm.core.nbt.mapString +import ru.dbotthepony.mc.otm.core.nbt.set +import ru.dbotthepony.mc.otm.core.util.ItemSorter +import ru.dbotthepony.mc.otm.core.util.ItemStackSorter +import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback +import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback + +interface IBaseSortingSettings : INBTSerializable { + var isAscending: Boolean + + override fun serializeNBT(): CompoundTag { + return CompoundTag().also { + it["isAscending"] = isAscending + } + } + + override fun deserializeNBT(nbt: CompoundTag?) { + nbt ?: return + isAscending = nbt.getBoolean("isAscending", true) + } +} + +interface IItemStackSortingSettings : IBaseSortingSettings { + var sorting: ItemStackSorter + + override fun serializeNBT(): CompoundTag { + return super.serializeNBT().also { + it["sorting"] = sorting.name + } + } + + override fun deserializeNBT(nbt: CompoundTag?) { + nbt ?: return + super.deserializeNBT(nbt) + sorting = nbt.mapString("sorting", ItemStackSorter::valueOf, ItemStackSorter.DEFAULT) + } + + val actualComparator: Comparator get() { + if (isAscending) { + return sorting + } else { + return sorting.reversed() + } + } + + companion object { + fun inputs(menu: MatteryMenu, observer: Runnable? = null) : IItemStackSortingSettings { + return object : IItemStackSortingSettings { + override var isAscending: Boolean by BooleanInputWithFeedback(menu).also { if (observer != null) it.addListener { observer.run() } } + override var sorting: ItemStackSorter by EnumInputWithFeedback(menu).also { if (observer != null) it.addListener { observer.run() } } + } + } + + fun inputs(menu: MatteryMenu, parent: IItemStackSortingSettings?, observer: Runnable? = null) : IItemStackSortingSettings { + if (parent == null) + return inputs(menu) + + return object : IItemStackSortingSettings { + override var isAscending: Boolean by BooleanInputWithFeedback(menu, parent::isAscending).also { if (observer != null) it.addListener { observer.run() } } + override var sorting: ItemStackSorter by EnumInputWithFeedback(menu, parent::sorting).also { if (observer != null) it.addListener { observer.run() } } + } + } + } +} + +interface IItemSortingSettings : IBaseSortingSettings { + var sorting: ItemSorter + + override fun serializeNBT(): CompoundTag { + return super.serializeNBT().also { + it["sorting"] = sorting.name + } + } + + override fun deserializeNBT(nbt: CompoundTag?) { + nbt ?: return + super.deserializeNBT(nbt) + sorting = nbt.mapString("sorting", ItemSorter::valueOf, ItemSorter.DEFAULT) + } + + val actualComparator: Comparator get() { + if (isAscending) { + return sorting + } else { + return sorting.reversed() + } + } + + companion object { + fun inputs(menu: MatteryMenu, observer: Runnable? = null) : IItemSortingSettings { + return object : IItemSortingSettings { + override var isAscending: Boolean by BooleanInputWithFeedback(menu).also { if (observer != null) it.addListener { observer.run() } } + override var sorting: ItemSorter by EnumInputWithFeedback(menu).also { if (observer != null) it.addListener { observer.run() } } + } + } + + fun inputs(menu: MatteryMenu, parent: IItemSortingSettings?, observer: Runnable? = null) : IItemSortingSettings { + if (parent == null) + return inputs(menu) + + return object : IItemSortingSettings { + override var isAscending: Boolean by BooleanInputWithFeedback(menu, parent::isAscending).also { if (observer != null) it.addListener { observer.run() } } + override var sorting: ItemSorter by EnumInputWithFeedback(menu, parent::sorting).also { if (observer != null) it.addListener { observer.run() } } + } + } + } +} 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 0ad8e4d61..8f8e31ef9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt @@ -209,6 +209,8 @@ abstract class MatteryMenu( var sortInventoryInput: PlayerInput? = null private set + val playerSortSettings = IItemStackSortingSettings.inputs(this, player.matteryPlayer?.sortingSettings) + var offhandSlot: InventorySlot? = null protected set @@ -352,7 +354,7 @@ abstract class MatteryMenu( } sortInventoryInput = PlayerInput(NullValueCodec) { - mattery.inventoryAndExopackNoHotbar.sort() + mattery.inventoryAndExopackNoHotbar.sort(playerSortSettings.actualComparator) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/CargoCrateMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/CargoCrateMenu.kt index 159d23324..d02b2af7b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/CargoCrateMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/CargoCrateMenu.kt @@ -5,32 +5,28 @@ import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity +import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.container.sort import ru.dbotthepony.mc.otm.core.util.NullValueCodec +import ru.dbotthepony.mc.otm.menu.IItemStackSortingSettings import ru.dbotthepony.mc.otm.menu.MatteryMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot import ru.dbotthepony.mc.otm.menu.UserFilteredSlot +import ru.dbotthepony.mc.otm.menu.makeSlots import ru.dbotthepony.mc.otm.registry.MMenus -class CargoCrateMenu @JvmOverloads constructor( - p_38852_: Int, +class CargoCrateMenu( + containerId: Int, inventory: Inventory, tile: CargoCrateBlockEntity? = null -) : MatteryMenu(MMenus.CARGO_CRATE, p_38852_, inventory, tile) { - val storageSlots: List +) : MatteryMenu(MMenus.CARGO_CRATE, containerId, inventory, tile) { + val storageSlots = makeSlots(tile?.container ?: SimpleContainer(CargoCrateBlockEntity.CAPACITY), ::UserFilteredSlot) private val trackedPlayerOpen = !inventory.player.isSpectator val sort = PlayerInput(NullValueCodec) { - tile?.container?.sort() + tile?.container?.sort(playerSortSettings.actualComparator) } init { - val container = tile?.container ?: SimpleContainer(CargoCrateBlockEntity.CAPACITY) - - storageSlots = immutableList(CargoCrateBlockEntity.CAPACITY) { - addStorageSlot(UserFilteredSlot(container, it)) - } - if (trackedPlayerOpen) { tile?.onPlayerOpen() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/MinecartCargoCrateMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/MinecartCargoCrateMenu.kt index 6b1f0253e..0968010bd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/MinecartCargoCrateMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/MinecartCargoCrateMenu.kt @@ -1,32 +1,31 @@ package ru.dbotthepony.mc.otm.menu.decorative -import net.minecraft.world.Container import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player -import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity +import ru.dbotthepony.mc.otm.container.sort +import ru.dbotthepony.mc.otm.core.util.NullValueCodec import ru.dbotthepony.mc.otm.entity.MinecartCargoCrate import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.makeSlots import ru.dbotthepony.mc.otm.registry.MMenus -class MinecartCargoCrateMenu @JvmOverloads constructor( - p_38852_: Int, +class MinecartCargoCrateMenu( + containerId: Int, inventory: Inventory, val cart: MinecartCargoCrate? = null -) : MatteryMenu(MMenus.CARGO_CRATE, p_38852_, inventory) { - val storageSlots: List +) : MatteryMenu(MMenus.CARGO_CRATE, containerId, inventory) { + val storageSlots = makeSlots(cart ?: SimpleContainer(CargoCrateBlockEntity.CAPACITY), ::MatterySlot) private val trackedPlayerOpen = !inventory.player.isSpectator + val sort = PlayerInput(NullValueCodec) { + cart?.sort(playerSortSettings.actualComparator) + } + init { - val container = cart as Container? ?: SimpleContainer(CargoCrateBlockEntity.CAPACITY) - - storageSlots = immutableList(CargoCrateBlockEntity.CAPACITY) { - addStorageSlot(MatterySlot(container, it)) - } - if (trackedPlayerOpen) { cart?.onPlayerOpen() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterPanelMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterPanelMenu.kt index 98e96e49d..95216979a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterPanelMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterPanelMenu.kt @@ -22,6 +22,7 @@ import ru.dbotthepony.mc.otm.core.util.codec import ru.dbotthepony.mc.otm.core.util.writeCollection import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphListener import ru.dbotthepony.mc.otm.graph.matter.MatterGraph +import ru.dbotthepony.mc.otm.menu.IItemSortingSettings import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.network.* @@ -142,10 +143,10 @@ class MatterPanelMenu( } private fun updateComparators() { - var p = sorting.map(PatternState::item) - var t = sorting.map(ReplicationTask::item) + var p = settings.sorting.map(PatternState::item) + var t = settings.sorting.map(ReplicationTask::item) - if (!isAscending) { + if (!settings.isAscending) { p = p.reversed() t = t.reversed() } @@ -154,20 +155,7 @@ class MatterPanelMenu( taskComparator = t } - var sorting: ItemSorter by GetterSetter.of( - mSynchronizer.ComputedField( - getter = { tile?.getPlayerSettings(player)?.sorter ?: ItemSorter.DEFAULT }, - codec = ItemSorter::class.codec(), - observer = { updateComparators() }), - PlayerInput(ItemSorter::class.codec(), allowSpectators = true) { tile?.getPlayerSettings(player)?.sorter = it } - ) - - var isAscending: Boolean by GetterSetter.of( - mSynchronizer.ComputedBooleanField( - getter = { tile?.getPlayerSettings(player)?.ascending ?: true }, - observer = { updateComparators() }), - booleanInput(allowSpectators = true) { tile?.getPlayerSettings(player)?.ascending = it } - ) + val settings = IItemSortingSettings.inputs(this, tile?.getPlayerSettings(player), ::updateComparators) var isProvidingTasks by BooleanInputWithFeedback(this, tile?.let { it::isProvidingTasks }) val cancelAll = PlayerInput(NullValueCodec) { tile?.dropAllTasks() } @@ -196,7 +184,7 @@ class MatterPanelMenu( } } - private var patternComparator = sorting.map(PatternState::item) + private var patternComparator = settings.sorting.map(PatternState::item) set(value) { if (value != field) { field = value @@ -205,7 +193,7 @@ class MatterPanelMenu( } } - private var taskComparator = sorting.map(ReplicationTask::item) + private var taskComparator = settings.sorting.map(ReplicationTask::item) set(value) { if (value != field) { field = value