Make sorting be performed on client, and sorted slot list be sent to server
This commit is contained in:
parent
4c94e92b90
commit
e94a267ac1
@ -271,14 +271,8 @@ class ExopackInventoryScreen(menu: ExopackInventoryMenu) : MatteryScreen<Exopack
|
|||||||
moveMousePosScaled(y = movePixels)
|
moveMousePosScaled(y = movePixels)
|
||||||
} as EditablePanel<ExopackInventoryScreen>)
|
} as EditablePanel<ExopackInventoryScreen>)
|
||||||
|
|
||||||
|
|
||||||
if (menu.sortInventoryInput != null) {
|
if (menu.sortInventoryInput != null) {
|
||||||
controls.addButton(LargeRectangleButtonPanel.input(
|
controls.customSortingButtons(menu.sortInventoryInput!!)
|
||||||
this,
|
|
||||||
controls,
|
|
||||||
menu.sortInventoryInput!!,
|
|
||||||
icon = Widgets18.SORT_NOW
|
|
||||||
).also { it.tooltips.add(TranslatableComponent("otm.gui.sorting.sort_now")) })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var x = -4f
|
var x = -4f
|
||||||
|
@ -308,7 +308,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (menu.sortInventoryInput != null) {
|
if (menu.sortInventoryInput != null) {
|
||||||
deviceControls.customSortingButtons(menu.playerSortSettings, menu.sortInventoryInput!!)
|
deviceControls.customSortingButtons(menu.sortInventoryInput!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (menu.exopackChargeSlots.isNotEmpty()) {
|
if (menu.exopackChargeSlots.isNotEmpty()) {
|
||||||
|
@ -28,7 +28,7 @@ class CargoCrateScreen(menu: CargoCrateMenu, inventory: Inventory, title: Compon
|
|||||||
|
|
||||||
val controls = DeviceControls(this, frame)
|
val controls = DeviceControls(this, frame)
|
||||||
|
|
||||||
controls.customSortingButtons(menu.playerSortSettings, menu.sort)
|
controls.customSortingButtons(menu.sort)
|
||||||
|
|
||||||
return frame
|
return frame
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ class MinecartCargoCrateScreen(menu: MinecartCargoCrateMenu, inventory: Inventor
|
|||||||
|
|
||||||
val controls = DeviceControls(this, frame)
|
val controls = DeviceControls(this, frame)
|
||||||
|
|
||||||
controls.customSortingButtons(menu.playerSortSettings, menu.sort)
|
controls.customSortingButtons(menu.sort)
|
||||||
|
|
||||||
return frame
|
return frame
|
||||||
}
|
}
|
||||||
|
@ -410,7 +410,7 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun customSortingButtons(settings: IItemStackSortingSettings, input: MatteryMenu.PlayerInput<Nothing?>) {
|
fun customSortingButtons(input: MatteryMenu.SortInput) {
|
||||||
addButton(object : LargeRectangleButtonPanel<S>(screen, this@DeviceControls) {
|
addButton(object : LargeRectangleButtonPanel<S>(screen, this@DeviceControls) {
|
||||||
var buttons: List<EditablePanel<*>>? = null
|
var buttons: List<EditablePanel<*>>? = null
|
||||||
|
|
||||||
@ -427,15 +427,15 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override var isDisabled: Boolean
|
override var isDisabled: Boolean
|
||||||
get() = !input.test(minecraft.player)
|
get() = !input.input.test(minecraft.player)
|
||||||
set(value) {}
|
set(value) {}
|
||||||
|
|
||||||
override fun onClick(mouseButton: Int) {
|
override fun onClick(mouseButton: Int) {
|
||||||
if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) {
|
if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) {
|
||||||
input.accept(null)
|
input.clientInput()
|
||||||
} else {
|
} else {
|
||||||
if (buttons == null) {
|
if (buttons == null) {
|
||||||
buttons = sortingButtons(settings::isAscending.asGetterSetter(), settings::sorting.asGetterSetter(), ItemStackSorter.DEFAULT) {
|
buttons = sortingButtons(input.settings::isAscending.asGetterSetter(), input.settings::sorting.asGetterSetter(), ItemStackSorter.DEFAULT) {
|
||||||
for (v in ItemStackSorter.entries) {
|
for (v in ItemStackSorter.entries) {
|
||||||
add(v, v.icon, v.title)
|
add(v, v.icon, v.title)
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,10 @@ package ru.dbotthepony.mc.otm.container
|
|||||||
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet
|
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList
|
import it.unimi.dsi.fastutil.ints.IntArrayList
|
||||||
import it.unimi.dsi.fastutil.ints.IntArraySet
|
import it.unimi.dsi.fastutil.ints.IntArraySet
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntCollection
|
||||||
import it.unimi.dsi.fastutil.ints.IntIterable
|
import it.unimi.dsi.fastutil.ints.IntIterable
|
||||||
import it.unimi.dsi.fastutil.ints.IntIterator
|
import it.unimi.dsi.fastutil.ints.IntIterator
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntList
|
||||||
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
|
||||||
@ -16,11 +18,10 @@ import net.minecraft.world.item.enchantment.EnchantmentHelper.hasVanishingCurse
|
|||||||
import net.minecraftforge.fluids.capability.IFluidHandler
|
import net.minecraftforge.fluids.capability.IFluidHandler
|
||||||
import ru.dbotthepony.mc.otm.container.util.IContainerSlot
|
import ru.dbotthepony.mc.otm.container.util.IContainerSlot
|
||||||
import ru.dbotthepony.mc.otm.container.util.ItemStackHashStrategy
|
import ru.dbotthepony.mc.otm.container.util.ItemStackHashStrategy
|
||||||
|
import ru.dbotthepony.mc.otm.container.util.containerSlot
|
||||||
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
|
||||||
@ -318,3 +319,62 @@ fun Container.sort(comparator: Comparator<ItemStack> = ItemStackSorter.DEFAULT)
|
|||||||
slots.forEach { it.remove() }
|
slots.forEach { it.remove() }
|
||||||
sortedItems.forEach { addItem(it, false) }
|
sortedItems.forEach { addItem(it, false) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Container.sortWithIndices(sortedSlots: IntCollection) {
|
||||||
|
if (sortedSlots.isEmpty() || isEmpty)
|
||||||
|
return
|
||||||
|
|
||||||
|
val seen = IntAVLTreeSet()
|
||||||
|
val valid = ArrayList<IContainerSlot>()
|
||||||
|
|
||||||
|
val iterator = sortedSlots.intIterator()
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
val value = iterator.nextInt()
|
||||||
|
|
||||||
|
if (value in 0 until containerSize && seen.add(value)) {
|
||||||
|
val slot = containerSlot(value)
|
||||||
|
|
||||||
|
if (slot.isNotEmpty && !slot.isForbiddenForAutomation && slot.item.count <= slot.getMaxStackSize()) {
|
||||||
|
valid.add(slot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valid.isEmpty())
|
||||||
|
return
|
||||||
|
|
||||||
|
val items = valid.map { it.item.copy() }
|
||||||
|
valid.forEach { it.remove() }
|
||||||
|
items.forEach { addItem(it, false) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Container.computeSortedIndices(comparator: Comparator<ItemStack> = ItemStackSorter.DEFAULT): IntList {
|
||||||
|
if (isEmpty)
|
||||||
|
return IntList.of()
|
||||||
|
|
||||||
|
val slots = slotIterator().filter { !it.isForbiddenForAutomation && it.getMaxStackSize() >= it.item.count }.toList()
|
||||||
|
|
||||||
|
if (slots.isEmpty())
|
||||||
|
return IntList.of()
|
||||||
|
|
||||||
|
val items = Object2ObjectOpenCustomHashMap<ItemStack, Pair<ItemStack, IntList>>(ItemStackHashStrategy)
|
||||||
|
|
||||||
|
slots.forEach {
|
||||||
|
val get = items[it.item]
|
||||||
|
|
||||||
|
if (get == null) {
|
||||||
|
items[it.item] = it.item.copy() to IntArrayList().also { s -> s.add(it.slot) }
|
||||||
|
} else {
|
||||||
|
get.first.count += it.item.count
|
||||||
|
get.second.add(it.slot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val sortedItems = ObjectArrayList(items.values)
|
||||||
|
sortedItems.sortWith(comparator.map { it.first })
|
||||||
|
|
||||||
|
val result = IntArrayList()
|
||||||
|
sortedItems.forEach { result.addAll(it.second) }
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
@ -105,6 +105,35 @@ class StreamCodec<V>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CollectionStreamCodec<E, C : MutableCollection<E>>(val elementCodec: IStreamCodec<E>, val collectionFactory: (Int) -> C) : IStreamCodec<C> {
|
||||||
|
override fun read(stream: DataInputStream, sizeLimit: NbtAccounter): C {
|
||||||
|
val size = stream.readVarIntLE(sizeLimit)
|
||||||
|
|
||||||
|
if (size <= 0) {
|
||||||
|
return collectionFactory.invoke(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
val collection = collectionFactory.invoke(size)
|
||||||
|
|
||||||
|
for (i in 0 until size) {
|
||||||
|
collection.add(elementCodec.read(stream, sizeLimit))
|
||||||
|
}
|
||||||
|
|
||||||
|
return collection
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun write(stream: DataOutputStream, value: C) {
|
||||||
|
stream.writeVarIntLE(value.size)
|
||||||
|
value.forEach { elementCodec.write(stream, it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun copy(value: C): C {
|
||||||
|
val new = collectionFactory.invoke(value.size)
|
||||||
|
value.forEach { new.add(elementCodec.copy(it)) }
|
||||||
|
return new
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val NullValueCodec = StreamCodec({ _, _ -> null }, { _, _ -> })
|
val NullValueCodec = StreamCodec({ _, _ -> null }, { _, _ -> })
|
||||||
val BooleanValueCodec = StreamCodec(DataInputStream::readBoolean, 1L, DataOutputStream::writeBoolean) { a, b -> a == b }
|
val BooleanValueCodec = StreamCodec(DataInputStream::readBoolean, 1L, DataOutputStream::writeBoolean) { a, b -> a == b }
|
||||||
val ByteValueCodec = StreamCodec(DataInputStream::readByte, 1L, { s, v -> s.writeByte(v.toInt()) }) { a, b -> a == b }
|
val ByteValueCodec = StreamCodec(DataInputStream::readByte, 1L, { s, v -> s.writeByte(v.toInt()) }) { a, b -> a == b }
|
||||||
|
@ -2,6 +2,9 @@ package ru.dbotthepony.mc.otm.menu
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableList
|
import com.google.common.collect.ImmutableList
|
||||||
import com.mojang.datafixers.util.Pair
|
import com.mojang.datafixers.util.Pair
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntArrayList
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntCollection
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntList
|
||||||
import it.unimi.dsi.fastutil.io.FastByteArrayInputStream
|
import it.unimi.dsi.fastutil.io.FastByteArrayInputStream
|
||||||
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
|
import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectFunction
|
import it.unimi.dsi.fastutil.objects.Reference2ObjectFunction
|
||||||
@ -36,7 +39,9 @@ import ru.dbotthepony.mc.otm.compat.curios.isCurioSlot
|
|||||||
import ru.dbotthepony.mc.otm.container.IMatteryContainer
|
import ru.dbotthepony.mc.otm.container.IMatteryContainer
|
||||||
import ru.dbotthepony.mc.otm.container.ItemFilter
|
import ru.dbotthepony.mc.otm.container.ItemFilter
|
||||||
import ru.dbotthepony.mc.otm.container.UpgradeContainer
|
import ru.dbotthepony.mc.otm.container.UpgradeContainer
|
||||||
|
import ru.dbotthepony.mc.otm.container.computeSortedIndices
|
||||||
import ru.dbotthepony.mc.otm.container.sort
|
import ru.dbotthepony.mc.otm.container.sort
|
||||||
|
import ru.dbotthepony.mc.otm.container.sortWithIndices
|
||||||
import ru.dbotthepony.mc.otm.core.GetterSetter
|
import ru.dbotthepony.mc.otm.core.GetterSetter
|
||||||
import ru.dbotthepony.mc.otm.core.collect.ConditionalEnumSet
|
import ru.dbotthepony.mc.otm.core.collect.ConditionalEnumSet
|
||||||
import ru.dbotthepony.mc.otm.core.collect.ConditionalSet
|
import ru.dbotthepony.mc.otm.core.collect.ConditionalSet
|
||||||
@ -45,6 +50,7 @@ import ru.dbotthepony.mc.otm.core.math.Decimal
|
|||||||
import ru.dbotthepony.mc.otm.core.util.BigDecimalValueCodec
|
import ru.dbotthepony.mc.otm.core.util.BigDecimalValueCodec
|
||||||
import ru.dbotthepony.mc.otm.core.util.BinaryStringCodec
|
import ru.dbotthepony.mc.otm.core.util.BinaryStringCodec
|
||||||
import ru.dbotthepony.mc.otm.core.util.BooleanValueCodec
|
import ru.dbotthepony.mc.otm.core.util.BooleanValueCodec
|
||||||
|
import ru.dbotthepony.mc.otm.core.util.CollectionStreamCodec
|
||||||
import ru.dbotthepony.mc.otm.core.util.IStreamCodec
|
import ru.dbotthepony.mc.otm.core.util.IStreamCodec
|
||||||
import ru.dbotthepony.mc.otm.core.util.ItemStackValueCodec
|
import ru.dbotthepony.mc.otm.core.util.ItemStackValueCodec
|
||||||
import ru.dbotthepony.mc.otm.core.util.ItemValueCodec
|
import ru.dbotthepony.mc.otm.core.util.ItemValueCodec
|
||||||
@ -173,6 +179,18 @@ abstract class MatteryMenu(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inner class SortInput(val container: Container, settings: IItemStackSortingSettings?) {
|
||||||
|
val settings = IItemStackSortingSettings.inputs(this@MatteryMenu, settings)
|
||||||
|
|
||||||
|
val input = PlayerInput(CollectionStreamCodec(VarIntValueCodec, ::IntArrayList) as IStreamCodec<IntCollection>) {
|
||||||
|
container.sortWithIndices(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clientInput() {
|
||||||
|
input.accept(container.computeSortedIndices(settings.actualComparator))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun oneWayInput(allowSpectators: Boolean = false, handler: () -> Unit): PlayerInput<Nothing?> {
|
fun oneWayInput(allowSpectators: Boolean = false, handler: () -> Unit): PlayerInput<Nothing?> {
|
||||||
return PlayerInput(NullValueCodec, allowSpectators) {
|
return PlayerInput(NullValueCodec, allowSpectators) {
|
||||||
handler.invoke()
|
handler.invoke()
|
||||||
@ -206,7 +224,7 @@ abstract class MatteryMenu(
|
|||||||
|
|
||||||
val exopackPowerLevel = ProfiledLevelGaugeWidget<ProfiledEnergyStorage<*>>(mSynchronizer)
|
val exopackPowerLevel = ProfiledLevelGaugeWidget<ProfiledEnergyStorage<*>>(mSynchronizer)
|
||||||
|
|
||||||
var sortInventoryInput: PlayerInput<Nothing?>? = null
|
var sortInventoryInput: SortInput? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
val playerSortSettings = IItemStackSortingSettings.inputs(this, player.matteryPlayer?.sortingSettings)
|
val playerSortSettings = IItemStackSortingSettings.inputs(this, player.matteryPlayer?.sortingSettings)
|
||||||
@ -353,9 +371,7 @@ abstract class MatteryMenu(
|
|||||||
exopackPowerLevel.with(mattery.exopackEnergy)
|
exopackPowerLevel.with(mattery.exopackEnergy)
|
||||||
}
|
}
|
||||||
|
|
||||||
sortInventoryInput = PlayerInput(NullValueCodec) {
|
sortInventoryInput = SortInput(mattery.inventoryAndExopackNoHotbar, playerSortSettings)
|
||||||
mattery.inventoryAndExopackNoHotbar.sort(playerSortSettings.actualComparator)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var broadcastOnce = false
|
private var broadcastOnce = false
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
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
|
||||||
@ -19,12 +20,11 @@ class CargoCrateMenu(
|
|||||||
inventory: Inventory,
|
inventory: Inventory,
|
||||||
tile: CargoCrateBlockEntity? = null
|
tile: CargoCrateBlockEntity? = null
|
||||||
) : MatteryMenu(MMenus.CARGO_CRATE, containerId, inventory, tile) {
|
) : MatteryMenu(MMenus.CARGO_CRATE, containerId, inventory, tile) {
|
||||||
val storageSlots = makeSlots(tile?.container ?: SimpleContainer(CargoCrateBlockEntity.CAPACITY), ::UserFilteredSlot)
|
val actualContainer: Container = tile?.container ?: SimpleContainer(CargoCrateBlockEntity.CAPACITY)
|
||||||
|
val storageSlots = makeSlots(actualContainer, ::UserFilteredSlot)
|
||||||
private val trackedPlayerOpen = !inventory.player.isSpectator
|
private val trackedPlayerOpen = !inventory.player.isSpectator
|
||||||
|
|
||||||
val sort = PlayerInput(NullValueCodec) {
|
val sort = SortInput(actualContainer, playerSortSettings)
|
||||||
tile?.container?.sort(playerSortSettings.actualComparator)
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (trackedPlayerOpen) {
|
if (trackedPlayerOpen) {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
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
|
||||||
@ -17,13 +18,12 @@ class MinecartCargoCrateMenu(
|
|||||||
inventory: Inventory,
|
inventory: Inventory,
|
||||||
val cart: MinecartCargoCrate? = null
|
val cart: MinecartCargoCrate? = null
|
||||||
) : MatteryMenu(MMenus.CARGO_CRATE, containerId, inventory) {
|
) : MatteryMenu(MMenus.CARGO_CRATE, containerId, inventory) {
|
||||||
val storageSlots = makeSlots(cart ?: SimpleContainer(CargoCrateBlockEntity.CAPACITY), ::MatterySlot)
|
val actualContainer: Container = cart ?: SimpleContainer(CargoCrateBlockEntity.CAPACITY)
|
||||||
|
val storageSlots = makeSlots(actualContainer, ::MatterySlot)
|
||||||
|
|
||||||
private val trackedPlayerOpen = !inventory.player.isSpectator
|
private val trackedPlayerOpen = !inventory.player.isSpectator
|
||||||
|
|
||||||
val sort = PlayerInput(NullValueCodec) {
|
val sort = SortInput(actualContainer, playerSortSettings)
|
||||||
cart?.sort(playerSortSettings.actualComparator)
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (trackedPlayerOpen) {
|
if (trackedPlayerOpen) {
|
||||||
|
Loading…
Reference in New Issue
Block a user