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)
|
||||
} as EditablePanel<ExopackInventoryScreen>)
|
||||
|
||||
|
||||
if (menu.sortInventoryInput != null) {
|
||||
controls.addButton(LargeRectangleButtonPanel.input(
|
||||
this,
|
||||
controls,
|
||||
menu.sortInventoryInput!!,
|
||||
icon = Widgets18.SORT_NOW
|
||||
).also { it.tooltips.add(TranslatableComponent("otm.gui.sorting.sort_now")) })
|
||||
controls.customSortingButtons(menu.sortInventoryInput!!)
|
||||
}
|
||||
|
||||
var x = -4f
|
||||
|
@ -308,7 +308,7 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
||||
}
|
||||
|
||||
if (menu.sortInventoryInput != null) {
|
||||
deviceControls.customSortingButtons(menu.playerSortSettings, menu.sortInventoryInput!!)
|
||||
deviceControls.customSortingButtons(menu.sortInventoryInput!!)
|
||||
}
|
||||
|
||||
if (menu.exopackChargeSlots.isNotEmpty()) {
|
||||
|
@ -28,7 +28,7 @@ class CargoCrateScreen(menu: CargoCrateMenu, inventory: Inventory, title: Compon
|
||||
|
||||
val controls = DeviceControls(this, frame)
|
||||
|
||||
controls.customSortingButtons(menu.playerSortSettings, menu.sort)
|
||||
controls.customSortingButtons(menu.sort)
|
||||
|
||||
return frame
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ class MinecartCargoCrateScreen(menu: MinecartCargoCrateMenu, inventory: Inventor
|
||||
|
||||
val controls = DeviceControls(this, frame)
|
||||
|
||||
controls.customSortingButtons(menu.playerSortSettings, menu.sort)
|
||||
controls.customSortingButtons(menu.sort)
|
||||
|
||||
return frame
|
||||
}
|
||||
|
@ -410,7 +410,7 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
||||
return result
|
||||
}
|
||||
|
||||
fun customSortingButtons(settings: IItemStackSortingSettings, input: MatteryMenu.PlayerInput<Nothing?>) {
|
||||
fun customSortingButtons(input: MatteryMenu.SortInput) {
|
||||
addButton(object : LargeRectangleButtonPanel<S>(screen, this@DeviceControls) {
|
||||
var buttons: List<EditablePanel<*>>? = null
|
||||
|
||||
@ -427,15 +427,15 @@ class DeviceControls<out S : MatteryScreen<*>>(
|
||||
}
|
||||
|
||||
override var isDisabled: Boolean
|
||||
get() = !input.test(minecraft.player)
|
||||
get() = !input.input.test(minecraft.player)
|
||||
set(value) {}
|
||||
|
||||
override fun onClick(mouseButton: Int) {
|
||||
if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) {
|
||||
input.accept(null)
|
||||
input.clientInput()
|
||||
} else {
|
||||
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) {
|
||||
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.IntArrayList
|
||||
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.IntIterator
|
||||
import it.unimi.dsi.fastutil.ints.IntList
|
||||
import it.unimi.dsi.fastutil.ints.IntSet
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
|
||||
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 ru.dbotthepony.mc.otm.container.util.IContainerSlot
|
||||
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.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
|
||||
@ -318,3 +319,62 @@ fun Container.sort(comparator: Comparator<ItemStack> = ItemStackSorter.DEFAULT)
|
||||
slots.forEach { it.remove() }
|
||||
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 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 }
|
||||
|
@ -2,6 +2,9 @@ package ru.dbotthepony.mc.otm.menu
|
||||
|
||||
import com.google.common.collect.ImmutableList
|
||||
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.FastByteArrayOutputStream
|
||||
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.ItemFilter
|
||||
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.sortWithIndices
|
||||
import ru.dbotthepony.mc.otm.core.GetterSetter
|
||||
import ru.dbotthepony.mc.otm.core.collect.ConditionalEnumSet
|
||||
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.BinaryStringCodec
|
||||
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.ItemStackValueCodec
|
||||
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?> {
|
||||
return PlayerInput(NullValueCodec, allowSpectators) {
|
||||
handler.invoke()
|
||||
@ -206,7 +224,7 @@ abstract class MatteryMenu(
|
||||
|
||||
val exopackPowerLevel = ProfiledLevelGaugeWidget<ProfiledEnergyStorage<*>>(mSynchronizer)
|
||||
|
||||
var sortInventoryInput: PlayerInput<Nothing?>? = null
|
||||
var sortInventoryInput: SortInput? = null
|
||||
private set
|
||||
|
||||
val playerSortSettings = IItemStackSortingSettings.inputs(this, player.matteryPlayer?.sortingSettings)
|
||||
@ -353,9 +371,7 @@ abstract class MatteryMenu(
|
||||
exopackPowerLevel.with(mattery.exopackEnergy)
|
||||
}
|
||||
|
||||
sortInventoryInput = PlayerInput(NullValueCodec) {
|
||||
mattery.inventoryAndExopackNoHotbar.sort(playerSortSettings.actualComparator)
|
||||
}
|
||||
sortInventoryInput = SortInput(mattery.inventoryAndExopackNoHotbar, playerSortSettings)
|
||||
}
|
||||
|
||||
private var broadcastOnce = false
|
||||
|
@ -1,5 +1,6 @@
|
||||
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
|
||||
@ -19,12 +20,11 @@ class CargoCrateMenu(
|
||||
inventory: Inventory,
|
||||
tile: CargoCrateBlockEntity? = null
|
||||
) : 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
|
||||
|
||||
val sort = PlayerInput(NullValueCodec) {
|
||||
tile?.container?.sort(playerSortSettings.actualComparator)
|
||||
}
|
||||
val sort = SortInput(actualContainer, playerSortSettings)
|
||||
|
||||
init {
|
||||
if (trackedPlayerOpen) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
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
|
||||
@ -17,13 +18,12 @@ class MinecartCargoCrateMenu(
|
||||
inventory: Inventory,
|
||||
val cart: MinecartCargoCrate? = null
|
||||
) : 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
|
||||
|
||||
val sort = PlayerInput(NullValueCodec) {
|
||||
cart?.sort(playerSortSettings.actualComparator)
|
||||
}
|
||||
val sort = SortInput(actualContainer, playerSortSettings)
|
||||
|
||||
init {
|
||||
if (trackedPlayerOpen) {
|
||||
|
Loading…
Reference in New Issue
Block a user