Proper sorting inputs in regular storage menus

This commit is contained in:
DBotThePony 2023-08-20 17:35:39 +07:00
parent 35b186556e
commit e7c9abcebb
Signed by: DBot
GPG Key ID: DCC23B5715498507
17 changed files with 291 additions and 107 deletions

View File

@ -806,6 +806,7 @@ private fun gui(provider: MatteryLanguageProvider) {
gui("balance_inputs", "Balance input slots") gui("balance_inputs", "Balance input slots")
gui("sorting.sort_now", "Sort") gui("sorting.sort_now", "Sort")
gui("sorting.sort_settings", "Right click to show settings")
gui("sorting.default", "Default sorting") gui("sorting.default", "Default sorting")
gui("sorting.name", "Sort by name") gui("sorting.name", "Sort by name")
gui("sorting.id", "Sort by ID") gui("sorting.id", "Sort by ID")

View File

@ -806,6 +806,7 @@ private fun gui(provider: MatteryLanguageProvider) {
gui("balance_inputs", "Балансировать входные слоты") gui("balance_inputs", "Балансировать входные слоты")
gui("sorting.sort_now", "Отсортировать") gui("sorting.sort_now", "Отсортировать")
gui("sorting.sort_settings", "Нажмите правую кнопку мыши для настроек")
gui("sorting.default", "Сортировка по умолчанию") gui("sorting.default", "Сортировка по умолчанию")
gui("sorting.name", "Сортировка по имени") gui("sorting.name", "Сортировка по имени")
gui("sorting.id", "Сортировка по ID") gui("sorting.id", "Сортировка по ID")

View File

@ -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.nbt.set
import ru.dbotthepony.mc.otm.core.util.ItemSorter import ru.dbotthepony.mc.otm.core.util.ItemSorter
import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode
import ru.dbotthepony.mc.otm.menu.IItemSortingSettings
import ru.dbotthepony.mc.otm.registry.MBlockEntities import ru.dbotthepony.mc.otm.registry.MBlockEntities
import java.util.* import java.util.*
import java.util.stream.Stream import java.util.stream.Stream
class MatterPanelBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.MATTER_PANEL, blockPos, blockState), IReplicationTaskProvider { class MatterPanelBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.MATTER_PANEL, blockPos, blockState), IReplicationTaskProvider {
inner class PlayerSettings : INBTSerializable<CompoundTag> { inner class PlayerSettings : IItemSortingSettings {
var sorter: ItemSorter = ItemSorter.DEFAULT override var sorting: ItemSorter = ItemSorter.DEFAULT
set(value) { set(value) {
field = value field = value
markDirtyFast() markDirtyFast()
} }
var ascending: Boolean = true override var isAscending: Boolean = true
set(value) { set(value) {
field = value field = value
markDirtyFast() 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 var isProvidingTasks = true

View File

@ -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.getStringList
import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.core.util.IntValueCodec 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.ItemValueCodec
import ru.dbotthepony.mc.otm.core.util.RGBCodec import ru.dbotthepony.mc.otm.core.util.RGBCodec
import ru.dbotthepony.mc.otm.core.util.Savetables 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.UUIDValueCodec
import ru.dbotthepony.mc.otm.core.util.VarIntValueCodec import ru.dbotthepony.mc.otm.core.util.VarIntValueCodec
import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu 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.*
import ru.dbotthepony.mc.otm.network.SmokeParticlesPacket.Companion.makeSmoke import ru.dbotthepony.mc.otm.network.SmokeParticlesPacket.Companion.makeSmoke
import ru.dbotthepony.mc.otm.network.synchronizer.FieldSynchronizer import ru.dbotthepony.mc.otm.network.synchronizer.FieldSynchronizer
@ -402,6 +404,11 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
return _exoPackMenu!! return _exoPackMenu!!
} }
val sortingSettings = object : IItemStackSortingSettings {
override var isAscending: Boolean = true
override var sorting: ItemStackSorter = ItemStackSorter.DEFAULT
}
fun recreateExoPackMenu() { fun recreateExoPackMenu() {
_exoPackMenu = ExopackInventoryMenu(this) _exoPackMenu = ExopackInventoryMenu(this)
} }
@ -591,6 +598,8 @@ class MatteryPlayerCapability(val ply: Player) : ICapabilityProvider, INBTSerial
savetables.codecNullable(::exopackColor, RGBAColor.CODECRGB) savetables.codecNullable(::exopackColor, RGBAColor.CODECRGB)
savetables.bool(::exopackGlows) savetables.bool(::exopackGlows)
savetables.stateful(::sortingSettings)
} }
fun invalidateNetworkState() { fun invalidateNetworkState() {

View File

@ -38,8 +38,8 @@ object Widgets18 {
val BUTTON_DISABLED = buttonGrids.next() val BUTTON_DISABLED = buttonGrids.next()
private val storageGrid = WidgetLocation.STORAGE_CONTROLS.grid(rows = 4, columns = 5) private val storageGrid = WidgetLocation.STORAGE_CONTROLS.grid(rows = 4, columns = 5)
val ARROW_DOWN = storageGrid.next() val SORT_DESCENDING = storageGrid.next()
val ARROW_UP = storageGrid.next() val SORT_ASCENDING = storageGrid.next()
val SORT_DEFAULT = storageGrid.next() val SORT_DEFAULT = storageGrid.next()
val SORT_ALPHABET = storageGrid.next() val SORT_ALPHABET = storageGrid.next()
val SORT_COUNT = storageGrid.next() val SORT_COUNT = storageGrid.next()

View File

@ -308,12 +308,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
} }
if (menu.sortInventoryInput != null) { if (menu.sortInventoryInput != null) {
deviceControls.addButton(LargeRectangleButtonPanel.input( deviceControls.customSortingButtons(menu.playerSortSettings, menu.sortInventoryInput!!)
this,
deviceControls,
menu.sortInventoryInput!!,
icon = Widgets18.SORT_NOW
).also { it.tooltips.add(TranslatableComponent("otm.gui.sorting.sort_now")) })
} }
if (menu.exopackChargeSlots.isNotEmpty()) { if (menu.exopackChargeSlots.isNotEmpty()) {

View File

@ -28,7 +28,7 @@ class CargoCrateScreen(menu: CargoCrateMenu, inventory: Inventory, title: Compon
val controls = DeviceControls(this, frame) 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 return frame
} }

View File

@ -4,6 +4,7 @@ import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen 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.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.util.GridPanel
import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel
import ru.dbotthepony.mc.otm.menu.decorative.MinecartCargoCrateMenu import ru.dbotthepony.mc.otm.menu.decorative.MinecartCargoCrateMenu
@ -20,6 +21,10 @@ class MinecartCargoCrateScreen(menu: MinecartCargoCrateMenu, inventory: Inventor
for (slot in menu.storageSlots) for (slot in menu.storageSlots)
SlotPanel(this, grid, slot) SlotPanel(this, grid, slot)
val controls = DeviceControls(this, frame)
controls.customSortingButtons(menu.playerSortSettings, menu.sort)
return frame return frame
} }
} }

View File

@ -55,7 +55,7 @@ class MatterPanelScreen(
val controls = DeviceControls(this, frame) 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) { for (v in ItemSorter.entries) {
add(v, skinElement = v.icon, tooltip = v.title) add(v, skinElement = v.icon, tooltip = v.title)
} }

View File

@ -140,7 +140,7 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
} }
/** /**
* Bigger values means lesser priority while docking * Bigger values means lesser priority while docking, rendering and processing inputs.
*/ */
var childrenOrder = 0 var childrenOrder = 0
set(value) { set(value) {
@ -881,7 +881,7 @@ open class EditablePanel<out S : Screen> @JvmOverloads constructor(
poseStack.popPose() poseStack.popPose()
} }
for (child in visibleChildrenInternal) { for (child in visibleChildrenInternal.asReversed()) {
child.absoluteX = absoluteX + child.x + xOffset child.absoluteX = absoluteX + child.x + xOffset
child.absoluteY = absoluteY + child.y + yOffset child.absoluteY = absoluteY + child.y + yOffset

View File

@ -27,9 +27,13 @@ import ru.dbotthepony.mc.otm.config.ClientConfig
import ru.dbotthepony.mc.otm.core.GetterSetter import ru.dbotthepony.mc.otm.core.GetterSetter
import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.core.TranslatableComponent 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.immutableList
import ru.dbotthepony.mc.otm.core.math.RelativeSide 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.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.UpgradeSlots
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput
@ -314,31 +318,59 @@ class DeviceControls<out S : MatteryScreen<*>>(
val balanceInputsButton: LargeBooleanRectangleButtonPanel<S>? val balanceInputsButton: LargeBooleanRectangleButtonPanel<S>?
val upgradesButton: LargeRectangleButtonPanel<S>? val upgradesButton: LargeRectangleButtonPanel<S>?
init {
childrenOrder = -1000
}
private var upgradeWindow: FramePanel<S>? = null private var upgradeWindow: FramePanel<S>? = null
private var nextY = 0f
private val buttons = ArrayList<EditablePanel<S>>()
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 <P : EditablePanel<@UnsafeVariance S>> addButton(button: P): P { fun <P : EditablePanel<@UnsafeVariance S>> addButton(button: P): P {
buttons.add(button)
button.parent = this button.parent = this
button.x = 0f alignButtons()
button.y = nextY return button
nextY += button.height + 2f }
height = nextY - 2f
width = button.width.coerceAtLeast(width) fun <P : EditablePanel<@UnsafeVariance S>> 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 return button
} }
fun <P : EditablePanel<@UnsafeVariance S>> prependButton(button: P): P { fun <P : EditablePanel<@UnsafeVariance S>> prependButton(button: P): P {
for (child in children) { buttons.add(0, button)
child.y += button.height + 2f button.parent = this
alignButtons()
return button
} }
button.parent = this override fun performLayout() {
button.x = 0f super.performLayout()
button.y = 0f alignButtons()
nextY += button.height + 2f
height = nextY - 2f
width = button.width.coerceAtLeast(width)
return button
} }
fun addStorageMode(prop: GetterSetter<FlowDirection>) { fun addStorageMode(prop: GetterSetter<FlowDirection>) {
@ -352,24 +384,74 @@ class DeviceControls<out S : MatteryScreen<*>>(
addButton(mode) addButton(mode)
} }
inline fun <reified T : Enum<T>> sortingButtons(ascending: GetterSetter<Boolean>, sorting: GetterSetter<T>, default: T, configurator: LargeEnumRectangleButtonPanel<S, T>.() -> Unit) { inline fun <reified T : Enum<T>> sortingButtons(ascending: GetterSetter<Boolean>, sorting: GetterSetter<T>, default: T, configurator: LargeEnumRectangleButtonPanel<S, T>.() -> Unit): List<EditablePanel<S>> {
val result = ArrayList<EditablePanel<S>>()
LargeBooleanRectangleButtonPanel( LargeBooleanRectangleButtonPanel(
screen, screen,
this, this,
prop = ascending, prop = ascending,
iconActive = Widgets18.ARROW_UP, iconActive = Widgets18.SORT_ASCENDING,
iconInactive = Widgets18.ARROW_DOWN, iconInactive = Widgets18.SORT_DESCENDING,
tooltipActive = TranslatableComponent("otm.gui.sorting.ascending"), tooltipActive = TranslatableComponent("otm.gui.sorting.ascending"),
tooltipInactive = TranslatableComponent("otm.gui.sorting.descending"), tooltipInactive = TranslatableComponent("otm.gui.sorting.descending"),
).also { ).also {
prependButton(it) prependButton(it)
result.add(it)
} }
LargeEnumRectangleButtonPanel(screen, this, enum = T::class.java, prop = sorting, defaultValue = default).also { LargeEnumRectangleButtonPanel(screen, this, enum = T::class.java, prop = sorting, defaultValue = default).also {
prependButton(it) prependButton(it)
configurator.invoke(it) configurator.invoke(it)
it.finish() it.finish()
result.add(it)
} }
return result
}
fun customSortingButtons(settings: IItemStackSortingSettings, input: MatteryMenu.PlayerInput<Nothing?>) {
addButton(object : LargeRectangleButtonPanel<S>(screen, this@DeviceControls) {
var buttons: List<EditablePanel<*>>? = 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<S>, this) }
} else {
buttons!!.forEach { it.remove() }
buttons = null
}
}
}
})
} }
init { init {
@ -492,7 +574,7 @@ class DeviceControls<out S : MatteryScreen<*>>(
} }
if (energyConfig != null) { if (energyConfig != null) {
energyConfigButton = addButton(object : LargeRectangleButtonPanel<S>(screen, this@DeviceControls, y = nextY, icon = Widgets18.ENERGY_CONFIGURATION) { energyConfigButton = addButton(object : LargeRectangleButtonPanel<S>(screen, this@DeviceControls, icon = Widgets18.ENERGY_CONFIGURATION) {
init { init {
tooltips.add(TranslatableComponent("otm.gui.sides.energy_config")) tooltips.add(TranslatableComponent("otm.gui.sides.energy_config"))
} }
@ -511,7 +593,7 @@ class DeviceControls<out S : MatteryScreen<*>>(
} }
if (fluidConfig != null) { if (fluidConfig != null) {
fluidConfigButton = addButton(object : LargeRectangleButtonPanel<S>(screen, this@DeviceControls, y = nextY, icon = Widgets18.FLUID_CONFIGURATION) { fluidConfigButton = addButton(object : LargeRectangleButtonPanel<S>(screen, this@DeviceControls, icon = Widgets18.FLUID_CONFIGURATION) {
init { init {
tooltips.add(TranslatableComponent("otm.gui.sides.fluid_config")) tooltips.add(TranslatableComponent("otm.gui.sides.fluid_config"))
} }

View File

@ -8,6 +8,7 @@ import it.unimi.dsi.fastutil.ints.IntIterator
import it.unimi.dsi.fastutil.ints.IntSet import it.unimi.dsi.fastutil.ints.IntSet
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap
import it.unimi.dsi.fastutil.objects.ObjectArrayList
import net.minecraft.world.Container import net.minecraft.world.Container
import net.minecraft.world.inventory.CraftingContainer import net.minecraft.world.inventory.CraftingContainer
import net.minecraft.world.item.ItemStack 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.container.util.slotIterator
import ru.dbotthepony.mc.otm.core.addAll import ru.dbotthepony.mc.otm.core.addAll
import ru.dbotthepony.mc.otm.core.collect.filter 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.collect.toList
import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.isNotEmpty
import ru.dbotthepony.mc.otm.core.map 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) get(column, row)
} }
private object FilteredFirst : Comparator<IContainerSlot> {
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<ItemStack> = ItemStackSorter.DEFAULT) { fun Container.sort(comparator: Comparator<ItemStack> = ItemStackSorter.DEFAULT) {
if (isEmpty) if (isEmpty)
return return
@ -310,8 +300,21 @@ fun Container.sort(comparator: Comparator<ItemStack> = ItemStackSorter.DEFAULT)
if (slots.isEmpty()) if (slots.isEmpty())
return return
slots.sortWith(FilteredFirst.thenComparing(comparator.map(IContainerSlot::item))) val items = Object2ObjectOpenCustomHashMap<ItemStack, ItemStack>(ItemStackHashStrategy)
val items = slots.map { it.item.copy() }
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() } slots.forEach { it.remove() }
items.forEach { addItem(it, false) } sortedItems.forEach { addItem(it, false) }
} }

View File

@ -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<CompoundTag?> {
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<ItemStack> 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<ItemStackSorter>(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<Item> 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<ItemSorter>(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() } }
}
}
}
}

View File

@ -209,6 +209,8 @@ abstract class MatteryMenu(
var sortInventoryInput: PlayerInput<Nothing?>? = null var sortInventoryInput: PlayerInput<Nothing?>? = null
private set private set
val playerSortSettings = IItemStackSortingSettings.inputs(this, player.matteryPlayer?.sortingSettings)
var offhandSlot: InventorySlot? = null var offhandSlot: InventorySlot? = null
protected set protected set
@ -352,7 +354,7 @@ abstract class MatteryMenu(
} }
sortInventoryInput = PlayerInput(NullValueCodec) { sortInventoryInput = PlayerInput(NullValueCodec) {
mattery.inventoryAndExopackNoHotbar.sort() mattery.inventoryAndExopackNoHotbar.sort(playerSortSettings.actualComparator)
} }
} }

View File

@ -5,32 +5,28 @@ import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.immutableList
import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity 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.container.sort
import ru.dbotthepony.mc.otm.core.util.NullValueCodec 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.MatteryMenu
import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.menu.UserFilteredSlot import ru.dbotthepony.mc.otm.menu.UserFilteredSlot
import ru.dbotthepony.mc.otm.menu.makeSlots
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
class CargoCrateMenu @JvmOverloads constructor( class CargoCrateMenu(
p_38852_: Int, containerId: Int,
inventory: Inventory, inventory: Inventory,
tile: CargoCrateBlockEntity? = null tile: CargoCrateBlockEntity? = null
) : MatteryMenu(MMenus.CARGO_CRATE, p_38852_, inventory, tile) { ) : MatteryMenu(MMenus.CARGO_CRATE, containerId, inventory, tile) {
val storageSlots: List<UserFilteredSlot> val storageSlots = makeSlots(tile?.container ?: SimpleContainer(CargoCrateBlockEntity.CAPACITY), ::UserFilteredSlot)
private val trackedPlayerOpen = !inventory.player.isSpectator private val trackedPlayerOpen = !inventory.player.isSpectator
val sort = PlayerInput(NullValueCodec) { val sort = PlayerInput(NullValueCodec) {
tile?.container?.sort() tile?.container?.sort(playerSortSettings.actualComparator)
} }
init { init {
val container = tile?.container ?: SimpleContainer(CargoCrateBlockEntity.CAPACITY)
storageSlots = immutableList(CargoCrateBlockEntity.CAPACITY) {
addStorageSlot(UserFilteredSlot(container, it))
}
if (trackedPlayerOpen) { if (trackedPlayerOpen) {
tile?.onPlayerOpen() tile?.onPlayerOpen()
} }

View File

@ -1,32 +1,31 @@
package ru.dbotthepony.mc.otm.menu.decorative package ru.dbotthepony.mc.otm.menu.decorative
import net.minecraft.world.Container
import net.minecraft.world.SimpleContainer import net.minecraft.world.SimpleContainer
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player 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.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.entity.MinecartCargoCrate
import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.menu.MatterySlot import ru.dbotthepony.mc.otm.menu.MatterySlot
import ru.dbotthepony.mc.otm.menu.makeSlots
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
class MinecartCargoCrateMenu @JvmOverloads constructor( class MinecartCargoCrateMenu(
p_38852_: Int, containerId: Int,
inventory: Inventory, inventory: Inventory,
val cart: MinecartCargoCrate? = null val cart: MinecartCargoCrate? = null
) : MatteryMenu(MMenus.CARGO_CRATE, p_38852_, inventory) { ) : MatteryMenu(MMenus.CARGO_CRATE, containerId, inventory) {
val storageSlots: List<MatterySlot> val storageSlots = makeSlots(cart ?: SimpleContainer(CargoCrateBlockEntity.CAPACITY), ::MatterySlot)
private val trackedPlayerOpen = !inventory.player.isSpectator private val trackedPlayerOpen = !inventory.player.isSpectator
init { val sort = PlayerInput(NullValueCodec) {
val container = cart as Container? ?: SimpleContainer(CargoCrateBlockEntity.CAPACITY) cart?.sort(playerSortSettings.actualComparator)
storageSlots = immutableList(CargoCrateBlockEntity.CAPACITY) {
addStorageSlot(MatterySlot(container, it))
} }
init {
if (trackedPlayerOpen) { if (trackedPlayerOpen) {
cart?.onPlayerOpen() cart?.onPlayerOpen()
} }

View File

@ -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.core.util.writeCollection
import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphListener import ru.dbotthepony.mc.otm.graph.matter.IMatterGraphListener
import ru.dbotthepony.mc.otm.graph.matter.MatterGraph 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.MatteryMenu
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
import ru.dbotthepony.mc.otm.network.* import ru.dbotthepony.mc.otm.network.*
@ -142,10 +143,10 @@ class MatterPanelMenu(
} }
private fun updateComparators() { private fun updateComparators() {
var p = sorting.map(PatternState::item) var p = settings.sorting.map(PatternState::item)
var t = sorting.map(ReplicationTask::item) var t = settings.sorting.map(ReplicationTask::item)
if (!isAscending) { if (!settings.isAscending) {
p = p.reversed() p = p.reversed()
t = t.reversed() t = t.reversed()
} }
@ -154,20 +155,7 @@ class MatterPanelMenu(
taskComparator = t taskComparator = t
} }
var sorting: ItemSorter by GetterSetter.of( val settings = IItemSortingSettings.inputs(this, tile?.getPlayerSettings(player), ::updateComparators)
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 }
)
var isProvidingTasks by BooleanInputWithFeedback(this, tile?.let { it::isProvidingTasks }) var isProvidingTasks by BooleanInputWithFeedback(this, tile?.let { it::isProvidingTasks })
val cancelAll = PlayerInput(NullValueCodec) { tile?.dropAllTasks() } 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) { set(value) {
if (value != field) { if (value != field) {
field = value 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) { set(value) {
if (value != field) { if (value != field) {
field = value field = value