From 660e41db88c99be23dd1907416bae5fdb389833e Mon Sep 17 00:00:00 2001 From: Bixilon Date: Fri, 18 Nov 2022 10:24:38 +0100 Subject: [PATCH] rework some container sections --- .../click/FastMoveContainerActionTest.kt | 14 ++---- .../minosoft/data/container/Container.kt | 10 ++++- .../minosoft/data/container/ContainerUtil.kt | 4 ++ .../InventorySynchronizedContainer.kt | 3 +- .../click/FastMoveContainerAction.kt | 44 +++++++++++-------- .../data/container/slots/FuelSlotType.kt | 1 - .../data/container/types/CraftingContainer.kt | 11 ++++- .../container/types/EnchantingContainer.kt | 22 +++++----- .../data/container/types/PlayerInventory.kt | 1 + .../types/generic/GenericContainer.kt | 19 +++----- .../processing/smelting/SmeltingContainer.kt | 18 ++++++-- 11 files changed, 87 insertions(+), 60 deletions(-) diff --git a/src/integration-test/kotlin/de/bixilon/minosoft/data/container/click/FastMoveContainerActionTest.kt b/src/integration-test/kotlin/de/bixilon/minosoft/data/container/click/FastMoveContainerActionTest.kt index d05c16e98..638079708 100644 --- a/src/integration-test/kotlin/de/bixilon/minosoft/data/container/click/FastMoveContainerActionTest.kt +++ b/src/integration-test/kotlin/de/bixilon/minosoft/data/container/click/FastMoveContainerActionTest.kt @@ -57,7 +57,7 @@ class FastMoveContainerActionTest { container.invokeAction(FastMoveContainerAction(0)) assertNull(container.floatingItem) assertEquals(container.slots, slotsOf(62 to ItemStack(AppleTestO.item, 9))) - connection.assertOnlyPacket(ContainerClickC2SP(9, container.serverRevision, 0, 1, 0, 0, slotsOf(62 to null, 0 to ItemStack(AppleTestO.item, count = 9)), null)) + connection.assertOnlyPacket(ContainerClickC2SP(9, container.serverRevision, 0, 1, 0, 0, slotsOf(0 to null, 62 to ItemStack(AppleTestO.item, count = 9)), null)) } fun fullHotbarChestToHotbar() { @@ -116,11 +116,7 @@ class FastMoveContainerActionTest { container.invokeAction(FastMoveContainerAction(30)) assertNull(container.floatingItem) - assertNull(container[0]) - assertNull(container[1]) - assertNull(container[2]) - assertNull(container[30]) - assertEquals(container[3], ItemStack(EggTestO.item, 12)) + assertEquals(container.slots, slotsOf(3 to ItemStack(EggTestO.item, 12))) connection.assertOnlyPacket(ContainerClickC2SP(9, container.serverRevision, 0, 1, 0, 0, slotsOf(30 to null, 3 to ItemStack(AppleTestO.item, count = 8)), null)) } @@ -133,11 +129,9 @@ class FastMoveContainerActionTest { container.invokeAction(FastMoveContainerAction(30)) assertNull(container.floatingItem) - assertNull(container[0]) - assertEquals(container[1], ItemStack(CoalTest0.item, 12)) - assertNull(container[2]) + assertEquals(container.slots, slotsOf(1 to ItemStack(CoalTest0.item, 12))) - connection.assertOnlyPacket(ContainerClickC2SP(9, container.serverRevision, 0, 1, 0, 0, slotsOf(30 to null, 1 to ItemStack(AppleTestO.item, count = 8)), null)) + connection.assertOnlyPacket(ContainerClickC2SP(9, container.serverRevision, 30, 1, 0, 0, slotsOf(30 to null, 1 to ItemStack(CoalTest0.item, count = 12)), null)) } // TODO: revert, full container diff --git a/src/main/java/de/bixilon/minosoft/data/container/Container.kt b/src/main/java/de/bixilon/minosoft/data/container/Container.kt index 59ae6615a..be54dbfc5 100644 --- a/src/main/java/de/bixilon/minosoft/data/container/Container.kt +++ b/src/main/java/de/bixilon/minosoft/data/container/Container.kt @@ -87,7 +87,15 @@ open class Container( open fun getSlotType(slotId: Int): SlotType? = DefaultSlotType open fun getSlotSwap(slot: SlotSwapContainerAction.SwapTargets): Int? = null - open fun getSection(slotId: Int): Int? = null + + open fun getSection(slotId: Int): Int? { + for ((index, section) in sections.withIndex()) { + if (slotId in section) { + return index + } + } + return null + } operator fun get(slotId: Int): ItemStack? { try { diff --git a/src/main/java/de/bixilon/minosoft/data/container/ContainerUtil.kt b/src/main/java/de/bixilon/minosoft/data/container/ContainerUtil.kt index a6030f669..99ae05853 100644 --- a/src/main/java/de/bixilon/minosoft/data/container/ContainerUtil.kt +++ b/src/main/java/de/bixilon/minosoft/data/container/ContainerUtil.kt @@ -32,4 +32,8 @@ object ContainerUtil { return map } + + fun section(offset: Int, count: Int): IntRange { + return offset until offset + count + } } diff --git a/src/main/java/de/bixilon/minosoft/data/container/InventorySynchronizedContainer.kt b/src/main/java/de/bixilon/minosoft/data/container/InventorySynchronizedContainer.kt index 040878ad3..c1a4c648c 100644 --- a/src/main/java/de/bixilon/minosoft/data/container/InventorySynchronizedContainer.kt +++ b/src/main/java/de/bixilon/minosoft/data/container/InventorySynchronizedContainer.kt @@ -13,6 +13,7 @@ package de.bixilon.minosoft.data.container +import de.bixilon.minosoft.data.container.ContainerUtil.section import de.bixilon.minosoft.data.container.stack.ItemStack import de.bixilon.minosoft.data.container.types.PlayerInventory import de.bixilon.minosoft.data.registries.other.containers.ContainerType @@ -24,7 +25,7 @@ abstract class InventorySynchronizedContainer( type: ContainerType, title: ChatComponent? = null, protected var synchronizedSlots: IntRange, - protected var inventorySlots: IntRange = PlayerInventory.MAIN_SLOTS_START until (PlayerInventory.MAIN_SLOTS_START + PlayerInventory.MAIN_SLOTS), + protected var inventorySlots: IntRange = section(PlayerInventory.MAIN_SLOTS_START, PlayerInventory.MAIN_SLOTS), ) : Container(connection, type, title) { private val playerInventory = connection.player.inventory diff --git a/src/main/java/de/bixilon/minosoft/data/container/click/FastMoveContainerAction.kt b/src/main/java/de/bixilon/minosoft/data/container/click/FastMoveContainerAction.kt index 2da949570..3f89dcfd4 100644 --- a/src/main/java/de/bixilon/minosoft/data/container/click/FastMoveContainerAction.kt +++ b/src/main/java/de/bixilon/minosoft/data/container/click/FastMoveContainerAction.kt @@ -18,6 +18,7 @@ import de.bixilon.minosoft.data.container.stack.ItemStack import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.protocol.packets.c2s.play.container.ContainerClickC2SP import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap +import it.unimi.dsi.fastutil.ints.IntArrayList class FastMoveContainerAction( val slot: Int, @@ -32,13 +33,18 @@ class FastMoveContainerAction( val sourceSection = container.getSection(slot) ?: Int.MAX_VALUE // loop over all sections and get the lowest slot in the lowest section that fits best - val targets = Int2ObjectOpenHashMap() + val targets: MutableList = mutableListOf() for ((index, section) in container.sections.withIndex()) { if (index == sourceSection) { // we don't want to swap into the same section, that is just useless // ToDo: Is this vanilla behavior? continue } + if (section.isEmpty()) { + continue + } + val list = IntArrayList() + targets += list for (slot in section) { val content = container.slots[slot] if (content != null && !source.matches(content)) { // only check slots that are not empty @@ -49,26 +55,28 @@ class FastMoveContainerAction( // this item is not allowed in this slot (e.g. blocks in armor slot) continue } - - targets[slot] = content + list += slot } } val changes: Int2ObjectOpenHashMap = Int2ObjectOpenHashMap() - for ((slot, content) in targets.toSortedMap()) { - if (content == null) { - changes[slot] = source - changes[this.slot] = null - container._set(slot, source) - container._set(this.slot, null) - break - } - val countToPut = source.item._count - (source.item.item.maxStackSize - content.item._count) - source.item._count -= countToPut - content.item._count += countToPut - changes[slot] = content - changes[this.slot] = source // duplicated - if (source.item._count <= 0) { - break + sections@ for (list in targets) { + for (slot in list.intIterator()) { + val content = container.slots[slot] + if (content == null) { + changes[slot] = source + changes[this.slot] = null + container._set(slot, source) + container._set(this.slot, null) + break@sections + } + val countToPut = source.item._count - (source.item.item.maxStackSize - content.item._count) + source.item._count -= countToPut + content.item._count += countToPut + changes[slot] = content + changes[this.slot] = source // duplicated + if (source.item._count <= 0) { + break + } } } diff --git a/src/main/java/de/bixilon/minosoft/data/container/slots/FuelSlotType.kt b/src/main/java/de/bixilon/minosoft/data/container/slots/FuelSlotType.kt index 993d0954e..d3d2b3881 100644 --- a/src/main/java/de/bixilon/minosoft/data/container/slots/FuelSlotType.kt +++ b/src/main/java/de/bixilon/minosoft/data/container/slots/FuelSlotType.kt @@ -18,7 +18,6 @@ import de.bixilon.minosoft.data.container.stack.ItemStack import de.bixilon.minosoft.data.registries.fluid.lava.LavaFluid import de.bixilon.minosoft.data.registries.item.items.bucket.BucketItem -@Deprecated("ToDo") object FuelSlotType : SlotType { override fun canPut(container: Container, slot: Int, stack: ItemStack): Boolean { diff --git a/src/main/java/de/bixilon/minosoft/data/container/types/CraftingContainer.kt b/src/main/java/de/bixilon/minosoft/data/container/types/CraftingContainer.kt index f1dc7db30..94108ee81 100644 --- a/src/main/java/de/bixilon/minosoft/data/container/types/CraftingContainer.kt +++ b/src/main/java/de/bixilon/minosoft/data/container/types/CraftingContainer.kt @@ -13,6 +13,7 @@ package de.bixilon.minosoft.data.container.types +import de.bixilon.minosoft.data.container.ContainerUtil.section import de.bixilon.minosoft.data.container.InventorySynchronizedContainer import de.bixilon.minosoft.data.container.click.SlotSwapContainerAction import de.bixilon.minosoft.data.container.slots.DefaultSlotType @@ -26,8 +27,8 @@ import de.bixilon.minosoft.data.text.ChatComponent import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.util.KUtil.toResourceLocation -class CraftingContainer(connection: PlayConnection, type: ContainerType, title: ChatComponent?) : InventorySynchronizedContainer(connection, type, title, (CRAFTING_SLOTS + 1)..(CRAFTING_SLOTS + PlayerInventory.MAIN_SLOTS)) { - override val sections: Array = arrayOf(0 until 1, 1 until 1 + CRAFTING_SLOTS, 1 + CRAFTING_SLOTS until 1 + CRAFTING_SLOTS + PlayerInventory.MAIN_SLOTS) +class CraftingContainer(connection: PlayConnection, type: ContainerType, title: ChatComponent?) : InventorySynchronizedContainer(connection, type, title, section(CRAFTING_SLOTS + 1, PlayerInventory.MAIN_SLOTS)) { + override val sections: Array get() = SECTIONS override fun getSlotType(slotId: Int): SlotType? { if (slotId == 0) { @@ -64,6 +65,12 @@ class CraftingContainer(connection: PlayConnection, type: ContainerType, title: override val RESOURCE_LOCATION: ResourceLocation = "minecraft:crafting".toResourceLocation() override val ALIASES: Set = setOf("minecraft:crafting_table".toResourceLocation()) const val CRAFTING_SLOTS = 3 * 3 + val SECTIONS: Array = arrayOf( + // crafting slots are not shift clickable, no section + section(CRAFTING_SLOTS + 1 + PlayerInventory.PASSIVE_SLOTS, PlayerInventory.HOTBAR_SLOTS), + section(CRAFTING_SLOTS + 1, PlayerInventory.PASSIVE_SLOTS), + ) + override fun build(connection: PlayConnection, type: ContainerType, title: ChatComponent?): CraftingContainer { return CraftingContainer(connection, type, title) diff --git a/src/main/java/de/bixilon/minosoft/data/container/types/EnchantingContainer.kt b/src/main/java/de/bixilon/minosoft/data/container/types/EnchantingContainer.kt index bd60ae29f..b3d99e4ac 100644 --- a/src/main/java/de/bixilon/minosoft/data/container/types/EnchantingContainer.kt +++ b/src/main/java/de/bixilon/minosoft/data/container/types/EnchantingContainer.kt @@ -14,6 +14,7 @@ package de.bixilon.minosoft.data.container.types import de.bixilon.minosoft.data.container.Container +import de.bixilon.minosoft.data.container.ContainerUtil.section import de.bixilon.minosoft.data.container.InventorySynchronizedContainer import de.bixilon.minosoft.data.container.click.SlotSwapContainerAction import de.bixilon.minosoft.data.container.slots.DefaultSlotType @@ -30,8 +31,8 @@ import de.bixilon.minosoft.data.text.ChatComponent import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection import de.bixilon.minosoft.util.KUtil.toResourceLocation -class EnchantingContainer(connection: PlayConnection, type: ContainerType, title: ChatComponent?) : InventorySynchronizedContainer(connection, type, title, ENCHANTING_SLOTS until (ENCHANTING_SLOTS + PlayerInventory.MAIN_SLOTS)) { - override val sections: Array = arrayOf(0 until ENCHANTING_SLOTS, ENCHANTING_SLOTS until ENCHANTING_SLOTS + PlayerInventory.MAIN_SLOTS) +class EnchantingContainer(connection: PlayConnection, type: ContainerType, title: ChatComponent?) : InventorySynchronizedContainer(connection, type, title, section(ENCHANTING_SLOTS, PlayerInventory.MAIN_SLOTS)) { + override val sections: Array get() = SECTIONS val costs = IntArray(ENCHANTING_OPTIONS) { -1 } val enchantments: Array = arrayOfNulls(ENCHANTING_OPTIONS) var enchantmentLevels = IntArray(ENCHANTING_OPTIONS) { -1 } @@ -47,16 +48,6 @@ class EnchantingContainer(connection: PlayConnection, type: ContainerType, title } } - override fun getSection(slotId: Int): Int? { - if (slotId in 0..1) { - return 0 - } - if (slotId in ENCHANTING_SLOTS..ENCHANTING_SLOTS + PlayerInventory.MAIN_SLOTS) { - return 1 - } - return null - } - override fun getSlotSwap(slot: SlotSwapContainerAction.SwapTargets): Int? { if (slot == SlotSwapContainerAction.SwapTargets.OFFHAND) { return null // ToDo: It is possible to press F in vanilla, but there is no slot for it @@ -87,6 +78,13 @@ class EnchantingContainer(connection: PlayConnection, type: ContainerType, title const val ENCHANTING_SLOTS = 2 const val ENCHANTING_OPTIONS = 3 + + private val SECTIONS: Array = arrayOf( + section(0, ENCHANTING_SLOTS), + section(ENCHANTING_SLOTS + PlayerInventory.PASSIVE_SLOTS, PlayerInventory.HOTBAR_SLOTS), + section(ENCHANTING_SLOTS, PlayerInventory.PASSIVE_SLOTS), + ) + override fun build(connection: PlayConnection, type: ContainerType, title: ChatComponent?): EnchantingContainer { return EnchantingContainer(connection, type, title) } diff --git a/src/main/java/de/bixilon/minosoft/data/container/types/PlayerInventory.kt b/src/main/java/de/bixilon/minosoft/data/container/types/PlayerInventory.kt index f0d044e00..54da90018 100644 --- a/src/main/java/de/bixilon/minosoft/data/container/types/PlayerInventory.kt +++ b/src/main/java/de/bixilon/minosoft/data/container/types/PlayerInventory.kt @@ -155,6 +155,7 @@ class PlayerInventory(connection: PlayConnection) : Container(connection = conne const val MAIN_SLOTS_PER_ROW = 9 const val MAIN_ROWS = 4 + const val PASSIVE_SLOTS = MAIN_SLOTS_PER_ROW * (MAIN_ROWS - 1) const val MAIN_SLOTS = MAIN_SLOTS_PER_ROW * MAIN_ROWS const val MAIN_SLOTS_START = ARMOR_OFFSET + 4 diff --git a/src/main/java/de/bixilon/minosoft/data/container/types/generic/GenericContainer.kt b/src/main/java/de/bixilon/minosoft/data/container/types/generic/GenericContainer.kt index 2341ce108..4ada41fde 100644 --- a/src/main/java/de/bixilon/minosoft/data/container/types/generic/GenericContainer.kt +++ b/src/main/java/de/bixilon/minosoft/data/container/types/generic/GenericContainer.kt @@ -13,6 +13,7 @@ package de.bixilon.minosoft.data.container.types.generic +import de.bixilon.minosoft.data.container.ContainerUtil.section import de.bixilon.minosoft.data.container.InventorySynchronizedContainer import de.bixilon.minosoft.data.container.click.SlotSwapContainerAction import de.bixilon.minosoft.data.container.slots.DefaultSlotType @@ -27,8 +28,12 @@ abstract class GenericContainer( connection: PlayConnection, type: ContainerType, title: ChatComponent?, -) : InventorySynchronizedContainer(connection, type, title, (rows * SLOTS_PER_ROW) until (rows * SLOTS_PER_ROW + PlayerInventory.MAIN_SLOTS)) { - override val sections: Array = arrayOf(0 until rows * SLOTS_PER_ROW, rows * SLOTS_PER_ROW + 1 until rows * SLOTS_PER_ROW + PlayerInventory.MAIN_SLOTS) +) : InventorySynchronizedContainer(connection, type, title, section(rows * SLOTS_PER_ROW, PlayerInventory.MAIN_SLOTS)) { + override val sections: Array = arrayOf( + section(0, rows * SLOTS_PER_ROW), + section(rows * SLOTS_PER_ROW + PlayerInventory.PASSIVE_SLOTS, PlayerInventory.HOTBAR_SLOTS), + section(rows * SLOTS_PER_ROW, PlayerInventory.PASSIVE_SLOTS), + ) override fun getSlotType(slotId: Int): SlotType? { if (slotId in 0 until rows * SLOTS_PER_ROW + PlayerInventory.MAIN_SLOTS) { @@ -37,16 +42,6 @@ abstract class GenericContainer( return null } - override fun getSection(slotId: Int): Int? { - if (slotId in 0 until rows * SLOTS_PER_ROW) { - return 0 - } - if (slotId in rows * SLOTS_PER_ROW until rows * SLOTS_PER_ROW + PlayerInventory.MAIN_SLOTS) { - return 1 - } - return null - } - override fun getSlotSwap(slot: SlotSwapContainerAction.SwapTargets): Int? { if (slot == SlotSwapContainerAction.SwapTargets.OFFHAND) { return null // ToDo: It is possible to press F in vanilla, but there is no slot for it diff --git a/src/main/java/de/bixilon/minosoft/data/container/types/processing/smelting/SmeltingContainer.kt b/src/main/java/de/bixilon/minosoft/data/container/types/processing/smelting/SmeltingContainer.kt index 9486caae1..aa8968b7f 100644 --- a/src/main/java/de/bixilon/minosoft/data/container/types/processing/smelting/SmeltingContainer.kt +++ b/src/main/java/de/bixilon/minosoft/data/container/types/processing/smelting/SmeltingContainer.kt @@ -37,10 +37,12 @@ abstract class SmeltingContainer(connection: PlayConnection, type: ContainerType var maxFuel: Int = 0 private set + override val sections: Array get() = SECTIONS + override fun getSlotType(slotId: Int): SlotType? { if (slotId == 0) { - return DefaultSlotType // ToDo: only smeltable items + return DefaultSlotType // ToDo: only smeltable items (check recipes) } if (slotId == 1) { return FuelSlotType @@ -58,12 +60,15 @@ abstract class SmeltingContainer(connection: PlayConnection, type: ContainerType if (slotId == 2) { return 0 } - if (slotId == 0 || slotId == 1) { + if (slotId == 1) { return 1 } - if (slotId in SMELTING_SLOTS until SMELTING_SLOTS + PlayerInventory.MAIN_SLOTS) { + if (slotId == 0) { return 2 } + if (slotId in SMELTING_SLOTS until SMELTING_SLOTS + PlayerInventory.MAIN_SLOTS) { + return 3 + } return null } @@ -86,5 +91,12 @@ abstract class SmeltingContainer(connection: PlayConnection, type: ContainerType companion object { const val SMELTING_SLOTS = 3 + + val SECTIONS: Array = arrayOf( + 2..2, + 1..1, + 0..0, + SMELTING_SLOTS..SMELTING_SLOTS + PlayerInventory.MAIN_SLOTS, + ) } }