From ca6ff30414f5006f618b3f5007d0504faba0749e Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 27 Feb 2025 19:19:33 +0700 Subject: [PATCH 001/154] Initial code for new containers --- .../mc/otm/container/ContainerHelpers.kt | 107 +----- .../mc/otm/container/ContainerSlot.kt | 171 +++++++++ .../mc/otm/container/IContainerSlot.kt | 79 ++-- .../mc/otm/container/IEnhancedContainer.kt | 338 ++++++++++++++++++ .../otm/container/IFilteredContainerSlot.kt | 29 ++ .../IFilteredSlottedContainerSlot.kt | 9 + .../mc/otm/container/IMatteryContainer.kt | 41 +-- .../mc/otm/container/ISlottedContainer.kt | 220 ++++++++++++ .../mc/otm/container/ISlottedContainerSlot.kt | 95 +++++ .../mc/otm/container/MatteryContainer.kt | 36 +- .../mc/otm/container/SlottedContainer.kt | 177 +++++++++ .../otm/container/SlottedContainerBuilder.kt | 48 +++ .../mc/otm/container/util/Iterators.kt | 49 +-- .../mc/otm/core/collect/IntRange2Set.kt | 206 +++++++++++ .../mc/otm/core/collect/Iterables.kt | 30 ++ 15 files changed, 1430 insertions(+), 205 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerSlot.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredSlottedContainerSlot.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainerSlot.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainer.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainerBuilder.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/IntRange2Set.kt 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 42f781e8f..84b25bfe9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerHelpers.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerHelpers.kt @@ -9,6 +9,7 @@ import it.unimi.dsi.fastutil.ints.IntIterator import it.unimi.dsi.fastutil.ints.IntList import it.unimi.dsi.fastutil.ints.IntOpenHashSet import it.unimi.dsi.fastutil.ints.IntSet +import it.unimi.dsi.fastutil.ints.IntSortedSet import it.unimi.dsi.fastutil.objects.Object2ObjectFunction import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap import it.unimi.dsi.fastutil.objects.ObjectArrayList @@ -22,6 +23,7 @@ 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.IntRange2Set import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.collect.toList import ru.dbotthepony.mc.otm.core.isNotEmpty @@ -38,89 +40,12 @@ inline operator fun Container.get(index: Int): ItemStack = getItem(index) @Suppress("nothing_to_inline") inline operator fun IFluidHandler.get(index: Int) = getFluidInTank(index) -val Container.slotRange: IntIterable get() { - return IntIterable { - val i = (0 until containerSize).iterator() - - object : IntIterator { - override fun hasNext(): Boolean { - return i.hasNext() - } - - override fun remove() { - throw UnsupportedOperationException() - } - - override fun nextInt(): Int { - return i.nextInt() - } - } - } +val Container.slotRange: IntRange2Set get() { + return IntRange2Set.openEnded(0, containerSize) } -fun Container.addItem(stack: ItemStack, simulate: Boolean, slots: IntIterable = slotRange): ItemStack { - if (this is IMatteryContainer) { - return this.addItem(stack, simulate, slots) - } - - if (stack.isEmpty) - return stack - - val copy = stack.copy() - - // двигаем в одинаковые слоты - var i = slots.intIterator() - - while (i.hasNext()) { - val slot = i.nextInt() - - if (ItemStack.isSameItemSameComponents(this[slot], copy)) { - val slotStack = this[slot] - val slotLimit = maxStackSize.coerceAtMost(slotStack.maxStackSize) - - if (slotStack.count < slotLimit) { - val newCount = (slotStack.count + copy.count).coerceAtMost(slotLimit) - val diff = newCount - slotStack.count - - if (!simulate) { - slotStack.count = newCount - setChanged() - } - - copy.shrink(diff) - - if (copy.isEmpty) { - return copy - } - } - } - } - - // двигаем в пустые слоты - i = slots.intIterator() - - while (i.hasNext()) { - val slot = i.nextInt() - - if (this[slot].isEmpty) { - val diff = copy.count.coerceAtMost(maxStackSize.coerceAtMost(copy.maxStackSize)) - - if (!simulate) { - val copyToPut = copy.copy() - copyToPut.count = diff - this[slot] = copyToPut - setChanged() - } - - copy.shrink(diff) - - if (copy.isEmpty) { - return copy - } - } - } - - return copy +fun Container.addItem(stack: ItemStack, simulate: Boolean, slots: IntSortedSet = slotRange): ItemStack { + return IEnhancedContainer.wrap(this).addItem(stack, simulate, slots) } fun Container.vanishCursedItems() { @@ -312,12 +237,18 @@ fun Container.sortWithIndices(sortedSlots: IntCollection) { if (value in 0 until containerSize && seen.add(value)) { val slot = containerSlot(value) - if ( - slot.isNotEmpty && - !slot.isForbiddenForAutomation && - slot.item.count <= slot.getMaxStackSize() && - (!slot.hasFilter || slot.getFilter() != slot.item.item || slot.getMaxStackSize() > 1) - ) { + val condition: Boolean + + if (slot is IFilteredContainerSlot) { + condition = slot.isNotEmpty && + !slot.isForbiddenForAutomation && + slot.item.count <= slot.maxStackSize(slot.item) && + (!slot.hasFilter || slot.filter != slot.item.item || slot.maxStackSize(slot.item) > 1) + } else { + condition = slot.isNotEmpty && slot.item.count <= slot.maxStackSize(slot.item) + } + + if (condition) { valid.add(slot) } } @@ -335,7 +266,7 @@ fun Container.computeSortedIndices(comparator: Comparator = ItemStack if (isEmpty) return IntList.of() - val slots = slotIterator().filter { !it.isForbiddenForAutomation && it.getMaxStackSize() >= it.item.count }.toList() + val slots = slotIterator().filter { (it !is IFilteredContainerSlot || !it.isForbiddenForAutomation) && it.maxStackSize(it.item) >= it.item.count }.toList() if (slots.isEmpty()) return IntList.of() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerSlot.kt new file mode 100644 index 000000000..027939b62 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerSlot.kt @@ -0,0 +1,171 @@ +package ru.dbotthepony.mc.otm.container + +import net.minecraft.core.HolderLookup +import net.minecraft.core.registries.BuiltInRegistries +import net.minecraft.nbt.CompoundTag +import net.minecraft.nbt.NbtOps +import net.minecraft.resources.ResourceLocation +import net.minecraft.world.item.Item +import net.minecraft.world.item.ItemStack +import net.neoforged.neoforge.common.util.INBTSerializable +import org.apache.logging.log4j.LogManager +import ru.dbotthepony.mc.otm.core.isNotEmpty +import ru.dbotthepony.mc.otm.core.nbt.set +import ru.dbotthepony.mc.otm.core.registryName +import ru.dbotthepony.mc.otm.data.getOrNull + +open class ContainerSlot( + final override val container: SlottedContainer, + final override val slot: Int +) : ISlottedContainerSlot, INBTSerializable { + private var _item: ItemStack = ItemStack.EMPTY + + final override var item: ItemStack + get() = _item + set(value) { + _item = value + setChanged() + } + + private var observedItem = ItemStack.EMPTY + + // called from inside setChanged + protected open fun notifyChanged(old: ItemStack) {} + + final override fun setChanged() { + observeChanges() + } + + /** + * Called when slot needs to be cleared of any data present + */ + open fun clear() { + _item = ItemStack.EMPTY + + if (observedItem.isNotEmpty) { + notifyChanged(observedItem) + } + + observedItem = ItemStack.EMPTY + } + + fun observeChanges(): Boolean { + if (observedItem.count != item.count || !ItemStack.isSameItemSameComponents(item, observedItem)) { + notifyChanged(observedItem) + observedItem = item.copy() + container.notifyChanged() + return true + } + + return false + } + + override fun remove(): ItemStack { + val item = item + + if (item.isEmpty) { + return ItemStack.EMPTY + } else { + this.item = ItemStack.EMPTY + return item + } + } + + override val maxStackSize: Int + get() = Item.DEFAULT_MAX_STACK_SIZE + + override fun remove(count: Int): ItemStack { + val item = item + + if (item.isEmpty) { + return ItemStack.EMPTY + } + + if (item.count >= count) { + this.item = ItemStack.EMPTY + return item + } else { + val split = item.split(count) + setChanged() + return split + } + } + + override fun serializeNBT(provider: HolderLookup.Provider): CompoundTag { + return CompoundTag().also { + it["item"] = ItemStack.OPTIONAL_CODEC.encodeStart(provider.createSerializationContext(NbtOps.INSTANCE), item) + .getOrThrow { RuntimeException("Unable to serialize $item in slot $slot: $it") } + } + } + + override fun deserializeNBT(provider: HolderLookup.Provider, nbt: CompoundTag) { + _item = ItemStack.OPTIONAL_CODEC.decode(provider.createSerializationContext(NbtOps.INSTANCE), nbt["item"]) + .ifError { LOGGER.error("Unable to deserialize item at slot $slot: ${it.message()}") } + .getOrNull()?.first ?: ItemStack.EMPTY + + observedItem = item.copy() + notifyChanged(ItemStack.EMPTY) + } + + open class Simple( + protected val listener: (new: ItemStack, old: ItemStack) -> Unit, + protected val maxStackSize: Int = Item.DEFAULT_MAX_STACK_SIZE, + ) : SlottedContainerBuilder.SlotProvider { + protected open inner class Instance(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) { + override val maxStackSize: Int + get() = this@Simple.maxStackSize + + override fun notifyChanged(old: ItemStack) { + super.notifyChanged(old) + listener(item, old) + } + } + + override fun create(container: SlottedContainer, index: Int): ContainerSlot { + return Instance(container, index) + } + } + + open class Filtered( + listener: (new: ItemStack, old: ItemStack) -> Unit, + maxStackSize: Int = Item.DEFAULT_MAX_STACK_SIZE, + ) : Simple(listener, maxStackSize) { + protected open inner class Instance(container: SlottedContainer, slot: Int) : Simple.Instance(container, slot), IFilteredSlottedContainerSlot { + override var filter: Item? = null + set(value) { + if (field !== value) { + field = value + container.notifyChanged() + } + } + + override fun clear() { + super.clear() + filter = null + } + + override fun serializeNBT(provider: HolderLookup.Provider): CompoundTag { + return super.serializeNBT(provider).also { + if (filter != null) + it["filter"] = filter!!.registryName!!.toString() + } + } + + override fun deserializeNBT(provider: HolderLookup.Provider, nbt: CompoundTag) { + super.deserializeNBT(provider, nbt) + + if ("filter" in nbt) { + filter = BuiltInRegistries.ITEM.get(ResourceLocation.parse(nbt.getString("filter"))) + } + } + } + + override fun create(container: SlottedContainer, index: Int): ContainerSlot { + return Instance(container, index) + } + } + + companion object { + private val LOGGER = LogManager.getLogger() + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IContainerSlot.kt index ee1ccfd22..e8860b407 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IContainerSlot.kt @@ -1,9 +1,7 @@ package ru.dbotthepony.mc.otm.container import net.minecraft.world.Container -import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack -import net.minecraft.world.item.Items import ru.dbotthepony.kommons.util.Delegate import ru.dbotthepony.mc.otm.core.isNotEmpty @@ -15,54 +13,67 @@ interface IContainerSlot : Delegate { val slot: Int val container: Container + fun setChanged() + var item: ItemStack + operator fun component1() = slot operator fun component2() = item - fun getMaxStackSize(item: ItemStack = this.item): Int { - return container.maxStackSize - } - - val isForbiddenForAutomation: Boolean get() { - return getFilter() === Items.AIR - } - - fun getFilter(): Item? + /** + * Max stack size regardless of item + * + * Prefer to use ItemStack version instead + */ + val maxStackSize: Int /** - * @return whenever the filter was set. Returns false only if container can't be filtered. + * Max amount of [item] that can be stored in this slot. + * + * This may be larger or smaller than value returned [ItemStack.getMaxStackSize], + * and as such returned value by this method should be ground truth */ - fun setFilter(filter: Item? = null): Boolean - - val hasFilter: Boolean - get() = getFilter() != null - - fun remove() { - container[slot] = ItemStack.EMPTY + fun maxStackSize(item: ItemStack): Int { + return maxStackSize.coerceAtMost(item.maxStackSize) } - fun remove(count: Int): ItemStack { - return container.removeItem(slot, count) - } + fun remove(): ItemStack + fun remove(count: Int): ItemStack override fun get(): ItemStack { - return container[slot] + return item } override fun accept(t: ItemStack) { - container[slot] = t + item = t } - fun setChanged() { - container.setChanged() - } - - var item: ItemStack - get() = container[slot] - set(value) { container[slot] = value } - val isEmpty: Boolean - get() = container[slot].isEmpty + get() = item.isEmpty val isNotEmpty: Boolean - get() = container[slot].isNotEmpty + get() = item.isNotEmpty + + class Simple(override val slot: Int, override val container: Container) : IContainerSlot { + override fun setChanged() { + container.setChanged() + } + + override var item: ItemStack + get() = container[slot] + set(value) { container[slot] = value } + override val maxStackSize: Int + get() = container.maxStackSize + + override fun remove(count: Int): ItemStack { + return container.removeItem(slot, count) + } + + override fun remove(): ItemStack { + return container.removeItemNoUpdate(slot) + } + + override fun maxStackSize(item: ItemStack): Int { + return maxStackSize.coerceAtMost(item.maxStackSize) + } + } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt new file mode 100644 index 000000000..f61bc6b86 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt @@ -0,0 +1,338 @@ +package ru.dbotthepony.mc.otm.container + +import it.unimi.dsi.fastutil.ints.IntSet +import net.minecraft.world.Container +import net.minecraft.world.entity.player.Player +import net.minecraft.world.item.Item +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import net.minecraft.world.item.crafting.RecipeInput +import ru.dbotthepony.mc.otm.core.collect.any +import ru.dbotthepony.mc.otm.core.collect.filter +import ru.dbotthepony.mc.otm.core.collect.map +import ru.dbotthepony.mc.otm.core.isNotEmpty +import java.util.function.Predicate + +/** + * "Backward-compatible" enhanced container interface, where all methods can be derived/emulated from existing [IContainer] ([Container]) code + * + * This is useful because it allows to interact with actually enhanced and regular containers through unified interface, + * and actual implementations of this interface are likely to provide efficient method implementations in place of derived/emulated ones. + */ +interface IEnhancedContainer : IContainer, RecipeInput, Iterable { + fun containerSlot(slot: Int): IContainerSlot { + return IContainerSlot.Simple(slot, this) + } + + fun slotIterator(): Iterator { + return (0 until containerSize).iterator().map { containerSlot(it) } + } + + fun nonEmptySlotIterator(): Iterator { + return (0 until containerSize).iterator().map { containerSlot(it) }.filter { it.isNotEmpty } + } + + private fun slotIterator(allowedSlots: IntSet, predicate: Predicate): IntIterator { + return object : IntIterator() { + private val parent = allowedSlots.intIterator() + private var foundNext = false + private var next = -1 + + private fun findNext() { + if (!foundNext) { + foundNext = true + next = -1 + + while (parent.hasNext()) { + val i = parent.nextInt() + + if (predicate.test(this@IEnhancedContainer[i])) { + next = i + break + } + } + } + } + + override fun nextInt(): Int { + findNext() + + if (next == -1) + throw NoSuchElementException() + + foundNext = false + val next = next + this.next = -1 + return next + } + + override fun hasNext(): Boolean { + findNext() + return next != -1 + } + } + } + + fun emptySlotIterator(allowedSlots: IntSet = slotRange): IntIterator { + return slotIterator(allowedSlots) { it.isEmpty } + } + + fun nonEmptySlotIterator(allowedSlots: IntSet = slotRange): IntIterator { + return slotIterator(allowedSlots) { it.isNotEmpty } + } + + fun slotWithItemIterator(item: Item, allowedSlots: IntSet = slotRange): IntIterator { + return slotIterator(allowedSlots) { it.isNotEmpty && it.item === item } + } + + fun nextEmptySlot(startIndex: Int): Int { + for (i in startIndex until containerSize) { + if (this[i].isEmpty) { + return i + } + } + + return -1 + } + + fun nextNonEmptySlot(startIndex: Int): Int { + for (i in startIndex until containerSize) { + if (this[i].isNotEmpty) { + return i + } + } + + return -1 + } + + fun nextSlotWithItem(startIndex: Int, item: Item): Int { + var find = nextNonEmptySlot(startIndex) + + while (find != -1 && this[find].item !== item) + find = nextNonEmptySlot(find + 1) + + return find + } + + fun setChanged(slot: Int) { + return setChanged() + } + + fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int { + return maxStackSize + } + + override fun iterator(): Iterator { + return (0 until containerSize).iterator().map { this[it] }.filter { it.isNotEmpty } + } + + override fun isEmpty(): Boolean { + return super.isEmpty() + } + + val hasEmptySlots: Boolean get() { + for (i in 0 until containerSize) { + if (this[i].isEmpty) { + return true + } + } + + return false + } + + override fun size(): Int { + return containerSize + } + + override fun countItem(item: Item): Int { + var count = 0 + + for (stack in this) { + if (stack.item === item) { + count += stack.count + } + } + + return count + } + + override fun hasAnyOf(items: Set): Boolean { + if (Items.AIR in items && hasEmptySlots) + return true + + return iterator().any { it.item in items } + } + + override fun hasAnyMatching(predicate: Predicate): Boolean { + if (predicate.test(ItemStack.EMPTY) && hasEmptySlots) + return true + + return iterator().any(predicate) + } + + fun toList(): MutableList { + val list = ArrayList(containerSize) + + for (i in 0 until containerSize) { + list.add(this[i]) + } + + return list + } + + fun addItem(stack: ItemStack, simulate: Boolean, slots: IntSet = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null): ItemStack { + if (stack.isEmpty || slots.isEmpty()) + return stack + + val copy = stack.copy() + + // двигаем в одинаковые слоты + for (slot in slotWithItemIterator(stack.item, slots)) { + if (ItemStack.isSameItemSameComponents(this[slot], copy)) { + val slotStack = this[slot] + val slotLimit = getMaxStackSize(slot, slotStack) + + if (slotStack.count < slotLimit) { + val newCount = (slotStack.count + copy.count).coerceAtMost(slotLimit) + val diff = newCount - slotStack.count + + if (!simulate) { + slotStack.count = newCount + setChanged(slot) + + if (popTime != null) { + slotStack.popTime = popTime + } + } + + copy.shrink(diff) + + if (copy.isEmpty) { + return ItemStack.EMPTY + } + } + } + } + + if (!onlyIntoExisting) { + // двигаем в пустые слоты + for (slot in emptySlotIterator(slots)) { + val diff = copy.count.coerceAtMost(getMaxStackSize(slot, stack)) + + if (!simulate) { + val copyToPut = copy.copy() + copyToPut.count = diff + this[slot] = copyToPut + setChanged() + } + + copy.shrink(diff) + + if (copy.isEmpty) + return ItemStack.EMPTY + } + } + + return copy + } + + /** + * Unlike [addItem], modifies original [stack] + * + * @return Whenever [stack] was modified + */ + fun consumeItem(stack: ItemStack, simulate: Boolean, slots: IntSet = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null): Boolean { + if (stack.isEmpty || slots.isEmpty()) + return false + + val result = addItem(stack, simulate, slots, onlyIntoExisting, popTime) + if (!simulate) stack.count = result.count + return result.count != stack.count + } + + fun fullyAddItem(stack: ItemStack, slots: IntSet = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null): Boolean { + if (!addItem(stack, true, slots, onlyIntoExisting, popTime).isEmpty) + return false + + return addItem(stack, false, slots, onlyIntoExisting, popTime).isEmpty + } + + private class Wrapper(private val parent: Container) : IEnhancedContainer { + override fun clearContent() { + return parent.clearContent() + } + + override fun setChanged() { + return parent.setChanged() + } + + override fun getContainerSize(): Int { + return parent.containerSize + } + + override fun getItem(slot: Int): ItemStack { + return parent.getItem(slot) + } + + override fun removeItem(slot: Int, amount: Int): ItemStack { + return parent.removeItem(slot, amount) + } + + override fun removeItemNoUpdate(slot: Int): ItemStack { + return parent.removeItemNoUpdate(slot) + } + + override fun setItem(slot: Int, itemStack: ItemStack) { + return parent.setItem(slot, itemStack) + } + + override fun stillValid(player: Player): Boolean { + return parent.stillValid(player) + } + + override fun getMaxStackSize(): Int { + return parent.maxStackSize + } + + override fun startOpen(player: Player) { + parent.startOpen(player) + } + + override fun stopOpen(player: Player) { + parent.stopOpen(player) + } + + override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean { + return parent.canPlaceItem(slot, itemStack) + } + + override fun canTakeItem(container: Container, slot: Int, itemStack: ItemStack): Boolean { + return parent.canTakeItem(container, slot, itemStack) + } + + override fun isEmpty(): Boolean { + return parent.isEmpty + } + + override fun hasAnyMatching(predicate: Predicate): Boolean { + return parent.hasAnyMatching(predicate) + } + + override fun hasAnyOf(items: Set): Boolean { + return parent.hasAnyOf(items) + } + + override fun countItem(item: Item): Int { + return parent.countItem(item) + } + } + + companion object { + fun wrap(other: Container): IEnhancedContainer { + if (other is IEnhancedContainer) + return other + + return Wrapper(other) + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt new file mode 100644 index 000000000..054f0719d --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt @@ -0,0 +1,29 @@ +package ru.dbotthepony.mc.otm.container + +import net.minecraft.world.item.Item +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items + +interface IFilteredContainerSlot : IContainerSlot { + var filter: Item? + + val isForbiddenForAutomation: Boolean get() { + return filter === Items.AIR + } + + val hasFilter: Boolean + get() = filter != null + + + fun testSlotFilter(itemStack: ItemStack): Boolean { + return testSlotFilter(itemStack.item) + } + + fun testSlotFilter(item: Item): Boolean { + if (filter == null) { + return true + } else { + return filter === item + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredSlottedContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredSlottedContainerSlot.kt new file mode 100644 index 000000000..91f1d9da2 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredSlottedContainerSlot.kt @@ -0,0 +1,9 @@ +package ru.dbotthepony.mc.otm.container + +import net.minecraft.world.item.ItemStack + +interface IFilteredSlottedContainerSlot : IFilteredContainerSlot, ISlottedContainerSlot { + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + return super.canAutomationPlaceItem(itemStack) && testSlotFilter(itemStack) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt index 03644d292..6dc2e7e87 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt @@ -50,27 +50,6 @@ interface IMatteryContainer : IContainer, RecipeInput, Iterable { } } - open class ContainerSlot(override val slot: Int, override val container: IMatteryContainer) : IContainerSlot { - override val isForbiddenForAutomation: Boolean - get() = container.isSlotForbiddenForAutomation(slot) - - override fun getFilter(): Item? { - return container.getSlotFilter(slot) - } - - override fun setFilter(filter: Item?): Boolean { - return container.setSlotFilter(slot, filter) - } - - override fun getMaxStackSize(item: ItemStack): Int { - return container.getMaxStackSize(slot, item) - } - - override fun setChanged() { - container.setChanged(slot) - } - } - /** * Iterates either non-empty slots of container or all slots of container */ @@ -83,7 +62,7 @@ interface IMatteryContainer : IContainer, RecipeInput, Iterable { } fun containerSlot(slot: Int): IContainerSlot { - return ContainerSlot(slot, this) + return IContainerSlot.Simple(slot, this) } fun hasSlotFilter(slot: Int) = getSlotFilter(slot) !== null @@ -234,22 +213,4 @@ interface IMatteryContainer : IContainer, RecipeInput, Iterable { return list } - - fun shrink(slot: Int, amount: Int): Boolean { - if (slot < 0 || slot > size()) - return false - - val item = this[slot] - if (item.isEmpty) - return false - - if (item.count <= amount) { - this[slot] = ItemStack.EMPTY - } else { - item.shrink(amount) - setChanged(slot) - } - - return true - } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt new file mode 100644 index 000000000..dfccd28e0 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt @@ -0,0 +1,220 @@ +package ru.dbotthepony.mc.otm.container + +import it.unimi.dsi.fastutil.ints.IntSet +import net.minecraft.world.Container +import net.minecraft.world.item.ItemStack +import net.neoforged.neoforge.items.IItemHandler +import ru.dbotthepony.kommons.collect.any +import ru.dbotthepony.mc.otm.core.collect.filter +import ru.dbotthepony.mc.otm.core.collect.map + +/** + * Container which revolve around embedding slot objects rather than providing direct item access, + * and subsequently fully implement [IItemHandler] + */ +interface ISlottedContainer : IEnhancedContainer, IItemHandler { + override fun containerSlot(slot: Int): ISlottedContainerSlot + + override fun slotIterator(): Iterator { + return (0 until containerSize).iterator().map { containerSlot(it) } + } + + override fun nonEmptySlotIterator(): Iterator { + return (0 until containerSize).iterator().map { containerSlot(it) }.filter { it.isNotEmpty } + } + + override fun setChanged(slot: Int) { + containerSlot(slot).setChanged() + } + + override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int { + return containerSlot(slot).maxStackSize(itemStack) + } + + override fun getItem(slot: Int): ItemStack { + return containerSlot(slot).item + } + + override fun removeItem(slot: Int, amount: Int): ItemStack { + return containerSlot(slot).remove(amount) + } + + override fun removeItemNoUpdate(slot: Int): ItemStack { + return containerSlot(slot).remove() + } + + override fun setItem(slot: Int, itemStack: ItemStack) { + containerSlot(slot).item = itemStack + } + + override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean { + return containerSlot(slot).canAutomationPlaceItem(itemStack) + } + + override fun canTakeItem(container: Container, slot: Int, itemStack: ItemStack): Boolean { + return containerSlot(slot).canAutomationTakeItem() + } + + override fun getSlots() = containerSize + override fun getStackInSlot(slot: Int) = containerSlot(slot).item + + override fun insertItem(slot: Int, stack: ItemStack, simulate: Boolean): ItemStack { + return containerSlot(slot).insertItem(stack, simulate) + } + + override fun extractItem(slot: Int, amount: Int, simulate: Boolean): ItemStack { + return containerSlot(slot).extractItem(amount, simulate) + } + + override fun getSlotLimit(slot: Int): Int { + return containerSlot(slot).maxStackSize + } + + override fun isItemValid(slot: Int, stack: ItemStack): Boolean { + return canPlaceItem(slot, stack) + } + + private fun addItem(stack: ItemStack, simulate: Boolean, filterPass: Boolean, slots: IntSet, onlyIntoExisting: Boolean, popTime: Int?, ignoreFilters: Boolean): ItemStack { + if (stack.isEmpty || slots.isEmpty()) + return stack + + // двигаем в одинаковые слоты + for (i in slotWithItemIterator(stack.item, slots)) { + val slot = containerSlot(i) + + val condition: Boolean + + if (slot is IFilteredContainerSlot) { + condition = (ignoreFilters || !slot.isForbiddenForAutomation) && + ItemStack.isSameItemSameComponents(slot.item, stack) && + (ignoreFilters || !filterPass && !slot.hasFilter || filterPass && slot.hasFilter && slot.testSlotFilter(stack)) + } else { + condition = (ignoreFilters || !filterPass) && ItemStack.isSameItemSameComponents(slot.item, stack) + } + + if (condition) { + val slotLimit = slot.maxStackSize(slot.item) + + if (slot.item.count < slotLimit) { + val newCount = (slot.item.count + stack.count).coerceAtMost(slotLimit) + val diff = newCount - slot.item.count + + if (!simulate) { + slot.item.count = newCount + slot.setChanged() + + if (popTime != null) { + slot.item.popTime = popTime + } + } + + stack.shrink(diff) + + if (stack.isEmpty) + return ItemStack.EMPTY + } + } + } + + if (!onlyIntoExisting) { + for (i in emptySlotIterator(slots)) { + val slot = containerSlot(i) + + val condition: Boolean + + if (slot is IFilteredContainerSlot) { + condition = (ignoreFilters || !slot.isForbiddenForAutomation) && + (ignoreFilters || !filterPass && !slot.hasFilter || filterPass && slot.hasFilter && slot.testSlotFilter(stack)) + } else { + condition = ignoreFilters || !filterPass + } + + if (condition) { + val diff = stack.count.coerceAtMost(slot.maxStackSize(stack)) + + if (!simulate) { + val copyToPut = stack.copy() + copyToPut.count = diff + slot.item = copyToPut + + if (popTime != null) { + copyToPut.popTime = popTime + } + } + + stack.shrink(diff) + + if (stack.isEmpty) + return ItemStack.EMPTY + } + } + } + + return stack + } + + /** + * Hint used internally by [ISlottedContainer] to potentially speed up default method implementations + */ + val hasFilterableSlots: Boolean + get() = slotIterator().any { it is IFilteredContainerSlot } + + fun addItem(stack: ItemStack, simulate: Boolean, slots: IntSet = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean): ItemStack { + if (stack.isEmpty || slots.isEmpty()) + return stack + + if (ignoreFilters || !hasFilterableSlots) { + return addItem(stack.copy(), simulate, filterPass = true, slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = true) + } else { + var copy = addItem(stack.copy(), simulate, filterPass = true, slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = false) + copy = addItem(copy, simulate, filterPass = false, slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = false) + return copy + } + } + + + /** + * Unlike [addItem], modifies original [stack] + * + * @return Whenever [stack] was modified + */ + fun consumeItem(stack: ItemStack, simulate: Boolean, slots: IntSet = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean): Boolean { + if (stack.isEmpty) + return false + + val result = addItem(stack, simulate, slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = ignoreFilters) + if (!simulate) stack.count = result.count + return result.count != stack.count + } + + fun fullyAddItem(stack: ItemStack, slots: IntSet = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean): Boolean { + if (!addItem(stack, true, slots, popTime = popTime, onlyIntoExisting = onlyIntoExisting, ignoreFilters = ignoreFilters).isEmpty) + return false + + return addItem(stack, false, slots, popTime = popTime, onlyIntoExisting = onlyIntoExisting, ignoreFilters = ignoreFilters).isEmpty + } + + override fun addItem( + stack: ItemStack, + simulate: Boolean, + slots: IntSet, + onlyIntoExisting: Boolean, + popTime: Int? + ): ItemStack { + return addItem(stack, simulate, slots, onlyIntoExisting, popTime, ignoreFilters = false) + } + + override fun consumeItem( + stack: ItemStack, + simulate: Boolean, + slots: IntSet, + onlyIntoExisting: Boolean, + popTime: Int? + ): Boolean { + return consumeItem(stack, simulate, slots, onlyIntoExisting, popTime, ignoreFilters = false) + } + + override fun fullyAddItem(stack: ItemStack, slots: IntSet, onlyIntoExisting: Boolean, popTime: Int?): Boolean { + return fullyAddItem(stack, slots, onlyIntoExisting, popTime, ignoreFilters = false) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainerSlot.kt new file mode 100644 index 000000000..23db5590a --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainerSlot.kt @@ -0,0 +1,95 @@ +package ru.dbotthepony.mc.otm.container + +import net.minecraft.world.item.ItemStack +import net.neoforged.neoforge.items.IItemHandler + +/** + * Slot of [ISlottedContainer], with additional methods to implement interaction behavior for both for players and mechanisms + */ +interface ISlottedContainerSlot : IContainerSlot { + override val container: ISlottedContainer + + fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + return true + } + + fun canAutomationTakeItem(desired: Int = item.count): Boolean { + return true + } + + fun modifyAutomationPlaceCount(itemStack: ItemStack): Int { + return itemStack.count + } + + fun modifyAutomationExtractionCount(desired: Int): Int { + return desired + } + + /** + * Slot-specific implementation for [IItemHandler.insertItem] + */ + fun insertItem(stack: ItemStack, simulate: Boolean): ItemStack { + if (!canAutomationPlaceItem(stack)) + return stack + + var amount = modifyAutomationPlaceCount(stack) + + if (amount <= 0) + return stack + + if (item.isEmpty) { + amount = stack.count.coerceAtMost(maxStackSize(stack)).coerceAtMost(amount) + + if (!simulate) { + item = stack.copyWithCount(amount) + } + + if (stack.count <= amount) { + return ItemStack.EMPTY + } else { + return stack.copyWithCount(stack.count - amount) + } + } else if (item.isStackable && maxStackSize(item) > item.count && ItemStack.isSameItemSameComponents(item, stack)) { + val newCount = maxStackSize(item).coerceAtMost(item.count + stack.count.coerceAtMost(amount)) + val diff = newCount - item.count + + if (diff != 0) { + if (!simulate) { + item.grow(diff) + setChanged() + } + + val copy = stack.copy() + copy.shrink(diff) + return copy + } + } + + return stack + } + + fun extractItem(amount: Int, simulate: Boolean): ItemStack { + if (amount <= 0 || !canAutomationTakeItem(amount) || item.isEmpty) + return ItemStack.EMPTY + + @Suppress("name_shadowing") + val amount = modifyAutomationExtractionCount(amount) + if (amount <= 0 || !canAutomationTakeItem(amount)) return ItemStack.EMPTY + + val minimal = amount.coerceAtMost(item.count) + val copy = item.copy() + copy.count = minimal + + if (!simulate) { + if (item.count == minimal) { + item = ItemStack.EMPTY + } else { + item.shrink(minimal) + } + + setChanged() + } + + return copy + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt index 7cee2b9e7..53b155f8d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt @@ -426,22 +426,32 @@ open class MatteryContainer(var listener: ContainerListener, private val size: I } } - private inner class Slot(override val slot: Int) : IContainerSlot { + private inner class Slot(override val slot: Int) : IFilteredContainerSlot { override val container: Container get() = this@MatteryContainer + override var item: ItemStack + get() = this@MatteryContainer[slot] + set(value) { this@MatteryContainer[slot] = value } + override val maxStackSize: Int + get() = this@MatteryContainer.maxStackSize + + override fun remove(): ItemStack { + return removeItemNoUpdate(slot) + } + + override fun remove(count: Int): ItemStack { + return removeItem(slot, count) + } + + override var filter: Item? + get() = getSlotFilter(slot) + set(value) { setSlotFilter(slot, value) } + override val isForbiddenForAutomation: Boolean get() = isSlotForbiddenForAutomation(slot) - override fun getFilter(): Item? { - return getSlotFilter(slot) - } - - override fun setFilter(filter: Item?): Boolean { - return setSlotFilter(slot, filter) - } - - override fun getMaxStackSize(item: ItemStack): Int { + override fun maxStackSize(item: ItemStack): Int { return getMaxStackSize(slot, item) } @@ -450,12 +460,12 @@ open class MatteryContainer(var listener: ContainerListener, private val size: I } } - final override fun slotIterator(): kotlin.collections.Iterator { + final override fun slotIterator(): kotlin.collections.Iterator { indicesReferenced = true return nonEmptyIndices.iterator().map { Slot(it) } } - final override fun slotIterator(nonEmpty: Boolean): kotlin.collections.Iterator { + final override fun slotIterator(nonEmpty: Boolean): kotlin.collections.Iterator { if (!nonEmpty) { return (0 until size).iterator().map { Slot(it) } } else if (isEmpty) { @@ -466,7 +476,7 @@ open class MatteryContainer(var listener: ContainerListener, private val size: I } } - final override fun containerSlot(slot: Int): IContainerSlot { + final override fun containerSlot(slot: Int): IFilteredContainerSlot { return Slot(slot) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainer.kt new file mode 100644 index 000000000..6d81f58e1 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainer.kt @@ -0,0 +1,177 @@ +package ru.dbotthepony.mc.otm.container + +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder +import net.minecraft.core.HolderLookup +import net.minecraft.core.registries.BuiltInRegistries +import net.minecraft.nbt.CompoundTag +import net.minecraft.nbt.ListTag +import net.minecraft.nbt.NbtOps +import net.minecraft.nbt.Tag +import net.minecraft.world.entity.player.Player +import net.minecraft.world.item.Item +import net.minecraft.world.item.ItemStack +import net.neoforged.neoforge.common.util.INBTSerializable +import org.apache.logging.log4j.LogManager +import ru.dbotthepony.mc.otm.data.codec.minRange +import java.util.function.Predicate + +class SlottedContainer( + slots: Collection, + private val stillValid: Predicate, + private val globalChangeListeners: Array +) : ISlottedContainer, INBTSerializable { + private val slots: Array + + init { + val itr = slots.iterator() + this.slots = Array(slots.size) { itr.next().create(this, it) } + } + + override val hasFilterableSlots: Boolean = this.slots.any { it is IFilteredContainerSlot } + private var suppressListeners = false + + override fun clearContent() { + suppressListeners = true + + try { + slots.forEach { it.remove() } + notifyChanged() + } finally { + suppressListeners = false + } + } + + override fun containerSlot(slot: Int): ISlottedContainerSlot { + return slots[slot] + } + + fun notifyChanged() { + if (suppressListeners) return + globalChangeListeners.forEach { it.run() } + } + + // called by outside code (vanilla and other unaware mods) + override fun setChanged() { + suppressListeners = true + var hasChanges = false + + try { + slots.forEach { hasChanges = it.observeChanges() || hasChanges } + } finally { + suppressListeners = false + + if (hasChanges) + notifyChanged() + } + } + + override fun getContainerSize(): Int { + return slots.size + } + + override fun stillValid(player: Player): Boolean { + return stillValid.test(player) + } + + private data class LegacySerializedItem(val item: ItemStack, val slot: Int) { + companion object { + val CODEC: Codec = RecordCodecBuilder.create { + it.group( + ItemStack.OPTIONAL_CODEC.fieldOf("item").forGetter { it.item }, + Codec.INT.minRange(0).fieldOf("slot").forGetter { it.slot }, + ).apply(it, ::LegacySerializedItem) + } + } + } + + private data class LegacySerializedFilter(val item: Item, val slot: Int) { + companion object { + val CODEC: Codec = RecordCodecBuilder.create { + it.group( + BuiltInRegistries.ITEM.byNameCodec().fieldOf("item").forGetter { it.item }, + Codec.INT.minRange(0).fieldOf("slot").forGetter { it.slot }, + ).apply(it, ::LegacySerializedFilter) + } + } + } + + private data class LegacySerializedState( + val items: List, + val filters: List + ) { + companion object { + val CODEC: Codec = RecordCodecBuilder.create { + it.group( + Codec.list(LegacySerializedItem.CODEC).fieldOf("items").forGetter { it.items }, + Codec.list(LegacySerializedFilter.CODEC).fieldOf("filters").forGetter { it.filters }, + ).apply(it, ::LegacySerializedState) + } + } + } + + private val lostItems = ArrayList() + + override fun serializeNBT(provider: HolderLookup.Provider): ListTag { + return ListTag().also { + for (slot in slots) { + it.add(slot.serializeNBT(provider)) + } + + it.addAll(lostItems) + } + } + + override fun deserializeNBT(provider: HolderLookup.Provider, nbt: Tag) { + lostItems.clear() + slots.forEach { it.clear() } + + if (nbt is CompoundTag) { + // legacy container + LegacySerializedState.CODEC.decode(provider.createSerializationContext(NbtOps.INSTANCE), nbt) + .resultOrPartial { LOGGER.error("Error deserializing container: $it") } + .ifPresent { + val (items, filters) = it.first + + // excessive items will be lost + for ((item, slot) in items) { + if (slot in 0 until containerSize) { + slots[slot].item = item + } + } + + for ((filter, slot) in filters) { + if (slot in 0 until containerSize) { + val getSlot = slots[slot] + + if (getSlot is IFilteredContainerSlot) { + getSlot.filter = filter + } + } + } + } + } else if (nbt is ListTag) { + // normal container + for ((i, element) in nbt.withIndex()) { + if (element !is CompoundTag) { + LOGGER.error("Deserializing mattery container: Expected compound tag at $i, got $element") + continue + } + + if (i in 0 until containerSize) { + slots[i].deserializeNBT(provider, element) + } else { + lostItems.add(element) + } + } + } else { + LOGGER.error("Unable to deserialize mattery container, expected CompoundTag or ListTag, got $nbt") + } + + notifyChanged() + } + + companion object { + private val LOGGER = LogManager.getLogger() + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainerBuilder.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainerBuilder.kt new file mode 100644 index 000000000..5edb2d5b0 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainerBuilder.kt @@ -0,0 +1,48 @@ +package ru.dbotthepony.mc.otm.container + +import net.minecraft.world.entity.player.Player +import java.util.function.Predicate + +class SlottedContainerBuilder { + fun interface SlotProvider { + fun create(container: SlottedContainer, index: Int): ContainerSlot + } + + private val slots = ArrayList() + private var stillValid = Predicate { true } + private val globalChangeListeners = ArrayList() + + fun add(slot: SlotProvider): SlottedContainerBuilder { + slots.add(slot) + return this + } + + fun add(amount: Int, provider: SlotProvider): SlottedContainerBuilder { + for (i in 0 until amount) + slots.add(provider) + + return this + } + + fun stillValid(predicate: Predicate): SlottedContainerBuilder { + this.stillValid = predicate + return this + } + + fun onChanged(listener: Runnable): SlottedContainerBuilder { + globalChangeListeners.add(listener) + return this + } + + fun copy(): SlottedContainerBuilder { + val copy = SlottedContainerBuilder() + copy.slots.addAll(slots) + copy.globalChangeListeners.addAll(globalChangeListeners) + copy.stillValid = stillValid + return copy + } + + fun build(): SlottedContainer { + return SlottedContainer(slots, stillValid, globalChangeListeners.toTypedArray()) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/util/Iterators.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/util/Iterators.kt index 1dd6bad9c..64f4a9b73 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/util/Iterators.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/util/Iterators.kt @@ -4,52 +4,41 @@ import net.minecraft.world.Container import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.container.IContainerSlot +import ru.dbotthepony.mc.otm.container.IEnhancedContainer import ru.dbotthepony.mc.otm.container.IMatteryContainer import ru.dbotthepony.mc.otm.container.get import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.collect.map import ru.dbotthepony.mc.otm.core.isNotEmpty -class SimpleContainerSlot(override val slot: Int, override val container: Container) : IContainerSlot { - init { - require(slot in 0 until container.containerSize) { "Slot out of bounds: $slot (container: $container with size ${container.containerSize})" } - } - - override fun getFilter(): Item? { - return null - } - - override fun setFilter(filter: Item?): Boolean { - return false - } -} - fun Container.containerSlot(slot: Int): IContainerSlot { - if (this is IMatteryContainer) { + if (this is IEnhancedContainer) { return containerSlot(slot) } else { - return SimpleContainerSlot(slot, this) + return IContainerSlot.Simple(slot, this) } } -operator fun Container.iterator() = iterator(true) - -fun Container.iterator(nonEmpty: Boolean): Iterator { - if (this is IMatteryContainer) { - return iterator(nonEmpty) - } else if (nonEmpty) { +operator fun Container.iterator(): Iterator { + if (this is IEnhancedContainer) { + return iterator() + } else { return (0 until containerSize).iterator().map { this[it] }.filter { it.isNotEmpty } - } else { - return (0 until containerSize).iterator().map { this[it] } } } -fun Container.slotIterator(nonEmpty: Boolean = true): Iterator { - if (this is IMatteryContainer) { - return slotIterator(nonEmpty) - } else if (nonEmpty) { - return (0 until containerSize).iterator().filter { this[it].isNotEmpty }.map { SimpleContainerSlot(it, this) } +fun Container.slotIterator(): Iterator { + if (this is IEnhancedContainer) { + return slotIterator() } else { - return (0 until containerSize).iterator().map { SimpleContainerSlot(it, this) } + return (0 until containerSize).iterator().map { IContainerSlot.Simple(it, this) } + } +} + +fun Container.nonEmptySlotIterator(): Iterator { + if (this is IEnhancedContainer) { + return nonEmptySlotIterator() + } else { + return (0 until containerSize).iterator().filter { this[it].isNotEmpty }.map { IContainerSlot.Simple(it, this) } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/IntRange2Set.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/IntRange2Set.kt new file mode 100644 index 000000000..fccb08844 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/IntRange2Set.kt @@ -0,0 +1,206 @@ +package ru.dbotthepony.mc.otm.core.collect + +import it.unimi.dsi.fastutil.HashCommon +import it.unimi.dsi.fastutil.ints.IntBidirectionalIterator +import it.unimi.dsi.fastutil.ints.IntCollection +import it.unimi.dsi.fastutil.ints.IntComparator +import it.unimi.dsi.fastutil.ints.IntIterators +import it.unimi.dsi.fastutil.ints.IntSet +import it.unimi.dsi.fastutil.ints.IntSortedSet + +class IntRange2Set private constructor(private val first: Int, private val last: Int) : IntSortedSet { + constructor(range: IntRange) : this(range.first, range.last) { + require(range.step == 1) { "Provided range has non-standard step of ${range.step}" } + } + + @Deprecated("Not supported", level = DeprecationLevel.ERROR) + override fun add(element: Int): Boolean { + throw UnsupportedOperationException() + } + + @Deprecated("Not supported", level = DeprecationLevel.ERROR) + override fun addAll(c: IntCollection?): Boolean { + throw UnsupportedOperationException() + } + + @Deprecated("Not supported", level = DeprecationLevel.ERROR) + override fun addAll(elements: Collection): Boolean { + throw UnsupportedOperationException() + } + + @Deprecated("Not supported", level = DeprecationLevel.ERROR) + override fun clear() { + throw UnsupportedOperationException() + } + + override fun iterator(fromElement: Int): IntBidirectionalIterator { + if (isEmpty() || fromElement > last) + return IntIterators.EMPTY_ITERATOR + else if (fromElement <= first) + return IntIterators.fromTo(first, last + 1) + else + return IntIterators.fromTo(fromElement, last + 1) + } + + override fun iterator(): IntBidirectionalIterator { + if (isEmpty()) + return IntIterators.EMPTY_ITERATOR + + return IntIterators.fromTo(first, last + 1) + } + + @Deprecated("Not supported", level = DeprecationLevel.ERROR) + override fun remove(k: Int): Boolean { + throw UnsupportedOperationException() + } + + @Deprecated("Not supported", level = DeprecationLevel.ERROR) + override fun removeAll(c: IntCollection?): Boolean { + throw UnsupportedOperationException() + } + + @Deprecated("Not supported", level = DeprecationLevel.ERROR) + override fun removeAll(elements: Collection): Boolean { + throw UnsupportedOperationException() + } + + @Deprecated("Not supported", level = DeprecationLevel.ERROR) + override fun retainAll(c: IntCollection?): Boolean { + throw UnsupportedOperationException() + } + + @Deprecated("Not supported", level = DeprecationLevel.ERROR) + override fun retainAll(elements: Collection): Boolean { + throw UnsupportedOperationException() + } + + override fun contains(key: Int): Boolean { + return key in first .. last + } + + override fun containsAll(c: IntCollection): Boolean { + return c.ktIterator().all { it in first .. last } + } + + override fun containsAll(elements: Collection): Boolean { + return elements.all { it in first .. last } + } + + override fun isEmpty(): Boolean { + return last > first + } + + override fun toArray(a: IntArray?): IntArray { + if (a == null || a.size < size) + return toIntArray() + + var index = 0 + + for (i in first .. last) { + a[index++] = i + } + + return a + } + + override fun toIntArray(): IntArray { + if (isEmpty()) + return EMPTY_ARRAY + + return IntArray(last - first + 1) { first + it } + } + + override fun comparator(): IntComparator? { + return null + } + + override fun subSet(fromElement: Int, toElement: Int): IntSortedSet { + if (fromElement <= first && toElement > last) + return this + else if (fromElement <= first) + return IntRange2Set(first, toElement - 1) + else if (toElement > last) + return IntRange2Set(fromElement, last) + else + return EMPTY + } + + override fun headSet(toElement: Int): IntSortedSet { + if (isEmpty() || toElement <= first) + return EMPTY + else if (toElement < last) + return this + else + return IntRange2Set(first, toElement - 1) + } + + override fun tailSet(fromElement: Int): IntSortedSet { + if (isEmpty() || fromElement > last) + return EMPTY + else if (fromElement < first) + return this + else + return IntRange2Set(fromElement, last) + } + + override fun firstInt(): Int { + if (isEmpty()) + throw NoSuchElementException("Range is empty") + + return first + } + + override fun lastInt(): Int { + if (isEmpty()) + throw NoSuchElementException("Range is empty") + + return last + } + + override val size: Int + get() = if (last > first) 0 else last - first + 1 + + override fun toString(): String { + if (isEmpty()) + return "IntRange2Set[EMPTY]" + + return "IntRange2Set[$first .. $last]" + } + + override fun equals(other: Any?): Boolean { + return this === other || + other is IntRange2Set && (isEmpty() == other.isEmpty() || first == other.first && last == other.last) || + other is IntSet && other.size == size && containsAll(other) || + other is Set<*> && other.size == size && other.all { it is Int && it in first .. last } + } + + override fun hashCode(): Int { + if (isEmpty()) + return EMPTY_HASH + + return HashCommon.murmurHash3(last - first) + } + + companion object { + /** + * Returns set containing values beginning from [from] (inclusive) to [to] (inclusive) + */ + fun closed(from: Int, to: Int): IntRange2Set { + if (from > to) + return EMPTY + + return IntRange2Set(from, to) + } + + /** + * Returns set containing values beginning from [from] (inclusive) to [to] (exclusive) + */ + fun openEnded(from: Int, to: Int): IntRange2Set { + return closed(from, to - 1) + } + + private val EMPTY_ARRAY = IntArray(0) + val EMPTY = IntRange2Set(0, -1) + private val EMPTY_HASH = HashCommon.murmurHash3(0) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/Iterables.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/Iterables.kt index 469b95915..4c1a23635 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/Iterables.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/Iterables.kt @@ -1,7 +1,9 @@ package ru.dbotthepony.mc.otm.core.collect +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.IntSortedSet fun IntRange.asIterable(): IntIterable { return IntIterable { @@ -22,3 +24,31 @@ fun IntRange.asIterable(): IntIterable { } } } + +fun IntCollection.ktIterator(): kotlin.collections.IntIterator { + return object : kotlin.collections.IntIterator() { + private val parent = this@ktIterator.intIterator() + + override fun nextInt(): Int { + return parent.nextInt() + } + + override fun hasNext(): Boolean { + return parent.hasNext() + } + } +} + +fun IntSortedSet.ktIterator(fromElement: Int): kotlin.collections.IntIterator { + return object : kotlin.collections.IntIterator() { + private val parent = this@ktIterator.iterator(fromElement) + + override fun nextInt(): Int { + return parent.nextInt() + } + + override fun hasNext(): Boolean { + return parent.hasNext() + } + } +} From fc1d9d64488654f7cd972904a9f6ce77fe91bd51 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 27 Feb 2025 20:41:56 +0700 Subject: [PATCH 002/154] Make SlottedContainerBuilder be embedded inside SlottedContainer --- .../mc/otm/container/SlottedContainer.kt | 47 +++++++++++++++++- .../otm/container/SlottedContainerBuilder.kt | 48 ------------------- 2 files changed, 46 insertions(+), 49 deletions(-) delete mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainerBuilder.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainer.kt index 6d81f58e1..b68cca149 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainer.kt @@ -17,7 +17,7 @@ import ru.dbotthepony.mc.otm.data.codec.minRange import java.util.function.Predicate class SlottedContainer( - slots: Collection, + slots: Collection, private val stillValid: Predicate, private val globalChangeListeners: Array ) : ISlottedContainer, INBTSerializable { @@ -171,6 +171,51 @@ class SlottedContainer( notifyChanged() } + fun interface SlotProvider { + fun create(container: SlottedContainer, index: Int): ContainerSlot + } + + class Builder { + private val slots = ArrayList() + private var stillValid = Predicate { true } + private val globalChangeListeners = ArrayList() + + fun add(slot: SlotProvider): Builder { + slots.add(slot) + return this + } + + fun add(amount: Int, provider: SlotProvider): Builder { + for (i in 0 until amount) + slots.add(provider) + + return this + } + + fun stillValid(predicate: Predicate): Builder { + this.stillValid = predicate + return this + } + + fun onChanged(listener: Runnable): Builder { + globalChangeListeners.add(listener) + return this + } + + fun copy(): Builder { + val copy = Builder() + copy.slots.addAll(slots) + copy.globalChangeListeners.addAll(globalChangeListeners) + copy.stillValid = stillValid + return copy + } + + fun build(): SlottedContainer { + return SlottedContainer(slots, stillValid, globalChangeListeners.toTypedArray()) + } + } + + companion object { private val LOGGER = LogManager.getLogger() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainerBuilder.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainerBuilder.kt deleted file mode 100644 index 5edb2d5b0..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainerBuilder.kt +++ /dev/null @@ -1,48 +0,0 @@ -package ru.dbotthepony.mc.otm.container - -import net.minecraft.world.entity.player.Player -import java.util.function.Predicate - -class SlottedContainerBuilder { - fun interface SlotProvider { - fun create(container: SlottedContainer, index: Int): ContainerSlot - } - - private val slots = ArrayList() - private var stillValid = Predicate { true } - private val globalChangeListeners = ArrayList() - - fun add(slot: SlotProvider): SlottedContainerBuilder { - slots.add(slot) - return this - } - - fun add(amount: Int, provider: SlotProvider): SlottedContainerBuilder { - for (i in 0 until amount) - slots.add(provider) - - return this - } - - fun stillValid(predicate: Predicate): SlottedContainerBuilder { - this.stillValid = predicate - return this - } - - fun onChanged(listener: Runnable): SlottedContainerBuilder { - globalChangeListeners.add(listener) - return this - } - - fun copy(): SlottedContainerBuilder { - val copy = SlottedContainerBuilder() - copy.slots.addAll(slots) - copy.globalChangeListeners.addAll(globalChangeListeners) - copy.stillValid = stillValid - return copy - } - - fun build(): SlottedContainer { - return SlottedContainer(slots, stillValid, globalChangeListeners.toTypedArray()) - } -} From 8a4abb90bd5312e5bedddb0e9a7fa6214ab1ca5e Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 27 Feb 2025 21:08:00 +0700 Subject: [PATCH 003/154] Forgot to switch IntSortedSet to IntSet --- .../kotlin/ru/dbotthepony/mc/otm/container/ContainerHelpers.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 84b25bfe9..74cd6669f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerHelpers.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerHelpers.kt @@ -44,7 +44,7 @@ val Container.slotRange: IntRange2Set get() { return IntRange2Set.openEnded(0, containerSize) } -fun Container.addItem(stack: ItemStack, simulate: Boolean, slots: IntSortedSet = slotRange): ItemStack { +fun Container.addItem(stack: ItemStack, simulate: Boolean, slots: IntSet = slotRange): ItemStack { return IEnhancedContainer.wrap(this).addItem(stack, simulate, slots) } From a0b04fc1f44d74a0b32ff7b252d698fc96dc159c Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 27 Feb 2025 21:17:13 +0700 Subject: [PATCH 004/154] Extracting 'lost' items from SlottedContainer --- .../mc/otm/container/SlottedContainer.kt | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainer.kt index b68cca149..d978031c2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainer.kt @@ -8,11 +8,15 @@ import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.ListTag import net.minecraft.nbt.NbtOps import net.minecraft.nbt.Tag +import net.minecraft.server.level.ServerPlayer import net.minecraft.world.entity.player.Player import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import net.neoforged.neoforge.common.util.INBTSerializable import org.apache.logging.log4j.LogManager +import ru.dbotthepony.mc.otm.core.isNotEmpty +import ru.dbotthepony.mc.otm.core.math.set +import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.data.codec.minRange import java.util.function.Predicate @@ -111,6 +115,36 @@ class SlottedContainer( } private val lostItems = ArrayList() + private var provider: HolderLookup.Provider? = null + + fun takeLostItems(): List { + if (lostItems.isEmpty()) + return listOf() + + val provider = provider?.createSerializationContext(NbtOps.INSTANCE) ?: return listOf() + val result = ArrayList() + + for (entry in lostItems) { + if ("item" in entry) { + ItemStack.OPTIONAL_CODEC.decode(provider, entry["item"]) + .ifError { LOGGER.warn("Unable to deserialize 'lost' item: ${it.message()}") } + .ifSuccess { if (it.first.isNotEmpty) result.add(it.first) } + } + } + + lostItems.clear() + return result + } + + fun takeLostItems(player: ServerPlayer) { + for (stack in takeLostItems()) { + player.inventory.add(stack) + + if (stack.isNotEmpty) { + player.drop(stack, false, false) + } + } + } override fun serializeNBT(provider: HolderLookup.Provider): ListTag { return ListTag().also { @@ -137,6 +171,16 @@ class SlottedContainer( for ((item, slot) in items) { if (slot in 0 until containerSize) { slots[slot].item = item + } else if (item.isNotEmpty) { + ItemStack.CODEC.encodeStart(provider.createSerializationContext(NbtOps.INSTANCE), item) + .ifError { LOGGER.warn("Unable to serialize 'lost' item: ${it.message()}") } + .ifSuccess { s -> + this.provider = provider + + lostItems.add(CompoundTag().also { + it["item"] = s + }) + } } } @@ -162,6 +206,7 @@ class SlottedContainer( slots[i].deserializeNBT(provider, element) } else { lostItems.add(element) + this.provider = provider } } } else { From 124a1b3db646feaf8b2bd47bbcdb3d5f059449a3 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 27 Feb 2025 21:55:03 +0700 Subject: [PATCH 005/154] Get rid of "slot" and "container" in IContainerSlot since they were bad design choices --- .../dbotthepony/mc/otm/container/ContainerHelpers.kt | 11 +++++++---- .../ru/dbotthepony/mc/otm/container/ContainerSlot.kt | 6 +++--- .../ru/dbotthepony/mc/otm/container/IContainerSlot.kt | 8 +------- .../mc/otm/container/ISlottedContainerSlot.kt | 2 -- 4 files changed, 11 insertions(+), 16 deletions(-) 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 74cd6669f..4a3f69ce2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerHelpers.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerHelpers.kt @@ -266,21 +266,24 @@ fun Container.computeSortedIndices(comparator: Comparator = ItemStack if (isEmpty) return IntList.of() - val slots = slotIterator().filter { (it !is IFilteredContainerSlot || !it.isForbiddenForAutomation) && it.maxStackSize(it.item) >= it.item.count }.toList() + val slots = slotIterator() + .withIndex() + .filter { (_, it) -> (it !is IFilteredContainerSlot || !it.isForbiddenForAutomation) && it.maxStackSize(it.item) >= it.item.count } + .toList() if (slots.isEmpty()) return IntList.of() val items = Object2ObjectOpenCustomHashMap>(ItemStackHashStrategy) - slots.forEach { + slots.forEach { (index, it) -> val get = items[it.item] if (get == null) { - items[it.item] = it.item.copy() to IntArrayList().also { s -> s.add(it.slot) } + items[it.item] = it.item.copy() to IntArrayList().also { s -> s.add(index) } } else { get.first.count += it.item.count - get.second.add(it.slot) + get.second.add(index) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerSlot.kt index 027939b62..2106682a5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerSlot.kt @@ -15,8 +15,8 @@ import ru.dbotthepony.mc.otm.core.registryName import ru.dbotthepony.mc.otm.data.getOrNull open class ContainerSlot( - final override val container: SlottedContainer, - final override val slot: Int + protected val container: SlottedContainer, + protected val slot: Int ) : ISlottedContainerSlot, INBTSerializable { private var _item: ItemStack = ItemStack.EMPTY @@ -110,7 +110,7 @@ open class ContainerSlot( open class Simple( protected val listener: (new: ItemStack, old: ItemStack) -> Unit, protected val maxStackSize: Int = Item.DEFAULT_MAX_STACK_SIZE, - ) : SlottedContainerBuilder.SlotProvider { + ) : SlottedContainer.SlotProvider { protected open inner class Instance(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) { override val maxStackSize: Int get() = this@Simple.maxStackSize diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IContainerSlot.kt index e8860b407..de28c6fa4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IContainerSlot.kt @@ -10,15 +10,9 @@ import ru.dbotthepony.mc.otm.core.isNotEmpty * for Player interaction. */ interface IContainerSlot : Delegate { - val slot: Int - val container: Container - fun setChanged() var item: ItemStack - operator fun component1() = slot - operator fun component2() = item - /** * Max stack size regardless of item * @@ -53,7 +47,7 @@ interface IContainerSlot : Delegate { val isNotEmpty: Boolean get() = item.isNotEmpty - class Simple(override val slot: Int, override val container: Container) : IContainerSlot { + class Simple(private val slot: Int, private val container: Container) : IContainerSlot { override fun setChanged() { container.setChanged() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainerSlot.kt index 23db5590a..9da3d32da 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainerSlot.kt @@ -7,8 +7,6 @@ import net.neoforged.neoforge.items.IItemHandler * Slot of [ISlottedContainer], with additional methods to implement interaction behavior for both for players and mechanisms */ interface ISlottedContainerSlot : IContainerSlot { - override val container: ISlottedContainer - fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { return true } From 6747d5f471dc6b9cca378b64a07070a106e1e3f3 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 27 Feb 2025 23:40:29 +0700 Subject: [PATCH 006/154] Further split ISlottedContainer into IAutomatedContainer --- .../mc/otm/container/CombinedContainer.kt | 100 ++++++++---------- .../mc/otm/container/ContainerSlot.kt | 4 +- .../mc/otm/container/IAutomatedContainer.kt | 40 +++++++ ...inerSlot.kt => IAutomatedContainerSlot.kt} | 2 +- .../mc/otm/container/IEnhancedContainer.kt | 6 ++ ....kt => IFilteredAutomatedContainerSlot.kt} | 2 +- .../mc/otm/container/ISlottedContainer.kt | 38 +------ .../mc/otm/container/SlottedContainer.kt | 5 +- 8 files changed, 98 insertions(+), 99 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt rename src/main/kotlin/ru/dbotthepony/mc/otm/container/{ISlottedContainerSlot.kt => IAutomatedContainerSlot.kt} (97%) rename src/main/kotlin/ru/dbotthepony/mc/otm/container/{IFilteredSlottedContainerSlot.kt => IFilteredAutomatedContainerSlot.kt} (71%) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt index 542ebb252..3eb596d83 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt @@ -5,6 +5,7 @@ import com.google.common.collect.ImmutableMap import com.google.common.collect.ImmutableSet import it.unimi.dsi.fastutil.ints.IntAVLTreeSet import it.unimi.dsi.fastutil.ints.IntArrayList +import it.unimi.dsi.fastutil.ints.IntOpenHashSet import it.unimi.dsi.fastutil.ints.IntSet import it.unimi.dsi.fastutil.objects.Object2ObjectFunction import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap @@ -22,39 +23,36 @@ import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.stream import java.util.stream.Stream -class CombinedContainer(containers: Stream>>) : IMatteryContainer { - constructor(vararg containers: Container) : this(containers.stream().map { it to (0 until it.containerSize) }) - constructor(containers: Collection) : this(containers.stream().map { it to (0 until it.containerSize) }) +class CombinedContainer(containers: Stream>>) : ISlottedContainer { + constructor(vararg containers: IEnhancedContainer) : this(containers.stream().map { it to (0 until it.containerSize) }) + constructor(containers: Collection) : this(containers.stream().map { it to (0 until it.containerSize) }) - private inner class Slot(override val slot: Int, val outer: IContainerSlot) : IContainerSlot by outer { - override val container: Container - get() = this@CombinedContainer - } - - private val slots: ImmutableList + private val slots: ImmutableList private val slotsMap: ImmutableMap> private val containers: ImmutableSet private val fullCoverage: ImmutableList private val notFullCoverage: ImmutableMap> init { - val list = ImmutableList.Builder() - var i = 0 + val list = ImmutableList.Builder() val validationMap = Reference2ObjectOpenHashMap() val slotsMap = Reference2ObjectOpenHashMap>() + var i = 0 for ((container, slots) in containers) { - val validator = validationMap.computeIfAbsent(container, Object2ObjectFunction { IntAVLTreeSet() }) + val validator = validationMap.computeIfAbsent(container, Object2ObjectFunction { IntOpenHashSet() }) val slotList = slotsMap.computeIfAbsent(container, Object2ObjectFunction { ArrayList() }) for (slot in slots) { if (validator.add(slot)) { val slotObj = container.containerSlot(slot) - list.add(Slot(i++, slotObj)) + list.add(slotObj) slotList.add(slotObj) } else { throw IllegalArgumentException("Duplicate mapping for $container at $i for slot $slot") } + + i++ } } @@ -85,20 +83,7 @@ class CombinedContainer(containers: Stream>>) : IM for (slots in notFullCoverage.values) { for (slot in slots) { - slot.item = ItemStack.EMPTY - } - } - } - - override fun clearSlotFilters() { - for (container in fullCoverage) { - if (container is IMatteryContainer) - container.clearSlotFilters() - } - - for (slots in notFullCoverage.values) { - for (slot in slots) { - slot.setFilter() + slot.remove() } } } @@ -127,16 +112,6 @@ class CombinedContainer(containers: Stream>>) : IM return slots.getOrNull(slot)?.item ?: ItemStack.EMPTY } - override fun removeItem(slot: Int, amount: Int): ItemStack { - val data = slots.getOrNull(slot) ?: return ItemStack.EMPTY - return data.outer.container.removeItem(data.outer.slot, amount) - } - - override fun removeItemNoUpdate(slot: Int): ItemStack { - val data = slots.getOrNull(slot) ?: return ItemStack.EMPTY - return data.outer.container.removeItemNoUpdate(data.outer.slot) - } - override fun setItem(slot: Int, itemStack: ItemStack) { slots.getOrNull(slot)?.item = itemStack } @@ -155,20 +130,17 @@ class CombinedContainer(containers: Stream>>) : IM return true } - override fun iterator(nonEmpty: Boolean): Iterator { + override fun iterator(): Iterator { if (notFullCoverage.isEmpty()) - return fullCoverage.iterator().flatMap { it.iterator(nonEmpty) } + return fullCoverage.iterator().flatMap { it.iterator() } return concatIterators( - fullCoverage.iterator().flatMap { it.iterator(nonEmpty) }, - notFullCoverage.values.iterator().flatMap { it.iterator() }.map { it.item }.let { if (nonEmpty) it.filter { it.isNotEmpty } else it } + fullCoverage.iterator().flatMap { it.iterator() }, + notFullCoverage.values.iterator().flatMap { it.iterator() }.map { it.item }.filter { it.isNotEmpty } ) } - override fun slotIterator(nonEmpty: Boolean): Iterator { - if (nonEmpty) - return slots.iterator().filter { it.isNotEmpty } - + override fun slotIterator(): Iterator { return slots.iterator() } @@ -176,42 +148,54 @@ class CombinedContainer(containers: Stream>>) : IM return slots[slot] } - override fun getSlotFilter(slot: Int): Item? { - return slots[slot].getFilter() - } - override fun setChanged(slot: Int) { slots[slot].setChanged() } - override fun setSlotFilter(slot: Int, filter: Item?): Boolean { - return slots[slot].setFilter(filter) - } - class Builder { - private val values = ArrayList>>() + private val values = ArrayList>>() fun add(container: Container): Builder { + return add(IEnhancedContainer.wrap(container)) + } + + fun add(container: Container, slots: Iterator): Builder { + return add(IEnhancedContainer.wrap(container), slots) + } + + fun add(container: Container, slot: Int): Builder { + return add(IEnhancedContainer.wrap(container), slot) + } + + fun add(container: Container, from: Int, to: Int): Builder { + return add(IEnhancedContainer.wrap(container), from, to) + } + + fun add(container: Container, slots: Iterable): Builder { + return add(IEnhancedContainer.wrap(container), slots) + } + + fun add(container: IEnhancedContainer): Builder { values.add(container to container.slotRange) return this } - fun add(container: Container, slots: Iterator): Builder { + fun add(container: IEnhancedContainer, slots: Iterator): Builder { values.add(container to IntArrayList(slots)) return this } - fun add(container: Container, slot: Int): Builder { + fun add(container: IEnhancedContainer, slot: Int): Builder { values.add(container to intArrayOf(slot).asIterable()) return this } - fun add(container: Container, from: Int, to: Int): Builder { + fun add(container: IEnhancedContainer, from: Int, to: Int): Builder { values.add(container to (from .. to)) return this } - fun add(container: Container, slots: Iterable): Builder { + fun add(container: IEnhancedContainer, slots: Iterable): Builder { values.add(container to slots) return this } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerSlot.kt index 2106682a5..2ab6e6119 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerSlot.kt @@ -17,7 +17,7 @@ import ru.dbotthepony.mc.otm.data.getOrNull open class ContainerSlot( protected val container: SlottedContainer, protected val slot: Int -) : ISlottedContainerSlot, INBTSerializable { +) : IAutomatedContainerSlot, INBTSerializable { private var _item: ItemStack = ItemStack.EMPTY final override var item: ItemStack @@ -130,7 +130,7 @@ open class ContainerSlot( listener: (new: ItemStack, old: ItemStack) -> Unit, maxStackSize: Int = Item.DEFAULT_MAX_STACK_SIZE, ) : Simple(listener, maxStackSize) { - protected open inner class Instance(container: SlottedContainer, slot: Int) : Simple.Instance(container, slot), IFilteredSlottedContainerSlot { + protected open inner class Instance(container: SlottedContainer, slot: Int) : Simple.Instance(container, slot), IFilteredAutomatedContainerSlot { override var filter: Item? = null set(value) { if (field !== value) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt new file mode 100644 index 000000000..644b30b3e --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt @@ -0,0 +1,40 @@ +package ru.dbotthepony.mc.otm.container + +import net.minecraft.world.Container +import net.minecraft.world.item.ItemStack +import net.neoforged.neoforge.items.IItemHandler + +/** + * Reinforced [ISlottedContainer] which slots are [IAutomatedContainerSlot]s, which + * subsequently allow this container to implement [IItemHandler] + */ +interface IAutomatedContainer : ISlottedContainer, IItemHandler { + override fun containerSlot(slot: Int): IAutomatedContainerSlot + + override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean { + return containerSlot(slot).canAutomationPlaceItem(itemStack) + } + + override fun canTakeItem(container: Container, slot: Int, itemStack: ItemStack): Boolean { + return containerSlot(slot).canAutomationTakeItem() + } + + override fun getSlots() = containerSize + override fun getStackInSlot(slot: Int) = containerSlot(slot).item + + override fun insertItem(slot: Int, stack: ItemStack, simulate: Boolean): ItemStack { + return containerSlot(slot).insertItem(stack, simulate) + } + + override fun extractItem(slot: Int, amount: Int, simulate: Boolean): ItemStack { + return containerSlot(slot).extractItem(amount, simulate) + } + + override fun getSlotLimit(slot: Int): Int { + return containerSlot(slot).maxStackSize + } + + override fun isItemValid(slot: Int, stack: ItemStack): Boolean { + return canPlaceItem(slot, stack) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainerSlot.kt similarity index 97% rename from src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainerSlot.kt rename to src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainerSlot.kt index 9da3d32da..16ca182f2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainerSlot.kt @@ -6,7 +6,7 @@ import net.neoforged.neoforge.items.IItemHandler /** * Slot of [ISlottedContainer], with additional methods to implement interaction behavior for both for players and mechanisms */ -interface ISlottedContainerSlot : IContainerSlot { +interface IAutomatedContainerSlot : IContainerSlot { fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { return true } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt index f61bc6b86..34a1ddd75 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt @@ -24,6 +24,9 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable { return IContainerSlot.Simple(slot, this) } + /** + * Returns iterator over **all** slots this container has + */ fun slotIterator(): Iterator { return (0 until containerSize).iterator().map { containerSlot(it) } } @@ -122,6 +125,9 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable { return maxStackSize } + /** + * Returns iterator over **non-empty** [ItemStack]s inside this container + */ override fun iterator(): Iterator { return (0 until containerSize).iterator().map { this[it] }.filter { it.isNotEmpty } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredSlottedContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredAutomatedContainerSlot.kt similarity index 71% rename from src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredSlottedContainerSlot.kt rename to src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredAutomatedContainerSlot.kt index 91f1d9da2..b61234064 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredSlottedContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredAutomatedContainerSlot.kt @@ -2,7 +2,7 @@ package ru.dbotthepony.mc.otm.container import net.minecraft.world.item.ItemStack -interface IFilteredSlottedContainerSlot : IFilteredContainerSlot, ISlottedContainerSlot { +interface IFilteredAutomatedContainerSlot : IFilteredContainerSlot, IAutomatedContainerSlot { override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { return super.canAutomationPlaceItem(itemStack) && testSlotFilter(itemStack) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt index dfccd28e0..c6cdb88ad 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt @@ -9,17 +9,14 @@ import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.collect.map /** - * Container which revolve around embedding slot objects rather than providing direct item access, - * and subsequently fully implement [IItemHandler] + * Container which revolve around embedding slot objects rather than providing direct item access */ -interface ISlottedContainer : IEnhancedContainer, IItemHandler { - override fun containerSlot(slot: Int): ISlottedContainerSlot - - override fun slotIterator(): Iterator { +interface ISlottedContainer : IEnhancedContainer { + override fun slotIterator(): Iterator { return (0 until containerSize).iterator().map { containerSlot(it) } } - override fun nonEmptySlotIterator(): Iterator { + override fun nonEmptySlotIterator(): Iterator { return (0 until containerSize).iterator().map { containerSlot(it) }.filter { it.isNotEmpty } } @@ -47,33 +44,6 @@ interface ISlottedContainer : IEnhancedContainer, IItemHandler { containerSlot(slot).item = itemStack } - override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean { - return containerSlot(slot).canAutomationPlaceItem(itemStack) - } - - override fun canTakeItem(container: Container, slot: Int, itemStack: ItemStack): Boolean { - return containerSlot(slot).canAutomationTakeItem() - } - - override fun getSlots() = containerSize - override fun getStackInSlot(slot: Int) = containerSlot(slot).item - - override fun insertItem(slot: Int, stack: ItemStack, simulate: Boolean): ItemStack { - return containerSlot(slot).insertItem(stack, simulate) - } - - override fun extractItem(slot: Int, amount: Int, simulate: Boolean): ItemStack { - return containerSlot(slot).extractItem(amount, simulate) - } - - override fun getSlotLimit(slot: Int): Int { - return containerSlot(slot).maxStackSize - } - - override fun isItemValid(slot: Int, stack: ItemStack): Boolean { - return canPlaceItem(slot, stack) - } - private fun addItem(stack: ItemStack, simulate: Boolean, filterPass: Boolean, slots: IntSet, onlyIntoExisting: Boolean, popTime: Int?, ignoreFilters: Boolean): ItemStack { if (stack.isEmpty || slots.isEmpty()) return stack diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainer.kt index d978031c2..18dde606f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainer.kt @@ -15,7 +15,6 @@ import net.minecraft.world.item.ItemStack import net.neoforged.neoforge.common.util.INBTSerializable import org.apache.logging.log4j.LogManager import ru.dbotthepony.mc.otm.core.isNotEmpty -import ru.dbotthepony.mc.otm.core.math.set import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.data.codec.minRange import java.util.function.Predicate @@ -24,7 +23,7 @@ class SlottedContainer( slots: Collection, private val stillValid: Predicate, private val globalChangeListeners: Array -) : ISlottedContainer, INBTSerializable { +) : IAutomatedContainer, INBTSerializable { private val slots: Array init { @@ -46,7 +45,7 @@ class SlottedContainer( } } - override fun containerSlot(slot: Int): ISlottedContainerSlot { + override fun containerSlot(slot: Int): IAutomatedContainerSlot { return slots[slot] } From 6764af0dcc60984768f9131ed90810ac2885440d Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 28 Feb 2025 08:38:09 +0700 Subject: [PATCH 007/154] Misc improvements for CombinedContainer --- .../mc/otm/container/CombinedContainer.kt | 28 ++----------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt index 3eb596d83..e255cd03a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt @@ -93,27 +93,7 @@ class CombinedContainer(containers: Stream { From ab1446b6820692daec1e3a3f3ca16005cc259ed5 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 28 Feb 2025 09:10:03 +0700 Subject: [PATCH 008/154] Move SlottedContainer to subpackage --- .../mc/otm/container/{ => slotted}/ContainerSlot.kt | 7 +++++-- .../otm/container/{ => slotted}/SlottedContainer.kt | 11 +++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) rename src/main/kotlin/ru/dbotthepony/mc/otm/container/{ => slotted}/ContainerSlot.kt (94%) rename src/main/kotlin/ru/dbotthepony/mc/otm/container/{ => slotted}/SlottedContainer.kt (94%) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt similarity index 94% rename from src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerSlot.kt rename to src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt index 2ab6e6119..990bb32fc 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt @@ -1,4 +1,4 @@ -package ru.dbotthepony.mc.otm.container +package ru.dbotthepony.mc.otm.container.slotted import net.minecraft.core.HolderLookup import net.minecraft.core.registries.BuiltInRegistries @@ -9,6 +9,8 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import net.neoforged.neoforge.common.util.INBTSerializable import org.apache.logging.log4j.LogManager +import ru.dbotthepony.mc.otm.container.IAutomatedContainerSlot +import ru.dbotthepony.mc.otm.container.IFilteredAutomatedContainerSlot import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.registryName @@ -130,7 +132,8 @@ open class ContainerSlot( listener: (new: ItemStack, old: ItemStack) -> Unit, maxStackSize: Int = Item.DEFAULT_MAX_STACK_SIZE, ) : Simple(listener, maxStackSize) { - protected open inner class Instance(container: SlottedContainer, slot: Int) : Simple.Instance(container, slot), IFilteredAutomatedContainerSlot { + protected open inner class Instance(container: SlottedContainer, slot: Int) : Simple.Instance(container, slot), + IFilteredAutomatedContainerSlot { override var filter: Item? = null set(value) { if (field !== value) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt similarity index 94% rename from src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainer.kt rename to src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt index 18dde606f..45c7d60b9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/SlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt @@ -1,4 +1,4 @@ -package ru.dbotthepony.mc.otm.container +package ru.dbotthepony.mc.otm.container.slotted import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder @@ -14,6 +14,9 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import net.neoforged.neoforge.common.util.INBTSerializable import org.apache.logging.log4j.LogManager +import ru.dbotthepony.mc.otm.container.IAutomatedContainer +import ru.dbotthepony.mc.otm.container.IAutomatedContainerSlot +import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.data.codec.minRange @@ -83,7 +86,7 @@ class SlottedContainer( it.group( ItemStack.OPTIONAL_CODEC.fieldOf("item").forGetter { it.item }, Codec.INT.minRange(0).fieldOf("slot").forGetter { it.slot }, - ).apply(it, ::LegacySerializedItem) + ).apply(it, SlottedContainer::LegacySerializedItem) } } } @@ -94,7 +97,7 @@ class SlottedContainer( it.group( BuiltInRegistries.ITEM.byNameCodec().fieldOf("item").forGetter { it.item }, Codec.INT.minRange(0).fieldOf("slot").forGetter { it.slot }, - ).apply(it, ::LegacySerializedFilter) + ).apply(it, SlottedContainer::LegacySerializedFilter) } } } @@ -108,7 +111,7 @@ class SlottedContainer( it.group( Codec.list(LegacySerializedItem.CODEC).fieldOf("items").forGetter { it.items }, Codec.list(LegacySerializedFilter.CODEC).fieldOf("filters").forGetter { it.filters }, - ).apply(it, ::LegacySerializedState) + ).apply(it, SlottedContainer::LegacySerializedState) } } } From 9f6b9ad85b56d464f49d51fe2a1e5b2ae6b389ba Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 28 Feb 2025 15:23:08 +0700 Subject: [PATCH 009/154] Some helper functions, split "Filtered" into own subclass with own "Simple" factory --- .../mc/otm/container/ContainerHelpers.kt | 2 +- .../mc/otm/container/IEnhancedContainer.kt | 11 +- .../mc/otm/container/ISlottedContainer.kt | 19 +-- .../mc/otm/container/slotted/ContainerSlot.kt | 56 ++----- .../slotted/FilteredContainerSlot.kt | 83 +++++++++ .../otm/container/slotted/SimpleCallbacks.kt | 19 +++ .../otm/container/slotted/SlottedContainer.kt | 157 ++++++++++++++++-- 7 files changed, 280 insertions(+), 67 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SimpleCallbacks.kt 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 4a3f69ce2..cb61feae0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerHelpers.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerHelpers.kt @@ -56,7 +56,7 @@ fun Container.vanishCursedItems() { } } -fun Container.balance(slots: IntSet, checkForEmpty: Boolean = true) { +fun Container.balance(slots: IntCollection, checkForEmpty: Boolean = true) { if (slots.isEmpty() || checkForEmpty && !slots.any { getItem(it).isNotEmpty }) return val empty = IntArrayList() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt index 34a1ddd75..c7deb64af 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt @@ -1,5 +1,6 @@ package ru.dbotthepony.mc.otm.container +import it.unimi.dsi.fastutil.ints.IntCollection import it.unimi.dsi.fastutil.ints.IntSet import net.minecraft.world.Container import net.minecraft.world.entity.player.Player @@ -32,10 +33,10 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable { } fun nonEmptySlotIterator(): Iterator { - return (0 until containerSize).iterator().map { containerSlot(it) }.filter { it.isNotEmpty } + return slotIterator().filter { it.isNotEmpty } } - private fun slotIterator(allowedSlots: IntSet, predicate: Predicate): IntIterator { + private fun slotIterator(allowedSlots: IntCollection, predicate: Predicate): IntIterator { return object : IntIterator() { private val parent = allowedSlots.intIterator() private var foundNext = false @@ -76,15 +77,15 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable { } } - fun emptySlotIterator(allowedSlots: IntSet = slotRange): IntIterator { + fun emptySlotIterator(allowedSlots: IntCollection = slotRange): IntIterator { return slotIterator(allowedSlots) { it.isEmpty } } - fun nonEmptySlotIterator(allowedSlots: IntSet = slotRange): IntIterator { + fun nonEmptySlotIterator(allowedSlots: IntCollection = slotRange): IntIterator { return slotIterator(allowedSlots) { it.isNotEmpty } } - fun slotWithItemIterator(item: Item, allowedSlots: IntSet = slotRange): IntIterator { + fun slotWithItemIterator(item: Item, allowedSlots: IntCollection = slotRange): IntIterator { return slotIterator(allowedSlots) { it.isNotEmpty && it.item === item } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt index c6cdb88ad..58430a103 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt @@ -1,5 +1,6 @@ package ru.dbotthepony.mc.otm.container +import it.unimi.dsi.fastutil.ints.IntCollection import it.unimi.dsi.fastutil.ints.IntSet import net.minecraft.world.Container import net.minecraft.world.item.ItemStack @@ -9,17 +10,9 @@ import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.collect.map /** - * Container which revolve around embedding slot objects rather than providing direct item access + * Skeletal implementation for containers which revolve around [IContainerSlot] */ interface ISlottedContainer : IEnhancedContainer { - override fun slotIterator(): Iterator { - return (0 until containerSize).iterator().map { containerSlot(it) } - } - - override fun nonEmptySlotIterator(): Iterator { - return (0 until containerSize).iterator().map { containerSlot(it) }.filter { it.isNotEmpty } - } - override fun setChanged(slot: Int) { containerSlot(slot).setChanged() } @@ -44,7 +37,7 @@ interface ISlottedContainer : IEnhancedContainer { containerSlot(slot).item = itemStack } - private fun addItem(stack: ItemStack, simulate: Boolean, filterPass: Boolean, slots: IntSet, onlyIntoExisting: Boolean, popTime: Int?, ignoreFilters: Boolean): ItemStack { + private fun addItem(stack: ItemStack, simulate: Boolean, filterPass: Boolean, slots: IntCollection, onlyIntoExisting: Boolean, popTime: Int?, ignoreFilters: Boolean): ItemStack { if (stack.isEmpty || slots.isEmpty()) return stack @@ -129,7 +122,7 @@ interface ISlottedContainer : IEnhancedContainer { val hasFilterableSlots: Boolean get() = slotIterator().any { it is IFilteredContainerSlot } - fun addItem(stack: ItemStack, simulate: Boolean, slots: IntSet = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean): ItemStack { + fun addItem(stack: ItemStack, simulate: Boolean, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean): ItemStack { if (stack.isEmpty || slots.isEmpty()) return stack @@ -148,7 +141,7 @@ interface ISlottedContainer : IEnhancedContainer { * * @return Whenever [stack] was modified */ - fun consumeItem(stack: ItemStack, simulate: Boolean, slots: IntSet = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean): Boolean { + fun consumeItem(stack: ItemStack, simulate: Boolean, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean): Boolean { if (stack.isEmpty) return false @@ -157,7 +150,7 @@ interface ISlottedContainer : IEnhancedContainer { return result.count != stack.count } - fun fullyAddItem(stack: ItemStack, slots: IntSet = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean): Boolean { + fun fullyAddItem(stack: ItemStack, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean): Boolean { if (!addItem(stack, true, slots, popTime = popTime, onlyIntoExisting = onlyIntoExisting, ignoreFilters = ignoreFilters).isEmpty) return false diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt index 990bb32fc..7ab61cebd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt @@ -109,11 +109,15 @@ open class ContainerSlot( notifyChanged(ItemStack.EMPTY) } - open class Simple( - protected val listener: (new: ItemStack, old: ItemStack) -> Unit, - protected val maxStackSize: Int = Item.DEFAULT_MAX_STACK_SIZE, - ) : SlottedContainer.SlotProvider { - protected open inner class Instance(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) { + class Simple( + private val listener: (new: ItemStack, old: ItemStack) -> Unit = { _, _ -> }, + private val maxStackSize: Int = Item.DEFAULT_MAX_STACK_SIZE, + private val canAutomationPlaceItem: AutomationPlaceItem = AutomationPlaceItem { _, _ -> true }, + private val canAutomationTakeItem: AutomationTakeItem = AutomationTakeItem { _, _ -> true }, + private val modifyAutomationPlaceCount: AutomationModifyPlaceCount = AutomationModifyPlaceCount { _, item -> item.count }, + private val modifyAutomationExtractionCount: AutomationModifyExtractionCount = AutomationModifyExtractionCount { _, desired -> desired }, + ) : SlottedContainer.SlotProvider { + private open inner class Instance(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) { override val maxStackSize: Int get() = this@Simple.maxStackSize @@ -121,45 +125,21 @@ open class ContainerSlot( super.notifyChanged(old) listener(item, old) } - } - override fun create(container: SlottedContainer, index: Int): ContainerSlot { - return Instance(container, index) - } - } - - open class Filtered( - listener: (new: ItemStack, old: ItemStack) -> Unit, - maxStackSize: Int = Item.DEFAULT_MAX_STACK_SIZE, - ) : Simple(listener, maxStackSize) { - protected open inner class Instance(container: SlottedContainer, slot: Int) : Simple.Instance(container, slot), - IFilteredAutomatedContainerSlot { - override var filter: Item? = null - set(value) { - if (field !== value) { - field = value - container.notifyChanged() - } - } - - override fun clear() { - super.clear() - filter = null + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + return super.canAutomationPlaceItem(itemStack) && canAutomationPlaceItem.canAutomationPlaceItem(this, itemStack) } - override fun serializeNBT(provider: HolderLookup.Provider): CompoundTag { - return super.serializeNBT(provider).also { - if (filter != null) - it["filter"] = filter!!.registryName!!.toString() - } + override fun canAutomationTakeItem(desired: Int): Boolean { + return super.canAutomationTakeItem(desired) && canAutomationTakeItem.canAutomationTakeItem(this, desired) } - override fun deserializeNBT(provider: HolderLookup.Provider, nbt: CompoundTag) { - super.deserializeNBT(provider, nbt) + override fun modifyAutomationPlaceCount(itemStack: ItemStack): Int { + return modifyAutomationPlaceCount.modifyAutomationPlaceCount(this, itemStack) + } - if ("filter" in nbt) { - filter = BuiltInRegistries.ITEM.get(ResourceLocation.parse(nbt.getString("filter"))) - } + override fun modifyAutomationExtractionCount(desired: Int): Int { + return modifyAutomationExtractionCount.modifyAutomationExtractionCount(this, desired) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt new file mode 100644 index 000000000..4a067fd75 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt @@ -0,0 +1,83 @@ +package ru.dbotthepony.mc.otm.container.slotted + +import net.minecraft.core.HolderLookup +import net.minecraft.core.registries.BuiltInRegistries +import net.minecraft.nbt.CompoundTag +import net.minecraft.resources.ResourceLocation +import net.minecraft.world.item.Item +import net.minecraft.world.item.ItemStack +import ru.dbotthepony.mc.otm.container.IFilteredAutomatedContainerSlot +import ru.dbotthepony.mc.otm.core.nbt.set +import ru.dbotthepony.mc.otm.core.registryName + +open class FilteredContainerSlot( + container: SlottedContainer, + slot: Int +) : ContainerSlot(container, slot), IFilteredAutomatedContainerSlot { + override var filter: Item? = null + set(value) { + if (field !== value) { + field = value + container.notifyChanged() + } + } + + override fun clear() { + super.clear() + filter = null + } + + override fun serializeNBT(provider: HolderLookup.Provider): CompoundTag { + return super.serializeNBT(provider).also { + if (filter != null) + it["filter"] = filter!!.registryName!!.toString() + } + } + + override fun deserializeNBT(provider: HolderLookup.Provider, nbt: CompoundTag) { + super.deserializeNBT(provider, nbt) + + if ("filter" in nbt) { + filter = BuiltInRegistries.ITEM.get(ResourceLocation.parse(nbt.getString("filter"))) + } + } + + class Simple( + private val listener: (new: ItemStack, old: ItemStack) -> Unit = { _, _ -> }, + private val maxStackSize: Int = Item.DEFAULT_MAX_STACK_SIZE, + private val canAutomationPlaceItem: AutomationPlaceItem = AutomationPlaceItem { _, _ -> true }, + private val canAutomationTakeItem: AutomationTakeItem = AutomationTakeItem { _, _ -> true }, + private val modifyAutomationPlaceCount: AutomationModifyPlaceCount = AutomationModifyPlaceCount { _, item -> item.count }, + private val modifyAutomationExtractionCount: AutomationModifyExtractionCount = AutomationModifyExtractionCount { _, desired -> desired }, + ) : SlottedContainer.SlotProvider { + private open inner class Instance(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) { + override val maxStackSize: Int + get() = this@Simple.maxStackSize + + override fun notifyChanged(old: ItemStack) { + super.notifyChanged(old) + listener(item, old) + } + + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + return super.canAutomationPlaceItem(itemStack) && canAutomationPlaceItem.canAutomationPlaceItem(this, itemStack) + } + + override fun canAutomationTakeItem(desired: Int): Boolean { + return super.canAutomationTakeItem(desired) && canAutomationTakeItem.canAutomationTakeItem(this, desired) + } + + override fun modifyAutomationPlaceCount(itemStack: ItemStack): Int { + return modifyAutomationPlaceCount.modifyAutomationPlaceCount(this, itemStack) + } + + override fun modifyAutomationExtractionCount(desired: Int): Int { + return modifyAutomationExtractionCount.modifyAutomationExtractionCount(this, desired) + } + } + + override fun create(container: SlottedContainer, index: Int): FilteredContainerSlot { + return Instance(container, index) + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SimpleCallbacks.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SimpleCallbacks.kt new file mode 100644 index 000000000..664d268f0 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SimpleCallbacks.kt @@ -0,0 +1,19 @@ +package ru.dbotthepony.mc.otm.container.slotted + +import net.minecraft.world.item.ItemStack + +fun interface AutomationPlaceItem { + fun canAutomationPlaceItem(self: S, itemStack: ItemStack): Boolean +} + +fun interface AutomationTakeItem { + fun canAutomationTakeItem(self: S, desired: Int): Boolean +} + +fun interface AutomationModifyPlaceCount { + fun modifyAutomationPlaceCount(self: S, itemStack: ItemStack): Int +} + +fun interface AutomationModifyExtractionCount { + fun modifyAutomationExtractionCount(self: S, desired: Int): Int +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt index 45c7d60b9..c342b464c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt @@ -2,6 +2,11 @@ package ru.dbotthepony.mc.otm.container.slotted import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder +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.ints.IntSet +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet import net.minecraft.core.HolderLookup import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.nbt.CompoundTag @@ -14,24 +19,106 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import net.neoforged.neoforge.common.util.INBTSerializable import org.apache.logging.log4j.LogManager +import ru.dbotthepony.kommons.util.Either import ru.dbotthepony.mc.otm.container.IAutomatedContainer import ru.dbotthepony.mc.otm.container.IAutomatedContainerSlot import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot +import ru.dbotthepony.mc.otm.container.balance +import ru.dbotthepony.mc.otm.container.slotRange import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.data.codec.minRange import java.util.function.Predicate +import kotlin.reflect.KClass class SlottedContainer( - slots: Collection, + slots: Collection>, private val stillValid: Predicate, private val globalChangeListeners: Array ) : IAutomatedContainer, INBTSerializable { + interface ISlotGroup : List { + /** + * @see IAutomatedContainer.addItem + */ + fun addItem(stack: ItemStack, simulate: Boolean, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean = false): ItemStack + + /** + * @see IAutomatedContainer.consumeItem + */ + fun consumeItem(stack: ItemStack, simulate: Boolean, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean = false): Boolean + + /** + * @see IAutomatedContainer.fullyAddItem + */ + fun fullyAddItem(stack: ItemStack, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean = false): Boolean + + fun balance() + } + + private inner class SlotGroup : ISlotGroup, AbstractList() { + val slots = IntArrayList() + + override val size: Int + get() = slots.size + + override fun get(index: Int): T { + return this@SlottedContainer.slots[slots.getInt(index)] as T + } + + override fun addItem(stack: ItemStack, simulate: Boolean, onlyIntoExisting: Boolean, popTime: Int?, ignoreFilters: Boolean): ItemStack { + return this@SlottedContainer.addItem(stack, simulate, slots, onlyIntoExisting, popTime, ignoreFilters) + } + + override fun consumeItem(stack: ItemStack, simulate: Boolean, onlyIntoExisting: Boolean, popTime: Int?, ignoreFilters: Boolean): Boolean { + return this@SlottedContainer.consumeItem(stack, simulate, slots, onlyIntoExisting, popTime, ignoreFilters) + } + + override fun fullyAddItem( + stack: ItemStack, + onlyIntoExisting: Boolean, + popTime: Int?, + ignoreFilters: Boolean + ): Boolean { + return this@SlottedContainer.fullyAddItem(stack, slots, onlyIntoExisting, popTime, ignoreFilters) + } + + override fun balance() { + return this@SlottedContainer.balance(slots) + } + } + + class SingleTag(val clazz: KClass) { + override fun toString(): String { + return "SlottedContainer.SingleTag[${System.identityHashCode(this).toString(16)}@${clazz.qualifiedName}]" + } + } + + class MultiTag(val clazz: KClass) { + override fun toString(): String { + return "SlottedContainer.MultiTag[${System.identityHashCode(this).toString(16)}@${clazz.qualifiedName}]" + } + } + + private val sets = HashMap, SlotGroup<*>>() + private val singular = HashMap, ContainerSlot>() private val slots: Array init { val itr = slots.iterator() - this.slots = Array(slots.size) { itr.next().create(this, it) } + this.slots = Array(slots.size) { index -> + val (mark, provider) = itr.next() + val slot = provider.create(this, index) + mark?.map({ require(singular.put(it, slot) == null) { "Duplicate Slot tag: $it" } }, { sets.computeIfAbsent(it) { SlotGroup() }.slots.add(index) }) + slot + } + } + + operator fun get(tag: MultiTag): ISlotGroup { + return sets[tag] as ISlotGroup? ?: throw NoSuchElementException("Container does not contain $tag") + } + + operator fun get(tag: SingleTag): T { + return singular[tag] as T? ?: throw NoSuchElementException("Container does not contain $tag") } override val hasFilterableSlots: Boolean = this.slots.any { it is IFilteredContainerSlot } @@ -218,23 +305,44 @@ class SlottedContainer( notifyChanged() } - fun interface SlotProvider { - fun create(container: SlottedContainer, index: Int): ContainerSlot + fun interface SlotProvider { + fun create(container: SlottedContainer, index: Int): T } + data class MarkedSlotProvider(val mark: Either, MultiTag>?, val provider: SlotProvider) + class Builder { - private val slots = ArrayList() + private val slots = ArrayList>() private var stillValid = Predicate { true } private val globalChangeListeners = ArrayList() + private val seenSingleTags = ObjectOpenHashSet>() - fun add(slot: SlotProvider): Builder { - slots.add(slot) + fun add(slot: SlotProvider<*>): Builder { + slots.add(MarkedSlotProvider(null, slot)) return this } - fun add(amount: Int, provider: SlotProvider): Builder { + fun add(tag: SingleTag, slot: SlotProvider): Builder { + require(seenSingleTags.add(tag)) { "Duplicate slot tag: $tag" } + slots.add(MarkedSlotProvider(Either.left(tag), slot)) + return this + } + + fun add(tag: MultiTag, slot: SlotProvider): Builder { + slots.add(MarkedSlotProvider(Either.right(tag), slot)) + return this + } + + fun add(amount: Int, provider: SlotProvider<*>): Builder { for (i in 0 until amount) - slots.add(provider) + slots.add(MarkedSlotProvider(null, provider)) + + return this + } + + fun add(amount: Int, tag: MultiTag, provider: SlotProvider): Builder { + for (i in 0 until amount) + slots.add(MarkedSlotProvider(Either.right(tag), provider)) return this } @@ -262,8 +370,37 @@ class SlottedContainer( } } - companion object { private val LOGGER = LogManager.getLogger() + + inline fun tag(): SingleTag { + return SingleTag(T::class) + } + + inline fun tagList(): MultiTag { + return MultiTag(T::class) + } + + fun simple(size: Int): SlottedContainer { + return Builder().add(size, ::ContainerSlot).build() + } + + fun simple(size: Int, listener: Runnable): SlottedContainer { + return Builder() + .add(size, ::ContainerSlot) + .onChanged(listener) + .build() + } + + fun filtered(size: Int): SlottedContainer { + return Builder().add(size, ::FilteredContainerSlot).build() + } + + fun filtered(size: Int, listener: Runnable): SlottedContainer { + return Builder() + .add(size, ::FilteredContainerSlot) + .onChanged(listener) + .build() + } } } From 5e8ab76f4943207086fbe8d04f4f7c432ce36e2b Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 28 Feb 2025 15:38:37 +0700 Subject: [PATCH 010/154] Update MatteryContainer to fix compilation error --- .../dbotthepony/mc/otm/container/MatteryContainer.kt | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt index 53b155f8d..9f890e005 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt @@ -426,10 +426,7 @@ open class MatteryContainer(var listener: ContainerListener, private val size: I } } - private inner class Slot(override val slot: Int) : IFilteredContainerSlot { - override val container: Container - get() = this@MatteryContainer - + inner class Slot(val slot: Int) : IFilteredContainerSlot { override var item: ItemStack get() = this@MatteryContainer[slot] set(value) { this@MatteryContainer[slot] = value } @@ -460,12 +457,12 @@ open class MatteryContainer(var listener: ContainerListener, private val size: I } } - final override fun slotIterator(): kotlin.collections.Iterator { + final override fun slotIterator(): kotlin.collections.Iterator { indicesReferenced = true return nonEmptyIndices.iterator().map { Slot(it) } } - final override fun slotIterator(nonEmpty: Boolean): kotlin.collections.Iterator { + final override fun slotIterator(nonEmpty: Boolean): kotlin.collections.Iterator { if (!nonEmpty) { return (0 until size).iterator().map { Slot(it) } } else if (isEmpty) { @@ -476,7 +473,7 @@ open class MatteryContainer(var listener: ContainerListener, private val size: I } } - final override fun containerSlot(slot: Int): IFilteredContainerSlot { + final override fun containerSlot(slot: Int): Slot { return Slot(slot) } From ffdd44357db5f3f145b454df28feef97c4bde0c2 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 28 Feb 2025 20:16:23 +0700 Subject: [PATCH 011/154] Make it compile again so migration can be done incrementally --- .../ru/dbotthepony/mc/otm/capability/Ext.kt | 2 +- .../mc/otm/capability/MatteryPlayer.kt | 10 ++++++++ .../mc/otm/container/IContainerSlot.kt | 2 +- .../mc/otm/container/IMatteryContainer.kt | 23 ++++--------------- .../mc/otm/menu/decorative/PainterMenu.kt | 3 ++- .../mc/otm/menu/matter/MatterBottlerMenu.kt | 3 ++- .../otm/menu/matter/MatterReplicatorMenu.kt | 3 ++- 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/Ext.kt index d2ac47101..a95c4f8b7 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/Ext.kt @@ -149,7 +149,7 @@ val ItemStack.matteryEnergy: IMatteryEnergyStorage? get() { } fun Player.items(includeCosmetics: Boolean = true): Iterator { - val matteryPlayer = matteryPlayer ?: return emptyIterator() + val matteryPlayer = matteryPlayer val iterators = ArrayList>() iterators.add(matteryPlayer.wrappedInventory.slotIterator().filter { !it.isForbiddenForAutomation }.map { it.item }) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayer.kt index a0211b503..72eedca24 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayer.kt @@ -79,6 +79,8 @@ import ru.dbotthepony.mc.otm.config.ExopackConfig import ru.dbotthepony.mc.otm.container.CombinedContainer import ru.dbotthepony.mc.otm.container.DynamicallyProxiedContainer import ru.dbotthepony.mc.otm.container.IContainer +import ru.dbotthepony.mc.otm.container.IContainerSlot +import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot import ru.dbotthepony.mc.otm.container.IMatteryContainer import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.get @@ -329,6 +331,14 @@ class MatteryPlayer(val ply: Player) { override fun clearSlotFilters() { regularSlotFilters.forEach { it.accept(null) } } + + override fun containerSlot(slot: Int): IFilteredContainerSlot { + return object : IContainerSlot.Simple(slot, this), IFilteredContainerSlot { + override var filter: Item? + get() = regularSlotFilters.getOrNull(slot)?.get() + set(value) { regularSlotFilters.getOrNull(slot)?.accept(value) } + } + } } val wrappedItemInventory: IMatteryContainer = object : IMatteryContainer by wrappedInventory { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IContainerSlot.kt index de28c6fa4..f5f8e26d2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IContainerSlot.kt @@ -47,7 +47,7 @@ interface IContainerSlot : Delegate { val isNotEmpty: Boolean get() = item.isNotEmpty - class Simple(private val slot: Int, private val container: Container) : IContainerSlot { + open class Simple(protected val slot: Int, protected val container: Container) : IContainerSlot { override fun setChanged() { container.setChanged() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt index 6dc2e7e87..b41c5f2eb 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt @@ -9,7 +9,7 @@ import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.collect.map import ru.dbotthepony.mc.otm.core.isNotEmpty -interface IMatteryContainer : IContainer, RecipeInput, Iterable { +interface IMatteryContainer : IEnhancedContainer { fun getSlotFilter(slot: Int): Item? /** @@ -22,7 +22,6 @@ interface IMatteryContainer : IContainer, RecipeInput, Iterable { fun clearSlotFilters() override fun isEmpty(): Boolean - fun setChanged(slot: Int) override fun size(): Int { return containerSize @@ -38,7 +37,7 @@ interface IMatteryContainer : IContainer, RecipeInput, Iterable { /** * Iterates non-empty slots of this container */ - fun slotIterator(): Iterator { + override fun slotIterator(): Iterator { return slotIterator(true) } @@ -53,7 +52,7 @@ interface IMatteryContainer : IContainer, RecipeInput, Iterable { /** * Iterates either non-empty slots of container or all slots of container */ - fun slotIterator(nonEmpty: Boolean): Iterator { + fun slotIterator(nonEmpty: Boolean): Iterator { if (nonEmpty) { return (0 until containerSize).iterator().filter { this[it].isNotEmpty }.map { containerSlot(it) } } else { @@ -61,9 +60,7 @@ interface IMatteryContainer : IContainer, RecipeInput, Iterable { } } - fun containerSlot(slot: Int): IContainerSlot { - return IContainerSlot.Simple(slot, this) - } + override fun containerSlot(slot: Int): IFilteredContainerSlot fun hasSlotFilter(slot: Int) = getSlotFilter(slot) !== null fun isSlotForbiddenForAutomation(slot: Int) = getSlotFilter(slot) === Items.AIR @@ -80,7 +77,7 @@ interface IMatteryContainer : IContainer, RecipeInput, Iterable { } } - fun getMaxStackSize(slot: Int, itemStack: ItemStack) = maxStackSize.coerceAtMost(itemStack.maxStackSize) + override fun getMaxStackSize(slot: Int, itemStack: ItemStack) = maxStackSize.coerceAtMost(itemStack.maxStackSize) private fun addItem(stack: ItemStack, simulate: Boolean, filterPass: Boolean, slots: IntIterable, onlyIntoExisting: Boolean, popTime: Int?, ignoreFilters: Boolean): ItemStack { if (stack.isEmpty) @@ -203,14 +200,4 @@ interface IMatteryContainer : IContainer, RecipeInput, Iterable { return addItem(stack, false, slots, ignoreFilters).isEmpty } - - fun toList(): MutableList { - val list = ArrayList(size()) - - for (i in 0 until size()) { - list.add(this[i]) - } - - return list - } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/PainterMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/PainterMenu.kt index 027b7ed25..99f364506 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/PainterMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/PainterMenu.kt @@ -79,7 +79,8 @@ class PainterMenu( if (isBulk.value) { val found = player.matteryPlayer.inventoryAndExopack .slotIterator() - .filter { !it.isForbiddenForAutomation && ItemStack.isSameItemSameComponents(it.item, inputSlot.item) } + //.filter { !it.isForbiddenForAutomation && ItemStack.isSameItemSameComponents(it.item, inputSlot.item) } + .filter { ItemStack.isSameItemSameComponents(it.item, inputSlot.item) } .maybe() if (found != null) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterBottlerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterBottlerMenu.kt index b83cd4b6b..b3817461c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterBottlerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterBottlerMenu.kt @@ -9,6 +9,7 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.matter.canExtractMatter import ru.dbotthepony.mc.otm.capability.matter.canReceiveMatter import ru.dbotthepony.mc.otm.container.CombinedContainer +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget @@ -28,7 +29,7 @@ class MatterBottlerMenu( val progressWidget = ProgressGaugeWidget(this) val matterWidget = ProfiledLevelGaugeWidget(this, tile?.matter, LevelGaugeWidget(this, tile?.matter)) - val storageSlots: ImmutableList = makeSlots(CombinedContainer(tile?.bottling ?: SimpleContainer(3), tile?.unbottling ?: SimpleContainer(3))) { it, index -> + val storageSlots: ImmutableList = makeSlots(CombinedContainer(tile?.bottling ?: SlottedContainer.simple(3), tile?.unbottling ?: SlottedContainer.simple(3))) { it, index -> object : MatterySlot(it, index) { override fun mayPlace(itemStack: ItemStack): Boolean { val cap = itemStack.getCapability(MatteryCapability.MATTER_ITEM) ?: return false diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReplicatorMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReplicatorMenu.kt index 0bbc18fec..d37fba87d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReplicatorMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReplicatorMenu.kt @@ -8,6 +8,7 @@ import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget import net.minecraft.world.SimpleContainer import ru.dbotthepony.mc.otm.container.CombinedContainer +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.menu.OutputSlot @@ -34,7 +35,7 @@ class MatterReplicatorMenu @JvmOverloads constructor( val upgrades = makeUpgradeSlots(3, tile?.upgrades) init { - val container = CombinedContainer(tile?.outputContainer ?: SimpleContainer(3), tile?.dustContainer ?: SimpleContainer(2)) + val container = CombinedContainer(tile?.outputContainer ?: SlottedContainer.simple(3), tile?.dustContainer ?: SlottedContainer.simple(2)) storageSlots = immutableList(5) { addStorageSlot(OutputSlot(container, it, onTake = { From 30263bf30e6832058f94dd5fb0c4e8fec5bec4e8 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 28 Feb 2025 20:29:20 +0700 Subject: [PATCH 012/154] Make CombinedContainer temporarily implement old IMatteryContainer so it no longer crashes --- .../mc/otm/container/CombinedContainer.kt | 26 +++++++++++++++---- .../otm/container/IFilteredContainerSlot.kt | 8 ++++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt index e255cd03a..456f87cde 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt @@ -23,7 +23,7 @@ import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.stream import java.util.stream.Stream -class CombinedContainer(containers: Stream>>) : ISlottedContainer { +class CombinedContainer(containers: Stream>>) : ISlottedContainer, IMatteryContainer { constructor(vararg containers: IEnhancedContainer) : this(containers.stream().map { it to (0 until it.containerSize) }) constructor(containers: Collection) : this(containers.stream().map { it to (0 until it.containerSize) }) @@ -116,12 +116,28 @@ class CombinedContainer(containers: Stream { - return slots.iterator() + override fun slotIterator(): Iterator { + return slots.iterator().map { + if (it is IFilteredContainerSlot) it else IFilteredContainerSlot.Dummy(it) + } } - override fun containerSlot(slot: Int): IContainerSlot { - return slots[slot] + override fun containerSlot(slot: Int): IFilteredContainerSlot { + val getSlot = slots[slot] + if (getSlot is IFilteredContainerSlot) return getSlot + return IFilteredContainerSlot.Dummy(getSlot) + } + + override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int { + return super.getMaxStackSize(slot, itemStack) + } + + override fun getSlotFilter(slot: Int): Item? { + return containerSlot(slot).filter + } + + override fun clearSlotFilters() { + } override fun setChanged(slot: Int) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt index 054f0719d..0eaa8ee8f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt @@ -1,5 +1,6 @@ package ru.dbotthepony.mc.otm.container +import net.minecraft.world.Container import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Items @@ -26,4 +27,11 @@ interface IFilteredContainerSlot : IContainerSlot { return filter === item } } + + @Deprecated("Dummy implementation") + class Dummy(parent: IContainerSlot) : IFilteredContainerSlot, IContainerSlot by parent { + override var filter: Item? + get() = null + set(value) {} + } } From f79b49d4221b63b7c6758396393424b4c9bdf721 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 28 Feb 2025 21:57:28 +0700 Subject: [PATCH 013/154] Move CargoCrate to SlottedContainer implement necessary changes to MatteryMenu, MatterySlot and panels to reflect networking slot filters as part of container state, and not as part of menu slot --- .../decorative/CargoCrateBlockEntity.kt | 30 +++-- .../mc/otm/client/screen/MatteryScreen.kt | 2 - .../screen/decorative/CargoCrateScreen.kt | 2 +- .../screen/panels/slot/InventorySlotPanel.kt | 4 - .../client/screen/panels/slot/SlotPanel.kt | 70 ++++++++++ .../panels/slot/UserFilteredSlotPanel.kt | 125 ++---------------- .../otm/client/screen/tech/ItemHatchScreen.kt | 2 +- .../otm/container/IAutomatedContainerSlot.kt | 2 +- .../otm/container/IFilteredContainerSlot.kt | 2 - .../mc/otm/container/slotted/ContainerSlot.kt | 2 +- .../mc/otm/container/util/Iterators.kt | 20 +++ .../ru/dbotthepony/mc/otm/menu/MatteryMenu.kt | 46 ++----- .../ru/dbotthepony/mc/otm/menu/Slots.kt | 61 ++++----- .../mc/otm/menu/decorative/CargoCrateMenu.kt | 3 +- 14 files changed, 170 insertions(+), 201 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt index 6d7b5c27c..fd17ee839 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt @@ -32,6 +32,8 @@ import ru.dbotthepony.mc.otm.block.decorative.CargoCrateBlock import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter +import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.nbt.map import ru.dbotthepony.mc.otm.core.nbt.set @@ -43,20 +45,24 @@ class CargoCrateBlockEntity( p_155229_: BlockPos, p_155230_: BlockState ) : MatteryDeviceBlockEntity(MBlockEntities.CARGO_CRATE, p_155229_, p_155230_) { - val container = MatteryContainer(this::setChanged, CAPACITY).also(::addDroppableContainer) + private inner class Slot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) { + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + return super.canAutomationPlaceItem(itemStack) && lootTable == null + } + + override fun canAutomationTakeItem(desired: Int): Boolean { + return super.canAutomationTakeItem(desired) && lootTable == null + } + } + + val container = SlottedContainer.Builder() + .add(CAPACITY, ::Slot) + .onChanged(::setChanged) + .build() + .also(::addDroppableContainer) private var interactingPlayers = 0 - val handler = container.handler(object : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return lootTable == null - } - - override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return lootTable == null - } - }) - override fun beforeDroppingItems(oldBlockState: BlockState, level: Level, blockPos: BlockPos, newBlockState: BlockState, movedByPiston: Boolean) { unpackLootTable() } @@ -88,7 +94,7 @@ class CargoCrateBlockEntity( } init { - exposeGlobally(Capabilities.ItemHandler.BLOCK, handler) + exposeGlobally(Capabilities.ItemHandler.BLOCK, container) savetablesLevel.stateful(::container, INVENTORY_KEY) } 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 2eeccb3e4..b0fed5874 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 @@ -348,8 +348,6 @@ abstract class MatteryScreen(menu: T, inventory: Inventory, tit override fun mouseScrolledInner(x: Double, y: Double, scroll: Double): Boolean { return false } - - override var slotFilter: Item? by slot.filter!! } } 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 26bb90d13..974878362 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 @@ -20,7 +20,7 @@ class CargoCrateScreen(menu: CargoCrateMenu, inventory: Inventory, title: Compon val grid = GridPanel(this, frame, 8f, 18f, 9f * 18f, 6f * 18f, 9, 6) for (slot in menu.storageSlots) - UserFilteredSlotPanel.of(this, grid, slot) + UserFilteredSlotPanel(this, grid, slot) val controls = DeviceControls(this, frame) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/InventorySlotPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/InventorySlotPanel.kt index caa01f6aa..09588c48d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/InventorySlotPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/InventorySlotPanel.kt @@ -18,10 +18,6 @@ open class InventorySlotPanel, out T : MatteryMenu.Inve x: Float = 0f, y: Float = 0f, ) : UserFilteredSlotPanel(screen, parent, slot, x, y, SIZE, SIZE) { - override var slotFilter: Item? - get() = slot.filter?.get() - set(value) { slot.filter?.accept(value) } - override fun renderBackgroundBeforeFilter(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) { if (slot.chargeFlag?.get() == true) { Widgets18.CHARGE_SLOT_BACKGROUND.render(graphics, 0f, 0f, width, height) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/SlotPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/SlotPanel.kt index e7139cff1..6453b8d7b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/SlotPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/SlotPanel.kt @@ -5,9 +5,13 @@ package ru.dbotthepony.mc.otm.client.screen.panels.slot import com.mojang.blaze3d.systems.RenderSystem import net.minecraft.ChatFormatting import net.minecraft.client.renderer.GameRenderer +import net.minecraft.network.chat.Component import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.inventory.Slot import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import net.neoforged.neoforge.client.extensions.common.IClientItemExtensions +import ru.dbotthepony.kommons.math.RGBAColor import ru.dbotthepony.mc.otm.client.render.MGUIGraphics import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.client.render.Widgets18 @@ -15,6 +19,10 @@ import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.compat.itemborders.isItemBordersLoaded import ru.dbotthepony.mc.otm.compat.itemborders.renderSlotBorder +import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot +import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull +import ru.dbotthepony.mc.otm.core.TextComponent +import ru.dbotthepony.mc.otm.core.TranslatableComponent import javax.annotation.Nonnull import kotlin.math.roundToInt @@ -52,6 +60,31 @@ open class SlotPanel, out T : Slot>( } } + protected open fun renderBackgroundBeforeFilter(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {} + + override fun renderSlotBackground(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) { + super.renderSlotBackground(graphics, mouseX, mouseY, partialTick) + + val containerSlot = slot.container.containerSlotOrNull(slot.slotIndex) + + if (containerSlot is IFilteredContainerSlot) { + renderBackgroundBeforeFilter(graphics, mouseX, mouseY, partialTick) + + if (containerSlot.filter !== null) { + if (containerSlot.filter !== Items.AIR) { + val itemStack = ItemStack(containerSlot.filter!!, 1) + + screen.renderItemStack(graphics, itemStack, null) + clearDepth(graphics) + + graphics.renderRect(0f, 0f, width, height, color = SLOT_FILTER_COLOR) + } else { + graphics.renderRect(0f, 0f, width, height, color = SLOT_BLOCK_COLOR) + } + } + } + } + override fun innerRender(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) { slot.x = absoluteX.roundToInt() - screen.guiLeft slot.y = absoluteY.roundToInt() - screen.guiTop @@ -121,9 +154,46 @@ open class SlotPanel, out T : Slot>( } override fun innerRenderTooltips(@Nonnull graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float): Boolean { + val slot = slot.container.containerSlotOrNull(slot.containerSlot) as? IFilteredContainerSlot + + if (isHovered && slot?.filter != null && slot.filter !== Items.AIR && itemStack.isEmpty) { + val itemstack = ItemStack(slot.filter!!, 1) + + graphics.renderComponentTooltip( + IClientItemExtensions.of(itemstack).getFont(itemstack, IClientItemExtensions.FontContext.TOOLTIP) ?: font, + getItemStackTooltip(itemstack).toMutableList().also { + it.add(0, TranslatableComponent("otm.gui.slot_filter.filtered").withStyle(ChatFormatting.GRAY)) + it.add(1, TranslatableComponent("otm.gui.slot_filter.hint").withStyle(ChatFormatting.GRAY)) + it.add(2, TextComponent("")) + }, + mouseX.toInt(), + mouseY.toInt(), + itemstack + ) + + return true + } else if (isHovered && slot?.filter === Items.AIR && itemStack.isEmpty) { + graphics.renderComponentTooltip( + font, + ArrayList().also { + it.add(TranslatableComponent("otm.gui.slot_filter.forbidden").withStyle(ChatFormatting.GRAY)) + it.add(TranslatableComponent("otm.gui.slot_filter.hint").withStyle(ChatFormatting.GRAY)) + }, + mouseX.toInt(), + mouseY.toInt() + ) + + return true + } + // no op, screen does it for us (completely) return false } + + companion object { + val SLOT_FILTER_COLOR = RGBAColor(85, 113, 216, 150) + val SLOT_BLOCK_COLOR = RGBAColor(219, 113, 113, 150) + } } fun , T : Slot> BatterySlotPanel( diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/UserFilteredSlotPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/UserFilteredSlotPanel.kt index 86c93d76a..8fdb61822 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/UserFilteredSlotPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/UserFilteredSlotPanel.kt @@ -1,28 +1,16 @@ package ru.dbotthepony.mc.otm.client.screen.panels.slot import com.mojang.blaze3d.platform.InputConstants -import net.minecraft.ChatFormatting -import net.minecraft.network.chat.Component -import net.minecraft.world.inventory.Slot -import net.minecraft.world.item.Item -import net.minecraft.world.item.ItemStack -import net.minecraft.world.item.Items -import net.neoforged.neoforge.client.extensions.common.IClientItemExtensions -import ru.dbotthepony.mc.otm.client.render.MGUIGraphics import ru.dbotthepony.mc.otm.client.isCtrlDown import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.client.playGuiClickSound import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel -import ru.dbotthepony.mc.otm.core.TextComponent -import ru.dbotthepony.mc.otm.core.TranslatableComponent -import ru.dbotthepony.kommons.math.RGBAColor -import ru.dbotthepony.kommons.util.Delegate -import ru.dbotthepony.kommons.util.getValue -import ru.dbotthepony.kommons.util.setValue +import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot +import ru.dbotthepony.mc.otm.container.util.containerSlot import ru.dbotthepony.mc.otm.menu.UserFilteredSlot -abstract class UserFilteredSlotPanel, out T : Slot>( +open class UserFilteredSlotPanel, out T : UserFilteredSlot>( screen: S, parent: EditablePanel<*>?, slot: T, @@ -31,77 +19,24 @@ abstract class UserFilteredSlotPanel, out T : Slot>( width: Float = SIZE, height: Float = SIZE, ) : SlotPanel(screen, parent, slot, x, y, width, height) { - abstract var slotFilter: Item? - - protected open fun renderBackgroundBeforeFilter(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {} - - override fun renderSlotBackground(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) { - super.renderSlotBackground(graphics, mouseX, mouseY, partialTick) - - renderBackgroundBeforeFilter(graphics, mouseX, mouseY, partialTick) - - if (slotFilter != null) { - if (slotFilter !== Items.AIR) { - val itemStack = ItemStack(slotFilter!!, 1) - - screen.renderItemStack(graphics, itemStack, null) - clearDepth(graphics) - - graphics.renderRect(0f, 0f, width, height, color = SLOT_FILTER_COLOR) - } else { - graphics.renderRect(0f, 0f, width, height, color = SLOT_BLOCK_COLOR) - } - } - } - - override fun innerRenderTooltips(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float): Boolean { - if (isHovered && slotFilter != null && slotFilter !== Items.AIR && itemStack.isEmpty) { - val itemstack = ItemStack(slotFilter!!, 1) - - graphics.renderComponentTooltip( - IClientItemExtensions.of(itemstack).getFont(itemstack, IClientItemExtensions.FontContext.TOOLTIP) ?: font, - getItemStackTooltip(itemstack).toMutableList().also { - it.add(0, TranslatableComponent("otm.gui.slot_filter.filtered").withStyle(ChatFormatting.GRAY)) - it.add(1, TranslatableComponent("otm.gui.slot_filter.hint").withStyle(ChatFormatting.GRAY)) - it.add(2, TextComponent("")) - }, - mouseX.toInt(), - mouseY.toInt(), - itemstack - ) - - return true - } else if (isHovered && slotFilter === Items.AIR && itemStack.isEmpty) { - graphics.renderComponentTooltip( - font, - ArrayList().also { - it.add(TranslatableComponent("otm.gui.slot_filter.forbidden").withStyle(ChatFormatting.GRAY)) - it.add(TranslatableComponent("otm.gui.slot_filter.hint").withStyle(ChatFormatting.GRAY)) - }, - mouseX.toInt(), - mouseY.toInt() - ) - - return true - } - - return super.innerRenderTooltips(graphics, mouseX, mouseY, partialTick) - } - override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean { + if (slot.filterInput == null) + return super.mouseClickedInner(x, y, button) + + val containerSlot = slot.containerSlot() as IFilteredContainerSlot + if (button == InputConstants.MOUSE_BUTTON_LEFT && minecraft.window.isCtrlDown) { - if (slotFilter === null) { + if (containerSlot.filter === null) { if (screen.menu.carried.isEmpty) { - slotFilter = slot.item.item + slot.filterInput!!.accept(slot.item.item) } else { - slotFilter = screen.menu.carried.item + slot.filterInput!!.accept(screen.menu.carried.item) } } else { - slotFilter = null + slot.filterInput!!.accept(null) } playGuiClickSound() - return true } else { return super.mouseClickedInner(x, y, button) @@ -115,40 +50,4 @@ abstract class UserFilteredSlotPanel, out T : Slot>( return super.mouseReleasedInner(x, y, button) } - - companion object { - val SLOT_FILTER_COLOR = RGBAColor(85, 113, 216, 150) - val SLOT_BLOCK_COLOR = RGBAColor(219, 113, 113, 150) - - fun , T : Slot> of( - screen: S, - parent: EditablePanel<*>?, - slot: T, - x: Float = 0f, - y: Float = 0f, - width: Float = SIZE, - height: Float = SIZE, - filter: Delegate - ): UserFilteredSlotPanel { - return object : UserFilteredSlotPanel(screen, parent, slot, x, y, width, height) { - override var slotFilter: Item? by filter - } - } - - fun , T : UserFilteredSlot> of( - screen: S, - parent: EditablePanel<*>?, - slot: T, - x: Float = 0f, - y: Float = 0f, - width: Float = SIZE, - height: Float = SIZE, - ): UserFilteredSlotPanel { - return object : UserFilteredSlotPanel(screen, parent, slot, x, y, width, height) { - override var slotFilter: Item? - get() = slot.filter?.get() - set(value) { slot.filter?.accept(value) } - } - } - } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/ItemHatchScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/ItemHatchScreen.kt index 7408515ea..913f5bdbf 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/ItemHatchScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/ItemHatchScreen.kt @@ -20,7 +20,7 @@ class ItemHatchScreen(menu: ItemHatchMenu, inventory: Inventory, title: Componen val grid = GridPanel(this, frame, 8f, 18f, 9f * 18f, 6f * 18f, 9, 6) for (slot in menu.storageSlots) - UserFilteredSlotPanel.of(this, grid, slot) + UserFilteredSlotPanel(this, grid, slot) if (menu.isInput) { val controls = DeviceControls(this, frame) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainerSlot.kt index 16ca182f2..2c7df2085 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainerSlot.kt @@ -4,7 +4,7 @@ import net.minecraft.world.item.ItemStack import net.neoforged.neoforge.items.IItemHandler /** - * Slot of [ISlottedContainer], with additional methods to implement interaction behavior for both for players and mechanisms + * Slot of [IAutomatedContainer], with additional methods to implement interaction behavior for both for players and mechanisms */ interface IAutomatedContainerSlot : IContainerSlot { fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt index 0eaa8ee8f..1a6c6f250 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt @@ -1,6 +1,5 @@ package ru.dbotthepony.mc.otm.container -import net.minecraft.world.Container import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Items @@ -15,7 +14,6 @@ interface IFilteredContainerSlot : IContainerSlot { val hasFilter: Boolean get() = filter != null - fun testSlotFilter(itemStack: ItemStack): Boolean { return testSlotFilter(itemStack.item) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt index 7ab61cebd..18109d9be 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt @@ -83,7 +83,7 @@ open class ContainerSlot( return ItemStack.EMPTY } - if (item.count >= count) { + if (item.count <= count) { this.item = ItemStack.EMPTY return item } else { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/util/Iterators.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/util/Iterators.kt index 64f4a9b73..9160415c9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/util/Iterators.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/util/Iterators.kt @@ -1,6 +1,7 @@ package ru.dbotthepony.mc.otm.container.util import net.minecraft.world.Container +import net.minecraft.world.inventory.Slot import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.container.IContainerSlot @@ -19,6 +20,25 @@ fun Container.containerSlot(slot: Int): IContainerSlot { } } +/** + * Returns [IContainerSlot] only if this container is [IEnhancedContainer] + */ +fun Container.containerSlotOrNull(slot: Int): IContainerSlot? { + if (this is IEnhancedContainer) { + return containerSlot(slot) + } else { + return null + } +} + +fun Slot.containerSlot(): IContainerSlot { + return container.containerSlot(slotIndex) +} + +fun Slot.containerSlotOrNull(): IContainerSlot? { + return container.containerSlotOrNull(slotIndex) +} + operator fun Container.iterator(): Iterator { if (this is IEnhancedContainer) { return iterator() 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 5c7ed9174..9bff7873a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt @@ -38,9 +38,11 @@ import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.compat.cos.cosmeticArmorSlots import ru.dbotthepony.mc.otm.compat.curios.curiosSlots import ru.dbotthepony.mc.otm.compat.curios.isCurioSlot +import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot import ru.dbotthepony.mc.otm.container.IMatteryContainer import ru.dbotthepony.mc.otm.container.computeSortedIndices import ru.dbotthepony.mc.otm.container.sortWithIndices +import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull import ru.dbotthepony.mc.otm.core.ResourceLocation import ru.dbotthepony.mc.otm.core.collect.ConditionalSet import ru.dbotthepony.mc.otm.core.math.Decimal @@ -207,7 +209,7 @@ abstract class MatteryMenu( var sortInventoryInput: SortInput? = null private set - val playerSortSettings = IItemStackSortingSettings.inputs(this, player.matteryPlayer?.sortingSettings) + val playerSortSettings = IItemStackSortingSettings.inputs(this, player.matteryPlayer.sortingSettings) var offhandSlot: InventorySlot? = null protected set @@ -221,7 +223,7 @@ abstract class MatteryMenu( protected var inventorySlotIndexStart = 0 protected var inventorySlotIndexEnd = 0 - open inner class InventorySlot(container: Container, index: Int, addFilter: Boolean = false) : UserFilteredSlot(container, index, 0, 0) { + open inner class InventorySlot(container: Container, index: Int) : UserFilteredSlot(container, index, 0, 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return !isInventorySlotLocked(index) && super.mayPlace(itemStack) } @@ -236,15 +238,6 @@ abstract class MatteryMenu( init { val mattery = player.matteryPlayer - if (addFilter) { - val mContainer = container as IMatteryContainer - - filter = Delegate.Of( - getter = { mContainer.getSlotFilter(slotIndex) }, - setter = nullableItemInput(true) { mContainer.setSlotFilter(slotIndex, it) }::accept - ) - } - if (mattery.hasExopack) { chargeFlag = Delegate.Of( getter = { slotIndex in mattery.slotsChargeFlag }, @@ -302,7 +295,7 @@ abstract class MatteryMenu( for (i in 0 until if (mattery.hasExopack) mattery.combinedInventory.containerSize else mattery.wrappedItemInventory.containerSize) { if (i in Inventory.INVENTORY_SIZE until player.inventory.containerSize) continue - val slot = InventorySlot(mattery.combinedInventory, i, true) + val slot = InventorySlot(mattery.combinedInventory, i) _playerInventorySlots.add(slot) @@ -392,21 +385,8 @@ abstract class MatteryMenu( if (!seenSlots.add(pSlot)) return pSlot - if (pSlot is UserFilteredSlot && !pSlot.hasSetFilter) { - val container = pSlot.container - - val input: PlayerInput - val field: Delegate - - if (container is IMatteryContainer) { - input = PlayerInput(StreamCodecs.ITEM_TYPE_NULLABLE, handler = { container.setSlotFilter(pSlot.slotIndex, it) }) - field = mSynchronizer.add(delegate = { container.getSlotFilter(pSlot.slotIndex) }, StreamCodecs.ITEM_TYPE_NULLABLE) - } else { - input = PlayerInput(StreamCodecs.ITEM_TYPE_NULLABLE, handler = { throw UnsupportedOperationException() }) - field = mSynchronizer.add(delegate = { null }, StreamCodecs.ITEM_TYPE_NULLABLE) - } - - pSlot.filter = Delegate.Of(getter = field::get, setter = input::accept) + if (pSlot is MatterySlot) { + pSlot.setupNetworkControls(this) } return super.addSlot(pSlot) @@ -487,7 +467,7 @@ abstract class MatteryMenu( val copy = slot.item.copy() var any = false - if (target.any { it.any { it is UserFilteredSlot && it.filter != null } }) { + if (target.any { it.any { it.containerSlotOrNull() is IFilteredContainerSlot } }) { for (collection in target) { if (moveItemStackTo(slot, collection, onlyFiltered = true)) { any = true @@ -582,9 +562,9 @@ abstract class MatteryMenu( // first pass - stack with existing slots if (copy.isStackable) { for (slot in slots) { - if (onlyFiltered && (slot !is UserFilteredSlot || !slot.test(item))) { + if (onlyFiltered && slot.containerSlotOrNull().let { it !is IFilteredContainerSlot || it.filter == null || !it.testSlotFilter(item) }) { continue - } else if (!onlyFiltered && slot is UserFilteredSlot && !slot.test(item)) { + } else if (!onlyFiltered && slot.containerSlotOrNull().let { it is IFilteredContainerSlot && it.filter != null }) { continue } @@ -609,9 +589,9 @@ abstract class MatteryMenu( // second pass - drop stack into first free slot for (slot in slots) { - if (onlyFiltered && (slot !is UserFilteredSlot || slot.filter == null || slot.filter!!.get() != item.item)) { + if (onlyFiltered && slot.containerSlotOrNull().let { it !is IFilteredContainerSlot || it.filter == null || !it.testSlotFilter(item) }) { continue - } else if (!onlyFiltered && slot is UserFilteredSlot && slot.filter != null && slot.filter!!.get() != null && slot.filter!!.get() != item.item) { + } else if (!onlyFiltered && slot.containerSlotOrNull().let { it is IFilteredContainerSlot && it.filter != null }) { continue } @@ -651,7 +631,7 @@ abstract class MatteryMenu( val slot = slots[i] slots.add(slot) - if (slot is InventorySlot && slot.filter != null) { + if (slot.containerSlotOrNull() is IFilteredContainerSlot) { filters = true } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt index bf6ee95a6..e436740f1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt @@ -17,20 +17,22 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.UpgradeType import ru.dbotthepony.mc.otm.capability.energy import ru.dbotthepony.mc.otm.client.minecraft +import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot 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.util.containerSlotOrNull import ru.dbotthepony.mc.otm.core.collect.ConditionalEnumSet import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.InstantBooleanInput +import ru.dbotthepony.mc.otm.network.StreamCodecs import ru.dbotthepony.mc.otm.runOnClient import java.util.* import java.util.function.BooleanSupplier import java.util.function.DoubleSupplier import java.util.function.IntSupplier -import java.util.function.Predicate import java.util.function.Supplier import kotlin.reflect.KMutableProperty0 @@ -51,6 +53,14 @@ inline fun makeSlots(containers: List?, size: Int, initial open class MatterySlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : Slot(container, index, x, y) { var ignoreSpectators = true + open fun setupNetworkControls(menu: MatteryMenu) { + val slot = containerSlotOrNull() + + if (slot is IFilteredContainerSlot) { + menu.mSynchronizer.add(Delegate.Of(slot::filter), StreamCodecs.ITEM_TYPE_NULLABLE) + } + } + override fun setChanged() { if (container is IMatteryContainer) { (container as IMatteryContainer).setChanged(containerSlot) @@ -68,7 +78,7 @@ open class MatterySlot(container: Container, index: Int, x: Int = 0, y: Int = 0) } open fun canTakeItemForPickAll(): Boolean { - return true + return (container.containerSlotOrNull(slotIndex) as? IFilteredContainerSlot)?.filter == null } override fun getMaxStackSize(): Int { @@ -90,38 +100,29 @@ open class MatterySlot(container: Container, index: Int, x: Int = 0, y: Int = 0) return super.getMaxStackSize(itemStack) } } -} -open class UserFilteredSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatterySlot(container, index, x, y), Predicate { - var hasSetFilter = false - private set - - var filter: Delegate? = null - set(value) { - hasSetFilter = true - field = value - } - - override fun canTakeItemForPickAll(): Boolean { - return filter?.get() == null - } - - override fun test(t: ItemStack): Boolean { - return filter?.get() == null || filter?.get() == t.item - } - - fun isSameFilter(other: Slot): Boolean { - if (other !is UserFilteredSlot) - return filter?.get() == null - - return ( - (other.filter == null && filter == null) || - (other.filter != null && filter != null && other.filter!!.get() == filter!!.get()) - ) + private fun isSameFilter(other: Slot): Boolean { + val sSelf = containerSlotOrNull() as? IFilteredContainerSlot + val sOther = other.containerSlotOrNull() as? IFilteredContainerSlot + return sSelf?.filter == sOther?.filter } override fun isSameInventory(other: Slot): Boolean { - return isSameFilter(other) && super.isSameInventory(other) + return super.isSameInventory(other) && isSameFilter(other) + } +} + +open class UserFilteredSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatterySlot(container, index, x, y) { + var filterInput: MatteryMenu.PlayerInput? = null + private set + + override fun setupNetworkControls(menu: MatteryMenu) { + super.setupNetworkControls(menu) + val slot = containerSlotOrNull() + + if (slot is IFilteredContainerSlot) { + filterInput = menu.PlayerInput(StreamCodecs.ITEM_TYPE_NULLABLE, handler = { slot.filter = it }) + } } } 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 2dc02ccf9..4d997dcf9 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,6 +5,7 @@ import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.UserFilteredSlot import ru.dbotthepony.mc.otm.menu.makeSlots @@ -15,7 +16,7 @@ class CargoCrateMenu( inventory: Inventory, tile: CargoCrateBlockEntity? = null ) : MatteryMenu(MMenus.CARGO_CRATE, containerId, inventory, tile) { - val actualContainer: Container = tile?.container ?: SimpleContainer(CargoCrateBlockEntity.CAPACITY) + val actualContainer = tile?.container ?: SlottedContainer.filtered(CargoCrateBlockEntity.CAPACITY) val storageSlots = makeSlots(actualContainer, ::UserFilteredSlot) private val trackedPlayerOpen = !inventory.player.isSpectator From 1702f953703c099fef7e92c38b67931461009bff Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 28 Feb 2025 22:11:11 +0700 Subject: [PATCH 014/154] Rename "MatteryMenu" to "MatteryMenuSlot", along with all other slot classes to include "menu" in their name --- .../mc/otm/client/screen/MatteryScreen.kt | 7 ++-- .../screen/panels/PlayerEquipmentPanel.kt | 2 +- .../client/screen/panels/button/Buttons.kt | 7 ++-- .../panels/slot/UserFilteredSlotPanel.kt | 4 +-- .../mc/otm/compat/cos/CosmeticArmorCompat.kt | 16 ++++----- .../vanilla/ExtendedInventoryHandler.kt | 8 ++--- .../mc/otm/compat/vanilla/MatteryChestMenu.kt | 4 +-- .../mc/otm/menu/ExopackInventoryMenu.kt | 18 +++++----- .../ru/dbotthepony/mc/otm/menu/MatteryMenu.kt | 33 +++++++++---------- .../mc/otm/menu/MatteryPoweredMenu.kt | 2 +- .../ru/dbotthepony/mc/otm/menu/Slots.kt | 26 +++++++-------- .../mc/otm/menu/decorative/CargoCrateMenu.kt | 6 ++-- .../mc/otm/menu/decorative/FluidTankMenu.kt | 10 +++--- .../mc/otm/menu/decorative/GrillMenu.kt | 10 +++--- .../menu/decorative/MinecartCargoCrateMenu.kt | 4 +-- .../mc/otm/menu/decorative/PainterMenu.kt | 8 ++--- .../mc/otm/menu/matter/MatterBottlerMenu.kt | 7 ++-- .../menu/matter/MatterCapacitorBankMenu.kt | 6 ++-- .../otm/menu/matter/MatterDecomposerMenu.kt | 14 ++++---- .../mc/otm/menu/matter/MatterEntanglerMenu.kt | 18 +++++----- .../menu/matter/MatterReconstructorMenu.kt | 4 +-- .../mc/otm/menu/matter/MatterRecyclerMenu.kt | 4 +-- .../otm/menu/matter/MatterReplicatorMenu.kt | 7 ++-- .../mc/otm/menu/matter/MatterScannerMenu.kt | 6 ++-- .../mc/otm/menu/matter/PatternStorageMenu.kt | 6 ++-- .../mc/otm/menu/storage/DriveRackMenu.kt | 4 +-- .../mc/otm/menu/storage/DriveViewerMenu.kt | 4 +-- .../mc/otm/menu/storage/ItemMonitorMenu.kt | 12 +++---- .../mc/otm/menu/tech/AndroidStationMenu.kt | 6 ++-- .../mc/otm/menu/tech/BatteryBankMenu.kt | 8 ++--- .../mc/otm/menu/tech/ChemicalGeneratorMenu.kt | 8 ++--- .../mc/otm/menu/tech/CobblerMenu.kt | 4 +-- .../mc/otm/menu/tech/EnergyHatchMenu.kt | 4 +-- .../mc/otm/menu/tech/EnergyServoMenu.kt | 6 ++-- .../mc/otm/menu/tech/EssenceStorageMenu.kt | 8 ++--- .../mc/otm/menu/tech/ItemHatchMenu.kt | 6 ++-- .../mc/otm/menu/tech/MatterHatchMenu.kt | 4 +-- .../mc/otm/menu/tech/PlatePressMenu.kt | 8 ++--- .../mc/otm/menu/tech/PoweredFurnaceMenu.kt | 8 ++--- 39 files changed, 156 insertions(+), 171 deletions(-) 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 b0fed5874..34b9ea23a 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 @@ -10,13 +10,10 @@ import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen import net.minecraft.network.chat.Component import net.minecraft.world.entity.player.Inventory import net.minecraft.world.inventory.Slot -import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import net.neoforged.neoforge.client.event.ContainerScreenEvent import net.neoforged.neoforge.common.NeoForge import org.lwjgl.opengl.GL11 -import ru.dbotthepony.kommons.util.getValue -import ru.dbotthepony.kommons.util.setValue import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.client.render.MGUIGraphics import ru.dbotthepony.mc.otm.client.moveMousePosScaled @@ -49,7 +46,7 @@ import ru.dbotthepony.mc.otm.core.math.component1 import ru.dbotthepony.mc.otm.core.math.component2 import ru.dbotthepony.mc.otm.core.math.integerDivisionDown import ru.dbotthepony.mc.otm.menu.MatteryMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import java.util.* @@ -407,7 +404,7 @@ abstract class MatteryScreen(menu: T, inventory: Inventory, tit matter: LevelGaugeWidget? = null, profiledMatter: ProfiledLevelGaugeWidget<*>? = null, patterns: LevelGaugeWidget? = null, - batterySlot: MatterySlot? = null, + batterySlot: MatteryMenuSlot? = null, ) { var bars = 0 if (energy != null) bars++ diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/PlayerEquipmentPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/PlayerEquipmentPanel.kt index b28d2350d..bbb511306 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/PlayerEquipmentPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/PlayerEquipmentPanel.kt @@ -60,7 +60,7 @@ open class PlayerEquipmentPanel>( parent: EditablePanel<*>?, x: Float = 0f, y: Float = 0f, - val armorSlots: List> + val armorSlots: List> ) : EditablePanel(screen, parent, x, y, height = HEIGHT, width = WIDTH) { val armorSlotsStrip = EditablePanel(screen, this, width = AbstractSlotPanel.SIZE) val entityPanel = EntityRendererPanel(screen, this, minecraft.player!!) 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 71295e837..8f1d6daa9 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 @@ -2,11 +2,9 @@ package ru.dbotthepony.mc.otm.client.screen.panels.button import com.mojang.blaze3d.platform.InputConstants import net.minecraft.ChatFormatting -import net.minecraft.client.gui.screens.Screen import net.minecraft.network.chat.Component import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Items -import ru.dbotthepony.kommons.math.RGBAColor import ru.dbotthepony.kommons.util.Delegate import ru.dbotthepony.kommons.util.value import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity @@ -21,7 +19,6 @@ import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.client.render.IGUIRenderable import ru.dbotthepony.mc.otm.client.render.sprites.AbstractMatterySprite import ru.dbotthepony.mc.otm.client.render.ItemStackIcon -import ru.dbotthepony.mc.otm.client.render.UVWindingOrder import ru.dbotthepony.mc.otm.client.render.Widgets18 import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.panels.Dock @@ -39,7 +36,7 @@ import ru.dbotthepony.mc.otm.core.math.RelativeSide import ru.dbotthepony.mc.otm.core.util.ItemStackSorter import ru.dbotthepony.mc.otm.core.util.getLevelFromXp import ru.dbotthepony.mc.otm.menu.MatteryMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.UpgradeSlots import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput @@ -570,7 +567,7 @@ class DeviceControls>( val grid = GridPanel(screen, frame, columns = columns, rows = rows) for (slot in upgrades.slots) { - object : SlotPanel(screen, grid, slot) { + object : SlotPanel(screen, grid, slot) { override val cursorType: CursorType get() = if (upgrades.areLocked.get()) CursorType.NOT_ALLOWED else super.cursorType } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/UserFilteredSlotPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/UserFilteredSlotPanel.kt index 8fdb61822..2d6a269a7 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/UserFilteredSlotPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/UserFilteredSlotPanel.kt @@ -8,9 +8,9 @@ import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot import ru.dbotthepony.mc.otm.container.util.containerSlot -import ru.dbotthepony.mc.otm.menu.UserFilteredSlot +import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot -open class UserFilteredSlotPanel, out T : UserFilteredSlot>( +open class UserFilteredSlotPanel, out T : UserFilteredMenuSlot>( screen: S, parent: EditablePanel<*>?, slot: T, diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/cos/CosmeticArmorCompat.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/cos/CosmeticArmorCompat.kt index 8f2f3b46b..f4539471c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/cos/CosmeticArmorCompat.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/cos/CosmeticArmorCompat.kt @@ -6,7 +6,6 @@ import lain.mods.cos.impl.client.PlayerRenderHandler import lain.mods.cos.impl.client.gui.GuiCosArmorInventory import lain.mods.cos.impl.network.payload.PayloadSetSkinArmor import net.minecraft.client.gui.screens.Screen -import net.minecraft.network.chat.Component import net.minecraft.resources.ResourceLocation import net.minecraft.server.level.ServerPlayer import net.minecraft.world.Container @@ -20,9 +19,6 @@ import net.neoforged.neoforge.network.PacketDistributor import ru.dbotthepony.kommons.math.RGBAColor import ru.dbotthepony.mc.otm.client.render.MGUIGraphics import ru.dbotthepony.mc.otm.client.minecraft -import ru.dbotthepony.mc.otm.client.render.IGUIRenderable -import ru.dbotthepony.mc.otm.client.render.UVWindingOrder -import ru.dbotthepony.mc.otm.client.render.sprites.MatterySprite import ru.dbotthepony.mc.otm.client.render.sprites.sprite import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.client.screen.panels.button.ButtonPanel @@ -32,7 +28,7 @@ import ru.dbotthepony.mc.otm.container.util.awareStream import ru.dbotthepony.mc.otm.container.util.iterator import ru.dbotthepony.mc.otm.core.collect.AwareItemStack import ru.dbotthepony.mc.otm.core.collect.emptyIterator -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import java.util.stream.Stream val isCosmeticArmorLoaded by lazy { @@ -47,7 +43,7 @@ val Player.cosmeticArmorSlots: Map? get() { return cosmeticArmorSlotsImpl } -private class CosmeticSlot(container: Container, private val slot: EquipmentSlot, private val player: Player) : MatterySlot(container, when (slot) { +private class CosmeticMenuSlot(container: Container, private val slot: EquipmentSlot, private val player: Player) : MatteryMenuSlot(container, when (slot) { EquipmentSlot.FEET -> 0 EquipmentSlot.LEGS -> 1 EquipmentSlot.CHEST -> 2 @@ -127,10 +123,10 @@ private val Player.cosmeticArmorSlotsImpl: Map? get() { } return mapOf( - EquipmentSlot.HEAD to CosmeticSlot(container, EquipmentSlot.HEAD, this), - EquipmentSlot.CHEST to CosmeticSlot(container, EquipmentSlot.CHEST, this), - EquipmentSlot.LEGS to CosmeticSlot(container, EquipmentSlot.LEGS, this), - EquipmentSlot.FEET to CosmeticSlot(container, EquipmentSlot.FEET, this), + EquipmentSlot.HEAD to CosmeticMenuSlot(container, EquipmentSlot.HEAD, this), + EquipmentSlot.CHEST to CosmeticMenuSlot(container, EquipmentSlot.CHEST, this), + EquipmentSlot.LEGS to CosmeticMenuSlot(container, EquipmentSlot.LEGS, this), + EquipmentSlot.FEET to CosmeticMenuSlot(container, EquipmentSlot.FEET, this), ) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/ExtendedInventoryHandler.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/ExtendedInventoryHandler.kt index e5bb727c2..247a116cd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/ExtendedInventoryHandler.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/ExtendedInventoryHandler.kt @@ -22,7 +22,7 @@ import ru.dbotthepony.mc.otm.capability.MatteryPlayer import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.core.ResourceLocation import ru.dbotthepony.mc.otm.menu.MatteryMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import java.util.* private val menuConfigurations = WeakHashMap() @@ -47,9 +47,9 @@ private class MenuConfiguration( for (i in 0 .. 8) { if (matteryPlayer.exopackContainer.containerSize > i + offset) { - row.add(MatterySlot(matteryPlayer.exopackContainer, i + offset)) + row.add(MatteryMenuSlot(matteryPlayer.exopackContainer, i + offset)) } else { - row.add(FakeSlot()) + row.add(FakeMenuSlot()) } } @@ -150,7 +150,7 @@ private class MenuConfiguration( } } -private class FakeSlot : MatterySlot(SimpleContainer(1), 0, 0, 0) { +private class FakeMenuSlot : MatteryMenuSlot(SimpleContainer(1), 0, 0, 0) { override fun mayPickup(player: Player): Boolean { return false } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt index d5ef52363..231ef450d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt @@ -11,7 +11,7 @@ import net.neoforged.bus.api.IEventBus import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.menu.MatteryMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.makeSlots import ru.dbotthepony.mc.otm.registry.MDeferredRegister @@ -20,7 +20,7 @@ class MatteryChestMenu( inventory: Inventory, val rows: Int, val columns: Int, val container: Container = SimpleContainer(rows * columns) ) : MatteryMenu(type, containerId, inventory) { - val chestSlots = makeSlots(container, ::MatterySlot) + val chestSlots = makeSlots(container, ::MatteryMenuSlot) val sort = SortInput(container, playerSortSettings) init { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt index 6d27c6177..9d9135e4e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt @@ -21,7 +21,7 @@ import ru.dbotthepony.mc.otm.network.ExopackSlotPacket class ExopackInventoryMenu(val capability: MatteryPlayer) : MatteryMenu(null, CONTAINER_ID, capability.ply.inventory) { val craftingGrid: CraftingContainer - val craftingSlots: List + val craftingSlots: List init { if (capability.isExopackCraftingUpgraded) { @@ -30,10 +30,10 @@ class ExopackInventoryMenu(val capability: MatteryPlayer) : MatteryMenu(null, CO craftingGrid = TransientCraftingContainer(this, 2, 2) } - val builder = ImmutableList.builder() + val builder = ImmutableList.builder() for (i in 0 until craftingGrid.containerSize) { - builder.add(MatterySlot(craftingGrid, i)) + builder.add(MatteryMenuSlot(craftingGrid, i)) } craftingSlots = builder.build() @@ -91,16 +91,16 @@ class ExopackInventoryMenu(val capability: MatteryPlayer) : MatteryMenu(null, CO } } - val furnaceInputs: List = capability.smelters.map { - object : MatterySlot(it.input, 0) { + val furnaceInputs: List = capability.smelters.map { + object : MatteryMenuSlot(it.input, 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return super.mayPlace(itemStack) && capability.isExopackSmeltingInstalled } } } - val furnaceOutputs: List = capability.smelters.map { - object : OutputSlot(it.output, 0, onTake = { popFurnaceExp() }) { + val furnaceOutputs: List = capability.smelters.map { + object : OutputMenuSlot(it.output, 0, onTake = { popFurnaceExp() }) { override fun mayPickup(player: Player): Boolean { return super.mayPickup(player) && capability.isExopackSmeltingInstalled } @@ -115,7 +115,7 @@ class ExopackInventoryMenu(val capability: MatteryPlayer) : MatteryMenu(null, CO addStorageSlot(furnaceOutputs, condition = furnaceMenuOpenState) } - val enderChestSlots: List + val enderChestSlots: List val enderChestOpenState = InstantBooleanInput(this) val playerEnderSortSettings = IItemStackSortingSettings.inputs(this, capability.enderSortingSettings) val sortEnderChest: SortInput? @@ -123,7 +123,7 @@ class ExopackInventoryMenu(val capability: MatteryPlayer) : MatteryMenu(null, CO init { if (capability.isExopackEnderAccessInstalled) { enderChestSlots = makeSlots(player.enderChestInventory) { a, b -> - MatterySlot(a, b).also { + MatteryMenuSlot(a, b).also { addStorageSlot(it, condition = enderChestOpenState) } } 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 9bff7873a..4c4488d00 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt @@ -39,7 +39,6 @@ import ru.dbotthepony.mc.otm.compat.cos.cosmeticArmorSlots import ru.dbotthepony.mc.otm.compat.curios.curiosSlots import ru.dbotthepony.mc.otm.compat.curios.isCurioSlot import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot -import ru.dbotthepony.mc.otm.container.IMatteryContainer import ru.dbotthepony.mc.otm.container.computeSortedIndices import ru.dbotthepony.mc.otm.container.sortWithIndices import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull @@ -66,7 +65,7 @@ import java.util.function.Predicate data class PlayerSlot(val functional: A, val cosmetic: B? = null) data class EquipmentSlots( - val armorSlots: List>, + val armorSlots: List>, val curiosSlots: List> ) @@ -87,7 +86,7 @@ abstract class MatteryMenu( private val _playerInventorySlots = ArrayList() private val _playerHotbarSlots = ArrayList() private val _playerCombinedInventorySlots = ArrayList() - private val _exopackChargeSlots = ArrayList() + private val _exopackChargeSlots = ArrayList() private val playerInputs = ArrayList>() @@ -202,7 +201,7 @@ abstract class MatteryMenu( */ val playerCombinedInventorySlots: List = Collections.unmodifiableList(_playerCombinedInventorySlots) - val exopackChargeSlots: List = Collections.unmodifiableList(_exopackChargeSlots) + val exopackChargeSlots: List = Collections.unmodifiableList(_exopackChargeSlots) val exopackPowerLevel = ProfiledLevelGaugeWidget>(mSynchronizer, player.matteryPlayer.exopackEnergy) @@ -223,7 +222,7 @@ abstract class MatteryMenu( protected var inventorySlotIndexStart = 0 protected var inventorySlotIndexEnd = 0 - open inner class InventorySlot(container: Container, index: Int) : UserFilteredSlot(container, index, 0, 0) { + open inner class InventorySlot(container: Container, index: Int) : UserFilteredMenuSlot(container, index, 0, 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return !isInventorySlotLocked(index) && super.mayPlace(itemStack) } @@ -247,7 +246,7 @@ abstract class MatteryMenu( } } - open inner class EquipmentSlot(container: Container, index: Int, val type: net.minecraft.world.entity.EquipmentSlot) : InventorySlot(container, index) { + open inner class EquipmentMenuSlot(container: Container, index: Int, val type: net.minecraft.world.entity.EquipmentSlot) : InventorySlot(container, index) { constructor(type: net.minecraft.world.entity.EquipmentSlot) : this(inventory, 34 + type.ordinal, type) override fun setByPlayer(newItem: ItemStack, oldItem: ItemStack) { @@ -310,10 +309,10 @@ abstract class MatteryMenu( } if (mattery.hasExopack) { - _exopackChargeSlots.add(BatterySlot(mattery.exopackEnergy.parent, 0).also { mapQuickMoveToExternal(it); mapQuickMoveToInventory(it); addSlot(it) }) + _exopackChargeSlots.add(BatteryMenuSlot(mattery.exopackEnergy.parent, 0).also { mapQuickMoveToExternal(it); mapQuickMoveToInventory(it); addSlot(it) }) for (i in 0 until mattery.exopackChargeSlots.containerSize) - _exopackChargeSlots.add(ChargeSlot(mattery.exopackChargeSlots, i).also { mapQuickMoveToExternal(it); mapQuickMoveToInventory(it); addSlot(it) }) + _exopackChargeSlots.add(ChargeMenuSlot(mattery.exopackChargeSlots, i).also { mapQuickMoveToExternal(it); mapQuickMoveToInventory(it); addSlot(it) }) } sortInventoryInput = SortInput(mattery.inventoryAndExopackNoHotbar, playerSortSettings) @@ -385,7 +384,7 @@ abstract class MatteryMenu( if (!seenSlots.add(pSlot)) return pSlot - if (pSlot is MatterySlot) { + if (pSlot is MatteryMenuSlot) { pSlot.setupNetworkControls(this) } @@ -505,10 +504,10 @@ abstract class MatteryMenu( } override fun canTakeItemForPickAll(itemStack: ItemStack, slot: Slot): Boolean { - if (slot is EquipmentSlot) + if (slot is EquipmentMenuSlot) return false - return super.canTakeItemForPickAll(itemStack, slot) && (slot !is MatterySlot || slot.canTakeItemForPickAll()) && !slot.isCurioSlot + return super.canTakeItemForPickAll(itemStack, slot) && (slot !is MatteryMenuSlot || slot.canTakeItemForPickAll()) && !slot.isCurioSlot } override fun moveItemStackTo( @@ -643,11 +642,11 @@ abstract class MatteryMenu( return moveItemStackToSlots(item, slots, simulate) } - private var armorSlots: ImmutableList>? = null + private var armorSlots: ImmutableList>? = null private var curiosSlots: ImmutableList>? = null private val equipmentSlots = ArrayList() - fun makeArmorSlots(mapMoveToExternal: Boolean = false): List> { + fun makeArmorSlots(mapMoveToExternal: Boolean = false): List> { if (armorSlots != null) { return armorSlots!! } @@ -655,10 +654,10 @@ abstract class MatteryMenu( val cosmetic = player.cosmeticArmorSlots return ImmutableList.of( - PlayerSlot(EquipmentSlot(net.minecraft.world.entity.EquipmentSlot.HEAD), cosmetic?.get(net.minecraft.world.entity.EquipmentSlot.HEAD)), - PlayerSlot(EquipmentSlot(net.minecraft.world.entity.EquipmentSlot.CHEST), cosmetic?.get(net.minecraft.world.entity.EquipmentSlot.CHEST)), - PlayerSlot(EquipmentSlot(net.minecraft.world.entity.EquipmentSlot.LEGS), cosmetic?.get(net.minecraft.world.entity.EquipmentSlot.LEGS)), - PlayerSlot(EquipmentSlot(net.minecraft.world.entity.EquipmentSlot.FEET), cosmetic?.get(net.minecraft.world.entity.EquipmentSlot.FEET)), + PlayerSlot(EquipmentMenuSlot(net.minecraft.world.entity.EquipmentSlot.HEAD), cosmetic?.get(net.minecraft.world.entity.EquipmentSlot.HEAD)), + PlayerSlot(EquipmentMenuSlot(net.minecraft.world.entity.EquipmentSlot.CHEST), cosmetic?.get(net.minecraft.world.entity.EquipmentSlot.CHEST)), + PlayerSlot(EquipmentMenuSlot(net.minecraft.world.entity.EquipmentSlot.LEGS), cosmetic?.get(net.minecraft.world.entity.EquipmentSlot.LEGS)), + PlayerSlot(EquipmentMenuSlot(net.minecraft.world.entity.EquipmentSlot.FEET), cosmetic?.get(net.minecraft.world.entity.EquipmentSlot.FEET)), ).also { armorSlots = it diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryPoweredMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryPoweredMenu.kt index 8f0e8ca81..5168f7456 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryPoweredMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryPoweredMenu.kt @@ -15,7 +15,7 @@ abstract class MatteryPoweredMenu protected constructor( tile: MatteryPoweredBlockEntity? = null ) : MatteryMenu(menuType, containerID, inventory, tile) { val energyWidget = LevelGaugeWidget(this, tile?.energy) - val batterySlot = BatterySlot(tile?.batteryContainer ?: SimpleContainer(1), 0) + val batterySlot = BatteryMenuSlot(tile?.batteryContainer ?: SimpleContainer(1), 0) val redstoneConfig = EnumInputWithFeedback(this) init { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt index e436740f1..82ba35225 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt @@ -50,7 +50,7 @@ inline fun makeSlots(containers: List?, size: Int, initial return immutableList(size) { initializer(containers?.get(it) ?: SimpleContainer(1), 0) } } -open class MatterySlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : Slot(container, index, x, y) { +open class MatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : Slot(container, index, x, y) { var ignoreSpectators = true open fun setupNetworkControls(menu: MatteryMenu) { @@ -112,7 +112,7 @@ open class MatterySlot(container: Container, index: Int, x: Int = 0, y: Int = 0) } } -open class UserFilteredSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatterySlot(container, index, x, y) { +open class UserFilteredMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatteryMenuSlot(container, index, x, y) { var filterInput: MatteryMenu.PlayerInput? = null private set @@ -126,7 +126,7 @@ open class UserFilteredSlot(container: Container, index: Int, x: Int = 0, y: Int } } -open class OutputSlot(container: Container, index: Int, x: Int = 0, y: Int = 0, val onTake: (ItemStack) -> Unit = {}) : MatterySlot(container, index, x, y) { +open class OutputMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = 0, val onTake: (ItemStack) -> Unit = {}) : MatteryMenuSlot(container, index, x, y) { override fun mayPlace(itemStack: ItemStack): Boolean { return false } @@ -142,50 +142,50 @@ open class OutputSlot(container: Container, index: Int, x: Int = 0, y: Int = 0, } } -open class BatterySlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatterySlot(container, index, x, y) { +open class BatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatteryMenuSlot(container, index, x, y) { override fun mayPlace(itemStack: ItemStack): Boolean { return super.mayPlace(itemStack) && (itemStack.energy?.canExtract() ?: false) } } -open class ChemicalFuelSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatterySlot(container, index, x, y) { +open class ChemicalFuelMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatteryMenuSlot(container, index, x, y) { override fun mayPlace(itemStack: ItemStack): Boolean { return super.mayPlace(itemStack) && itemStack.getBurnTime(null) > 0 } } -open class ChargeSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatterySlot(container, index, x, y) { +open class ChargeMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatteryMenuSlot(container, index, x, y) { override fun mayPlace(itemStack: ItemStack): Boolean { return super.mayPlace(itemStack) && (itemStack.energy?.canReceive() ?: false) } } -open class EnergyContainerInputSlot(container: Container, index: Int, x: Int = 0, y: Int = 0, val direction: FlowDirection = FlowDirection.BI_DIRECTIONAL) : MatterySlot(container, index, x, y) { +open class EnergyContainerInputMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = 0, val direction: FlowDirection = FlowDirection.BI_DIRECTIONAL) : MatteryMenuSlot(container, index, x, y) { override fun mayPlace(itemStack: ItemStack): Boolean { return super.mayPlace(itemStack) && (itemStack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { direction.test(FlowDirection.of(it.canReceive(), it.canExtract())) } ?: false) } } -open class MatterContainerInputSlot( +open class MatterContainerInputMenuSlot( container: Container, index: Int, x: Int = 0, y: Int = 0, val direction: FlowDirection = FlowDirection.BI_DIRECTIONAL -) : MatterySlot(container, index, x, y) { +) : MatteryMenuSlot(container, index, x, y) { override fun mayPlace(itemStack: ItemStack): Boolean { val handler = itemStack.getCapability(MatteryCapability.MATTER_ITEM) return handler != null && super.mayPlace(itemStack) && this.direction.test(handler.matterFlow) } } -open class PatternSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatterySlot(container, index, x, y) { +open class PatternMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatteryMenuSlot(container, index, x, y) { override fun mayPlace(itemStack: ItemStack): Boolean { return super.mayPlace(itemStack) && itemStack.getCapability(MatteryCapability.PATTERN_ITEM) != null } } -open class DriveSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatterySlot(container, index, x, y) { +open class DriveMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatteryMenuSlot(container, index, x, y) { override fun mayPlace(itemStack: ItemStack): Boolean { return super.mayPlace(itemStack) && itemStack.getCapability(MatteryCapability.CONDENSATION_DRIVE) != null } @@ -255,7 +255,7 @@ fun MatteryMenu.addFilterControls(slots: KMutableProperty0?, amount: * in classloading exceptions. */ data class UpgradeSlots( - val slots: List, + val slots: List, val allowedTypes: Set, val openState: Delegate, val currentStats: IMatteryUpgrade, @@ -291,7 +291,7 @@ fun MatteryMenu.makeUpgradeSlots(count: Int, container: UpgradeContainer?): Upgr return UpgradeSlots( slots = immutableList(count) { - object : MatterySlot(syncContainer, it) { + object : MatteryMenuSlot(syncContainer, it) { init { mapQuickMoveToInventory(this) } 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 4d997dcf9..723250b6c 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 @@ -1,13 +1,11 @@ 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.block.entity.decorative.CargoCrateBlockEntity import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.MatteryMenu -import ru.dbotthepony.mc.otm.menu.UserFilteredSlot +import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot import ru.dbotthepony.mc.otm.menu.makeSlots import ru.dbotthepony.mc.otm.registry.game.MMenus @@ -17,7 +15,7 @@ class CargoCrateMenu( tile: CargoCrateBlockEntity? = null ) : MatteryMenu(MMenus.CARGO_CRATE, containerId, inventory, tile) { val actualContainer = tile?.container ?: SlottedContainer.filtered(CargoCrateBlockEntity.CAPACITY) - val storageSlots = makeSlots(actualContainer, ::UserFilteredSlot) + val storageSlots = makeSlots(actualContainer, ::UserFilteredMenuSlot) private val trackedPlayerOpen = !inventory.player.isSpectator val sort = SortInput(actualContainer, playerSortSettings) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/FluidTankMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/FluidTankMenu.kt index acebffafb..abc66ec71 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/FluidTankMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/FluidTankMenu.kt @@ -8,9 +8,9 @@ import net.neoforged.neoforge.fluids.capability.IFluidHandler import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.block.entity.decorative.FluidTankBlockEntity import ru.dbotthepony.mc.otm.capability.isNotEmpty -import ru.dbotthepony.mc.otm.menu.OutputSlot +import ru.dbotthepony.mc.otm.menu.OutputMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.FluidConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput @@ -24,14 +24,14 @@ class FluidTankMenu(containerId: Int, inventory: Inventory, tile: FluidTankBlock val redstoneConfig = EnumInputWithFeedback(this) val fluidConfig = FluidConfigPlayerInput(this, tile?.fluidConfig) - val drainInput = object : MatterySlot(tile?.drainInput ?: SimpleContainer(1), 0) { + val drainInput = object : MatteryMenuSlot(tile?.drainInput ?: SimpleContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return super.mayPlace(itemStack) && (itemStack.getCapability(Capabilities.FluidHandler.ITEM)?.isNotEmpty ?: false) } } - val fillInput = object : MatterySlot(tile?.fillInput ?: SimpleContainer(1), 0) { + val fillInput = object : MatteryMenuSlot(tile?.fillInput ?: SimpleContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return super.mayPlace(itemStack) && (if (itemStack.count <= 1) itemStack @@ -46,7 +46,7 @@ class FluidTankMenu(containerId: Int, inventory: Inventory, tile: FluidTankBlock } } - val output = OutputSlot(tile?.output ?: SimpleContainer(1), 0) + val output = OutputMenuSlot(tile?.output ?: SimpleContainer(1), 0) init { // сначала слот на заполнение из бака diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/GrillMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/GrillMenu.kt index c883ad281..58914fa00 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/GrillMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/GrillMenu.kt @@ -12,9 +12,9 @@ import ru.dbotthepony.kommons.util.getValue import ru.dbotthepony.mc.otm.block.entity.decorative.GrillBlockEntity import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.core.immutableList -import ru.dbotthepony.mc.otm.menu.ChemicalFuelSlot +import ru.dbotthepony.mc.otm.menu.ChemicalFuelMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.makeSlots import ru.dbotthepony.mc.otm.menu.widget.IProgressGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.TakeExperienceWidget @@ -30,14 +30,14 @@ class GrillMenu( override fun getMaxStackSize(): Int { return 4 } - }, ::ChemicalFuelSlot) + }, ::ChemicalFuelMenuSlot) - val inputSlots = makeSlots(tile?.inputSlots ?: object : MatteryContainer(GrillBlockEntity.SLOTS) { + val inputSlots = makeSlots(tile?.inputSlots ?: object : MatteryContainer(GrillBlockEntity.SLOTS) { override fun getMaxStackSize(): Int { return 1 } }) { c, i -> - object : MatterySlot(c, i) { + object : MatteryMenuSlot(c, i) { override fun onTake(p_150645_: Player, p_150646_: ItemStack) { super.onTake(p_150645_, p_150646_) 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 29a3b889b..c7869e695 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 @@ -7,7 +7,7 @@ import net.minecraft.world.entity.player.Player import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity 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.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.makeSlots import ru.dbotthepony.mc.otm.registry.game.MMenus @@ -17,7 +17,7 @@ class MinecartCargoCrateMenu( val cart: MinecartCargoCrate? = null ) : MatteryMenu(MMenus.CARGO_CRATE, containerId, inventory) { val actualContainer: Container = cart ?: SimpleContainer(CargoCrateBlockEntity.CAPACITY) - val storageSlots = makeSlots(actualContainer, ::MatterySlot) + val storageSlots = makeSlots(actualContainer, ::MatteryMenuSlot) private val trackedPlayerOpen = !inventory.player.isSpectator diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/PainterMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/PainterMenu.kt index 99f364506..924e73fdd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/PainterMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/PainterMenu.kt @@ -23,7 +23,7 @@ import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.collect.maybe import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.menu.MatteryMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.network.StreamCodecs @@ -56,7 +56,7 @@ class PainterMenu( selectedRecipe = it } - val inputSlot = object : MatterySlot(inputContainer, 0) { + val inputSlot = object : MatteryMenuSlot(inputContainer, 0) { override fun mayPlace(itemStack: ItemStack): Boolean { if (!itemStack.isEmpty && itemStack.`is`(ItemTags.DYEABLE)) { return super.mayPlace(itemStack) @@ -66,7 +66,7 @@ class PainterMenu( } } - val outputSlot = object : MatterySlot(outputContainer, 0) { + val outputSlot = object : MatteryMenuSlot(outputContainer, 0) { override fun tryRemove(p_150642_: Int, p_150643_: Int, p_150644_: Player): Optional { rescan() return super.tryRemove(p_150642_, p_150643_, p_150644_) @@ -102,7 +102,7 @@ class PainterMenu( } } - val dyeSlot = object : MatterySlot(tile?.dyeInput ?: SimpleContainer(1), 0) { + val dyeSlot = object : MatteryMenuSlot(tile?.dyeInput ?: SimpleContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return super.mayPlace(itemStack) && (( itemStack.getCapability(Capabilities.FluidHandler.ITEM)?.let { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterBottlerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterBottlerMenu.kt index b3817461c..a460eec64 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterBottlerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterBottlerMenu.kt @@ -1,7 +1,6 @@ package ru.dbotthepony.mc.otm.menu.matter import com.google.common.collect.ImmutableList -import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.block.entity.matter.MatterBottlerBlockEntity @@ -14,7 +13,7 @@ import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.makeSlots import ru.dbotthepony.mc.otm.menu.makeUpgradeSlots import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget @@ -29,8 +28,8 @@ class MatterBottlerMenu( val progressWidget = ProgressGaugeWidget(this) val matterWidget = ProfiledLevelGaugeWidget(this, tile?.matter, LevelGaugeWidget(this, tile?.matter)) - val storageSlots: ImmutableList = makeSlots(CombinedContainer(tile?.bottling ?: SlottedContainer.simple(3), tile?.unbottling ?: SlottedContainer.simple(3))) { it, index -> - object : MatterySlot(it, index) { + val storageSlots: ImmutableList = makeSlots(CombinedContainer(tile?.bottling ?: SlottedContainer.simple(3), tile?.unbottling ?: SlottedContainer.simple(3))) { it, index -> + object : MatteryMenuSlot(it, index) { override fun mayPlace(itemStack: ItemStack): Boolean { val cap = itemStack.getCapability(MatteryCapability.MATTER_ITEM) ?: return false diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterCapacitorBankMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterCapacitorBankMenu.kt index d117c9a07..424e32bda 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterCapacitorBankMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterCapacitorBankMenu.kt @@ -4,7 +4,7 @@ import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.block.entity.matter.MatterCapacitorBankBlockEntity -import ru.dbotthepony.mc.otm.menu.MatterContainerInputSlot +import ru.dbotthepony.mc.otm.menu.MatterContainerInputMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget @@ -20,7 +20,7 @@ class MatterCapacitorBankMenu @JvmOverloads constructor( val totalMatterGauge = LevelGaugeWidget(this) val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig) - val storageSlots: List + val storageSlots: List init { if (tile != null) { @@ -34,7 +34,7 @@ class MatterCapacitorBankMenu @JvmOverloads constructor( val container = tile?.container ?: SimpleContainer(2 * 6) storageSlots = immutableList(2 * 6) { - addStorageSlot(MatterContainerInputSlot(container, it)) + addStorageSlot(MatterContainerInputMenuSlot(container, it)) } addInventorySlots() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterDecomposerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterDecomposerMenu.kt index 07b5ef42f..ac81f806b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterDecomposerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterDecomposerMenu.kt @@ -8,9 +8,9 @@ import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import net.minecraft.world.SimpleContainer import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.matter.MatterManager -import ru.dbotthepony.mc.otm.menu.OutputSlot +import ru.dbotthepony.mc.otm.menu.OutputMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.makeUpgradeSlots @@ -22,12 +22,12 @@ class MatterDecomposerMenu @JvmOverloads constructor( inventory: Inventory, tile: MatterDecomposerBlockEntity? = null ) : MatteryPoweredMenu(MMenus.MATTER_DECOMPOSER, containerID, inventory, tile) { - val input = object : MatterySlot(tile?.inputContainer ?: SimpleContainer(1), 0) { + val input = object : MatteryMenuSlot(tile?.inputContainer ?: SimpleContainer(1), 0) { override fun mayPlace(itemStack: ItemStack) = MatterManager.canDecompose(itemStack) } - val outputMain: OutputSlot - val outputStacking: OutputSlot + val outputMain: OutputMenuSlot + val outputStacking: OutputMenuSlot val progressWidget = ProgressGaugeWidget(this, tile) val matterWidget = ProfiledLevelGaugeWidget(this, tile?.matter, LevelGaugeWidget(this, tile?.matter)) val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig) @@ -39,8 +39,8 @@ class MatterDecomposerMenu @JvmOverloads constructor( val container = tile?.outputContainer ?: SimpleContainer(2) // Выход - outputMain = OutputSlot(container, 0) - outputStacking = OutputSlot(container, 1) + outputMain = OutputMenuSlot(container, 0) + outputStacking = OutputMenuSlot(container, 1) addStorageSlot(outputMain) addStorageSlot(outputStacking) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterEntanglerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterEntanglerMenu.kt index 3a3249333..9ecd5d33d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterEntanglerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterEntanglerMenu.kt @@ -14,9 +14,9 @@ import ru.dbotthepony.mc.otm.container.get import ru.dbotthepony.mc.otm.container.set import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.item.IQuantumLinked -import ru.dbotthepony.mc.otm.menu.OutputSlot +import ru.dbotthepony.mc.otm.menu.OutputMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.makeSlots @@ -39,12 +39,12 @@ class MatterEntanglerMenu( val progress = ProgressGaugeWidget(this, tile?.jobEventLoops?.get(0)) - val inputs: List = makeSlots(tile?.inputs ?: object : MatteryCraftingContainer(3, 3) { + val inputs: List = makeSlots(tile?.inputs ?: object : MatteryCraftingContainer(3, 3) { override fun getMaxStackSize(): Int { return 1 } }) { it, i -> - object : MatterySlot(it, i) { + object : MatteryMenuSlot(it, i) { override fun mayPlace(itemStack: ItemStack): Boolean { val list = it.toList() list[i] = itemStack @@ -59,7 +59,7 @@ class MatterEntanglerMenu( } } - val outputs = makeSlots(tile?.output ?: SimpleContainer(1)) { a, b -> OutputSlot(a, b) { tile?.experience?.popExperience(player as ServerPlayer) } } + val outputs = makeSlots(tile?.output ?: SimpleContainer(1)) { a, b -> OutputMenuSlot(a, b) { tile?.experience?.popExperience(player as ServerPlayer) } } val upgrades = makeUpgradeSlots(3, tile?.upgrades) val experience = TakeExperienceWidget(this, tile?.experience) @@ -82,15 +82,15 @@ class MatterEntanglerMenu( } } - private inner class EntanglingInputSlot(index: Int) : MatterySlot(entangling, index) { + private inner class EntanglingInputMenuSlot(index: Int) : MatteryMenuSlot(entangling, index) { override fun mayPlace(itemStack: ItemStack): Boolean { return super.mayPlace(itemStack) && itemStack.item is IQuantumLinked } } - val entanglingA: MatterySlot = EntanglingInputSlot(0) - val entanglingB: MatterySlot = EntanglingInputSlot(1) - val entanglingC: MatterySlot = object : MatterySlot(MatteryContainer(1), 0) { + val entanglingA: MatteryMenuSlot = EntanglingInputMenuSlot(0) + val entanglingB: MatteryMenuSlot = EntanglingInputMenuSlot(1) + val entanglingC: MatteryMenuSlot = object : MatteryMenuSlot(MatteryContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return false } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReconstructorMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReconstructorMenu.kt index 6b2d5d83a..8af81790f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReconstructorMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReconstructorMenu.kt @@ -5,7 +5,7 @@ import net.minecraft.world.entity.player.Inventory import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.block.entity.matter.MatterReconstructorBlockEntity import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.makeUpgradeSlots @@ -20,7 +20,7 @@ class MatterReconstructorMenu( tile: MatterReconstructorBlockEntity? = null ) : MatteryPoweredMenu(MMenus.ITEM_REPAIER, containerId, inventory, tile) { val matterWidget = ProfiledLevelGaugeWidget(this, tile?.matter, LevelGaugeWidget(this, tile?.matter)) - val slot = object : MatterySlot(tile?.repairContainer ?: SimpleContainer(1), 0) { + val slot = object : MatteryMenuSlot(tile?.repairContainer ?: SimpleContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.isRepairable && itemStack.isDamaged && super.mayPlace(itemStack) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterRecyclerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterRecyclerMenu.kt index acc96bfc0..33d4e1e0c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterRecyclerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterRecyclerMenu.kt @@ -6,7 +6,7 @@ import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.block.entity.matter.MatterRecyclerBlockEntity import ru.dbotthepony.mc.otm.item.matter.MatterDustItem import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.makeUpgradeSlots @@ -20,7 +20,7 @@ class MatterRecyclerMenu @JvmOverloads constructor( inventory: Inventory, tile: MatterRecyclerBlockEntity? = null ) : MatteryPoweredMenu(MMenus.MATTER_RECYCLER, containerID, inventory, tile) { - val input = object : MatterySlot(tile?.container ?: SimpleContainer(1), 0) { + val input = object : MatteryMenuSlot(tile?.container ?: SimpleContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.item is MatterDustItem && (itemStack.item as MatterDustItem).getMatterValue(itemStack) != null } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReplicatorMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReplicatorMenu.kt index d37fba87d..387c24526 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReplicatorMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReplicatorMenu.kt @@ -6,12 +6,11 @@ import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.block.entity.matter.MatterReplicatorBlockEntity import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget -import net.minecraft.world.SimpleContainer import ru.dbotthepony.mc.otm.container.CombinedContainer import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.isNotEmpty -import ru.dbotthepony.mc.otm.menu.OutputSlot +import ru.dbotthepony.mc.otm.menu.OutputMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput @@ -27,7 +26,7 @@ class MatterReplicatorMenu @JvmOverloads constructor( ) : MatteryPoweredMenu(MMenus.MATTER_REPLICATOR, p_38852_, inventory, tile) { val matter = ProfiledLevelGaugeWidget(this, tile?.matter, LevelGaugeWidget(this, tile?.matter)) val progress = ProgressGaugeWidget(this, tile) - val storageSlots: List + val storageSlots: List val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig) val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget) @@ -38,7 +37,7 @@ class MatterReplicatorMenu @JvmOverloads constructor( val container = CombinedContainer(tile?.outputContainer ?: SlottedContainer.simple(3), tile?.dustContainer ?: SlottedContainer.simple(2)) storageSlots = immutableList(5) { - addStorageSlot(OutputSlot(container, it, onTake = { + addStorageSlot(OutputMenuSlot(container, it, onTake = { if (inventory.player is ServerPlayer && it.isNotEmpty) TakeItemOutOfReplicatorTrigger.trigger(inventory.player as ServerPlayer, it) })) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterScannerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterScannerMenu.kt index 65a27c4f4..1ab6f917a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterScannerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterScannerMenu.kt @@ -10,7 +10,7 @@ import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.matter.MatterManager import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.makeUpgradeSlots @@ -22,7 +22,7 @@ class MatterScannerMenu @JvmOverloads constructor( inventory: Inventory, tile: MatterScannerBlockEntity? = null ) : MatteryPoweredMenu(MMenus.MATTER_SCANNER, p_38852_, inventory, tile) { - val input: MatterySlot + val input: MatteryMenuSlot val progress = ProgressGaugeWidget(this, tile) val patterns = LevelGaugeWidget(this) val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig) @@ -33,7 +33,7 @@ class MatterScannerMenu @JvmOverloads constructor( init { val container = tile?.container ?: SimpleContainer(1) - input = object : MatterySlot(container, 0, 64, 38) { + input = object : MatteryMenuSlot(container, 0, 64, 38) { override fun mayPlace(itemStack: ItemStack) = MatterManager.canDecompose(itemStack) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/PatternStorageMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/PatternStorageMenu.kt index 2c21d118a..5f38eccd3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/PatternStorageMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/PatternStorageMenu.kt @@ -6,7 +6,7 @@ import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.block.entity.matter.PatternStorageBlockEntity import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.menu.MatteryMenu -import ru.dbotthepony.mc.otm.menu.PatternSlot +import ru.dbotthepony.mc.otm.menu.PatternMenuSlot import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import ru.dbotthepony.mc.otm.registry.game.MMenus @@ -20,7 +20,7 @@ class PatternStorageMenu @JvmOverloads constructor( val storedGrid = LevelGaugeWidget(this) val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig) - val storageSlots: List + val storageSlots: List init { if (tile != null) { @@ -34,7 +34,7 @@ class PatternStorageMenu @JvmOverloads constructor( val patterns = tile?.container ?: SimpleContainer(2 * 4) storageSlots = immutableList(2 * 4) { - addStorageSlot(PatternSlot(patterns, it)) + addStorageSlot(PatternMenuSlot(patterns, it)) } addInventorySlots() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveRackMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveRackMenu.kt index 9f9897b6f..9855f5b58 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveRackMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveRackMenu.kt @@ -4,7 +4,7 @@ import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.block.entity.storage.DriveRackBlockEntity import ru.dbotthepony.mc.otm.capability.FlowDirection -import ru.dbotthepony.mc.otm.menu.DriveSlot +import ru.dbotthepony.mc.otm.menu.DriveMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback @@ -18,7 +18,7 @@ class DriveRackMenu @JvmOverloads constructor( inventory: Inventory, tile: DriveRackBlockEntity? = null ) : MatteryPoweredMenu(MMenus.DRIVE_RACK, containerId, inventory, tile) { - val storageSlots = makeSlots(tile?.container ?: SimpleContainer(4), ::DriveSlot) + val storageSlots = makeSlots(tile?.container ?: SimpleContainer(4), ::DriveMenuSlot) val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget) val insertPriority = IntInputWithFeedback(this, tile?.let { it::insertPriority }) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveViewerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveViewerMenu.kt index 994b3811f..8d9121892 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveViewerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveViewerMenu.kt @@ -17,7 +17,7 @@ import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.util.ItemStorageStackSorter import ru.dbotthepony.mc.otm.item.PortableCondensationDriveItem import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewProvider import ru.dbotthepony.mc.otm.menu.data.NetworkedItemView import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback @@ -36,7 +36,7 @@ class DriveViewerMenu( ) : MatteryPoweredMenu(MMenus.DRIVE_VIEWER, containerID, inventory, tile), INetworkedItemViewProvider { override val networkedItemView = NetworkedItemView(inventory.player, this, tile == null) - val driveSlot = object : MatterySlot(tile?.container ?: SimpleContainer(1), 0) { + val driveSlot = object : MatteryMenuSlot(tile?.container ?: SimpleContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.getCapability(MatteryCapability.CONDENSATION_DRIVE) != null } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/ItemMonitorMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/ItemMonitorMenu.kt index 71c83bc06..54a2d1287 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/ItemMonitorMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/ItemMonitorMenu.kt @@ -16,7 +16,7 @@ import ru.dbotthepony.mc.otm.core.collect.map import ru.dbotthepony.mc.otm.core.collect.reduce import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewProvider import ru.dbotthepony.mc.otm.menu.data.NetworkedItemView import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback @@ -27,7 +27,7 @@ import ru.dbotthepony.mc.otm.registry.game.MMenus import ru.dbotthepony.mc.otm.storage.* import java.util.* -private class ResultSlot(container: Container) : MatterySlot(container, 0) { +private class ResultMenuSlot(container: Container) : MatteryMenuSlot(container, 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return false } @@ -105,16 +105,16 @@ class ItemMonitorMenu( } } - val craftingResult: MatterySlot - val craftingSlots: List + val craftingResult: MatteryMenuSlot + val craftingSlots: List init { if (tile != null) { networkedItemView.component = tile.poweredView } - craftingResult = ResultSlot(tile?.craftingResultContainer ?: SimpleContainer(1)) - craftingSlots = makeSlots(tile?.craftingGrid ?: SimpleContainer(9), ::MatterySlot) + craftingResult = ResultMenuSlot(tile?.craftingResultContainer ?: SimpleContainer(1)) + craftingSlots = makeSlots(tile?.craftingGrid ?: SimpleContainer(9), ::MatteryMenuSlot) craftingSlots.forEach(this::addSlot) addSlot(craftingResult) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidStationMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidStationMenu.kt index 9b3f0da7e..6eb9b1ddb 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidStationMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidStationMenu.kt @@ -12,7 +12,7 @@ import ru.dbotthepony.mc.otm.capability.MatteryPlayer import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.registry.game.MMenus @@ -90,7 +90,7 @@ class AndroidStationMenu @JvmOverloads constructor( } } - private inner class AndroidSlot(container: Container, private val condition: (ItemStack) -> Boolean) : MatterySlot(container, 0) { + private inner class AndroidMenuSlot(container: Container, private val condition: (ItemStack) -> Boolean) : MatteryMenuSlot(container, 0) { override fun mayPickup(player: Player): Boolean { if (tile is AndroidStationBlockEntity) { return super.mayPickup(player) && tile.energy.batteryLevel >= MachinesConfig.AndroidStation.ENERGY_PER_OPERATION @@ -108,7 +108,7 @@ class AndroidStationMenu @JvmOverloads constructor( } } - val androidBattery: MatterySlot = AndroidSlot(container { it.androidEnergy::item }) { + val androidBattery: MatteryMenuSlot = AndroidMenuSlot(container { it.androidEnergy::item }) { it.getCapability(Capabilities.EnergyStorage.ITEM) != null } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/BatteryBankMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/BatteryBankMenu.kt index aebd6ad6f..36a469139 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/BatteryBankMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/BatteryBankMenu.kt @@ -6,9 +6,9 @@ import ru.dbotthepony.mc.otm.block.entity.tech.BatteryBankBlockEntity import net.minecraft.world.SimpleContainer import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.core.immutableList -import ru.dbotthepony.mc.otm.menu.BatterySlot +import ru.dbotthepony.mc.otm.menu.BatteryMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput @@ -21,7 +21,7 @@ class BatteryBankMenu( tile: BatteryBankBlockEntity? = null, ) : MatteryMenu(MMenus.BATTERY_BANK, p_38852_, inventory, tile) { val powerLevel = ProfiledLevelGaugeWidget(this, tile?.energyConfig?.energy) - val storageSlots: List + val storageSlots: List val redstone = EnumInputWithFeedback(this, RedstoneSetting::class.java) val energyConfig = EnergyConfigPlayerInput(this, allowPull = false, allowPush = true) val itemConfig = ItemConfigPlayerInput(this, allowPull = false, allowPush = false) @@ -36,7 +36,7 @@ class BatteryBankMenu( val container: Container = tile?.container ?: SimpleContainer(BatteryBankBlockEntity.CAPACITY) storageSlots = immutableList(BatteryBankBlockEntity.CAPACITY) { - addStorageSlot(BatterySlot(container, it)) + addStorageSlot(BatteryMenuSlot(container, it)) } addInventorySlots() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ChemicalGeneratorMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ChemicalGeneratorMenu.kt index 33b45a780..f5bffee67 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ChemicalGeneratorMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ChemicalGeneratorMenu.kt @@ -9,7 +9,7 @@ import ru.dbotthepony.kommons.util.setValue import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.block.entity.tech.ChemicalGeneratorBlockEntity import ru.dbotthepony.mc.otm.menu.MatteryMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput @@ -30,19 +30,19 @@ class ChemicalGeneratorMenu @JvmOverloads constructor(id: Int, inv: Inventory, t } } - val fuelSlot = object : MatterySlot(tile?.fuelContainer ?: SimpleContainer(1), 0) { + val fuelSlot = object : MatteryMenuSlot(tile?.fuelContainer ?: SimpleContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.getBurnTime(null) > 0 } } - val residueSlot = object : MatterySlot(tile?.residueContainer ?: SimpleContainer(1), 0) { + val residueSlot = object : MatteryMenuSlot(tile?.residueContainer ?: SimpleContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return false } } - val batterySlot = object : MatterySlot(tile?.batteryContainer ?: SimpleContainer(1), 0) { + val batterySlot = object : MatteryMenuSlot(tile?.batteryContainer ?: SimpleContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.getCapability(Capabilities.EnergyStorage.ITEM)?.canReceive() ?: false } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/CobblerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/CobblerMenu.kt index 9eb8920b6..272fcc3cb 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/CobblerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/CobblerMenu.kt @@ -5,7 +5,7 @@ import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.block.entity.tech.CobblerBlockEntity import ru.dbotthepony.mc.otm.core.immutableList -import ru.dbotthepony.mc.otm.menu.OutputSlot +import ru.dbotthepony.mc.otm.menu.OutputMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput @@ -17,7 +17,7 @@ class CobblerMenu @JvmOverloads constructor( inventory: Inventory, tile: CobblerBlockEntity? = null ) : MatteryMenu(MMenus.COBBLESTONE_GENERATOR, p_38852_, inventory, tile) { - val storageSlots = (tile?.container ?: SimpleContainer(CobblerBlockEntity.CONTAINER_SIZE)).let { c -> immutableList(c.containerSize) { addStorageSlot(OutputSlot(c, it)) } } + val storageSlots = (tile?.container ?: SimpleContainer(CobblerBlockEntity.CONTAINER_SIZE)).let { c -> immutableList(c.containerSize) { addStorageSlot(OutputMenuSlot(c, it)) } } val redstone = EnumInputWithFeedback(this) val itemConfig = ItemConfigPlayerInput(this) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyHatchMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyHatchMenu.kt index 94b8e70f8..4a97d460f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyHatchMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyHatchMenu.kt @@ -6,7 +6,7 @@ import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.block.entity.tech.EnergyHatchBlockEntity import ru.dbotthepony.mc.otm.capability.FlowDirection -import ru.dbotthepony.mc.otm.menu.EnergyContainerInputSlot +import ru.dbotthepony.mc.otm.menu.EnergyContainerInputMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.makeSlots @@ -22,7 +22,7 @@ class EnergyHatchMenu( val container: Container = tile?.container ?: SimpleContainer(EnergyHatchBlockEntity.CAPACITY) val inputSlots = makeSlots(container) { a, b -> - EnergyContainerInputSlot(a, b, direction = FlowDirection.input(isInput)) + EnergyContainerInputMenuSlot(a, b, direction = FlowDirection.input(isInput)) } val gauge = ProfiledLevelGaugeWidget(this, tile?.energy) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyServoMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyServoMenu.kt index 51809ffdb..73b7568d3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyServoMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyServoMenu.kt @@ -7,7 +7,7 @@ import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.block.entity.tech.EnergyServoBlockEntity import ru.dbotthepony.mc.otm.capability.energy import ru.dbotthepony.mc.otm.menu.MatteryMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput @@ -19,13 +19,13 @@ class EnergyServoMenu @JvmOverloads constructor( inventory: Inventory, tile: EnergyServoBlockEntity? = null ) : MatteryMenu(MMenus.ENERGY_SERVO, p_38852_, inventory, tile) { - val dischargeSlot = object : MatterySlot(tile?.discharge ?: SimpleContainer(1), 0) { + val dischargeSlot = object : MatteryMenuSlot(tile?.discharge ?: SimpleContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return super.mayPlace(itemStack) && (itemStack.energy?.canExtract() ?: false) } } - val chargeSlot = object : MatterySlot(tile?.charge ?: SimpleContainer(1), 0) { + val chargeSlot = object : MatteryMenuSlot(tile?.charge ?: SimpleContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return super.mayPlace(itemStack) && (itemStack.energy?.canReceive() ?: false) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EssenceStorageMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EssenceStorageMenu.kt index 5abc2d3b5..a80d14515 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EssenceStorageMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EssenceStorageMenu.kt @@ -13,7 +13,7 @@ import ru.dbotthepony.mc.otm.core.util.getTotalXpRequiredForLevel import ru.dbotthepony.mc.otm.item.consumables.EssenceCapsuleItem import ru.dbotthepony.mc.otm.item.EssenceServoItem import ru.dbotthepony.mc.otm.menu.MatteryMenu -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.FluidConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput @@ -31,19 +31,19 @@ class EssenceStorageMenu( val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig) val fluidConfig = FluidConfigPlayerInput(this, tile?.fluidConfig) - val capsuleSlot = object : MatterySlot(tile?.capsuleContainer ?: SimpleContainer(1), 0) { + val capsuleSlot = object : MatteryMenuSlot(tile?.capsuleContainer ?: SimpleContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.item is EssenceCapsuleItem && super.mayPlace(itemStack) } } - val servoSlot = object : MatterySlot(tile?.servoContainer ?: SimpleContainer(1), 0) { + val servoSlot = object : MatteryMenuSlot(tile?.servoContainer ?: SimpleContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.item == MItems.ESSENCE_SERVO && super.mayPlace(itemStack) } } - val mendingSlot = object : MatterySlot(tile?.mendingContainer ?: SimpleContainer(1), 0) { + val mendingSlot = object : MatteryMenuSlot(tile?.mendingContainer ?: SimpleContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.isDamaged && EnchantmentHelper.has(itemStack, EnchantmentEffectComponents.REPAIR_WITH_XP) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ItemHatchMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ItemHatchMenu.kt index 620d9f509..eae68b777 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ItemHatchMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ItemHatchMenu.kt @@ -8,7 +8,7 @@ import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.block.entity.tech.ItemHatchBlockEntity import ru.dbotthepony.mc.otm.menu.MatteryMenu -import ru.dbotthepony.mc.otm.menu.UserFilteredSlot +import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.makeSlots import ru.dbotthepony.mc.otm.registry.game.MMenus @@ -20,8 +20,8 @@ class ItemHatchMenu( tile: ItemHatchBlockEntity? = null ) : MatteryMenu(if (isInput) MMenus.ITEM_INPUT_HATCH else MMenus.ITEM_OUTPUT_HATCH, containerId, inventory, tile) { val actualContainer: Container = tile?.container ?: SimpleContainer(ItemHatchBlockEntity.CAPACITY) - val storageSlots: ImmutableList = makeSlots(actualContainer) { a, b -> - object : UserFilteredSlot(a, b) { + val storageSlots: ImmutableList = makeSlots(actualContainer) { a, b -> + object : UserFilteredMenuSlot(a, b) { override fun mayPlace(itemStack: ItemStack): Boolean { return isInput && super.mayPlace(itemStack) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/MatterHatchMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/MatterHatchMenu.kt index 94ea8f34e..db04cf5ea 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/MatterHatchMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/MatterHatchMenu.kt @@ -6,7 +6,7 @@ import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.block.entity.tech.MatterHatchBlockEntity import ru.dbotthepony.mc.otm.capability.FlowDirection -import ru.dbotthepony.mc.otm.menu.MatterContainerInputSlot +import ru.dbotthepony.mc.otm.menu.MatterContainerInputMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.makeSlots @@ -22,7 +22,7 @@ class MatterHatchMenu( val container: Container = tile?.container ?: SimpleContainer(MatterHatchBlockEntity.CAPACITY) val inputSlots = makeSlots(container) { a, b -> - MatterContainerInputSlot(a, b, direction = FlowDirection.input(isInput)) + MatterContainerInputMenuSlot(a, b, direction = FlowDirection.input(isInput)) } val gauge = ProfiledLevelGaugeWidget(this, tile?.matter) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PlatePressMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PlatePressMenu.kt index d1afe3c85..e18661ad1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PlatePressMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PlatePressMenu.kt @@ -8,8 +8,8 @@ import net.minecraft.world.inventory.MenuType import ru.dbotthepony.mc.otm.block.entity.tech.PlatePressBlockEntity import ru.dbotthepony.mc.otm.compat.jei.PlatePressRecipeCategory import ru.dbotthepony.mc.otm.core.immutableList -import ru.dbotthepony.mc.otm.menu.OutputSlot -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.OutputMenuSlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput @@ -28,8 +28,8 @@ class PlatePressMenu( tile: PlatePressBlockEntity? = null, isTwin: Boolean ) : AbstractProcessingMachineMenu(type, containerID, inventory, tile) { - val inputSlots = makeSlots(tile?.inputContainer ?: SimpleContainer(if (isTwin) 2 else 1), ::MatterySlot) - val outputSlots = makeSlots(tile?.outputContainer ?: SimpleContainer(if (isTwin) 2 else 1)) { a, b -> OutputSlot(a, b) { tile?.experience?.popExperience(player as ServerPlayer) } } + val inputSlots = makeSlots(tile?.inputContainer ?: SimpleContainer(if (isTwin) 2 else 1), ::MatteryMenuSlot) + val outputSlots = makeSlots(tile?.outputContainer ?: SimpleContainer(if (isTwin) 2 else 1)) { a, b -> OutputMenuSlot(a, b) { tile?.experience?.popExperience(player as ServerPlayer) } } val gauges = immutableList(if (isTwin) 2 else 1) { ProgressGaugeWidget(this, tile?.jobEventLoops?.get(it)) } override val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig, allowPush = true) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PoweredFurnaceMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PoweredFurnaceMenu.kt index 8d709e278..85739a185 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PoweredFurnaceMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PoweredFurnaceMenu.kt @@ -12,8 +12,8 @@ import ru.dbotthepony.mc.otm.block.entity.tech.PoweredFurnaceBlockEntity import ru.dbotthepony.mc.otm.block.entity.tech.PoweredSmokerBlockEntity import ru.dbotthepony.mc.otm.compat.jei.MicrowaveRecipeCategory import ru.dbotthepony.mc.otm.core.immutableList -import ru.dbotthepony.mc.otm.menu.OutputSlot -import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.OutputMenuSlot +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput @@ -31,8 +31,8 @@ class PoweredFurnaceMenu( inventory: Inventory, tile: AbstractPoweredFurnaceBlockEntity<*, *>? = null ) : AbstractProcessingMachineMenu(type, containerID, inventory, tile) { - val inputSlots = makeSlots(tile?.inputs ?: SimpleContainer(2), ::MatterySlot) - val outputSlots = makeSlots(tile?.outputs ?: SimpleContainer(2)) { c, s -> OutputSlot(c, s) { tile?.experience?.popExperience(player as ServerPlayer) } } + val inputSlots = makeSlots(tile?.inputs ?: SimpleContainer(2), ::MatteryMenuSlot) + val outputSlots = makeSlots(tile?.outputs ?: SimpleContainer(2)) { c, s -> OutputMenuSlot(c, s) { tile?.experience?.popExperience(player as ServerPlayer) } } val progressGauge = immutableList(2) { ProgressGaugeWidget(this, tile?.jobEventLoops?.get(it)) } override val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig, allowPush = true) From 66a4adecf924a05d39c11a8080a061552d8e658b Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 1 Mar 2025 00:06:07 +0700 Subject: [PATCH 015/154] Move Fluid tank to SlottedContainer, and make it accept slot filters --- .../entity/decorative/FluidTankBlockEntity.kt | 103 +++++++----- .../screen/decorative/FluidTankScreen.kt | 5 +- .../otm/container/slotted/AutomationFilter.kt | 50 ++++++ .../container/slotted/AutomationFilters.kt | 146 ++++++++++++++++++ .../mc/otm/container/slotted/ContainerSlot.kt | 14 +- .../slotted/FilteredContainerSlot.kt | 7 + .../otm/container/slotted/SimpleCallbacks.kt | 19 --- .../mc/otm/menu/decorative/FluidTankMenu.kt | 12 +- 8 files changed, 288 insertions(+), 68 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilter.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt delete mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SimpleCallbacks.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/FluidTankBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/FluidTankBlockEntity.kt index d6b669f68..8f8a2a83d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/FluidTankBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/FluidTankBlockEntity.kt @@ -21,6 +21,11 @@ import ru.dbotthepony.mc.otm.config.ItemsConfig import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.get +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilter +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters +import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.isNotSameAs import ru.dbotthepony.mc.otm.menu.decorative.FluidTankMenu @@ -37,28 +42,42 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery } }), FluidStack.OPTIONAL_STREAM_CODEC.wrap())) - val fillInput = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer) - val drainInput = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer) - val output = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer) + private inner class FillSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) { + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + if (!super.canAutomationPlaceItem(itemStack)) + return false + + if (fluid.isEmpty) { + return itemStack.getCapability(Capabilities.FluidHandler.ITEM)?.let { it.tanks > 0 } ?: false + } + + return itemStack.getCapability(Capabilities.FluidHandler.ITEM)?.let { it.fill(fluid[0], IFluidHandler.FluidAction.SIMULATE) > 0 } ?: false + } + + override fun canAutomationTakeItem(desired: Int): Boolean { + return super.canAutomationTakeItem(desired) && !canAutomationPlaceItem(item) + } + } + + val inputContainer = SlottedContainer.Builder() + .add(DRAIN_TAG, AutomationFilters.DRAINABLE_FLUID_CONTAINERS.filteredProvider) + .add(FILL_TAG, ::FillSlot) + .onChanged(::markDirtyFast) + .build() + .also(::addDroppableContainer) + + val outputContainer = SlottedContainer.Builder() + .add(AutomationFilters.ONLY_OUT.simpleProvider) + .onChanged(::markDirtyFast) + .build() + .also(::addDroppableContainer) + + private val fillSlot = inputContainer[FILL_TAG] + private val drainSlot = inputContainer[DRAIN_TAG] val itemConfig = ConfigurableItemHandler( - input = CombinedItemHandler( - drainInput.handler(HandlerFilter.DrainableFluidContainers), - fillInput.handler(object : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - if (fluid.isEmpty) { - return stack.getCapability(Capabilities.FluidHandler.ITEM)?.let { it.tanks > 0 } ?: false - } - - return stack.getCapability(Capabilities.FluidHandler.ITEM)?.let { it.fill(fluid[0], IFluidHandler.FluidAction.SIMULATE) > 0 } ?: false - } - - override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return !canInsert(slot, stack) - } - }) - ), - output = output.handler(HandlerFilter.OnlyOut), + input = inputContainer, + output = outputContainer, frontDefault = ItemHandlerMode.INPUT_OUTPUT, backDefault = ItemHandlerMode.INPUT_OUTPUT, leftDefault = ItemHandlerMode.INPUT_OUTPUT, @@ -71,20 +90,19 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery init { savetables.stateful(::fluid, FLUID_KEY) - savetables.stateful(::fillInput) - savetables.stateful(::drainInput) - savetables.stateful(::output) + savetables.stateful(::inputContainer) + savetables.stateful(::outputContainer) } private fun drainItem() { - val item = drainInput[0] + val item = drainSlot.item if (item.isNotEmpty) { val cap = (if (item.count == 1) item else item.copyWithCount(1)).getCapability(Capabilities.FluidHandler.ITEM) if (cap == null) { - if (output.consumeItem(item, simulate = false)) { - drainInput.setChanged(0) + if (outputContainer.consumeItem(item, simulate = false)) { + drainSlot.setChanged() } return @@ -95,17 +113,17 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery val moved0 = moveFluid(source = cap, destination = fluid) if (moved0.isNotEmpty) { - drainInput[0] = cap.container + drainSlot.item = cap.container - if (output.consumeItem(drainInput[0], simulate = false)) { - drainInput.setChanged(0) + if (outputContainer.consumeItem(drainSlot.item, simulate = false)) { + drainSlot.setChanged() } } } else { val moved0 = moveFluid(source = cap, destination = fluid, actuallyFill = false) if (moved0.isNotEmpty) { - if (output.consumeItem(cap.container, simulate = true)) { + if (outputContainer.consumeItem(cap.container, simulate = true)) { val cap1 = item.copyWithCount(1).getCapability(Capabilities.FluidHandler.ITEM) ?: throw ConcurrentModificationException() val moved1 = moveFluid(source = cap1, destination = fluid) @@ -114,9 +132,9 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery LOGGER.error("Error moving fluids in Fluid tank at $blockPos: moved $moved0 during simulation from ${cap.container}, moved $moved1 from ${cap1.container} during execution. This is likely a bug in OTM or other mod!") } else { item.count-- - drainInput.setChanged(0) + drainSlot.setChanged() - if (!output.consumeItem(cap1.container, simulate = false)) { + if (!outputContainer.consumeItem(cap1.container, simulate = false)) { LOGGER.error("Unable to insert ${cap1.container} into output slot of Fluid tank at $blockPos, popping item in world instead to avoid item loss! This is likely a bug in OTM or other mod!") (level as? ServerLevel)?.addFreshEntity(ItemEntity(level!!, blockPos.x.toDouble(), blockPos.y.toDouble(), blockPos.z.toDouble(), cap1.container)) } @@ -129,14 +147,14 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery } private fun fillItem() { - val item = fillInput[0] + val item = fillSlot.item if (item.isNotEmpty) { val cap = (if (item.count == 1) item else item.copyWithCount(1)).getCapability(Capabilities.FluidHandler.ITEM) if (cap == null) { - if (output.consumeItem(item, simulate = false)) { - fillInput.setChanged(0) + if (outputContainer.consumeItem(item, simulate = false)) { + fillSlot.setChanged() } return @@ -147,17 +165,17 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery val moved0 = moveFluid(source = fluid, destination = cap) if (moved0.isNotEmpty) { - fillInput[0] = cap.container + fillSlot.item = cap.container - if (output.consumeItem(fillInput[0], simulate = false)) { - fillInput.setChanged(0) + if (outputContainer.consumeItem(fillSlot.item, simulate = false)) { + fillSlot.setChanged() } } } else { val moved0 = moveFluid(source = fluid, destination = cap, actuallyDrain = false) if (moved0.isNotEmpty) { - if (output.consumeItem(cap.container, simulate = true)) { + if (outputContainer.consumeItem(cap.container, simulate = true)) { val cap1 = item.copyWithCount(1).getCapability(Capabilities.FluidHandler.ITEM) ?: throw ConcurrentModificationException() val moved1 = moveFluid(source = fluid, destination = cap1) @@ -166,9 +184,9 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery LOGGER.error("Error moving fluids in Fluid tank at $blockPos: moved $moved0 during simulation from ${cap.container}, moved $moved1 from ${cap1.container} during execution. This is likely a bug in OTM or other mod!") } else { item.count-- - fillInput.setChanged(0) + fillSlot.setChanged() - if (!output.consumeItem(cap1.container, simulate = false)) { + if (!outputContainer.consumeItem(cap1.container, simulate = false)) { LOGGER.error("Unable to insert ${cap1.container} into output slot of Fluid tank at $blockPos, popping item in world instead to avoid item loss! This is likely a bug in OTM or other mod!") (level as? ServerLevel)?.addFreshEntity(ItemEntity(level!!, blockPos.x.toDouble(), blockPos.y.toDouble(), blockPos.z.toDouble(), cap1.container)) } @@ -194,5 +212,8 @@ class FluidTankBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery companion object { const val FLUID_KEY = "fluid" private val LOGGER = LogManager.getLogger() + + private val FILL_TAG = SlottedContainer.tag() + private val DRAIN_TAG = SlottedContainer.tag() } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/FluidTankScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/FluidTankScreen.kt index 1027ce7f7..058b7a3a3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/FluidTankScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/decorative/FluidTankScreen.kt @@ -12,6 +12,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls import ru.dbotthepony.mc.otm.client.screen.panels.makeCuriosPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.SpritePanel +import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel import ru.dbotthepony.mc.otm.client.screen.widget.FluidGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel import ru.dbotthepony.mc.otm.menu.decorative.FluidTankMenu @@ -25,8 +26,8 @@ class FluidTankScreen(menu: FluidTankMenu, inventory: Inventory, title: Componen val s = SpritePanel(this, frame, ProgressGaugePanel.GAUGE_BACKGROUND, x = 30f, y = 30f) SpritePanel(this, frame, ProgressGaugePanel.GAUGE_BACKGROUND, x = 30f, y = 55f, winding = UVWindingOrder.FLOP) - SlotPanel(this, frame, menu.fillInput, x = 30f + s.width + 4f, y = 28f) - SlotPanel(this, frame, menu.drainInput, x = 30f + s.width + 4f, y = 53f) + UserFilteredSlotPanel(this, frame, menu.fillInput, x = 30f + s.width + 4f, y = 28f) + UserFilteredSlotPanel(this, frame, menu.drainInput, x = 30f + s.width + 4f, y = 53f) SlotPanel(this, frame, menu.output, x = 30f + s.width + 4f + 20f, y = 53f) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilter.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilter.kt new file mode 100644 index 000000000..c7cf2bf35 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilter.kt @@ -0,0 +1,50 @@ +package ru.dbotthepony.mc.otm.container.slotted + +import net.minecraft.world.item.ItemStack + +fun interface AutomationPlaceItem { + fun canAutomationPlaceItem(self: S, itemStack: ItemStack): Boolean +} + +fun interface AutomationTakeItem { + fun canAutomationTakeItem(self: S, desired: Int): Boolean +} + +fun interface AutomationModifyPlaceCount { + fun modifyAutomationPlaceCount(self: S, itemStack: ItemStack): Int +} + +fun interface AutomationModifyExtractionCount { + fun modifyAutomationExtractionCount(self: S, desired: Int): Int +} + +interface AutomationFilter : AutomationPlaceItem, AutomationTakeItem, AutomationModifyPlaceCount, AutomationModifyExtractionCount { + override fun modifyAutomationPlaceCount(self: S, itemStack: ItemStack): Int { + return itemStack.count + } + + override fun modifyAutomationExtractionCount(self: S, desired: Int): Int { + return desired + } +} + +fun AutomationFilter.and(other: AutomationFilter): AutomationFilter { + return object : AutomationFilter { + override fun canAutomationPlaceItem(self: T, itemStack: ItemStack): Boolean { + return this@and.canAutomationPlaceItem(self, itemStack) && other.canAutomationPlaceItem(self, itemStack) + } + + override fun canAutomationTakeItem(self: T, desired: Int): Boolean { + return this@and.canAutomationTakeItem(self, desired) && other.canAutomationTakeItem(self, desired) + } + + override fun modifyAutomationPlaceCount(self: T, itemStack: ItemStack): Int { + return this@and.modifyAutomationPlaceCount(self, itemStack) + } + + override fun modifyAutomationExtractionCount(self: T, desired: Int): Int { + return this@and.modifyAutomationExtractionCount(self, desired) + } + } +} + diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt new file mode 100644 index 000000000..aa7602ba5 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt @@ -0,0 +1,146 @@ +package ru.dbotthepony.mc.otm.container.slotted + +import net.minecraft.world.item.ItemStack +import net.neoforged.neoforge.capabilities.Capabilities +import ru.dbotthepony.mc.otm.capability.MatteryCapability +import ru.dbotthepony.mc.otm.capability.fluid.stream +import ru.dbotthepony.mc.otm.core.isNotEmpty +import ru.dbotthepony.mc.otm.core.math.Decimal + +enum class AutomationFilters : AutomationFilter { + ONLY_OUT { + override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + return true + } + + override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + return false + } + }, + + ONLY_IN { + override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + return false + } + + override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + return true + } + }, + + ALLOW { + override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + return true + } + + override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + return true + } + }, + + DENY { + override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + return false + } + + override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + return false + } + }, + + FLUID_CONTAINERS { + override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + return itemStack.getCapability(Capabilities.FluidHandler.ITEM)?.let { it.tanks > 0 } ?: false + } + + override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + return true + } + }, + + DRAINABLE_FLUID_CONTAINERS { + override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + return itemStack.getCapability(Capabilities.FluidHandler.ITEM)?.let { it.stream().anyMatch { it.isNotEmpty } } ?: false + } + + override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + return !canAutomationPlaceItem(self, self.item) + } + }, + + DICHARGEABLE { + override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + return itemStack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { it.canExtract() && it.extractEnergy(Int.MAX_VALUE, true) > 0 } ?: false + } + + override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + return self.item.getCapability(Capabilities.EnergyStorage.ITEM)?.let { !it.canExtract() || it.extractEnergy(Int.MAX_VALUE, true) <= 0 } ?: true + } + }, + + CHARGEABLE { + override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + return itemStack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { it.canReceive() && it.receiveEnergy(Int.MAX_VALUE, true) > 0 } ?: false + } + + override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + return self.item.getCapability(Capabilities.EnergyStorage.ITEM)?.let { !it.canReceive() || it.receiveEnergy(Int.MAX_VALUE, true) <= 0 } ?: true + } + }, + + CHEMICAL_FUEL { + override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + return itemStack.getBurnTime(null) > 0 + } + + override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + return self.item.getBurnTime(null) <= 0 + } + }, + + IS_PATTERN { + override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + return itemStack.getCapability(MatteryCapability.PATTERN_ITEM) != null + } + + override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + return true + } + }, + + MATTER_PROVIDERS { + override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + return itemStack.getCapability(MatteryCapability.MATTER_ITEM) + ?.let { it.matterFlow.output && it.extractMatterChecked(Decimal.POSITIVE_INFINITY, true) > Decimal.ZERO } + ?: false + } + + override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + return self.item.getCapability(MatteryCapability.MATTER_ITEM) + ?.let { !it.matterFlow.output || it.extractMatterChecked(Decimal.POSITIVE_INFINITY, true) <= Decimal.ZERO } + ?: true + } + }, + + MATTER_CONSUMERS { + override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + return itemStack.getCapability(MatteryCapability.MATTER_ITEM) + ?.let { it.matterFlow.input && it.receiveMatterChecked(Decimal.POSITIVE_INFINITY, true) > Decimal.ZERO } + ?: false + } + + override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + return self.item.getCapability(MatteryCapability.MATTER_ITEM) + ?.let { !it.matterFlow.input || it.receiveMatterChecked(Decimal.POSITIVE_INFINITY, true) <= Decimal.ZERO } + ?: true + } + }; + + val simpleProvider: SlottedContainer.SlotProvider by lazy { + ContainerSlot.Simple(filter = this) + } + + val filteredProvider: SlottedContainer.SlotProvider by lazy { + FilteredContainerSlot.Simple(filter = this) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt index 18109d9be..62780ee8c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt @@ -52,7 +52,13 @@ open class ContainerSlot( } fun observeChanges(): Boolean { - if (observedItem.count != item.count || !ItemStack.isSameItemSameComponents(item, observedItem)) { + if (observedItem.isNotEmpty && item.isEmpty) { + notifyChanged(observedItem) + observedItem = ItemStack.EMPTY + _item = ItemStack.EMPTY + container.notifyChanged() + return true + } else if (observedItem.count != item.count || !ItemStack.isSameItemSameComponents(item, observedItem)) { notifyChanged(observedItem) observedItem = item.copy() container.notifyChanged() @@ -117,6 +123,12 @@ open class ContainerSlot( private val modifyAutomationPlaceCount: AutomationModifyPlaceCount = AutomationModifyPlaceCount { _, item -> item.count }, private val modifyAutomationExtractionCount: AutomationModifyExtractionCount = AutomationModifyExtractionCount { _, desired -> desired }, ) : SlottedContainer.SlotProvider { + constructor( + listener: (new: ItemStack, old: ItemStack) -> Unit = { _, _ -> }, + maxStackSize: Int = Item.DEFAULT_MAX_STACK_SIZE, + filter: AutomationFilter = AutomationFilters.ALLOW + ) : this(listener, maxStackSize, filter, filter, filter, filter) + private open inner class Instance(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) { override val maxStackSize: Int get() = this@Simple.maxStackSize diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt index 4a067fd75..909534c01 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt @@ -9,6 +9,7 @@ import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.container.IFilteredAutomatedContainerSlot import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.registryName +import java.util.Collections open class FilteredContainerSlot( container: SlottedContainer, @@ -50,6 +51,12 @@ open class FilteredContainerSlot( private val modifyAutomationPlaceCount: AutomationModifyPlaceCount = AutomationModifyPlaceCount { _, item -> item.count }, private val modifyAutomationExtractionCount: AutomationModifyExtractionCount = AutomationModifyExtractionCount { _, desired -> desired }, ) : SlottedContainer.SlotProvider { + constructor( + listener: (new: ItemStack, old: ItemStack) -> Unit = { _, _ -> }, + maxStackSize: Int = Item.DEFAULT_MAX_STACK_SIZE, + filter: AutomationFilter = AutomationFilters.ALLOW + ) : this(listener, maxStackSize, filter, filter, filter, filter) + private open inner class Instance(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) { override val maxStackSize: Int get() = this@Simple.maxStackSize diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SimpleCallbacks.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SimpleCallbacks.kt deleted file mode 100644 index 664d268f0..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SimpleCallbacks.kt +++ /dev/null @@ -1,19 +0,0 @@ -package ru.dbotthepony.mc.otm.container.slotted - -import net.minecraft.world.item.ItemStack - -fun interface AutomationPlaceItem { - fun canAutomationPlaceItem(self: S, itemStack: ItemStack): Boolean -} - -fun interface AutomationTakeItem { - fun canAutomationTakeItem(self: S, desired: Int): Boolean -} - -fun interface AutomationModifyPlaceCount { - fun modifyAutomationPlaceCount(self: S, itemStack: ItemStack): Int -} - -fun interface AutomationModifyExtractionCount { - fun modifyAutomationExtractionCount(self: S, desired: Int): Int -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/FluidTankMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/FluidTankMenu.kt index abc66ec71..bce9927e0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/FluidTankMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/FluidTankMenu.kt @@ -1,6 +1,5 @@ package ru.dbotthepony.mc.otm.menu.decorative -import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory import net.minecraft.world.item.ItemStack import net.neoforged.neoforge.capabilities.Capabilities @@ -8,9 +7,10 @@ import net.neoforged.neoforge.fluids.capability.IFluidHandler import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.block.entity.decorative.FluidTankBlockEntity import ru.dbotthepony.mc.otm.capability.isNotEmpty +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.OutputMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryMenu -import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.FluidConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput @@ -24,14 +24,16 @@ class FluidTankMenu(containerId: Int, inventory: Inventory, tile: FluidTankBlock val redstoneConfig = EnumInputWithFeedback(this) val fluidConfig = FluidConfigPlayerInput(this, tile?.fluidConfig) - val drainInput = object : MatteryMenuSlot(tile?.drainInput ?: SimpleContainer(1), 0) { + private val inputContainer = tile?.inputContainer ?: SlottedContainer.filtered(2) + + val drainInput = object : UserFilteredMenuSlot(inputContainer, 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return super.mayPlace(itemStack) && (itemStack.getCapability(Capabilities.FluidHandler.ITEM)?.isNotEmpty ?: false) } } - val fillInput = object : MatteryMenuSlot(tile?.fillInput ?: SimpleContainer(1), 0) { + val fillInput = object : UserFilteredMenuSlot(inputContainer, 1) { override fun mayPlace(itemStack: ItemStack): Boolean { return super.mayPlace(itemStack) && (if (itemStack.count <= 1) itemStack @@ -46,7 +48,7 @@ class FluidTankMenu(containerId: Int, inventory: Inventory, tile: FluidTankBlock } } - val output = OutputMenuSlot(tile?.output ?: SimpleContainer(1), 0) + val output = OutputMenuSlot(tile?.outputContainer ?: SlottedContainer.simple(1), 0) init { // сначала слот на заполнение из бака From d2ff43946eaa30b883b9eee2193c3bb946f6b758 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 1 Mar 2025 12:00:33 +0700 Subject: [PATCH 016/154] Update grill to use SlottedContainer --- .../entity/decorative/GrillBlockEntity.kt | 41 ++++++++++--------- .../mc/otm/container/IEnhancedContainer.kt | 5 +++ .../otm/container/slotted/SlottedContainer.kt | 11 +++++ .../mc/otm/menu/decorative/GrillMenu.kt | 14 ++----- 4 files changed, 41 insertions(+), 30 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt index da51be08f..bba8733a6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt @@ -24,7 +24,10 @@ import ru.dbotthepony.mc.otm.block.decorative.GrillBlock import ru.dbotthepony.mc.otm.block.entity.ExperienceStorage import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity import ru.dbotthepony.mc.otm.config.MachinesConfig -import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.set +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters +import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.get import ru.dbotthepony.mc.otm.core.isNotEmpty @@ -38,43 +41,39 @@ import ru.dbotthepony.mc.otm.menu.decorative.GrillMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBlockEntity(MBlockEntities.GRILL, blockPos, blockState), MenuProvider, IBlockWithCustomName { - val fuelSlot = object : MatteryContainer(this@GrillBlockEntity::markDirtyFast, 1) { - override fun getMaxStackSize(): Int { - return 4 - } - } + val fuelSlot = SlottedContainer.simple(1, FUEL_SLOT_PROVIDER, ::markDirtyFast) - val inputSlots = object : MatteryContainer(this@GrillBlockEntity::markDirtyFast, SLOTS) { - override fun getMaxStackSize(): Int { - return 1 - } + private inner class InputSlot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) { + override val maxStackSize: Int + get() = 1 - private fun clearSlot(slot: Int) { + + private fun clearSlot() { inputProgress[slot] = 0 outputs[slot] = null activeSlots.rem(slot) } - override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { - super.setChanged(slot, new, old) + override fun notifyChanged(old: ItemStack) { + super.notifyChanged(old) - if (new.isEmpty || new.count > 1) { - clearSlot(slot) + if (item.isEmpty || item.count > 1) { + clearSlot() } else { val level = level if (level == null) { - clearSlot(slot) + clearSlot() return } - val input = SingleRecipeInput(new) + val input = SingleRecipeInput(item) val result = level.recipeManager .byType(RecipeType.SMOKING) .firstOrNull { it.value.matches(input, level) } if (result == null) { - clearSlot(slot) + clearSlot() } else { if (outputs[slot] != result.value) inputProgress[slot] = 0 @@ -86,10 +85,11 @@ class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBloc } } + val inputSlots = SlottedContainer.simple(SLOTS, ::InputSlot, ::markDirtyFast) override var customDisplayName: Component? = null - override fun createMenu(p_39954_: Int, p_39955_: Inventory, p_39956_: Player): AbstractContainerMenu { - return GrillMenu(p_39954_, p_39955_, this) + override fun createMenu(containerID: Int, inventory: Inventory, player: Player): AbstractContainerMenu { + return GrillMenu(containerID, inventory, this) } override fun getDisplayName(): Component { @@ -205,5 +205,6 @@ class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBloc const val SLOTS = 6 private val progressCodec = Codec.INT.minRange(0) + val FUEL_SLOT_PROVIDER = ContainerSlot.Simple(maxStackSize = 4, filter = AutomationFilters.CHEMICAL_FUEL) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt index c7deb64af..1aae7b23f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt @@ -21,6 +21,11 @@ import java.util.function.Predicate * and actual implementations of this interface are likely to provide efficient method implementations in place of derived/emulated ones. */ interface IEnhancedContainer : IContainer, RecipeInput, Iterable { + // provide non-ambiguous "get" operator + operator fun get(slot: Int): ItemStack { + return getItem(slot) + } + fun containerSlot(slot: Int): IContainerSlot { return IContainerSlot.Simple(slot, this) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt index c342b464c..f80c8b19e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt @@ -392,6 +392,17 @@ class SlottedContainer( .build() } + fun simple(size: Int, provider: SlotProvider<*>): SlottedContainer { + return Builder().add(size, provider).build() + } + + fun simple(size: Int, provider: SlotProvider<*>, listener: Runnable): SlottedContainer { + return Builder() + .add(size, provider) + .onChanged(listener) + .build() + } + fun filtered(size: Int): SlottedContainer { return Builder().add(size, ::FilteredContainerSlot).build() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/GrillMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/GrillMenu.kt index 58914fa00..644d81902 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/GrillMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/GrillMenu.kt @@ -11,6 +11,8 @@ import net.minecraft.world.item.crafting.SingleRecipeInput import ru.dbotthepony.kommons.util.getValue import ru.dbotthepony.mc.otm.block.entity.decorative.GrillBlockEntity import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.menu.ChemicalFuelMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryMenu @@ -26,17 +28,9 @@ class GrillMenu( inventory: Inventory, tile: GrillBlockEntity? = null ) : MatteryMenu(MMenus.GRILL, containerId, inventory, tile) { - val fuelSlot = makeSlots(tile?.fuelSlot ?: object : MatteryContainer(1) { - override fun getMaxStackSize(): Int { - return 4 - } - }, ::ChemicalFuelMenuSlot) + val fuelSlot = makeSlots(tile?.fuelSlot ?: SlottedContainer.simple(1, GrillBlockEntity.FUEL_SLOT_PROVIDER), ::ChemicalFuelMenuSlot) - val inputSlots = makeSlots(tile?.inputSlots ?: object : MatteryContainer(GrillBlockEntity.SLOTS) { - override fun getMaxStackSize(): Int { - return 1 - } - }) { c, i -> + val inputSlots = makeSlots(tile?.inputSlots ?: SlottedContainer.simple(GrillBlockEntity.SLOTS, ContainerSlot.Simple(maxStackSize = 1))) { c, i -> object : MatteryMenuSlot(c, i) { override fun onTake(p_150645_: Player, p_150646_: ItemStack) { super.onTake(p_150645_, p_150646_) From 454783a99a8b6ac89f0b0cba9f340cd12d2e2b70 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 1 Mar 2025 12:11:53 +0700 Subject: [PATCH 017/154] KOptional codec --- .../mc/otm/data/codec/KOptionalCodec.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/data/codec/KOptionalCodec.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/codec/KOptionalCodec.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/codec/KOptionalCodec.kt new file mode 100644 index 000000000..d83207062 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/data/codec/KOptionalCodec.kt @@ -0,0 +1,21 @@ +package ru.dbotthepony.mc.otm.data.codec + +import com.mojang.datafixers.util.Pair +import com.mojang.serialization.Codec +import com.mojang.serialization.DataResult +import com.mojang.serialization.DynamicOps +import ru.dbotthepony.kommons.util.KOptional + +class KOptionalCodec(val parent: Codec) : Codec> { + override fun encode(input: KOptional, ops: DynamicOps, prefix: T): DataResult { + return input.map { parent.encode(it, ops, prefix) }.orElse { DataResult.success(ops.empty()) } + } + + override fun decode(ops: DynamicOps, input: T): DataResult, T>> { + if (input == ops.empty()) { + return DataResult.success(Pair(KOptional(), ops.empty())) + } else { + return parent.decode(ops, input).map { Pair(KOptional(it.first), it.second) } + } + } +} From 2b2f78e528ee61747397ffd9fe83c933600133ce Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 1 Mar 2025 12:12:20 +0700 Subject: [PATCH 018/154] Fix Grill not properly saving cook progress when being deserialized from disk --- .../otm/block/entity/decorative/GrillBlockEntity.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt index bba8733a6..24d5f2f96 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt @@ -6,6 +6,7 @@ import net.minecraft.core.BlockPos import net.minecraft.core.HolderLookup import net.minecraft.nbt.CompoundTag import net.minecraft.network.chat.Component +import net.minecraft.resources.ResourceLocation import net.minecraft.server.level.ServerLevel import net.minecraft.world.Containers import net.minecraft.world.MenuProvider @@ -19,6 +20,7 @@ import net.minecraft.world.item.crafting.SmokingRecipe import net.minecraft.world.level.block.Block import net.minecraft.world.level.block.state.BlockState import ru.dbotthepony.kommons.util.Delegate +import ru.dbotthepony.kommons.util.KOptional import ru.dbotthepony.mc.otm.block.IBlockWithCustomName import ru.dbotthepony.mc.otm.block.decorative.GrillBlock import ru.dbotthepony.mc.otm.block.entity.ExperienceStorage @@ -36,6 +38,7 @@ import ru.dbotthepony.mc.otm.core.math.component2 import ru.dbotthepony.mc.otm.core.math.component3 import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.core.util.countingLazy +import ru.dbotthepony.mc.otm.data.codec.KOptionalCodec import ru.dbotthepony.mc.otm.data.codec.minRange import ru.dbotthepony.mc.otm.menu.decorative.GrillMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities @@ -51,6 +54,7 @@ class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBloc private fun clearSlot() { inputProgress[slot] = 0 outputs[slot] = null + outputsRecipeNames[slot] = KOptional.empty() activeSlots.rem(slot) } @@ -75,9 +79,10 @@ class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBloc if (result == null) { clearSlot() } else { - if (outputs[slot] != result.value) + if (outputsRecipeNames[slot].orNull() != result.id) inputProgress[slot] = 0 + outputsRecipeNames[slot] = KOptional.of(result.id) outputs[slot] = result.value activeSlots.add(slot) } @@ -96,6 +101,7 @@ class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBloc return customDisplayName ?: level?.getBlockState(blockPos)?.block?.name ?: TextComponent("null at $blockPos") } + private val outputsRecipeNames = Array>(SLOTS) { KOptional.empty() } private val outputs = arrayOfNulls(SLOTS) private val activeSlots = IntArrayList() private val inputProgress = IntArray(SLOTS) @@ -132,9 +138,12 @@ class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBloc savetables.stateful(::fuelSlot) savetables.stateful(::experience) + outputsRecipeNames.fill(KOptional()) + // TODO: could have been done as list (and get more space efficient storage), but we use an array, oh well for (i in inputProgress.indices) { savetables.codec(Delegate.Of({ inputProgress[i] }, { inputProgress[i] = it }), progressCodec, "inputProgress${i}") + savetables.codec(Delegate.Of({ outputsRecipeNames[i] }, { outputsRecipeNames[i] = it }), recipeNameCodec, "recipeName${i}") } // addDroppableContainer(inputSlots) @@ -205,6 +214,7 @@ class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBloc const val SLOTS = 6 private val progressCodec = Codec.INT.minRange(0) + private val recipeNameCodec = KOptionalCodec(ResourceLocation.CODEC) val FUEL_SLOT_PROVIDER = ContainerSlot.Simple(maxStackSize = 4, filter = AutomationFilters.CHEMICAL_FUEL) } } From a6891362d9612e0c13292db1ae72610d2d5c0c66 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 1 Mar 2025 12:15:33 +0700 Subject: [PATCH 019/154] Remove no longer needed operator --- .../kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt index 9f890e005..024ed041c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt @@ -230,9 +230,6 @@ open class MatteryContainer(var listener: ContainerListener, private val size: I return nonEmptyIndices.isEmpty } - @Suppress("nothing_to_inline") - inline operator fun get(slot: Int) = getItem(slot) - @Suppress("nothing_to_inline") inline operator fun set(slot: Int, stack: ItemStack) = setItem(slot, stack) From bf7c9277eeabf9a486ec9ee6e45ff1dc8d972446 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 1 Mar 2025 12:19:06 +0700 Subject: [PATCH 020/154] Update getMaxStackSize in MatteryMenuSlot to use IEnhancedContainer --- src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt index 82ba35225..b39f12222 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt @@ -17,6 +17,7 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.UpgradeType import ru.dbotthepony.mc.otm.capability.energy import ru.dbotthepony.mc.otm.client.minecraft +import ru.dbotthepony.mc.otm.container.IEnhancedContainer import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot import ru.dbotthepony.mc.otm.container.IMatteryContainer import ru.dbotthepony.mc.otm.container.ItemFilter @@ -84,7 +85,7 @@ open class MatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int override fun getMaxStackSize(): Int { val container = container - if (container is IMatteryContainer) { + if (container is IEnhancedContainer) { return container.getMaxStackSize(slotIndex, ItemStack.EMPTY) } else { return super.getMaxStackSize() @@ -94,7 +95,7 @@ open class MatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int override fun getMaxStackSize(itemStack: ItemStack): Int { val container = container - if (container is IMatteryContainer) { + if (container is IEnhancedContainer) { return container.getMaxStackSize(slotIndex, itemStack) } else { return super.getMaxStackSize(itemStack) From 1b5476de40baa2a406e527914f2887006a87268e Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 1 Mar 2025 12:22:24 +0700 Subject: [PATCH 021/154] Mark chunk dirty when grill fuel ticks --- .../mc/otm/block/entity/decorative/GrillBlockEntity.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt index 24d5f2f96..b909c6932 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt @@ -201,6 +201,8 @@ class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBloc level!!.setBlock(blockPos, blockState.set(GrillBlock.STATE_PROPERTY, GrillBlock.State.FUELED), Block.UPDATE_ALL) } } + + markDirtyFast() } else { fuelTotalTicks = 0 From 4292713874e508f1dcf41c4ba787352e81377795 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 1 Mar 2025 13:26:34 +0700 Subject: [PATCH 022/154] Oopsie --- .../entity/decorative/GrillBlockEntity.kt | 14 ++++++------- .../mc/otm/core/util/Savetables.kt | 3 ++- .../mc/otm/data/codec/KOptionalCodec.kt | 21 ------------------- 3 files changed, 8 insertions(+), 30 deletions(-) delete mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/data/codec/KOptionalCodec.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt index b909c6932..529c4aaa6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/GrillBlockEntity.kt @@ -38,7 +38,6 @@ import ru.dbotthepony.mc.otm.core.math.component2 import ru.dbotthepony.mc.otm.core.math.component3 import ru.dbotthepony.mc.otm.core.set import ru.dbotthepony.mc.otm.core.util.countingLazy -import ru.dbotthepony.mc.otm.data.codec.KOptionalCodec import ru.dbotthepony.mc.otm.data.codec.minRange import ru.dbotthepony.mc.otm.menu.decorative.GrillMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities @@ -54,7 +53,7 @@ class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBloc private fun clearSlot() { inputProgress[slot] = 0 outputs[slot] = null - outputsRecipeNames[slot] = KOptional.empty() + outputsRecipeNames[slot] = null activeSlots.rem(slot) } @@ -79,10 +78,10 @@ class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBloc if (result == null) { clearSlot() } else { - if (outputsRecipeNames[slot].orNull() != result.id) + if (outputsRecipeNames[slot] != result.id) inputProgress[slot] = 0 - outputsRecipeNames[slot] = KOptional.of(result.id) + outputsRecipeNames[slot] = result.id outputs[slot] = result.value activeSlots.add(slot) } @@ -101,7 +100,7 @@ class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBloc return customDisplayName ?: level?.getBlockState(blockPos)?.block?.name ?: TextComponent("null at $blockPos") } - private val outputsRecipeNames = Array>(SLOTS) { KOptional.empty() } + private val outputsRecipeNames = arrayOfNulls(SLOTS) private val outputs = arrayOfNulls(SLOTS) private val activeSlots = IntArrayList() private val inputProgress = IntArray(SLOTS) @@ -138,12 +137,12 @@ class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBloc savetables.stateful(::fuelSlot) savetables.stateful(::experience) - outputsRecipeNames.fill(KOptional()) + outputsRecipeNames.fill(null) // TODO: could have been done as list (and get more space efficient storage), but we use an array, oh well for (i in inputProgress.indices) { savetables.codec(Delegate.Of({ inputProgress[i] }, { inputProgress[i] = it }), progressCodec, "inputProgress${i}") - savetables.codec(Delegate.Of({ outputsRecipeNames[i] }, { outputsRecipeNames[i] = it }), recipeNameCodec, "recipeName${i}") + savetables.codecNullable(Delegate.Of({ outputsRecipeNames[i] }, { outputsRecipeNames[i] = it }), ResourceLocation.CODEC, "recipeName${i}") } // addDroppableContainer(inputSlots) @@ -216,7 +215,6 @@ class GrillBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBloc const val SLOTS = 6 private val progressCodec = Codec.INT.minRange(0) - private val recipeNameCodec = KOptionalCodec(ResourceLocation.CODEC) val FUEL_SLOT_PROVIDER = ContainerSlot.Simple(maxStackSize = 4, filter = AutomationFilters.CHEMICAL_FUEL) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Savetables.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Savetables.kt index 238f42d84..9f2e734b6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Savetables.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Savetables.kt @@ -7,6 +7,7 @@ import net.minecraft.core.HolderLookup.Provider import net.minecraft.nbt.ByteTag import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.DoubleTag +import net.minecraft.nbt.EndTag import net.minecraft.nbt.FloatTag import net.minecraft.nbt.IntTag import net.minecraft.nbt.LongTag @@ -297,7 +298,7 @@ class Savetables : INBTSerializable { for (entry in entries) { val value = entry.serializeNBT(registry) - if (value != null) + if (value != null && value !is EndTag) nbt[entry.name] = value } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/codec/KOptionalCodec.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/codec/KOptionalCodec.kt deleted file mode 100644 index d83207062..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/data/codec/KOptionalCodec.kt +++ /dev/null @@ -1,21 +0,0 @@ -package ru.dbotthepony.mc.otm.data.codec - -import com.mojang.datafixers.util.Pair -import com.mojang.serialization.Codec -import com.mojang.serialization.DataResult -import com.mojang.serialization.DynamicOps -import ru.dbotthepony.kommons.util.KOptional - -class KOptionalCodec(val parent: Codec) : Codec> { - override fun encode(input: KOptional, ops: DynamicOps, prefix: T): DataResult { - return input.map { parent.encode(it, ops, prefix) }.orElse { DataResult.success(ops.empty()) } - } - - override fun decode(ops: DynamicOps, input: T): DataResult, T>> { - if (input == ops.empty()) { - return DataResult.success(Pair(KOptional(), ops.empty())) - } else { - return parent.decode(ops, input).map { Pair(KOptional(it.first), it.second) } - } - } -} From 3ed935001b4f56892997af2ae50060b9cda076cd Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 1 Mar 2025 19:12:05 +0700 Subject: [PATCH 023/154] Move Painter to SlottedContainer --- .../entity/decorative/PainterBlockEntity.kt | 65 ++++++++++--------- .../mc/otm/menu/decorative/PainterMenu.kt | 18 ++--- 2 files changed, 46 insertions(+), 37 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/PainterBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/PainterBlockEntity.kt index 94311cead..fafd2c8fc 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/PainterBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/PainterBlockEntity.kt @@ -20,6 +20,8 @@ import net.neoforged.neoforge.fluids.capability.IFluidHandler import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.immutableMap import ru.dbotthepony.mc.otm.core.isNotEmpty @@ -34,7 +36,39 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe return PainterMenu(containerID, inventory, this) } - val dyeInput = MatteryContainer(this::markDirtyFast, 1) + private inner class InputSlot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) { + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + if (!super.canAutomationPlaceItem(itemStack)) + return false + + if (waterStored() < MAX_WATER_STORAGE) { + itemStack.getCapability(Capabilities.FluidHandler.ITEM)?.let { + val drain = it.drain(FluidStack(Fluids.WATER, MAX_WATER_STORAGE - waterStored()), IFluidHandler.FluidAction.SIMULATE) + + if (drain.isNotEmpty) { + return true + } + } + } + + val dye = DyeColor.getColor(itemStack) ?: return false + return dyeStored(dye) + HUE_PER_ITEM <= MAX_STORAGE + } + + override fun canAutomationTakeItem(desired: Int): Boolean { + return false + } + + override fun modifyAutomationPlaceCount(itemStack: ItemStack): Int { + if (itemStack.getCapability(Capabilities.FluidHandler.ITEM) != null) + return 1 + + val dye = DyeColor.getColor(itemStack) ?: return 0 + return itemStack.count.coerceAtMost((MAX_STORAGE - dyeStored(dye)) / HUE_PER_ITEM - item.count) + } + } + + val dyeInput = SlottedContainer.simple(1, ::InputSlot, ::markDirtyFast) // null - water val dyeStored = Object2IntArrayMap() @@ -108,34 +142,7 @@ class PainterBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDe markDirtyFast() } - val config = ConfigurableItemHandler(input = dyeInput.handler(object : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - if (waterStored() < MAX_WATER_STORAGE) { - stack.getCapability(Capabilities.FluidHandler.ITEM)?.let { - val drain = it.drain(FluidStack(Fluids.WATER, MAX_WATER_STORAGE - waterStored()), IFluidHandler.FluidAction.SIMULATE) - - if (drain.isNotEmpty) { - return true - } - } - } - - val dye = DyeColor.entries.firstOrNull { stack.`is`(it.tag) } ?: return false - return dyeStored(dye) + HUE_PER_ITEM <= MAX_STORAGE - } - - override fun modifyInsertCount(slot: Int, stack: ItemStack, existing: ItemStack, simulate: Boolean): Int { - if (!ItemStack.isSameItemSameComponents(stack, existing)) - return super.modifyInsertCount(slot, stack, existing, simulate) - - val dye = DyeColor.entries.firstOrNull { stack.`is`(it.tag) } ?: return 0 - return stack.count.coerceAtMost((MAX_STORAGE - dyeStored(dye)) / HUE_PER_ITEM - existing.count) - } - - override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return false - } - })) + val config = ConfigurableItemHandler(input = dyeInput) fun waterStored(): Int { return dyeStored.getInt(null) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/PainterMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/PainterMenu.kt index 924e73fdd..0c5b269c0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/PainterMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/PainterMenu.kt @@ -17,6 +17,8 @@ import ru.dbotthepony.kommons.util.setValue import ru.dbotthepony.mc.otm.block.entity.decorative.PainterBlockEntity import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.set +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.addAll import ru.dbotthepony.mc.otm.core.collect.SupplierMap import ru.dbotthepony.mc.otm.core.collect.filter @@ -45,8 +47,8 @@ class PainterMenu( val dyeStoredDirect = SupplierMap(dyeStored) val itemConfig = ItemConfigPlayerInput(this, tile?.config) - val inputContainer = MatteryContainer(::rescan, 1) - val outputContainer = MatteryContainer(1) + val inputContainer = SlottedContainer.simple(1, ::rescan) + val outputContainer = SlottedContainer.simple(1) private var lastRecipe: RecipeHolder? = null var selectedRecipe by mSynchronizer.add(ListenableDelegate.Box(null), StreamCodecs.RESOURCE_LOCATION.nullable()).also { it.addListener(Runnable { rescan() }) } @@ -102,13 +104,13 @@ class PainterMenu( } } - val dyeSlot = object : MatteryMenuSlot(tile?.dyeInput ?: SimpleContainer(1), 0) { + val dyeSlot = object : MatteryMenuSlot(tile?.dyeInput ?: SlottedContainer.simple(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { - return super.mayPlace(itemStack) && (( - itemStack.getCapability(Capabilities.FluidHandler.ITEM)?.let { - dyeStoredDirect[null]!! < PainterBlockEntity.MAX_WATER_STORAGE && it.drain(FluidStack(Fluids.WATER, PainterBlockEntity.MAX_WATER_STORAGE - dyeStoredDirect[null]!!), IFluidHandler.FluidAction.SIMULATE).isNotEmpty - } ?: false - ) || (DyeColor.getColor(itemStack)?.let { dyeStoredDirect[it]!! + PainterBlockEntity.HUE_PER_ITEM <= PainterBlockEntity.MAX_STORAGE } ?: false)) + return super.mayPlace(itemStack) && ( + itemStack.getCapability(Capabilities.FluidHandler.ITEM) + ?.drain(FluidStack(Fluids.WATER, PainterBlockEntity.MAX_WATER_STORAGE - dyeStoredDirect[null]!!), IFluidHandler.FluidAction.SIMULATE)?.isNotEmpty + ?: false + || DyeColor.getColor(itemStack) != null) } } From 6e7b90a8e8b802ed587e42ebe55e025d164e6448 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Mon, 3 Mar 2025 15:00:30 +0700 Subject: [PATCH 024/154] Move Matter capacitor bank to slotted container --- .../matter/MatterCapacitorBankBlockEntity.kt | 36 ++++++++++--------- .../menu/matter/MatterCapacitorBankMenu.kt | 7 ++-- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt index a9df1d08f..d5193ae07 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt @@ -18,14 +18,15 @@ import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode import ru.dbotthepony.mc.otm.menu.matter.MatterCapacitorBankMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities -class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity( - MBlockEntities.MATTER_CAPACITOR_BANK, p_155229_, p_155230_), IMatterStorage { +class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.MATTER_CAPACITOR_BANK, p_155229_, p_155230_), IMatterStorage { var gaugeLevel by syncher.float() private set @@ -125,31 +126,34 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) override val matterFlow: FlowDirection get() = FlowDirection.BI_DIRECTIONAL - val container = object : MatteryContainer(::markDirtyFast, BatteryBankBlockEntity.CAPACITY) { - override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { - super.setChanged(slot, new, old) - capacitorStatus[slot].value = new.getCapability(MatteryCapability.MATTER_ITEM) != null + private inner class Slot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) { + override fun notifyChanged(old: ItemStack) { + super.notifyChanged(old) + + capacitorStatus[slot].value = item.getCapability(MatteryCapability.MATTER_ITEM) != null gaugeLevel = storedMatter.percentage(maxStoredMatter) } - override fun getMaxStackSize(): Int = 1 - }.also(::addDroppableContainer) - - val itemConfig = ConfigurableItemHandler(inputOutput = container.handler(object : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return stack.getCapability(MatteryCapability.MATTER_ITEM) != null + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + return super.canAutomationPlaceItem(itemStack) && itemStack.getCapability(MatteryCapability.MATTER_ITEM) != null } - override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - stack.getCapability(MatteryCapability.MATTER_ITEM)?.let { + override fun canAutomationTakeItem(desired: Int): Boolean { + item.getCapability(MatteryCapability.MATTER_ITEM)?.let { if (it.storedMatter.isPositive) { return false } } - return true + return super.canAutomationTakeItem(desired) } - })) + + override val maxStackSize: Int + get() = 1 + } + + val container = SlottedContainer.simple(BatteryBankBlockEntity.CAPACITY, ::Slot, ::markDirtyFast).also(::addDroppableContainer) + val itemConfig = ConfigurableItemHandler(inputOutput = container) val capacitorStatus = immutableList(BatteryBankBlockEntity.CAPACITY) { syncher.boolean(false) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterCapacitorBankMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterCapacitorBankMenu.kt index 424e32bda..e820a9f62 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterCapacitorBankMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterCapacitorBankMenu.kt @@ -1,9 +1,10 @@ package ru.dbotthepony.mc.otm.menu.matter -import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.block.entity.matter.MatterCapacitorBankBlockEntity +import ru.dbotthepony.mc.otm.block.entity.tech.BatteryBankBlockEntity +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.MatterContainerInputMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput @@ -31,9 +32,9 @@ class MatterCapacitorBankMenu @JvmOverloads constructor( }) } - val container = tile?.container ?: SimpleContainer(2 * 6) + val container = tile?.container ?: SlottedContainer.simple(BatteryBankBlockEntity.CAPACITY) - storageSlots = immutableList(2 * 6) { + storageSlots = immutableList(BatteryBankBlockEntity.CAPACITY) { addStorageSlot(MatterContainerInputMenuSlot(container, it)) } From a5b96fa4c4925af43bc2ecffc920018d589dcda6 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Mon, 3 Mar 2025 18:33:24 +0700 Subject: [PATCH 025/154] Update bottler to use slotted container --- .../entity/matter/MatterBottlerBlockEntity.kt | 68 +++++++++---------- .../mc/otm/capability/FlowDirection.kt | 2 +- 2 files changed, 32 insertions(+), 38 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt index 17aae98fe..0a39c82f0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt @@ -24,9 +24,12 @@ import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.UpgradeContainer +import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.matter.MatterBottlerMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import ru.dbotthepony.mc.otm.core.math.Decimal +import ru.dbotthepony.mc.otm.core.util.countingLazy import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode import java.util.function.BooleanSupplier @@ -37,23 +40,20 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) : override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::markDirtyFast, upgrades.transform(MachinesConfig.MatterBottler.VALUES))) val energyConfig = ConfigurableEnergy(energy) - private inner class Container : MatteryContainer(3) { - init { - addDroppableContainer(this) - } - - override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int { - return 1 - } - - override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { - markDirtyFast() - updateBlockState() + private inner class BottlingSlot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) { + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + return super.canAutomationPlaceItem(itemStack) && isBottling && itemStack.getCapability(MatteryCapability.MATTER_ITEM)?.receiveMatterChecked(Decimal.ONE, true)?.isPositive == true } } - val unbottling: MatteryContainer = Container() - val bottling: MatteryContainer = Container() + private inner class UnBottlingSlot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) { + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + return super.canAutomationPlaceItem(itemStack) && !isBottling && itemStack.getCapability(MatteryCapability.MATTER_ITEM)?.extractMatterChecked(Decimal.ONE, true)?.isPositive == true + } + } + + val unbottling = SlottedContainer.simple(3, ::UnBottlingSlot, ::updateBlockState) + val bottling = SlottedContainer.simple(3, ::BottlingSlot, ::updateBlockState) var isBottling: Boolean = true set(value) { @@ -63,11 +63,11 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) : this.markDirtyFast() if (value) { - inputHandler.parent = bottlingHandler - outputHandler.parent = unbottlingHandler + inputHandler.parent = bottling + outputHandler.parent = unbottling } else { - inputHandler.parent = unbottlingHandler - outputHandler.parent = bottlingHandler + inputHandler.parent = unbottling + outputHandler.parent = bottling } updateBlockState() @@ -79,20 +79,8 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) : this.markDirtyFast() } - val bottlingHandler = bottling.handler(object : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return isBottling && stack.getCapability(MatteryCapability.MATTER_ITEM)?.let { it.matterFlow.input && it.missingMatter.isPositive } ?: false - } - }) - - val unbottlingHandler = unbottling.handler(object : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return !isBottling && stack.getCapability(MatteryCapability.MATTER_ITEM)?.let { it.matterFlow.output && it.storedMatter.isPositive } ?: false - } - }) - - private val inputHandler = ProxiedItemHandler(bottlingHandler) - private val outputHandler = ProxiedItemHandler(unbottlingHandler) + private val inputHandler = ProxiedItemHandler(bottling) + private val outputHandler = ProxiedItemHandler(unbottling) val itemConfig = ConfigurableItemHandler( input = inputHandler, @@ -141,12 +129,12 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) : matterNode.isValid = false } - private fun updateBlockState(container: MatteryContainer) { + private fun updateBlockState(container: SlottedContainer) { val level = level as? ServerLevel ?: return var state = blockState - for (i in 0 .. 2) { - val desired = !container.getItem(i).isEmpty && container.getItem(i).getCapability(MatteryCapability.MATTER_ITEM) != null + for ((i, slot) in container.slotIterator().withIndex()) { + val desired = !slot.isEmpty && slot.item.getCapability(MatteryCapability.MATTER_ITEM) != null if (state.getValue(MatterBottlerBlock.SLOT_PROPERTIES[i]) != desired) { state = state.setValue(MatterBottlerBlock.SLOT_PROPERTIES[i], desired) @@ -159,20 +147,25 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) : } private fun updateBlockState() { + markDirtyFast() if (isBottling) updateBlockState(bottling) else updateBlockState(unbottling) } + private val workerState by countingLazy(blockStateChangesCounter) { + blockState.getValue(WorkerState.SEMI_WORKER_STATE) + } + private fun blockstateToWorking() { - if (blockState.getValue(WorkerState.SEMI_WORKER_STATE) !== WorkerState.WORKING) { + if (workerState !== WorkerState.WORKING) { level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING), Block.UPDATE_CLIENTS) } } private fun blockstateToIdle() { - if (blockState.getValue(WorkerState.SEMI_WORKER_STATE) !== WorkerState.IDLE) { + if (workerState !== WorkerState.IDLE) { level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS) } } @@ -191,6 +184,7 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) : for (slot in bottling.slotIterator()) { val item = slot.item + item.getCapability(MatteryCapability.MATTER_ITEM)?.let { if (!it.missingMatter.isPositive) { unbottling.consumeItem(item, false) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/FlowDirection.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/FlowDirection.kt index d00b2fb32..38e798d47 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/FlowDirection.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/FlowDirection.kt @@ -136,7 +136,7 @@ enum class FlowDirection(val input: Boolean, val output: Boolean, val translatio */ @JvmStatic fun input(flag: Boolean): FlowDirection { - return of(flag, !flag) + return if (flag) INPUT else OUTPUT } /** From 70bfa114c87c892288bfb9357ea2b3f46ab1026f Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Mon, 3 Mar 2025 19:47:45 +0700 Subject: [PATCH 026/154] Use IEnhancedContainer in setChanged --- src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt index b39f12222..431d04c73 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt @@ -63,8 +63,8 @@ open class MatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int } override fun setChanged() { - if (container is IMatteryContainer) { - (container as IMatteryContainer).setChanged(containerSlot) + if (container is IEnhancedContainer) { + (container as IEnhancedContainer).setChanged(containerSlot) } else { super.setChanged() } From d76f2fe015ea87b4e72bc8f55be917357bf2327a Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Mon, 3 Mar 2025 19:54:22 +0700 Subject: [PATCH 027/154] lol --- .../dbotthepony/mc/otm/container/slotted/AutomationFilters.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt index aa7602ba5..46dd44472 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt @@ -68,7 +68,7 @@ enum class AutomationFilters : AutomationFilter { } }, - DICHARGEABLE { + DISCHARGABLE { override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { return itemStack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { it.canExtract() && it.extractEnergy(Int.MAX_VALUE, true) > 0 } ?: false } From 7f9af78734f0e81840a6f57b108eee5044d11138 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Mon, 3 Mar 2025 19:55:52 +0700 Subject: [PATCH 028/154] Update MatteryPoweredBlockEntity battery container to use SlottedContainer --- .../mc/otm/block/entity/MatteryPoweredBlockEntity.kt | 6 +++--- .../mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt | 2 +- .../block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt | 2 +- .../kotlin/ru/dbotthepony/mc/otm/menu/MatteryPoweredMenu.kt | 3 ++- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryPoweredBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryPoweredBlockEntity.kt index 40f1bd7b9..7455987c3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryPoweredBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryPoweredBlockEntity.kt @@ -7,12 +7,12 @@ import ru.dbotthepony.mc.otm.capability.energy import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage import ru.dbotthepony.mc.otm.capability.extractEnergy import ru.dbotthepony.mc.otm.container.HandlerFilter -import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.Decimal abstract class MatteryPoweredBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(p_155228_, p_155229_, p_155230_) { - val batteryContainer = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer) - val batteryItemHandler = batteryContainer.handler(HandlerFilter.Dischargeable) + val batteryContainer = SlottedContainer.simple(1, AutomationFilters.DISCHARGABLE.simpleProvider, ::markDirtyFast).also(::addDroppableContainer) open val energy: IMatteryEnergyStorage? get() = null diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt index 0a39c82f0..c93febf88 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt @@ -85,7 +85,7 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) : val itemConfig = ConfigurableItemHandler( input = inputHandler, output = outputHandler, - battery = batteryItemHandler + battery = batteryContainer ) val matter: ProfiledMatterStorage = ProfiledMatterStorage(object : MatterStorageImpl(this@MatterBottlerBlockEntity::markDirtyFast, FlowDirection.BI_DIRECTIONAL, upgrades.matterCapacity(MachinesConfig.MatterBottler.VALUES::matterCapacity)) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt index 4ca9c7317..6defd22b6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt @@ -78,7 +78,7 @@ sealed class AbstractPoweredFurnaceBlockEntity

(this) init { From d558252db977a672e9e315ccbc4dead087086859 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Mon, 3 Mar 2025 20:14:20 +0700 Subject: [PATCH 029/154] Update Matter Decomposer to use SlottedContainer --- .../matter/MatterDecomposerBlockEntity.kt | 31 +++++++++++-------- .../mc/otm/item/matter/MatterDustItem.kt | 5 +-- .../otm/menu/matter/MatterDecomposerMenu.kt | 9 +++--- 3 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt index 8ed8a703e..8a7836f9e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt @@ -23,6 +23,10 @@ import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters +import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.data.codec.DecimalCodec @@ -72,22 +76,23 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState) savetables.stateful(::matter, MATTER_STORAGE_KEY) } + private inner class InputSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) { + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + return super.canAutomationPlaceItem(itemStack) && MatterManager.canDecompose(itemStack) + } + + override fun canAutomationTakeItem(desired: Int): Boolean { + return false + } + } + // вход, выход - val inputContainer = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer) - val outputContainer = MatteryContainer(::markDirtyFast, 2).also(::addDroppableContainer) + val inputContainer = SlottedContainer.simple(1, ::InputSlot, ::markDirtyFast).also(::addDroppableContainer) + val outputContainer = SlottedContainer.simple(2, AutomationFilters.ONLY_OUT.simpleProvider, ::markDirtyFast).also(::addDroppableContainer) val itemConfig = ConfigurableItemHandler( - input = inputContainer.handler(object : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return MatterManager.canDecompose(stack) - } - - override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return false - } - }), - - output = outputContainer.handler(HandlerFilter.OnlyOut) + input = inputContainer, + output = outputContainer ) init { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/matter/MatterDustItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/matter/MatterDustItem.kt index db22662eb..717524447 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/matter/MatterDustItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/matter/MatterDustItem.kt @@ -17,7 +17,8 @@ import net.minecraft.world.level.storage.loot.LootContext import net.minecraft.world.level.storage.loot.functions.LootItemFunction import net.minecraft.world.level.storage.loot.functions.LootItemFunctionType import ru.dbotthepony.mc.otm.config.ItemsConfig -import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.IEnhancedContainer +import ru.dbotthepony.mc.otm.container.set import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.matter.IMatterItem @@ -65,7 +66,7 @@ class MatterDustItem : Item(Properties().stacksTo(64)), IMatterItem { return MatterValue(value, 1.0) } - fun moveIntoContainer(matterValue: Decimal, container: MatteryContainer, mainSlot: Int, stackingSlot: Int): Decimal { + fun moveIntoContainer(matterValue: Decimal, container: IEnhancedContainer, mainSlot: Int, stackingSlot: Int): Decimal { @Suppress("name_shadowing") var matterValue = matterValue diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterDecomposerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterDecomposerMenu.kt index ac81f806b..919bfc6e9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterDecomposerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterDecomposerMenu.kt @@ -1,12 +1,11 @@ package ru.dbotthepony.mc.otm.menu.matter -import kotlin.jvm.JvmOverloads import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.block.entity.matter.MatterDecomposerBlockEntity import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget -import net.minecraft.world.SimpleContainer import net.minecraft.world.item.ItemStack +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.matter.MatterManager import ru.dbotthepony.mc.otm.menu.OutputMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu @@ -17,12 +16,12 @@ import ru.dbotthepony.mc.otm.menu.makeUpgradeSlots import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.registry.game.MMenus -class MatterDecomposerMenu @JvmOverloads constructor( +class MatterDecomposerMenu( containerID: Int, inventory: Inventory, tile: MatterDecomposerBlockEntity? = null ) : MatteryPoweredMenu(MMenus.MATTER_DECOMPOSER, containerID, inventory, tile) { - val input = object : MatteryMenuSlot(tile?.inputContainer ?: SimpleContainer(1), 0) { + val input = object : MatteryMenuSlot(tile?.inputContainer ?: SlottedContainer.filtered(1), 0) { override fun mayPlace(itemStack: ItemStack) = MatterManager.canDecompose(itemStack) } @@ -36,7 +35,7 @@ class MatterDecomposerMenu @JvmOverloads constructor( val upgrades = makeUpgradeSlots(4, tile?.upgrades) init { - val container = tile?.outputContainer ?: SimpleContainer(2) + val container = tile?.outputContainer ?: SlottedContainer.simple(2) // Выход outputMain = OutputMenuSlot(container, 0) From 8696d268adb21cda7ab39b0f739c7b0d8068474e Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 5 Mar 2025 13:03:42 +0700 Subject: [PATCH 030/154] Make IEnhancedContainer implement StackedContentsCompatible --- .../ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt index 1aae7b23f..1a4cb4267 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt @@ -4,6 +4,8 @@ import it.unimi.dsi.fastutil.ints.IntCollection import it.unimi.dsi.fastutil.ints.IntSet import net.minecraft.world.Container import net.minecraft.world.entity.player.Player +import net.minecraft.world.entity.player.StackedContents +import net.minecraft.world.inventory.StackedContentsCompatible import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Items @@ -20,7 +22,7 @@ import java.util.function.Predicate * This is useful because it allows to interact with actually enhanced and regular containers through unified interface, * and actual implementations of this interface are likely to provide efficient method implementations in place of derived/emulated ones. */ -interface IEnhancedContainer : IContainer, RecipeInput, Iterable { +interface IEnhancedContainer : IContainer, RecipeInput, Iterable, StackedContentsCompatible { // provide non-ambiguous "get" operator operator fun get(slot: Int): ItemStack { return getItem(slot) @@ -30,6 +32,10 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable { return IContainerSlot.Simple(slot, this) } + override fun fillStackedContents(contents: StackedContents) { + forEach { contents.accountStack(it) } + } + /** * Returns iterator over **all** slots this container has */ From 5942ab2126e9cd6becfdc8f18e6683e6f0ceedbd Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 5 Mar 2025 13:03:49 +0700 Subject: [PATCH 031/154] Implement IEnhancedCraftingContainer --- .../container/IEnhancedCraftingContainer.kt | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedCraftingContainer.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedCraftingContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedCraftingContainer.kt new file mode 100644 index 000000000..61dc89142 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedCraftingContainer.kt @@ -0,0 +1,33 @@ +package ru.dbotthepony.mc.otm.container + +import net.minecraft.world.entity.player.StackedContents +import net.minecraft.world.inventory.CraftingContainer +import net.minecraft.world.item.ItemStack + +interface IEnhancedCraftingContainer : IEnhancedContainer, CraftingContainer { + override fun getItems(): MutableList { + return toList() + } + + override fun fillStackedContents(contents: StackedContents) { + forEach { contents.accountSimpleStack(it) } + } + + class Wrapper(val parent: C, private val width: Int, private val height: Int) : IEnhancedCraftingContainer, IEnhancedContainer by parent { + init { + require(width * height == parent.containerSize) { "Crafting container dimensions ($width x $height) do not match container size provided (${parent.containerSize})" } + } + + override fun getWidth(): Int { + return width + } + + override fun getHeight(): Int { + return height + } + + override fun fillStackedContents(contents: StackedContents) { + super.fillStackedContents(contents) + } + } +} From 3910e38addcad4682dc6683ee539502bba981b57 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 5 Mar 2025 13:17:57 +0700 Subject: [PATCH 032/154] Move Matter Entangler to Slotted container --- .../matter/MatterEntanglerBlockEntity.kt | 66 +++++++++---------- .../container/slotted/AutomationFilters.kt | 20 +++++- .../mc/otm/menu/matter/MatterEntanglerMenu.kt | 33 +++------- 3 files changed, 61 insertions(+), 58 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt index a09006236..e66525d66 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt @@ -24,9 +24,10 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage import ru.dbotthepony.mc.otm.config.MachinesConfig -import ru.dbotthepony.mc.otm.container.MatteryCraftingContainer -import ru.dbotthepony.mc.otm.container.HandlerFilter -import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.IEnhancedCraftingContainer +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters +import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.data.codec.DecimalCodec import ru.dbotthepony.mc.otm.data.codec.minRange @@ -35,8 +36,7 @@ import ru.dbotthepony.mc.otm.menu.matter.MatterEntanglerMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import ru.dbotthepony.mc.otm.registry.game.MRecipes -class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryWorkerBlockEntity( - MBlockEntities.MATTER_ENTANGLER, blockPos, blockState, Job.CODEC) { +class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryWorkerBlockEntity(MBlockEntities.MATTER_ENTANGLER, blockPos, blockState, Job.CODEC) { class Job(itemStack: ItemStack, val matter: Decimal, ticks: Double, experience: Float) : ItemJob(itemStack, ticks, MachinesConfig.MATTER_ENTANGLER.energyConsumption, experience = experience) { val matterPerTick = matter / ticks @@ -60,36 +60,36 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M val experience = ExperienceStorage(MachinesConfig.MATTER_ENTANGLER::maxExperienceStored).also(::addNeighbourListener) val energyConfig = ConfigurableEnergy(energy) - val inputs = object : MatteryCraftingContainer(::itemContainerUpdated, 3, 3) { - override fun getMaxStackSize(): Int { - return 1 + private inner class InputSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) { + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + if (!super.canAutomationPlaceItem(itemStack)) + return false + + val level = level ?: return false + val list = container.toList() + list[slot] = itemStack + val shadow = CraftingInput.ofPositioned(3, 3, list) + + return level + .recipeManager + .byType(MRecipes.MATTER_ENTANGLER) + .any { it.value.preemptivelyMatches(shadow, level, 3, 3) } } + + override fun canAutomationTakeItem(desired: Int): Boolean { + return false + } + + override val maxStackSize: Int + get() = 1 } - val output = object : MatteryContainer(::itemContainerUpdated, 1) { - override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int { - return Int.MAX_VALUE - } - } + val inputs = IEnhancedCraftingContainer.Wrapper(SlottedContainer.simple(3 * 3, ::InputSlot, ::setChanged), 3, 3) + val output = SlottedContainer.simple(1, AutomationFilters.ONLY_OUT.unlimitedSimpleProvider, ::markDirtyFast) val itemConfig = ConfigurableItemHandler( - input = inputs.handler(object : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - val list = inputs.toList() - list[slot] = stack - val shadow = CraftingInput.ofPositioned(3, 3, list) - - return (level ?: return false) - .recipeManager - .byType(MRecipes.MATTER_ENTANGLER) - .any { it.value.preemptivelyMatches(shadow, level!!, 3, 3) } - } - - override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return false - } - }), - output = output.handler(HandlerFilter.OnlyOut) + input = inputs.parent, + output = output ) init { @@ -98,7 +98,7 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M savetables.stateful(::energy, ENERGY_KEY) savetables.stateful(::matter, MATTER_STORAGE_KEY) savetables.stateful(::upgrades) - savetables.stateful(::inputs) + savetables.stateful(inputs::parent, "inputs") savetables.stateful(::output) savetables.stateful(::experience) @@ -124,7 +124,7 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M val required = status.job.matterPerTick * status.ticksAdvanced if (matter.storedMatter < required) { - matter.receiveMatter(node.graph.extractMatter(status.job.matterPerTick.coerceAtLeast(Decimal.TEN).coerceAtMost(matter.missingMatter), false), false) + matter.receiveMatter(node.graph.extractMatter(status.job.matterPerTick.coerceIn(Decimal.TEN, matter.missingMatter), false), false) } status.scale(matter.extractMatter(required, false) / required) @@ -150,7 +150,7 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M if (!energy.batteryLevel.isPositive) return JobContainer.noEnergy() - val inputs = CraftingInput.of(3, 3, inputs.toList()) + val inputs = this.inputs.asCraftInput() val recipe = (level ?: return JobContainer.failure()) .recipeManager diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt index 46dd44472..702cd4a54 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt @@ -136,11 +136,27 @@ enum class AutomationFilters : AutomationFilter { } }; - val simpleProvider: SlottedContainer.SlotProvider by lazy { + val simpleProvider: SlottedContainer.SlotProvider by lazy(LazyThreadSafetyMode.PUBLICATION) { ContainerSlot.Simple(filter = this) } - val filteredProvider: SlottedContainer.SlotProvider by lazy { + val filteredProvider: SlottedContainer.SlotProvider by lazy(LazyThreadSafetyMode.PUBLICATION) { FilteredContainerSlot.Simple(filter = this) } + + val unlimitedSimpleProvider: SlottedContainer.SlotProvider by lazy(LazyThreadSafetyMode.PUBLICATION) { + ContainerSlot.Simple(filter = this, maxStackSize = Int.MAX_VALUE) + } + + val unlimitedFilteredProvider: SlottedContainer.SlotProvider by lazy(LazyThreadSafetyMode.PUBLICATION) { + FilteredContainerSlot.Simple(filter = this, maxStackSize = Int.MAX_VALUE) + } + + val limitedSimpleProvider: SlottedContainer.SlotProvider by lazy(LazyThreadSafetyMode.PUBLICATION) { + ContainerSlot.Simple(filter = this, maxStackSize = 1) + } + + val limitedFilteredProvider: SlottedContainer.SlotProvider by lazy(LazyThreadSafetyMode.PUBLICATION) { + FilteredContainerSlot.Simple(filter = this, maxStackSize = 1) + } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterEntanglerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterEntanglerMenu.kt index 9ecd5d33d..62eaf1120 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterEntanglerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterEntanglerMenu.kt @@ -1,22 +1,19 @@ package ru.dbotthepony.mc.otm.menu.matter import net.minecraft.server.level.ServerPlayer -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 net.minecraft.world.item.ItemStack import net.minecraft.world.item.crafting.CraftingInput import ru.dbotthepony.mc.otm.block.entity.matter.MatterEntanglerBlockEntity -import ru.dbotthepony.mc.otm.container.MatteryContainer -import ru.dbotthepony.mc.otm.container.MatteryCraftingContainer -import ru.dbotthepony.mc.otm.container.get import ru.dbotthepony.mc.otm.container.set +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.item.IQuantumLinked -import ru.dbotthepony.mc.otm.menu.OutputMenuSlot -import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu +import ru.dbotthepony.mc.otm.menu.OutputMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.makeSlots @@ -39,11 +36,7 @@ class MatterEntanglerMenu( val progress = ProgressGaugeWidget(this, tile?.jobEventLoops?.get(0)) - val inputs: List = makeSlots(tile?.inputs ?: object : MatteryCraftingContainer(3, 3) { - override fun getMaxStackSize(): Int { - return 1 - } - }) { it, i -> + val inputs: List = makeSlots(tile?.inputs ?: SlottedContainer.simple(3 * 3, AutomationFilters.ALLOW.limitedFilteredProvider)) { it, i -> object : MatteryMenuSlot(it, i) { override fun mayPlace(itemStack: ItemStack): Boolean { val list = it.toList() @@ -59,21 +52,15 @@ class MatterEntanglerMenu( } } - val outputs = makeSlots(tile?.output ?: SimpleContainer(1)) { a, b -> OutputMenuSlot(a, b) { tile?.experience?.popExperience(player as ServerPlayer) } } + val outputs = makeSlots(tile?.output ?: SlottedContainer.simple(1, AutomationFilters.ONLY_OUT.unlimitedSimpleProvider)) { a, b -> OutputMenuSlot(a, b) { tile?.experience?.popExperience(player as ServerPlayer) } } val upgrades = makeUpgradeSlots(3, tile?.upgrades) val experience = TakeExperienceWidget(this, tile?.experience) - private val entangling: Container = if (tile == null) object : SimpleContainer(2) { - override fun getMaxStackSize(): Int { - return 1 - } - } else object : MatteryContainer(::rescan, 2) { - override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int { - return 1 - } - } + private val entangling = SlottedContainer.simple(2, AutomationFilters.ALLOW.limitedSimpleProvider) private fun rescan() { + if (tile == null) return + if (player is ServerPlayer && entangling[0].item is IQuantumLinked && entangling[1].item == entangling[0].item && entangling[0].isNotEmpty && entangling[1].isNotEmpty) { val result = (entangling[0].item as IQuantumLinked).merge(entangling[0], entangling[1]) entanglingC.container[0] = result @@ -90,7 +77,7 @@ class MatterEntanglerMenu( val entanglingA: MatteryMenuSlot = EntanglingInputMenuSlot(0) val entanglingB: MatteryMenuSlot = EntanglingInputMenuSlot(1) - val entanglingC: MatteryMenuSlot = object : MatteryMenuSlot(MatteryContainer(1), 0) { + val entanglingC: MatteryMenuSlot = object : MatteryMenuSlot(SlottedContainer.simple(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return false } From 83d11d531db950327d8ab846f111ed124412e053 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 5 Mar 2025 15:23:27 +0700 Subject: [PATCH 033/154] Cache recipes in Matter Entangler --- .../matter/MatterEntanglerBlockEntity.kt | 63 ++++++++++++++++--- .../mc/otm/core/util/ItemStackKey.kt | 35 +++++++++++ 2 files changed, 90 insertions(+), 8 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/core/util/ItemStackKey.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt index e66525d66..82def3e57 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt @@ -1,13 +1,18 @@ package ru.dbotthepony.mc.otm.block.entity.matter +import com.github.benmanes.caffeine.cache.Cache +import com.github.benmanes.caffeine.cache.Caffeine +import com.github.benmanes.caffeine.cache.Scheduler import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder +import net.minecraft.Util import net.minecraft.core.BlockPos import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.item.ItemStack import net.minecraft.world.item.crafting.CraftingInput +import net.minecraft.world.item.crafting.RecipeManager import net.minecraft.world.level.Level import net.minecraft.world.level.block.state.BlockState import net.neoforged.neoforge.capabilities.Capabilities @@ -28,13 +33,21 @@ import ru.dbotthepony.mc.otm.container.IEnhancedCraftingContainer import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer +import ru.dbotthepony.mc.otm.core.collect.filter +import ru.dbotthepony.mc.otm.core.collect.forEach +import ru.dbotthepony.mc.otm.core.collect.map +import ru.dbotthepony.mc.otm.core.collect.toList import ru.dbotthepony.mc.otm.core.math.Decimal +import ru.dbotthepony.mc.otm.core.util.ItemStackKey +import ru.dbotthepony.mc.otm.core.util.asKey import ru.dbotthepony.mc.otm.data.codec.DecimalCodec import ru.dbotthepony.mc.otm.data.codec.minRange import ru.dbotthepony.mc.otm.graph.matter.MatterNode import ru.dbotthepony.mc.otm.menu.matter.MatterEntanglerMenu +import ru.dbotthepony.mc.otm.recipe.IMatterEntanglerRecipe import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import ru.dbotthepony.mc.otm.registry.game.MRecipes +import java.time.Duration class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryWorkerBlockEntity(MBlockEntities.MATTER_ENTANGLER, blockPos, blockState, Job.CODEC) { class Job(itemStack: ItemStack, val matter: Decimal, ticks: Double, experience: Float) : ItemJob(itemStack, ticks, MachinesConfig.MATTER_ENTANGLER.energyConsumption, experience = experience) { @@ -60,20 +73,47 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M val experience = ExperienceStorage(MachinesConfig.MATTER_ENTANGLER::maxExperienceStored).also(::addNeighbourListener) val energyConfig = ConfigurableEnergy(energy) + private var recipeCache: Collection = listOf() + private var seenRecipeManager: RecipeManager? = null + + private fun getRecipes(): Collection { + val level = level!! + val manager = level.recipeManager + + if (seenRecipeManager !== manager) { + seenRecipeManager = manager + val input = inputs.asPositionedCraftInput() + + recipeCache = manager.byType(MRecipes.MATTER_ENTANGLER) + .iterator() + .map { it.value } + .filter { it.preemptivelyMatches(input, level, 3, 3) } + .toList() + } + + return recipeCache + } + private inner class InputSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) { + val insertCache: Cache = Caffeine.newBuilder() + .maximumSize(1024L) + .expireAfterWrite(Duration.ofMinutes(1L)) + .scheduler(Scheduler.systemScheduler()) + .executor(Util.backgroundExecutor()) + .build() + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { if (!super.canAutomationPlaceItem(itemStack)) return false val level = level ?: return false - val list = container.toList() - list[slot] = itemStack - val shadow = CraftingInput.ofPositioned(3, 3, list) - return level - .recipeManager - .byType(MRecipes.MATTER_ENTANGLER) - .any { it.value.preemptivelyMatches(shadow, level, 3, 3) } + return insertCache.get(itemStack.asKey()) { + val list = container.toList() + list[slot] = itemStack + val shadow = CraftingInput.ofPositioned(3, 3, list) + getRecipes().any { it.preemptivelyMatches(shadow, level, 3, 3) } + } } override fun canAutomationTakeItem(desired: Int): Boolean { @@ -84,7 +124,14 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M get() = 1 } - val inputs = IEnhancedCraftingContainer.Wrapper(SlottedContainer.simple(3 * 3, ::InputSlot, ::setChanged), 3, 3) + private fun inputsChanged() { + inputs.slotIterator().forEach { (it as InputSlot).insertCache.invalidateAll() } + seenRecipeManager = null + recipeCache = listOf() + setChanged() + } + + val inputs = IEnhancedCraftingContainer.Wrapper(SlottedContainer.simple(3 * 3, ::InputSlot, ::inputsChanged), 3, 3) val output = SlottedContainer.simple(1, AutomationFilters.ONLY_OUT.unlimitedSimpleProvider, ::markDirtyFast) val itemConfig = ConfigurableItemHandler( diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/ItemStackKey.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/ItemStackKey.kt new file mode 100644 index 000000000..875a6502c --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/ItemStackKey.kt @@ -0,0 +1,35 @@ +package ru.dbotthepony.mc.otm.core.util + +import it.unimi.dsi.fastutil.HashCommon +import net.minecraft.core.component.DataComponentMap +import net.minecraft.world.item.Item +import net.minecraft.world.item.ItemStack + +class ItemStackKey(val item: Item, val components: DataComponentMap) { + // make copy of original itemstack because there is no copy() method on DataComponentMap, which is returned by ItemStack#getComponents + constructor(itemStack: ItemStack) : this(itemStack.item, itemStack.copy().components) + + private var hashComputed = false + private var hash = 0 + + override fun equals(other: Any?): Boolean { + return this === other || other is ItemStackKey && other.item === item && other.components == components + } + + override fun hashCode(): Int { + if (!hashComputed) { + hash = HashCommon.murmurHash3(item.hashCode().toLong().shl(32) or components.hashCode().toLong()).toInt() + hashComputed = true + } + + return hash + } + + override fun toString(): String { + return "ItemStackKey[$item, $components]" + } +} + +fun ItemStack.asKey(): ItemStackKey { + return ItemStackKey(this) +} From 861b94a30a84f08af7d6778e6f6b53bb658e0c47 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 5 Mar 2025 15:30:13 +0700 Subject: [PATCH 034/154] Update Upgrade Container to use SlottedContainer --- .../entity/matter/MatterBottlerBlockEntity.kt | 2 +- .../matter/MatterDecomposerBlockEntity.kt | 2 +- .../matter/MatterEntanglerBlockEntity.kt | 2 +- .../matter/MatterReconstructorBlockEntity.kt | 5 ++--- .../matter/MatterRecyclerBlockEntity.kt | 2 +- .../matter/MatterReplicatorBlockEntity.kt | 2 +- .../entity/matter/MatterScannerBlockEntity.kt | 2 +- .../tech/AbstractPoweredFurnaceBlockEntity.kt | 2 +- .../entity/tech/PlatePressBlockEntity.kt | 2 +- .../mc/otm/container/UpgradeContainer.kt | 19 +++++++++++-------- .../ru/dbotthepony/mc/otm/menu/Slots.kt | 5 +++-- 11 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt index e9fe053a1..3bf343fd6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt @@ -106,7 +106,7 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) : savetables.stateful(::matter, MATTER_STORAGE_KEY) savetables.stateful(::bottling) savetables.stateful(::unbottling) - savetables.stateful(::upgrades) + savetables.stateful(upgrades::container, "upgrades") } var workProgress: Float = 0f diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt index 8a7836f9e..bb70e2ca1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt @@ -64,7 +64,7 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState) init { savetables.stateful(::energy, ENERGY_KEY) - savetables.stateful(::upgrades) + savetables.stateful(upgrades::container, "upgrades") } val matter = ProfiledMatterStorage(MatterStorageImpl(::markDirtyFast, FlowDirection.OUTPUT, upgrades.matterCapacity(MachinesConfig.MATTER_DECOMPOSER::matterCapacity))) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt index 82def3e57..9d4e37098 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt @@ -144,7 +144,7 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M savetables.stateful(::energy, ENERGY_KEY) savetables.stateful(::matter, MATTER_STORAGE_KEY) - savetables.stateful(::upgrades) + savetables.stateful(upgrades::container, "upgrades") savetables.stateful(inputs::parent, "inputs") savetables.stateful(::output) savetables.stateful(::experience) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReconstructorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReconstructorBlockEntity.kt index 2ce185aca..9a9a9bc87 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReconstructorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReconstructorBlockEntity.kt @@ -37,8 +37,7 @@ import ru.dbotthepony.mc.otm.menu.matter.MatterReconstructorMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import java.util.function.BooleanSupplier -class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity( - MBlockEntities.MATTER_RECONSTRUCTOR, blockPos, blockState) { +class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.MATTER_RECONSTRUCTOR, blockPos, blockState) { val repairContainer = MatteryContainer(::containerChanged, 1).also(::addDroppableContainer) private var matterPerTick = Decimal.ZERO @@ -86,7 +85,7 @@ class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState) savetables.stateful(::repairContainer) savetables.stateful(::matter) savetables.stateful(::energy) - savetables.stateful(::upgrades) + savetables.stateful(upgrades::container, "upgrades") savetables.decimal(::matterPerTick) savetables.double(::progressPerTick) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt index d8fe21afe..6f6616193 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt @@ -72,7 +72,7 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) savetables.stateful(::energy, ENERGY_KEY) savetables.stateful(::container, INVENTORY_KEY) savetables.stateful(::matter, MATTER_STORAGE_KEY) - savetables.stateful(::upgrades) + savetables.stateful(upgrades::container, "upgrades") } override fun setRemoved() { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt index ac9f9c181..e97ae3b62 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt @@ -103,7 +103,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : savetables.stateful(::matter, MATTER_STORAGE_KEY) savetables.stateful(::outputContainer, INVENTORY_KEY) savetables.stateful(::dustContainer) - savetables.stateful(::upgrades) + savetables.stateful(upgrades::container, "upgrades") } override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt index d57799340..15609ed92 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt @@ -68,7 +68,7 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : savetables.stateful(::container, INVENTORY_KEY) savetables.stateful(::energy, ENERGY_KEY) - savetables.stateful(::upgrades) + savetables.stateful(upgrades::container, "upgrades") } override fun setRemoved() { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt index 6defd22b6..beecf43c4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt @@ -84,7 +84,7 @@ sealed class AbstractPoweredFurnaceBlockEntity

= UpgradeType.ALL, val shouldLockUpgradeSlots: BooleanSupplier = BooleanSupplier { false }, listener: Runnable = Runnable {} -) : MatteryContainer(listener, slotCount), IMatteryUpgrade { +) : IMatteryUpgrade { + val container = SlottedContainer.simple(slotCount, listener) + override val upgradeTypes: Set get() = setOf() private fun positiveDecimals(fn: (IMatteryUpgrade) -> Decimal, reducer: (Decimal, Decimal) -> Decimal): Decimal { - if (isEmpty) + if (container.isEmpty) return Decimal.ZERO - return iterator() + return container.iterator() .map { (it.getCapability(MatteryCapability.UPGRADE)?.let(fn) ?: Decimal.ZERO).moreThanZero() * it.count } .reduce(Decimal.ZERO, reducer) } private fun anyDecimals(fn: (IMatteryUpgrade) -> Decimal, reducer: (Decimal, Decimal) -> Decimal): Decimal { - if (isEmpty) + if (container.isEmpty) return Decimal.ZERO - return iterator() + return container.iterator() .map { (it.getCapability(MatteryCapability.UPGRADE)?.let(fn) ?: Decimal.ZERO) * it.count } .reduce(Decimal.ZERO, reducer) } override val speedBonus: Double - get() = iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.speedBonus ?: 0.0) * it.count }.reduce(0.0) { a, b -> a + b } + get() = container.iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.speedBonus ?: 0.0) * it.count }.reduce(0.0) { a, b -> a + b } override val processingItems: Int - get() = iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.processingItems ?: 0).coerceAtLeast(0) * it.count }.reduce(0) { a, b -> a + b } + get() = container.iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.processingItems ?: 0).coerceAtLeast(0) * it.count }.reduce(0) { a, b -> a + b } override val energyStorageFlat: Decimal get() = positiveDecimals(IMatteryUpgrade::energyStorageFlat, Decimal::plus) override val energyStorage: Decimal @@ -53,7 +56,7 @@ class UpgradeContainer( override val energyConsumed: Decimal get() = anyDecimals(IMatteryUpgrade::energyConsumed, Decimal::plus) override val failureMultiplier: Double - get() = iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.failureMultiplier ?: 1.0).coerceAtLeast(0.0).pow(it.count.toDouble()) }.reduce(1.0) { a, b -> a * b } + get() = container.iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.failureMultiplier ?: 1.0).coerceAtLeast(0.0).pow(it.count.toDouble()) }.reduce(1.0) { a, b -> a * b } override val energyThroughputFlat: Decimal get() = positiveDecimals(IMatteryUpgrade::energyThroughputFlat, Decimal::plus) override val energyThroughput: Decimal diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt index 35ae8b6b5..70711603d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt @@ -22,6 +22,7 @@ import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot 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.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull import ru.dbotthepony.mc.otm.core.collect.ConditionalEnumSet import ru.dbotthepony.mc.otm.core.immutableList @@ -261,7 +262,7 @@ data class UpgradeSlots( fun MatteryMenu.makeUpgradeSlots(count: Int, container: UpgradeContainer?): UpgradeSlots { if (container != null) { - require(count == container.containerSize) { "Upgrade container size ${container.containerSize} does not match with provided size $count" } + require(count == container.container.containerSize) { "Upgrade container size ${container.container.containerSize} does not match with provided size $count" } } val shouldLockUpgradeSlots: Supplier @@ -283,7 +284,7 @@ fun MatteryMenu.makeUpgradeSlots(count: Int, container: UpgradeContainer?): Upgr allowedTypes[value] = BooleanSupplier { b.get() } } - val syncContainer = container ?: SimpleContainer(count) + val syncContainer = container?.container ?: SlottedContainer.simple(count) val isOpen = InstantBooleanInput(this) return UpgradeSlots( From efbc93e16a4a74fc8fb784a944ac3dab393946f5 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 5 Mar 2025 19:01:24 +0700 Subject: [PATCH 035/154] Make IAutomatedContainer implement IItemHandlerModifiable --- .../dbotthepony/mc/otm/container/IAutomatedContainer.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt index 644b30b3e..2a703741f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt @@ -1,14 +1,16 @@ package ru.dbotthepony.mc.otm.container import net.minecraft.world.Container +import net.minecraft.world.entity.player.Player import net.minecraft.world.item.ItemStack import net.neoforged.neoforge.items.IItemHandler +import net.neoforged.neoforge.items.IItemHandlerModifiable /** * Reinforced [ISlottedContainer] which slots are [IAutomatedContainerSlot]s, which * subsequently allow this container to implement [IItemHandler] */ -interface IAutomatedContainer : ISlottedContainer, IItemHandler { +interface IAutomatedContainer : ISlottedContainer, IItemHandlerModifiable { override fun containerSlot(slot: Int): IAutomatedContainerSlot override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean { @@ -34,6 +36,10 @@ interface IAutomatedContainer : ISlottedContainer, IItemHandler { return containerSlot(slot).maxStackSize } + override fun setStackInSlot(slot: Int, stack: ItemStack) { + setItem(slot, stack) + } + override fun isItemValid(slot: Int, stack: ItemStack): Boolean { return canPlaceItem(slot, stack) } From de79019f56b635a82bedaeff14b7ca3170495c37 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 16:06:04 +0700 Subject: [PATCH 036/154] Implement EnhancedContainer --- .../mc/otm/container/EnhancedContainer.kt | 190 ++++++++++++++++++ .../otm/container/slotted/SlottedContainer.kt | 15 +- 2 files changed, 201 insertions(+), 4 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt new file mode 100644 index 000000000..f3a4defd5 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt @@ -0,0 +1,190 @@ +package ru.dbotthepony.mc.otm.container + +import it.unimi.dsi.fastutil.ints.IntOpenHashSet +import net.minecraft.core.HolderLookup.Provider +import net.minecraft.nbt.CompoundTag +import net.minecraft.nbt.ListTag +import net.minecraft.nbt.NbtOps +import net.minecraft.nbt.Tag +import net.minecraft.resources.RegistryOps +import net.minecraft.world.SimpleContainer +import net.minecraft.world.entity.player.Player +import net.minecraft.world.item.ItemStack +import net.neoforged.neoforge.common.util.INBTSerializable +import org.apache.logging.log4j.LogManager +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer +import ru.dbotthepony.mc.otm.core.isNotEmpty +import ru.dbotthepony.mc.otm.core.nbt.set + +/** + * Flexible base implementation of [IEnhancedContainer], designed to be inherited, or used as-is + * if no specific logic is required (this implementation is more efficient than one provided by [SlottedContainer.simple]). + * + * This is supposed to be counterpart to [SimpleContainer] of Minecraft itself, with more features + * and improved performance (inside [IEnhancedContainer] defined methods). + */ +open class EnhancedContainer(private val size: Int) : IEnhancedContainer, INBTSerializable { + private val items = Array(size) { ItemStack.EMPTY } + private val observedItems = Array(size) { ItemStack.EMPTY } + private val slots by lazy(LazyThreadSafetyMode.PUBLICATION) { Array(size) { IContainerSlot.Simple(it, this) } } + + // can be safely overridden in subclasses, very little memory will be wasted + override fun containerSlot(slot: Int): IContainerSlot { + return slots[slot] + } + + protected open fun notifySlotChanged(slot: Int, old: ItemStack) {} + + private fun observeSlotChanges(slot: Int) { + if (items[slot].count != observedItems[slot].count || !ItemStack.isSameItemSameComponents(items[slot], observedItems[slot])) { + notifySlotChanged(slot, observedItems[slot]) + + if (items[slot].isEmpty) { + items[slot] = ItemStack.EMPTY + observedItems[slot] = ItemStack.EMPTY + } else { + notifySlotChanged(slot, observedItems[slot]) + observedItems[slot] = items[slot].copy() + } + } + } + + override fun setChanged(slot: Int) { + observeSlotChanges(slot) + } + + override fun clearContent() { + items.fill(ItemStack.EMPTY) + observedItems.fill(ItemStack.EMPTY) + } + + override fun setChanged() { + for (slot in 0 until size) + observeSlotChanges(slot) + } + + final override fun getContainerSize(): Int { + return size + } + + final override fun getItem(slot: Int): ItemStack { + return items[slot] + } + + final override fun removeItem(slot: Int, amount: Int): ItemStack { + val item = items[slot] + + if (item.isEmpty) + return ItemStack.EMPTY + else if (item.count >= amount) + return removeItemNoUpdate(slot) + else { + val split = item.split(amount) + notifySlotChanged(slot, observedItems[slot]) + observedItems[slot] = item.copy() + return split + } + } + + final override fun removeItemNoUpdate(slot: Int): ItemStack { + val item = items[slot] + + if (item.isEmpty) + return ItemStack.EMPTY + + items[slot] = ItemStack.EMPTY + notifySlotChanged(slot, observedItems[slot]) + observedItems[slot] = ItemStack.EMPTY + + return item + } + + final override fun setItem(slot: Int, itemStack: ItemStack) { + if (itemStack.count != items[slot].count || !ItemStack.isSameItemSameComponents(itemStack, items[slot])) { + items[slot] = itemStack + notifySlotChanged(slot, observedItems[slot]) + observedItems[slot] = itemStack.copy() + } + } + + override fun stillValid(player: Player): Boolean { + return true + } + + /** + * Called from inside [serializeNBT] per slot, return true if you have written something into [nbt]. + * If returning false, and slot does not contain an item, tag entry is discarded + */ + protected open fun attachSlotData(provider: Provider, slot: Int, nbt: CompoundTag, ops: RegistryOps): Boolean { + return false + } + + protected open fun loadSlotData(provider: Provider, slot: Int, nbt: CompoundTag, ops: RegistryOps) { + + } + + override fun serializeNBT(provider: Provider): CompoundTag { + val ops = provider.createSerializationContext(NbtOps.INSTANCE) + + return CompoundTag().also { + it["items"] = ListTag().also { + for (i in 0 until size) { + val tag = CompoundTag() + var attached = attachSlotData(provider, i, tag, ops) + + if (items[i].isNotEmpty) { + attached = true + tag["item"] = ItemStack.OPTIONAL_CODEC.encodeStart(ops, items[i]) + .getOrThrow { RuntimeException("Unable to serialize item ${items[i]} at slot $i: $it") } + } + + tag["slot"] = i + + if (attached) { + it.add(tag) + } + } + } + } + } + + override fun deserializeNBT(provider: Provider, nbt: CompoundTag) { + val copy = observedItems.copyOf() + items.fill(ItemStack.EMPTY) + observedItems.fill(ItemStack.EMPTY) + + val seenSlots = IntOpenHashSet() + val ops = provider.createSerializationContext(NbtOps.INSTANCE) + + if ("items" in nbt) { + for (element in nbt.getList("items", Tag.TAG_COMPOUND.toInt())) { + element as CompoundTag + + if ("slot" !in element) continue + val slot = element.getInt("slot") + if (!seenSlots.add(slot)) continue + + if ("item" in nbt) { + ItemStack.OPTIONAL_CODEC.decode(ops, nbt["item"]) + .map { it.first } + .ifError { LOGGER.error("Failed to deserialize item stack in slot $slot: ${it.message()}") } + .ifSuccess { + if (it.isNotEmpty) { + items[slot] = it + observedItems[slot] = it.copy() + + if (it.count != copy[slot].count || !ItemStack.isSameItemSameComponents(it, copy[slot])) + notifySlotChanged(slot, copy[slot]) + } + } + } + + loadSlotData(provider, slot, element, ops) + } + } + } + + companion object { + private val LOGGER = LogManager.getLogger() + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt index f80c8b19e..ca04ebf0b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt @@ -3,9 +3,6 @@ package ru.dbotthepony.mc.otm.container.slotted import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder 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.ints.IntSet import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet import net.minecraft.core.HolderLookup import net.minecraft.core.registries.BuiltInRegistries @@ -20,17 +17,25 @@ import net.minecraft.world.item.ItemStack import net.neoforged.neoforge.common.util.INBTSerializable import org.apache.logging.log4j.LogManager import ru.dbotthepony.kommons.util.Either +import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.IAutomatedContainer import ru.dbotthepony.mc.otm.container.IAutomatedContainerSlot import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot import ru.dbotthepony.mc.otm.container.balance -import ru.dbotthepony.mc.otm.container.slotRange import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.data.codec.minRange import java.util.function.Predicate import kotlin.reflect.KClass +/** + * Concrete container implementation, operating on slots. + * + * Due to inflexible constraints, it can not be inherited, and usually it is not required since + * most logic is embedded inside [ContainerSlot]. + * + * If you specifically need to inherit container implementation, use [EnhancedContainer], which was designed to be inherited. + */ class SlottedContainer( slots: Collection>, private val stillValid: Predicate, @@ -381,10 +386,12 @@ class SlottedContainer( return MultiTag(T::class) } + @Deprecated("Consider using EnhancedContainer", replaceWith = ReplaceWith("EnhancedContainer(size)", "ru.dbotthepony.mc.otm.container.EnhancedContainer")) fun simple(size: Int): SlottedContainer { return Builder().add(size, ::ContainerSlot).build() } + @Deprecated("Consider using EnhancedContainer", replaceWith = ReplaceWith("EnhancedContainer.withListener(size, listener)", "ru.dbotthepony.mc.otm.container.EnhancedContainer")) fun simple(size: Int, listener: Runnable): SlottedContainer { return Builder() .add(size, ::ContainerSlot) From 9806e1ec521bb47a0a96bb9bc4ae0b598f648a03 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 16:06:21 +0700 Subject: [PATCH 037/154] Revert "Update Upgrade Container to use SlottedContainer" This reverts commit 861b94a30a84f08af7d6778e6f6b53bb658e0c47. --- .../entity/matter/MatterBottlerBlockEntity.kt | 2 +- .../matter/MatterDecomposerBlockEntity.kt | 2 +- .../matter/MatterEntanglerBlockEntity.kt | 2 +- .../matter/MatterReconstructorBlockEntity.kt | 5 +++-- .../matter/MatterRecyclerBlockEntity.kt | 2 +- .../matter/MatterReplicatorBlockEntity.kt | 2 +- .../entity/matter/MatterScannerBlockEntity.kt | 2 +- .../tech/AbstractPoweredFurnaceBlockEntity.kt | 2 +- .../entity/tech/PlatePressBlockEntity.kt | 2 +- .../mc/otm/container/UpgradeContainer.kt | 19 ++++++++----------- .../ru/dbotthepony/mc/otm/menu/Slots.kt | 5 ++--- 11 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt index 3bf343fd6..e9fe053a1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt @@ -106,7 +106,7 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) : savetables.stateful(::matter, MATTER_STORAGE_KEY) savetables.stateful(::bottling) savetables.stateful(::unbottling) - savetables.stateful(upgrades::container, "upgrades") + savetables.stateful(::upgrades) } var workProgress: Float = 0f diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt index bb70e2ca1..8a7836f9e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt @@ -64,7 +64,7 @@ class MatterDecomposerBlockEntity(pos: BlockPos, state: BlockState) init { savetables.stateful(::energy, ENERGY_KEY) - savetables.stateful(upgrades::container, "upgrades") + savetables.stateful(::upgrades) } val matter = ProfiledMatterStorage(MatterStorageImpl(::markDirtyFast, FlowDirection.OUTPUT, upgrades.matterCapacity(MachinesConfig.MATTER_DECOMPOSER::matterCapacity))) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt index 9d4e37098..82def3e57 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt @@ -144,7 +144,7 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M savetables.stateful(::energy, ENERGY_KEY) savetables.stateful(::matter, MATTER_STORAGE_KEY) - savetables.stateful(upgrades::container, "upgrades") + savetables.stateful(::upgrades) savetables.stateful(inputs::parent, "inputs") savetables.stateful(::output) savetables.stateful(::experience) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReconstructorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReconstructorBlockEntity.kt index 9a9a9bc87..2ce185aca 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReconstructorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReconstructorBlockEntity.kt @@ -37,7 +37,8 @@ import ru.dbotthepony.mc.otm.menu.matter.MatterReconstructorMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import java.util.function.BooleanSupplier -class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.MATTER_RECONSTRUCTOR, blockPos, blockState) { +class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity( + MBlockEntities.MATTER_RECONSTRUCTOR, blockPos, blockState) { val repairContainer = MatteryContainer(::containerChanged, 1).also(::addDroppableContainer) private var matterPerTick = Decimal.ZERO @@ -85,7 +86,7 @@ class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState) savetables.stateful(::repairContainer) savetables.stateful(::matter) savetables.stateful(::energy) - savetables.stateful(upgrades::container, "upgrades") + savetables.stateful(::upgrades) savetables.decimal(::matterPerTick) savetables.double(::progressPerTick) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt index 6f6616193..d8fe21afe 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt @@ -72,7 +72,7 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) savetables.stateful(::energy, ENERGY_KEY) savetables.stateful(::container, INVENTORY_KEY) savetables.stateful(::matter, MATTER_STORAGE_KEY) - savetables.stateful(upgrades::container, "upgrades") + savetables.stateful(::upgrades) } override fun setRemoved() { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt index e97ae3b62..ac9f9c181 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt @@ -103,7 +103,7 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : savetables.stateful(::matter, MATTER_STORAGE_KEY) savetables.stateful(::outputContainer, INVENTORY_KEY) savetables.stateful(::dustContainer) - savetables.stateful(upgrades::container, "upgrades") + savetables.stateful(::upgrades) } override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt index 15609ed92..d57799340 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt @@ -68,7 +68,7 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : savetables.stateful(::container, INVENTORY_KEY) savetables.stateful(::energy, ENERGY_KEY) - savetables.stateful(upgrades::container, "upgrades") + savetables.stateful(::upgrades) } override fun setRemoved() { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt index beecf43c4..6defd22b6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt @@ -84,7 +84,7 @@ sealed class AbstractPoweredFurnaceBlockEntity

= UpgradeType.ALL, val shouldLockUpgradeSlots: BooleanSupplier = BooleanSupplier { false }, listener: Runnable = Runnable {} -) : IMatteryUpgrade { - val container = SlottedContainer.simple(slotCount, listener) - +) : MatteryContainer(listener, slotCount), IMatteryUpgrade { override val upgradeTypes: Set get() = setOf() private fun positiveDecimals(fn: (IMatteryUpgrade) -> Decimal, reducer: (Decimal, Decimal) -> Decimal): Decimal { - if (container.isEmpty) + if (isEmpty) return Decimal.ZERO - return container.iterator() + return iterator() .map { (it.getCapability(MatteryCapability.UPGRADE)?.let(fn) ?: Decimal.ZERO).moreThanZero() * it.count } .reduce(Decimal.ZERO, reducer) } private fun anyDecimals(fn: (IMatteryUpgrade) -> Decimal, reducer: (Decimal, Decimal) -> Decimal): Decimal { - if (container.isEmpty) + if (isEmpty) return Decimal.ZERO - return container.iterator() + return iterator() .map { (it.getCapability(MatteryCapability.UPGRADE)?.let(fn) ?: Decimal.ZERO) * it.count } .reduce(Decimal.ZERO, reducer) } override val speedBonus: Double - get() = container.iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.speedBonus ?: 0.0) * it.count }.reduce(0.0) { a, b -> a + b } + get() = iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.speedBonus ?: 0.0) * it.count }.reduce(0.0) { a, b -> a + b } override val processingItems: Int - get() = container.iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.processingItems ?: 0).coerceAtLeast(0) * it.count }.reduce(0) { a, b -> a + b } + get() = iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.processingItems ?: 0).coerceAtLeast(0) * it.count }.reduce(0) { a, b -> a + b } override val energyStorageFlat: Decimal get() = positiveDecimals(IMatteryUpgrade::energyStorageFlat, Decimal::plus) override val energyStorage: Decimal @@ -56,7 +53,7 @@ class UpgradeContainer( override val energyConsumed: Decimal get() = anyDecimals(IMatteryUpgrade::energyConsumed, Decimal::plus) override val failureMultiplier: Double - get() = container.iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.failureMultiplier ?: 1.0).coerceAtLeast(0.0).pow(it.count.toDouble()) }.reduce(1.0) { a, b -> a * b } + get() = iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.failureMultiplier ?: 1.0).coerceAtLeast(0.0).pow(it.count.toDouble()) }.reduce(1.0) { a, b -> a * b } override val energyThroughputFlat: Decimal get() = positiveDecimals(IMatteryUpgrade::energyThroughputFlat, Decimal::plus) override val energyThroughput: Decimal diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt index 70711603d..35ae8b6b5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt @@ -22,7 +22,6 @@ import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot 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.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull import ru.dbotthepony.mc.otm.core.collect.ConditionalEnumSet import ru.dbotthepony.mc.otm.core.immutableList @@ -262,7 +261,7 @@ data class UpgradeSlots( fun MatteryMenu.makeUpgradeSlots(count: Int, container: UpgradeContainer?): UpgradeSlots { if (container != null) { - require(count == container.container.containerSize) { "Upgrade container size ${container.container.containerSize} does not match with provided size $count" } + require(count == container.containerSize) { "Upgrade container size ${container.containerSize} does not match with provided size $count" } } val shouldLockUpgradeSlots: Supplier @@ -284,7 +283,7 @@ fun MatteryMenu.makeUpgradeSlots(count: Int, container: UpgradeContainer?): Upgr allowedTypes[value] = BooleanSupplier { b.get() } } - val syncContainer = container?.container ?: SlottedContainer.simple(count) + val syncContainer = container ?: SimpleContainer(count) val isOpen = InstantBooleanInput(this) return UpgradeSlots( From c376a99da057f7b6750192a08b8c6c9327723095 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 16:11:37 +0700 Subject: [PATCH 038/154] Make Upgrade container inherit EnhancedContainer instead --- .../dbotthepony/mc/otm/container/UpgradeContainer.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt index 0c0070806..78464971c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt @@ -1,5 +1,6 @@ package ru.dbotthepony.mc.otm.container +import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.capability.IMatteryUpgrade import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.UpgradeType @@ -15,8 +16,13 @@ class UpgradeContainer( slotCount: Int, val allowedUpgrades: Set = UpgradeType.ALL, val shouldLockUpgradeSlots: BooleanSupplier = BooleanSupplier { false }, - listener: Runnable = Runnable {} -) : MatteryContainer(listener, slotCount), IMatteryUpgrade { + private val listener: Runnable = Runnable {} +) : EnhancedContainer(slotCount), IMatteryUpgrade { + override fun notifySlotChanged(slot: Int, old: ItemStack) { + super.notifySlotChanged(slot, old) + listener.run() + } + override val upgradeTypes: Set get() = setOf() From c31549792e3dcc841a1e7b999cd547ff11cce6c3 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 16:37:30 +0700 Subject: [PATCH 039/154] More specific methods in enhanced container interface --- .../mc/otm/container/IEnhancedContainer.kt | 20 +++++++++++++++---- .../mc/otm/container/ISlottedContainer.kt | 6 +----- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt index 1a4cb4267..30509ab3a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt @@ -88,15 +88,27 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable, Sta } } - fun emptySlotIterator(allowedSlots: IntCollection = slotRange): IntIterator { + fun emptySlotIndexIterator(): IntIterator { + return emptySlotIndexIterator(slotRange) + } + + fun nonEmptySlotIndexIterator(): IntIterator { + return nonEmptySlotIndexIterator(slotRange) + } + + fun emptySlotIndexIterator(allowedSlots: IntCollection): IntIterator { return slotIterator(allowedSlots) { it.isEmpty } } - fun nonEmptySlotIterator(allowedSlots: IntCollection = slotRange): IntIterator { + fun nonEmptySlotIndexIterator(allowedSlots: IntCollection): IntIterator { return slotIterator(allowedSlots) { it.isNotEmpty } } - fun slotWithItemIterator(item: Item, allowedSlots: IntCollection = slotRange): IntIterator { + fun slotWithItemIterator(item: Item): IntIterator { + return slotWithItemIterator(item, slotRange) + } + + fun slotWithItemIterator(item: Item, allowedSlots: IntCollection): IntIterator { return slotIterator(allowedSlots) { it.isNotEmpty && it.item === item } } @@ -234,7 +246,7 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable, Sta if (!onlyIntoExisting) { // двигаем в пустые слоты - for (slot in emptySlotIterator(slots)) { + for (slot in emptySlotIndexIterator(slots)) { val diff = copy.count.coerceAtMost(getMaxStackSize(slot, stack)) if (!simulate) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt index 58430a103..92530f6a3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt @@ -2,12 +2,8 @@ package ru.dbotthepony.mc.otm.container import it.unimi.dsi.fastutil.ints.IntCollection import it.unimi.dsi.fastutil.ints.IntSet -import net.minecraft.world.Container import net.minecraft.world.item.ItemStack -import net.neoforged.neoforge.items.IItemHandler import ru.dbotthepony.kommons.collect.any -import ru.dbotthepony.mc.otm.core.collect.filter -import ru.dbotthepony.mc.otm.core.collect.map /** * Skeletal implementation for containers which revolve around [IContainerSlot] @@ -80,7 +76,7 @@ interface ISlottedContainer : IEnhancedContainer { } if (!onlyIntoExisting) { - for (i in emptySlotIterator(slots)) { + for (i in emptySlotIndexIterator(slots)) { val slot = containerSlot(i) val condition: Boolean From 7a4ce4f394922a0cefe898ce93ddecb0638a994b Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 16:38:20 +0700 Subject: [PATCH 040/154] Use EnhancedContainer in makeUpgradeSlots --- src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt index 35ae8b6b5..f14232d0e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt @@ -17,6 +17,7 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.UpgradeType import ru.dbotthepony.mc.otm.capability.energy import ru.dbotthepony.mc.otm.client.minecraft +import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.IEnhancedContainer import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot import ru.dbotthepony.mc.otm.container.IMatteryContainer @@ -283,7 +284,7 @@ fun MatteryMenu.makeUpgradeSlots(count: Int, container: UpgradeContainer?): Upgr allowedTypes[value] = BooleanSupplier { b.get() } } - val syncContainer = container ?: SimpleContainer(count) + val syncContainer = container ?: EnhancedContainer(count) val isOpen = InstantBooleanInput(this) return UpgradeSlots( From 84d4ed78eab32a959da7284e54bd9c6559390de5 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 16:49:10 +0700 Subject: [PATCH 041/154] Don't scramble xoshiro on fork since seed is already enough random --- .../ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt index 99438ed72..b38f5481b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt @@ -93,7 +93,7 @@ class Xoshiro256SSRandom private constructor( } override fun fork(): RandomSource { - return Xoshiro256SSRandom(nextLong(), nextLong(), nextLong(), nextLong()) + return Xoshiro256SSRandom(nextLong(), nextLong(), nextLong(), nextLong(), null) } override fun forkPositional(): PositionalRandomFactory { From bc2cfccffe446aa7b149feff4fd8f41080662705 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 18:22:04 +0700 Subject: [PATCH 042/154] Provide direct set operator --- .../ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt index 30509ab3a..24ca9c248 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt @@ -23,11 +23,15 @@ import java.util.function.Predicate * and actual implementations of this interface are likely to provide efficient method implementations in place of derived/emulated ones. */ interface IEnhancedContainer : IContainer, RecipeInput, Iterable, StackedContentsCompatible { - // provide non-ambiguous "get" operator + // provide non-ambiguous get and set operators operator fun get(slot: Int): ItemStack { return getItem(slot) } + operator fun set(slot: Int, value: ItemStack) { + setItem(slot, value) + } + fun containerSlot(slot: Int): IContainerSlot { return IContainerSlot.Simple(slot, this) } From f8e9a679941f7b0f20fda3de7e9526fcac8ee76c Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 20:00:26 +0700 Subject: [PATCH 043/154] Update Matter Reconstructor to use slotted container --- .../matter/MatterReconstructorBlockEntity.kt | 73 +++++++++---------- .../menu/matter/MatterReconstructorMenu.kt | 3 +- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReconstructorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReconstructorBlockEntity.kt index 2ce185aca..8f0f47ddd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReconstructorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReconstructorBlockEntity.kt @@ -25,8 +25,9 @@ import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.HandlerFilter -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.UpgradeContainer +import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.core.registryName @@ -37,9 +38,35 @@ import ru.dbotthepony.mc.otm.menu.matter.MatterReconstructorMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import java.util.function.BooleanSupplier -class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity( - MBlockEntities.MATTER_RECONSTRUCTOR, blockPos, blockState) { - val repairContainer = MatteryContainer(::containerChanged, 1).also(::addDroppableContainer) +class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.MATTER_RECONSTRUCTOR, blockPos, blockState) { + private inner class Slot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) { + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + if (!super.canAutomationPlaceItem(itemStack) || !itemStack.isRepairable || !itemStack.isDamaged) { + return false + } + + if (MachinesConfig.MatterReconstructor.ALLOW_TO_SKIP_ANVIL && !MachinesConfig.MatterReconstructor.ONLY_ANVIL && MatterManager.get(itemStack.item).hasMatterValue) { + return true + } + + return matterNode.graph + .patterns + .filter { itemStack.item.isValidRepairItem(itemStack, ItemStack(it.item, 1)) } + .findFirst().orElse(null).let { + if (it == null) { + IMatterValue.ZERO + } else { + MatterManager.get(it.item) + } + }.hasMatterValue + } + + override fun canAutomationTakeItem(desired: Int): Boolean { + return super.canAutomationTakeItem(desired) && (progressPerTick <= 0.0 || matterPerTick <= Decimal.ZERO) + } + } + + val repairContainer = SlottedContainer.simple(1, ::Slot, ::rescan).also(::addDroppableContainer) private var matterPerTick = Decimal.ZERO private var progressPerTick = 0.0 @@ -67,15 +94,15 @@ class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState) } override fun onPatternAdded(state: PatternState) { - containerChanged() + rescan() } override fun onPatternRemoved(state: PatternState) { - containerChanged() + rescan() } override fun onPatternUpdated(newState: PatternState, oldState: PatternState) { - containerChanged() + rescan() } } @@ -99,34 +126,7 @@ class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState) val energyConfig = ConfigurableEnergy(energy) val itemConfig = ConfigurableItemHandler( - inputOutput = repairContainer.handler(object : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - if (!stack.isRepairable || !stack.isDamaged) { - return false - } - - if (MachinesConfig.MatterReconstructor.ALLOW_TO_SKIP_ANVIL && !MachinesConfig.MatterReconstructor.ONLY_ANVIL) { - if (MatterManager.get(stack.item).hasMatterValue) { - return true - } - } - - return matterNode.graph - .patterns - .filter { stack.item.isValidRepairItem(stack, ItemStack(it.item, 1)) } - .findFirst().orElse(null).let { - if (it == null) { - IMatterValue.ZERO - } else { - MatterManager.get(it.item) - } - }.hasMatterValue - } - - override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return progressPerTick <= 0.0 || matterPerTick <= Decimal.ZERO - } - }) + inputOutput = repairContainer ) override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { @@ -145,7 +145,7 @@ class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState) private var changeset = 0 - private fun containerChanged() { + private fun rescan() { matterPerTick = Decimal.ZERO progressPerTick = 0.0 @@ -196,7 +196,6 @@ class MatterReconstructorBlockEntity(blockPos: BlockPos, blockState: BlockState) } } - @Suppress("name_shadowing") val matter = MatterManager.get(found.item) * 2 progressPerTick = (item.maxDamage / matter.complexity) / MachinesConfig.MatterReconstructor.DIVISOR diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReconstructorMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReconstructorMenu.kt index 8af81790f..d91502e7c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReconstructorMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReconstructorMenu.kt @@ -4,6 +4,7 @@ import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.block.entity.matter.MatterReconstructorBlockEntity +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput @@ -20,7 +21,7 @@ class MatterReconstructorMenu( tile: MatterReconstructorBlockEntity? = null ) : MatteryPoweredMenu(MMenus.ITEM_REPAIER, containerId, inventory, tile) { val matterWidget = ProfiledLevelGaugeWidget(this, tile?.matter, LevelGaugeWidget(this, tile?.matter)) - val slot = object : MatteryMenuSlot(tile?.repairContainer ?: SimpleContainer(1), 0) { + val slot = object : MatteryMenuSlot(tile?.repairContainer ?: SlottedContainer.filtered(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.isRepairable && itemStack.isDamaged && super.mayPlace(itemStack) } From e8ba5916b131b315a912802f19d75aea1d8cb1ed Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 20:31:28 +0700 Subject: [PATCH 044/154] Update Matter recycler to use Slotted Container --- .../matter/MatterRecyclerBlockEntity.kt | 30 +++++++++---------- .../mc/otm/menu/matter/MatterRecyclerMenu.kt | 3 +- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt index d8fe21afe..4636e7aa5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt @@ -21,8 +21,8 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage import ru.dbotthepony.mc.otm.config.MachinesConfig -import ru.dbotthepony.mc.otm.container.MatteryContainer -import ru.dbotthepony.mc.otm.container.HandlerFilter +import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.graph.matter.MatterGraph @@ -33,9 +33,7 @@ import ru.dbotthepony.mc.otm.data.codec.DecimalCodec import ru.dbotthepony.mc.otm.data.codec.minRange import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode -class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) - : MatteryWorkerBlockEntity(MBlockEntities.MATTER_RECYCLER, blockPos, blockState, RecyclerJob.CODEC) { - +class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryWorkerBlockEntity(MBlockEntities.MATTER_RECYCLER, blockPos, blockState, RecyclerJob.CODEC) { class RecyclerJob(ticks: Double, powerUsage: Decimal, var totalMatter: Decimal) : Job(ticks, powerUsage) { companion object { val CODEC: Codec by lazy { @@ -48,20 +46,22 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) override val upgrades = makeUpgrades(3, UpgradeType.BASIC_MATTER) val matter = ProfiledMatterStorage(MatterStorageImpl(::matterLevelUpdated, FlowDirection.OUTPUT, upgrades.matterCapacity(MachinesConfig.MatterRecycler.VALUES::matterCapacity))) - val container = MatteryContainer(::itemContainerUpdated, 1).also(::addDroppableContainer) + private class Slot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) { + override fun canAutomationTakeItem(desired: Int): Boolean { + return false + } + + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + return super.canAutomationPlaceItem(itemStack) && itemStack.item is MatterDustItem + } + } + + val container = SlottedContainer.simple(1, ::Slot, ::itemContainerUpdated).also(::addDroppableContainer) val matterNode = SimpleMatterNode(matter = matter) override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::energyLevelUpdated, upgrades.transform(MachinesConfig.MatterRecycler.VALUES))) - val itemConfig = ConfigurableItemHandler(input = container.handler(object : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return stack.item is MatterDustItem - } - - override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return false - } - })) + val itemConfig = ConfigurableItemHandler(container) val energyConfig = ConfigurableEnergy(energy) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterRecyclerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterRecyclerMenu.kt index 33d4e1e0c..8a7b3f2b4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterRecyclerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterRecyclerMenu.kt @@ -4,6 +4,7 @@ import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.block.entity.matter.MatterRecyclerBlockEntity +import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.item.matter.MatterDustItem import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot @@ -20,7 +21,7 @@ class MatterRecyclerMenu @JvmOverloads constructor( inventory: Inventory, tile: MatterRecyclerBlockEntity? = null ) : MatteryPoweredMenu(MMenus.MATTER_RECYCLER, containerID, inventory, tile) { - val input = object : MatteryMenuSlot(tile?.container ?: SimpleContainer(1), 0) { + val input = object : MatteryMenuSlot(tile?.container ?: EnhancedContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.item is MatterDustItem && (itemStack.item as MatterDustItem).getMatterValue(itemStack) != null } From e0e1ba864d824cca39bb737525bdabf0bf368431 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 20:41:39 +0700 Subject: [PATCH 045/154] Update Matter replicator to use Slotted Container --- .../block/entity/matter/MatterReplicatorBlockEntity.kt | 8 +++++--- .../mc/otm/menu/matter/MatterReplicatorMenu.kt | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt index ac9f9c181..681c6fd27 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt @@ -27,6 +27,8 @@ import ru.dbotthepony.mc.otm.capability.matter.* import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.data.codec.DecimalCodec @@ -71,11 +73,11 @@ class MatterReplicatorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : override val upgrades = makeUpgrades(3, UpgradeType.REPLICATOR) override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::energyLevelUpdated, upgrades.transform(MachinesConfig.MATTER_REPLICATOR))) val matter = ProfiledMatterStorage(MatterStorageImpl(::matterLevelUpdated, FlowDirection.INPUT, upgrades.matterCapacity(MachinesConfig.MATTER_REPLICATOR::matterCapacity))) - val outputContainer = MatteryContainer(::itemContainerUpdated, 3).also(::addDroppableContainer) - val dustContainer = MatteryContainer(::itemContainerUpdated, 2).also(::addDroppableContainer) + val outputContainer = SlottedContainer.simple(3, AutomationFilters.ONLY_OUT.simpleProvider, ::itemContainerUpdated).also(::addDroppableContainer) + val dustContainer = SlottedContainer.simple(2, AutomationFilters.ONLY_OUT.simpleProvider, ::itemContainerUpdated).also(::addDroppableContainer) val energyConfig = ConfigurableEnergy(energy) - val itemConfig = ConfigurableItemHandler(output = CombinedItemHandler(outputContainer.handler(HandlerFilter.OnlyOut), dustContainer.handler(HandlerFilter.OnlyOut))) + val itemConfig = ConfigurableItemHandler(output = CombinedItemHandler(outputContainer, dustContainer)) val matterNode = object : MatterNode() { override fun getMatterHandler(): IMatterStorage { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReplicatorMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReplicatorMenu.kt index 387c24526..d1956e505 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReplicatorMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReplicatorMenu.kt @@ -7,6 +7,7 @@ import ru.dbotthepony.mc.otm.block.entity.matter.MatterReplicatorBlockEntity import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget import ru.dbotthepony.mc.otm.container.CombinedContainer +import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.isNotEmpty @@ -34,7 +35,7 @@ class MatterReplicatorMenu @JvmOverloads constructor( val upgrades = makeUpgradeSlots(3, tile?.upgrades) init { - val container = CombinedContainer(tile?.outputContainer ?: SlottedContainer.simple(3), tile?.dustContainer ?: SlottedContainer.simple(2)) + val container = CombinedContainer(tile?.outputContainer ?: EnhancedContainer(3), tile?.dustContainer ?: EnhancedContainer(2)) storageSlots = immutableList(5) { addStorageSlot(OutputMenuSlot(container, it, onTake = { From 8967d3aafa40b6fa7e37bfc8d7550b05164dfa66 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 20:41:58 +0700 Subject: [PATCH 046/154] Make CombinedItemHandler aware that SlottedContainer does not need to be rechecked --- .../dbotthepony/mc/otm/capability/item/CombinedItemHandler.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/item/CombinedItemHandler.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/item/CombinedItemHandler.kt index 83c426d0f..cd21d7221 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/item/CombinedItemHandler.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/item/CombinedItemHandler.kt @@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList import net.minecraft.world.item.ItemStack import net.neoforged.neoforge.items.IItemHandler import ru.dbotthepony.mc.otm.container.ContainerHandler +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import java.util.stream.Stream class CombinedItemHandler(val handlers: ImmutableList) : IItemHandler { @@ -11,7 +12,7 @@ class CombinedItemHandler(val handlers: ImmutableList) : IItemHand constructor(handlers: Collection) : this(ImmutableList.copyOf(handlers)) constructor(vararg handlers: IItemHandler) : this(ImmutableList.copyOf(handlers)) - private val needsChecking = handlers.any { it !is ContainerHandler } + private val needsChecking = handlers.any { it !is ContainerHandler && it !is SlottedContainer } private val lastSizes = IntArray(this.handlers.size) private var totalSize = 0 private val mappings = ArrayList() From cfd64fac07c27dc2b78c05fe8dd5053d14d50cf0 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 21:48:05 +0700 Subject: [PATCH 047/154] Update Matter scanner to use SlottedContainer --- .../entity/matter/MatterScannerBlockEntity.kt | 17 ++++++++++------- .../mc/otm/menu/matter/MatterScannerMenu.kt | 10 +++++----- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt index d57799340..e7d68b96e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt @@ -22,6 +22,8 @@ import ru.dbotthepony.mc.otm.capability.matter.PatternState import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter +import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.matter.MatterScannerMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import ru.dbotthepony.mc.otm.graph.matter.MatterNode @@ -34,19 +36,20 @@ class MatterScannerBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryWorkerBlockEntity(MBlockEntities.MATTER_SCANNER, p_155229_, p_155230_, ItemJob.CODEC) { override val upgrades = makeUpgrades(2, UpgradeType.BASIC) - val container = MatteryContainer(::itemContainerUpdated, 1).also(::addDroppableContainer) override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(::energyLevelUpdated, upgrades.transform(MachinesConfig.MATTER_SCANNER))) - val itemConfig = ConfigurableItemHandler(inputOutput = container.handler(object : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return MatterManager.canDecompose(stack) + private inner class Slot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) { + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + return super.canAutomationPlaceItem(itemStack) && MatterManager.canDecompose(itemStack) } - override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return jobEventLoops[0].isIdling + override fun canAutomationTakeItem(desired: Int): Boolean { + return jobEventLoops[0].isIdling && super.canAutomationTakeItem(desired) } - })) + } + val container = SlottedContainer.simple(1, ::Slot, ::itemContainerUpdated).also(::addDroppableContainer) + val itemConfig = ConfigurableItemHandler(inputOutput = container) val energyConfig = ConfigurableEnergy(energy) val matterNode = object : MatterNode() { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterScannerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterScannerMenu.kt index 1ab6f917a..005e774c1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterScannerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterScannerMenu.kt @@ -5,8 +5,8 @@ import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.block.entity.matter.MatterScannerBlockEntity import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget -import net.minecraft.world.SimpleContainer import net.minecraft.world.item.ItemStack +import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.matter.MatterManager import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu @@ -17,11 +17,11 @@ import ru.dbotthepony.mc.otm.menu.makeUpgradeSlots import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.registry.game.MMenus -class MatterScannerMenu @JvmOverloads constructor( - p_38852_: Int, +class MatterScannerMenu( + containerID: Int, inventory: Inventory, tile: MatterScannerBlockEntity? = null -) : MatteryPoweredMenu(MMenus.MATTER_SCANNER, p_38852_, inventory, tile) { +) : MatteryPoweredMenu(MMenus.MATTER_SCANNER, containerID, inventory, tile) { val input: MatteryMenuSlot val progress = ProgressGaugeWidget(this, tile) val patterns = LevelGaugeWidget(this) @@ -31,7 +31,7 @@ class MatterScannerMenu @JvmOverloads constructor( val upgrades = makeUpgradeSlots(2, tile?.upgrades) init { - val container = tile?.container ?: SimpleContainer(1) + val container = tile?.container ?: EnhancedContainer(1) input = object : MatteryMenuSlot(container, 0, 64, 38) { override fun mayPlace(itemStack: ItemStack) = MatterManager.canDecompose(itemStack) From 6c42af9f3078948626dcbd7b40747a7011f73d46 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 21:58:08 +0700 Subject: [PATCH 048/154] Provide stream() method in enhanced container --- .../ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt index 24ca9c248..6edd68823 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt @@ -15,6 +15,8 @@ import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.collect.map import ru.dbotthepony.mc.otm.core.isNotEmpty import java.util.function.Predicate +import java.util.stream.Stream +import java.util.stream.StreamSupport /** * "Backward-compatible" enhanced container interface, where all methods can be derived/emulated from existing [IContainer] ([Container]) code @@ -291,6 +293,10 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable, Sta return addItem(stack, false, slots, onlyIntoExisting, popTime).isEmpty } + fun stream(): Stream { + return StreamSupport.stream(spliterator(), false) + } + private class Wrapper(private val parent: Container) : IEnhancedContainer { override fun clearContent() { return parent.clearContent() From caa8d1bb902cd05b82bbf6a0ab389f968a5da22d Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 21:58:50 +0700 Subject: [PATCH 049/154] Remove conflicting methods from mattery container --- .../ru/dbotthepony/mc/otm/container/MatteryContainer.kt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt index 024ed041c..fc9c3d58d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt @@ -230,9 +230,6 @@ open class MatteryContainer(var listener: ContainerListener, private val size: I return nonEmptyIndices.isEmpty } - @Suppress("nothing_to_inline") - inline operator fun set(slot: Int, stack: ItemStack) = setItem(slot, stack) - operator fun contains(other: ItemStack): Boolean { for (i in 0 until size) { if (ItemStack.isSameItemSameComponents(this[i], other)) { @@ -495,10 +492,6 @@ open class MatteryContainer(var listener: ContainerListener, private val size: I return Spliterator(nonEmptyIndices.intSpliterator()) } - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - companion object { private val LOGGER = LogManager.getLogger() } From d1a9825ea84ed0a0d562083d8f2f8804f9386f64 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 22:00:41 +0700 Subject: [PATCH 050/154] Update Pattern storage to use SlottedContainer --- .../matter/PatternStorageBlockEntity.kt | 60 +++++++++---------- .../mc/otm/menu/matter/PatternStorageMenu.kt | 5 +- 2 files changed, 31 insertions(+), 34 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/PatternStorageBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/PatternStorageBlockEntity.kt index b7908ae5e..27f0099e0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/PatternStorageBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/PatternStorageBlockEntity.kt @@ -1,8 +1,8 @@ package ru.dbotthepony.mc.otm.block.entity.matter import net.minecraft.core.BlockPos +import net.minecraft.server.level.ServerLevel import net.minecraft.world.level.block.state.BlockState -import ru.dbotthepony.mc.otm.container.MatteryContainer import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.block.matter.PatternStorageBlock @@ -14,7 +14,8 @@ import net.minecraft.world.level.Level import net.minecraft.world.level.block.Block import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.capability.matter.* -import ru.dbotthepony.mc.otm.container.HandlerFilter +import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.collect.filterNotNull import ru.dbotthepony.mc.otm.core.collect.map import ru.dbotthepony.mc.otm.core.filterNotNull @@ -23,53 +24,48 @@ import ru.dbotthepony.mc.otm.graph.matter.SimpleMatterNode import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import java.util.stream.Stream -class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : - MatteryDeviceBlockEntity(MBlockEntities.PATTERN_STORAGE, p_155229_, p_155230_), IPatternStorage { - +class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.PATTERN_STORAGE, p_155229_, p_155230_), IPatternStorage { val matterNode = SimpleMatterNode(patterns = this) - val container: MatteryContainer = object : MatteryContainer(::markDirtyFast, 8) { - override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { - if (!ItemStack.isSameItemSameComponents(new, old)) { + private inner class Slot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) { + override val maxStackSize: Int + get() = 1 + + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + return super.canAutomationPlaceItem(itemStack) && itemStack.getCapability(MatteryCapability.PATTERN_ITEM) != null + } + + override fun canAutomationTakeItem(desired: Int): Boolean { + return false + } + + override fun notifyChanged(old: ItemStack) { + if (!ItemStack.isSameItemSameComponents(item, old)) { if (!old.isEmpty) { old.getCapability(MatteryCapability.PATTERN_ITEM)?.let { cap: IPatternStorage -> cap.patterns.forEach { matterNode.graph.onPatternRemoved(it) } } } - if (!new.isEmpty) { - new.getCapability(MatteryCapability.PATTERN_ITEM)?.let { cap: IPatternStorage -> + if (!item.isEmpty) { + item.getCapability(MatteryCapability.PATTERN_ITEM)?.let { cap: IPatternStorage -> cap.patterns.forEach { matterNode.graph.onPatternAdded(it) } } } - updateBlockstate() + val level = level + + if (level is ServerLevel) { + level.setBlock(blockPos, blockState.setValue(PatternStorageBlock.PATTERN_STORAGE_DISKS_PROPS[slot], item.getCapability(MatteryCapability.PATTERN_ITEM) != null), Block.UPDATE_CLIENTS) + } } - super.setChanged(slot, new, old) - } - - override fun getMaxStackSize(): Int = 1 - }.also(::addDroppableContainer) - - private fun updateBlockstate() { - val level = level ?: return - - var state = blockState - - for (i in 0..7) { - state = state.setValue( - PatternStorageBlock.PATTERN_STORAGE_DISKS_PROPS[i], - this.container.getItem(i).getCapability(MatteryCapability.PATTERN_ITEM) != null - ) - } - - if (state !== blockState) { - level.setBlock(blockPos, state, Block.UPDATE_CLIENTS) + super.notifyChanged(old) } } - val itemConfig = ConfigurableItemHandler(inputOutput = container.handler(HandlerFilter.IsPattern.and(HandlerFilter.OnlyIn))) + val container = SlottedContainer.simple(2 * 4, ::Slot, ::markDirtyFast).also(::addDroppableContainer) + val itemConfig = ConfigurableItemHandler(inputOutput = container) override fun setLevel(level: Level) { super.setLevel(level) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/PatternStorageMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/PatternStorageMenu.kt index 5f38eccd3..920899dec 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/PatternStorageMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/PatternStorageMenu.kt @@ -4,6 +4,7 @@ import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.block.entity.matter.PatternStorageBlockEntity +import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.PatternMenuSlot @@ -31,9 +32,9 @@ class PatternStorageMenu @JvmOverloads constructor( }) } - val patterns = tile?.container ?: SimpleContainer(2 * 4) + val patterns = tile?.container ?: EnhancedContainer(2 * 4) - storageSlots = immutableList(2 * 4) { + storageSlots = immutableList(patterns.containerSize) { addStorageSlot(PatternMenuSlot(patterns, it)) } From 06f8d8838a37cfe3ece97bdba5d1f843fff59229 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 22:02:09 +0700 Subject: [PATCH 051/154] More efficient pattern storage patternCapacity and storedPatterns implementations --- .../block/entity/matter/PatternStorageBlockEntity.kt | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/PatternStorageBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/PatternStorageBlockEntity.kt index 27f0099e0..3948d6d64 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/PatternStorageBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/PatternStorageBlockEntity.kt @@ -92,20 +92,12 @@ class PatternStorageBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Ma } override val patternCapacity: Int get() { - var stored = 0L - - for (pattern in this.container.iterator().map { it.getCapability(MatteryCapability.PATTERN_ITEM) }.filterNotNull()) - stored += pattern.patternCapacity.toLong() - + val stored = container.sumOf { it.getCapability(MatteryCapability.PATTERN_ITEM)?.patternCapacity?.toLong() ?: 0L } return if (stored > Int.MAX_VALUE) Int.MAX_VALUE else stored.toInt() } override val storedPatterns: Int get() { - var stored = 0L - - for (pattern in this.container.iterator().map { it.getCapability(MatteryCapability.PATTERN_ITEM) }.filterNotNull()) - stored += pattern.storedPatterns.toLong() - + val stored = container.sumOf { it.getCapability(MatteryCapability.PATTERN_ITEM)?.storedPatterns?.toLong() ?: 0L } return if (stored > Int.MAX_VALUE) Int.MAX_VALUE else stored.toInt() } From 67fc8f99f62902201c01bf76413fd7badbc106fd Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 22:30:42 +0700 Subject: [PATCH 052/154] ooprs!! --- .../ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt | 6 +++--- .../ru/dbotthepony/mc/otm/container/ISlottedContainer.kt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt index 6edd68823..1c2a1994b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt @@ -216,7 +216,7 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable, Sta return list } - fun addItem(stack: ItemStack, simulate: Boolean, slots: IntSet = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null): ItemStack { + fun addItem(stack: ItemStack, simulate: Boolean, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null): ItemStack { if (stack.isEmpty || slots.isEmpty()) return stack @@ -277,7 +277,7 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable, Sta * * @return Whenever [stack] was modified */ - fun consumeItem(stack: ItemStack, simulate: Boolean, slots: IntSet = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null): Boolean { + fun consumeItem(stack: ItemStack, simulate: Boolean, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null): Boolean { if (stack.isEmpty || slots.isEmpty()) return false @@ -286,7 +286,7 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable, Sta return result.count != stack.count } - fun fullyAddItem(stack: ItemStack, slots: IntSet = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null): Boolean { + fun fullyAddItem(stack: ItemStack, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null): Boolean { if (!addItem(stack, true, slots, onlyIntoExisting, popTime).isEmpty) return false diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt index 92530f6a3..8e2442836 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt @@ -156,7 +156,7 @@ interface ISlottedContainer : IEnhancedContainer { override fun addItem( stack: ItemStack, simulate: Boolean, - slots: IntSet, + slots: IntCollection, onlyIntoExisting: Boolean, popTime: Int? ): ItemStack { @@ -166,14 +166,14 @@ interface ISlottedContainer : IEnhancedContainer { override fun consumeItem( stack: ItemStack, simulate: Boolean, - slots: IntSet, + slots: IntCollection, onlyIntoExisting: Boolean, popTime: Int? ): Boolean { return consumeItem(stack, simulate, slots, onlyIntoExisting, popTime, ignoreFilters = false) } - override fun fullyAddItem(stack: ItemStack, slots: IntSet, onlyIntoExisting: Boolean, popTime: Int?): Boolean { + override fun fullyAddItem(stack: ItemStack, slots: IntCollection, onlyIntoExisting: Boolean, popTime: Int?): Boolean { return fullyAddItem(stack, slots, onlyIntoExisting, popTime, ignoreFilters = false) } } From fbd34f3414473e1031daf04c1ac027fc6fe00a82 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 22:36:55 +0700 Subject: [PATCH 053/154] SimpleCache helper function --- .../entity/matter/MatterEntanglerBlockEntity.kt | 8 ++------ src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt | 13 +++++++++++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt index 82def3e57..079f70e18 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt @@ -33,6 +33,7 @@ import ru.dbotthepony.mc.otm.container.IEnhancedCraftingContainer import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer +import ru.dbotthepony.mc.otm.core.SimpleCache import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.collect.forEach import ru.dbotthepony.mc.otm.core.collect.map @@ -95,12 +96,7 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M } private inner class InputSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) { - val insertCache: Cache = Caffeine.newBuilder() - .maximumSize(1024L) - .expireAfterWrite(Duration.ofMinutes(1L)) - .scheduler(Scheduler.systemScheduler()) - .executor(Util.backgroundExecutor()) - .build() + val insertCache = SimpleCache(1024L, Duration.ofMinutes(1)) override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { if (!super.canAutomationPlaceItem(itemStack)) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt index 718e617b1..85e8b4e1c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt @@ -3,6 +3,9 @@ package ru.dbotthepony.mc.otm.core +import com.github.benmanes.caffeine.cache.Cache +import com.github.benmanes.caffeine.cache.Caffeine +import com.github.benmanes.caffeine.cache.Scheduler import com.google.common.collect.ImmutableList import com.google.common.collect.ImmutableMap import com.google.common.collect.ImmutableMultimap @@ -59,6 +62,7 @@ import java.io.InputStream import java.io.OutputStream import java.lang.ref.Reference import java.math.BigInteger +import java.time.Duration import java.util.* import java.util.concurrent.Callable import java.util.concurrent.Future @@ -655,3 +659,12 @@ fun RandomSource.nextNormalDoubles(stddev: Double, mean: Double): DoublePair { fun RandomSource.nextNormalDouble(stddev: Double, mean: Double): Double { return nextGaussian() * stddev + mean } + +fun SimpleCache(size: Long, freshness: Duration): Cache { + return Caffeine.newBuilder() + .maximumSize(size) + .scheduler(Scheduler.systemScheduler()) + .executor(Util.backgroundExecutor()) + .expireAfterWrite(freshness) + .build() +} From 3e086dcacf9d6c268135db60a74e3be9c8e7ae6f Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 22:56:26 +0700 Subject: [PATCH 054/154] Switch Powered furnaces to SlottedContainer, make them reject items which are not used in any recipe (in automation) --- .../tech/AbstractPoweredFurnaceBlockEntity.kt | 90 ++++++++++++++----- .../mc/otm/menu/tech/PoweredFurnaceMenu.kt | 14 ++- 2 files changed, 81 insertions(+), 23 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt index 6defd22b6..8afae2f5c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt @@ -29,33 +29,60 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.config.WorkerBalanceValues import ru.dbotthepony.mc.otm.container.CombinedContainer -import ru.dbotthepony.mc.otm.container.HandlerFilter -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.balance -import ru.dbotthepony.mc.otm.core.collect.filter -import ru.dbotthepony.mc.otm.core.collect.maybe +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters +import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer +import ru.dbotthepony.mc.otm.core.SimpleCache import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.otmRandom +import ru.dbotthepony.mc.otm.core.util.ItemStackKey +import ru.dbotthepony.mc.otm.core.util.asKey import ru.dbotthepony.mc.otm.menu.tech.PoweredFurnaceMenu import ru.dbotthepony.mc.otm.recipe.MatteryCookingRecipe import ru.dbotthepony.mc.otm.recipe.MicrowaveRecipe import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import ru.dbotthepony.mc.otm.registry.game.MRecipes +import java.time.Duration sealed class AbstractPoweredFurnaceBlockEntity

( type: BlockEntityType<*>, blockPos: BlockPos, blockState: BlockState, - val recipeType: RecipeType

, - val secondaryRecipeType: RecipeType?, - val config: WorkerBalanceValues, maxJobs: Int = 2 ) : MatteryWorkerBlockEntity(type, blockPos, blockState, ItemJob.CODEC, maxJobs) { + abstract val recipeType: RecipeType

+ abstract val secondaryRecipeType: RecipeType? + abstract val config: WorkerBalanceValues + final override val upgrades = makeUpgrades(2, UpgradeType.BASIC_PROCESSING) final override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyLevelUpdated, upgrades.transform(config))) - val inputs = MatteryContainer(this::itemContainerUpdated, maxJobs) - val outputs = MatteryContainer(this::itemContainerUpdated, maxJobs) + private inner class InputSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) { + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + if (!super.canAutomationPlaceItem(itemStack)) + return false + + val level = level ?: return true + + return acceptableItems.get(itemStack.asKey()) { + val input = SingleRecipeInput(itemStack) + val secondaryRecipeType = secondaryRecipeType + + if (secondaryRecipeType != null && level.recipeManager.byType(secondaryRecipeType).any { it.value.matches(input, level) }) + return@get true + + return@get level.recipeManager.byType(recipeType).any { it.value.matches(input, level) } + } + } + + override fun canAutomationTakeItem(desired: Int): Boolean { + return false + } + } + + val inputs = SlottedContainer.simple(maxJobs, ::InputSlot, ::itemContainerUpdated) + val outputs = SlottedContainer.simple(maxJobs, AutomationFilters.ONLY_OUT.simpleProvider, ::itemContainerUpdated) init { addDroppableContainer(inputs) @@ -76,8 +103,8 @@ sealed class AbstractPoweredFurnaceBlockEntity

(16384L, Duration.ofMinutes(1)) + } } -class PoweredFurnaceBlockEntity(blockPos: BlockPos, blockState: BlockState) : AbstractPoweredFurnaceBlockEntity( - MBlockEntities.POWERED_FURNACE, blockPos, blockState, RecipeType.SMELTING, null, MachinesConfig.POWERED_FURNACE) { +class PoweredFurnaceBlockEntity(blockPos: BlockPos, blockState: BlockState) : AbstractPoweredFurnaceBlockEntity(MBlockEntities.POWERED_FURNACE, blockPos, blockState) { + override val recipeType: RecipeType + get() = RecipeType.SMELTING + override val secondaryRecipeType: RecipeType? + get() = null + override val config: WorkerBalanceValues + get() = MachinesConfig.POWERED_FURNACE + override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { return PoweredFurnaceMenu.furnace(containerID, inventory, this) } } -class PoweredBlastFurnaceBlockEntity(blockPos: BlockPos, blockState: BlockState) : AbstractPoweredFurnaceBlockEntity( - MBlockEntities.POWERED_BLAST_FURNACE, blockPos, blockState, RecipeType.BLASTING, null, MachinesConfig.POWERED_FURNACE) { +class PoweredBlastFurnaceBlockEntity(blockPos: BlockPos, blockState: BlockState) : AbstractPoweredFurnaceBlockEntity(MBlockEntities.POWERED_BLAST_FURNACE, blockPos, blockState) { + override val recipeType: RecipeType + get() = RecipeType.BLASTING + override val secondaryRecipeType: RecipeType? + get() = null + override val config: WorkerBalanceValues + get() = MachinesConfig.POWERED_FURNACE + override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { return PoweredFurnaceMenu.blasting(containerID, inventory, this) } } -class PoweredSmokerBlockEntity(blockPos: BlockPos, blockState: BlockState) : AbstractPoweredFurnaceBlockEntity( - MBlockEntities.POWERED_SMOKER, blockPos, blockState, RecipeType.SMOKING, MRecipes.MICROWAVE, MachinesConfig.POWERED_FURNACE) { +class PoweredSmokerBlockEntity(blockPos: BlockPos, blockState: BlockState) : AbstractPoweredFurnaceBlockEntity(MBlockEntities.POWERED_SMOKER, blockPos, blockState) { + override val recipeType: RecipeType + get() = RecipeType.SMOKING + override val secondaryRecipeType: RecipeType + get() = MRecipes.MICROWAVE + override val config: WorkerBalanceValues + get() = MachinesConfig.POWERED_FURNACE + override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { return PoweredFurnaceMenu.smoking(containerID, inventory, this) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PoweredFurnaceMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PoweredFurnaceMenu.kt index 85739a185..f66e42b08 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PoweredFurnaceMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PoweredFurnaceMenu.kt @@ -1,19 +1,24 @@ package ru.dbotthepony.mc.otm.menu.tech +import com.google.common.collect.ImmutableList import mezz.jei.api.constants.RecipeTypes import mezz.jei.api.recipe.RecipeType import net.minecraft.server.level.ServerPlayer -import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory import net.minecraft.world.inventory.MenuType +import net.minecraft.world.item.crafting.Recipe +import net.minecraft.world.item.crafting.SingleRecipeInput import ru.dbotthepony.mc.otm.block.entity.tech.AbstractPoweredFurnaceBlockEntity import ru.dbotthepony.mc.otm.block.entity.tech.PoweredBlastFurnaceBlockEntity import ru.dbotthepony.mc.otm.block.entity.tech.PoweredFurnaceBlockEntity import ru.dbotthepony.mc.otm.block.entity.tech.PoweredSmokerBlockEntity import ru.dbotthepony.mc.otm.compat.jei.MicrowaveRecipeCategory +import ru.dbotthepony.mc.otm.container.EnhancedContainer +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.menu.OutputMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput @@ -23,6 +28,7 @@ import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.TakeExperienceWidget import ru.dbotthepony.mc.otm.registry.game.MMenus +import ru.dbotthepony.mc.otm.registry.game.MRecipes import java.util.function.Supplier class PoweredFurnaceMenu( @@ -31,8 +37,10 @@ class PoweredFurnaceMenu( inventory: Inventory, tile: AbstractPoweredFurnaceBlockEntity<*, *>? = null ) : AbstractProcessingMachineMenu(type, containerID, inventory, tile) { - val inputSlots = makeSlots(tile?.inputs ?: SimpleContainer(2), ::MatteryMenuSlot) - val outputSlots = makeSlots(tile?.outputs ?: SimpleContainer(2)) { c, s -> OutputMenuSlot(c, s) { tile?.experience?.popExperience(player as ServerPlayer) } } + // we can't make these slots to reject non-smeltable items + // since mods may add obscure recipes/ingredients which never test true on client + val inputSlots = makeSlots(tile?.inputs ?: SlottedContainer.filtered(2), ::UserFilteredMenuSlot) + val outputSlots = makeSlots(tile?.outputs ?: EnhancedContainer(2)) { c, s -> OutputMenuSlot(c, s) { tile?.experience?.popExperience(player as ServerPlayer) } } val progressGauge = immutableList(2) { ProgressGaugeWidget(this, tile?.jobEventLoops?.get(it)) } override val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig, allowPush = true) From 784930e396b92f581c603bb9ea99b5024f7b86d6 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 7 Mar 2025 09:26:54 +0700 Subject: [PATCH 055/154] Update AbstractProcessingMachineScreen to properly account for UserFilteredMenuSlot --- .../screen/tech/AbstractProcessingMachineScreen.kt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AbstractProcessingMachineScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AbstractProcessingMachineScreen.kt index 9409e8873..455788a82 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AbstractProcessingMachineScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AbstractProcessingMachineScreen.kt @@ -12,9 +12,11 @@ import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel +import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.WideProfiledPowerGaugePanel import ru.dbotthepony.mc.otm.compat.jei.isJeiLoaded +import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot import ru.dbotthepony.mc.otm.menu.tech.AbstractProcessingMachineMenu import kotlin.math.roundToInt @@ -50,9 +52,14 @@ open class AbstractProcessingMachineScreen(me row.dock = Dock.TOP row.dockBottom = 2f - SlotPanel(this, row, input).also { - it.dock = Dock.LEFT - } + if (input is UserFilteredMenuSlot) + UserFilteredSlotPanel(this, row, input).also { + it.dock = Dock.LEFT + } + else + SlotPanel(this, row, input).also { + it.dock = Dock.LEFT + } progressPanels.add(ProgressGaugePanel(this, row, progress).also { it.dock = Dock.LEFT From e3a11b3b9e6a84fa2d65a80e928db2f03375ff04 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 7 Mar 2025 09:31:58 +0700 Subject: [PATCH 056/154] Update menus to use UserFilteredSlot --- .../mc/otm/client/screen/matter/MatterDecomposerScreen.kt | 3 ++- .../mc/otm/client/screen/matter/MatterEntanglerScreen.kt | 3 ++- .../otm/client/screen/matter/MatterReconstructorScreen.kt | 6 ++---- .../dbotthepony/mc/otm/menu/matter/MatterDecomposerMenu.kt | 4 ++-- .../dbotthepony/mc/otm/menu/matter/MatterEntanglerMenu.kt | 5 +++-- .../mc/otm/menu/matter/MatterReconstructorMenu.kt | 5 ++--- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/matter/MatterDecomposerScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/matter/MatterDecomposerScreen.kt index 659f914bd..6ae193013 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/matter/MatterDecomposerScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/matter/MatterDecomposerScreen.kt @@ -8,6 +8,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel +import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledMatterGaugePanel @@ -25,7 +26,7 @@ class MatterDecomposerScreen(p_97741_: MatterDecomposerMenu, p_97742_: Inventory BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE) - SlotPanel(this, frame, menu.input, 122f, PROGRESS_SLOT_TOP) + UserFilteredSlotPanel(this, frame, menu.input, 122f, PROGRESS_SLOT_TOP) ProgressGaugePanel(this, frame, menu.progressWidget, 96f, PROGRESS_ARROW_TOP).also { it.flop = true } SlotPanel(this, frame, menu.outputMain, 74f, PROGRESS_SLOT_TOP) SlotPanel(this, frame, menu.outputStacking, 56f, PROGRESS_SLOT_TOP) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/matter/MatterEntanglerScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/matter/MatterEntanglerScreen.kt index e29d26246..1d7777813 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/matter/MatterEntanglerScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/matter/MatterEntanglerScreen.kt @@ -11,6 +11,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.SpritePanel import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel +import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel import ru.dbotthepony.mc.otm.compat.jei.MatterEntanglerRecipeCategory @@ -30,7 +31,7 @@ class MatterEntanglerScreen(menu: MatterEntanglerMenu, inventory: Inventory, tit it.dockResize = DockResizeMode.NONE for (slot in menu.inputs) - SlotPanel(this, it, slot) + UserFilteredSlotPanel(this, it, slot) } ProgressGaugePanel(this, frame, menu.progress).also { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/matter/MatterReconstructorScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/matter/MatterReconstructorScreen.kt index 7d9d99dff..2522480d6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/matter/MatterReconstructorScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/matter/MatterReconstructorScreen.kt @@ -10,9 +10,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.PlayerEquipmentPanel import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls import ru.dbotthepony.mc.otm.client.screen.panels.makeCuriosPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel -import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel -import ru.dbotthepony.mc.otm.client.screen.widget.MatterGaugePanel -import ru.dbotthepony.mc.otm.client.screen.widget.PowerGaugePanel +import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledMatterGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProfiledPowerGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel @@ -27,7 +25,7 @@ class MatterReconstructorScreen(menu: MatterReconstructorMenu, inventory: Invent BatterySlotPanel(this, frame, menu.batterySlot, LEFT_MARGIN, SLOT_TOP_UNDER_GAUGE) - SlotPanel(this, frame, menu.slot, 66f, PROGRESS_SLOT_TOP) + UserFilteredSlotPanel(this, frame, menu.slot, 66f, PROGRESS_SLOT_TOP) ProgressGaugePanel(this, frame, menu.progress, 37f, PROGRESS_ARROW_TOP) makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, itemConfig = menu.itemConfig, energyConfig = menu.energyConfig, upgrades = menu.upgrades) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterDecomposerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterDecomposerMenu.kt index 919bfc6e9..5774b6f54 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterDecomposerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterDecomposerMenu.kt @@ -9,7 +9,7 @@ import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.matter.MatterManager import ru.dbotthepony.mc.otm.menu.OutputMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu -import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.makeUpgradeSlots @@ -21,7 +21,7 @@ class MatterDecomposerMenu( inventory: Inventory, tile: MatterDecomposerBlockEntity? = null ) : MatteryPoweredMenu(MMenus.MATTER_DECOMPOSER, containerID, inventory, tile) { - val input = object : MatteryMenuSlot(tile?.inputContainer ?: SlottedContainer.filtered(1), 0) { + val input = object : UserFilteredMenuSlot(tile?.inputContainer ?: SlottedContainer.filtered(1), 0) { override fun mayPlace(itemStack: ItemStack) = MatterManager.canDecompose(itemStack) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterEntanglerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterEntanglerMenu.kt index 62eaf1120..aa99a86c9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterEntanglerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterEntanglerMenu.kt @@ -14,6 +14,7 @@ import ru.dbotthepony.mc.otm.item.IQuantumLinked import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu import ru.dbotthepony.mc.otm.menu.OutputMenuSlot +import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.makeSlots @@ -36,8 +37,8 @@ class MatterEntanglerMenu( val progress = ProgressGaugeWidget(this, tile?.jobEventLoops?.get(0)) - val inputs: List = makeSlots(tile?.inputs ?: SlottedContainer.simple(3 * 3, AutomationFilters.ALLOW.limitedFilteredProvider)) { it, i -> - object : MatteryMenuSlot(it, i) { + val inputs: List = makeSlots(tile?.inputs ?: SlottedContainer.simple(3 * 3, AutomationFilters.ALLOW.limitedFilteredProvider)) { it, i -> + object : UserFilteredMenuSlot(it, i) { override fun mayPlace(itemStack: ItemStack): Boolean { val list = it.toList() list[i] = itemStack diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReconstructorMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReconstructorMenu.kt index d91502e7c..5fe2022cc 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReconstructorMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReconstructorMenu.kt @@ -1,12 +1,11 @@ package ru.dbotthepony.mc.otm.menu.matter -import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.block.entity.matter.MatterReconstructorBlockEntity import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu -import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.makeUpgradeSlots @@ -21,7 +20,7 @@ class MatterReconstructorMenu( tile: MatterReconstructorBlockEntity? = null ) : MatteryPoweredMenu(MMenus.ITEM_REPAIER, containerId, inventory, tile) { val matterWidget = ProfiledLevelGaugeWidget(this, tile?.matter, LevelGaugeWidget(this, tile?.matter)) - val slot = object : MatteryMenuSlot(tile?.repairContainer ?: SlottedContainer.filtered(1), 0) { + val slot = object : UserFilteredMenuSlot(tile?.repairContainer ?: SlottedContainer.filtered(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.isRepairable && itemStack.isDamaged && super.mayPlace(itemStack) } From f011c1a91247ad816ffa31aad385e35bbdb71171 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 7 Mar 2025 09:38:22 +0700 Subject: [PATCH 057/154] Allow bottler slots to be filtered --- .../otm/block/entity/matter/MatterBottlerBlockEntity.kt | 5 +++-- .../mc/otm/client/screen/panels/slot/SlotPanel.kt | 9 +++++---- .../dbotthepony/mc/otm/menu/matter/MatterBottlerMenu.kt | 5 +++-- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt index e9fe053a1..485fea8b9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt @@ -25,6 +25,7 @@ import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.UpgradeContainer import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.matter.MatterBottlerMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities @@ -40,13 +41,13 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) : override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::markDirtyFast, upgrades.transform(MachinesConfig.MatterBottler.VALUES))) val energyConfig = ConfigurableEnergy(energy) - private inner class BottlingSlot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) { + private inner class BottlingSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) { override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { return super.canAutomationPlaceItem(itemStack) && isBottling && itemStack.getCapability(MatteryCapability.MATTER_ITEM)?.receiveMatterChecked(Decimal.ONE, true)?.isPositive == true } } - private inner class UnBottlingSlot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) { + private inner class UnBottlingSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) { override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { return super.canAutomationPlaceItem(itemStack) && !isBottling && itemStack.getCapability(MatteryCapability.MATTER_ITEM)?.extractMatterChecked(Decimal.ONE, true)?.isPositive == true } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/SlotPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/SlotPanel.kt index 6453b8d7b..1deb00732 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/SlotPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/SlotPanel.kt @@ -23,6 +23,7 @@ import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent +import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot import javax.annotation.Nonnull import kotlin.math.roundToInt @@ -204,7 +205,7 @@ fun , T : Slot> BatterySlotPanel( y: Float = 0f, width: Float = AbstractSlotPanel.SIZE, height: Float = AbstractSlotPanel.SIZE, -) = SlotPanel(screen, parent, slot, x, y, width, height).also { it.slotBackgroundEmpty = Widgets18.BATTERY_SLOT_BACKGROUND } +) = (if (slot is UserFilteredMenuSlot) UserFilteredSlotPanel(screen, parent, slot, x, y, width, height) else SlotPanel(screen, parent, slot, x, y, width, height)).also { it.slotBackgroundEmpty = Widgets18.BATTERY_SLOT_BACKGROUND } fun , T : Slot> EquipmentBatterySlotPanel( screen: S, @@ -214,7 +215,7 @@ fun , T : Slot> EquipmentBatterySlotPanel( y: Float = 0f, width: Float = AbstractSlotPanel.SIZE, height: Float = AbstractSlotPanel.SIZE, -) = SlotPanel(screen, parent, slot, x, y, width, height).also { it.slotBackgroundEmpty = Widgets18.EQUIPMENT_BATTERY_SLOT_BACKGROUND } +) = (if (slot is UserFilteredMenuSlot) UserFilteredSlotPanel(screen, parent, slot, x, y, width, height) else SlotPanel(screen, parent, slot, x, y, width, height)).also { it.slotBackgroundEmpty = Widgets18.EQUIPMENT_BATTERY_SLOT_BACKGROUND } fun , T : Slot> PatternSlotPanel( screen: S, @@ -224,7 +225,7 @@ fun , T : Slot> PatternSlotPanel( y: Float = 0f, width: Float = AbstractSlotPanel.SIZE, height: Float = AbstractSlotPanel.SIZE, -) = SlotPanel(screen, parent, slot, x, y, width, height).also { it.slotBackgroundEmpty = Widgets18.PATTERN_SLOT_BACKGROUND } +) = (if (slot is UserFilteredMenuSlot) UserFilteredSlotPanel(screen, parent, slot, x, y, width, height) else SlotPanel(screen, parent, slot, x, y, width, height)).also { it.slotBackgroundEmpty = Widgets18.PATTERN_SLOT_BACKGROUND } fun , T : Slot> MatterCapacitorSlotPanel( screen: S, @@ -234,4 +235,4 @@ fun , T : Slot> MatterCapacitorSlotPanel( y: Float = 0f, width: Float = AbstractSlotPanel.SIZE, height: Float = AbstractSlotPanel.SIZE, -) = SlotPanel(screen, parent, slot, x, y, width, height).also { it.slotBackgroundEmpty = Widgets18.MATTER_CAPACITOR_SLOT_BACKGROUND } +) = (if (slot is UserFilteredMenuSlot) UserFilteredSlotPanel(screen, parent, slot, x, y, width, height) else SlotPanel(screen, parent, slot, x, y, width, height)).also { it.slotBackgroundEmpty = Widgets18.MATTER_CAPACITOR_SLOT_BACKGROUND } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterBottlerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterBottlerMenu.kt index a460eec64..e21600457 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterBottlerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterBottlerMenu.kt @@ -14,6 +14,7 @@ import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot import ru.dbotthepony.mc.otm.menu.makeSlots import ru.dbotthepony.mc.otm.menu.makeUpgradeSlots import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget @@ -28,8 +29,8 @@ class MatterBottlerMenu( val progressWidget = ProgressGaugeWidget(this) val matterWidget = ProfiledLevelGaugeWidget(this, tile?.matter, LevelGaugeWidget(this, tile?.matter)) - val storageSlots: ImmutableList = makeSlots(CombinedContainer(tile?.bottling ?: SlottedContainer.simple(3), tile?.unbottling ?: SlottedContainer.simple(3))) { it, index -> - object : MatteryMenuSlot(it, index) { + val storageSlots: ImmutableList = makeSlots(CombinedContainer(tile?.bottling ?: SlottedContainer.filtered(3), tile?.unbottling ?: SlottedContainer.filtered(3))) { it, index -> + object : UserFilteredMenuSlot(it, index) { override fun mayPlace(itemStack: ItemStack): Boolean { val cap = itemStack.getCapability(MatteryCapability.MATTER_ITEM) ?: return false From bbf4e752e759a4036788612a229732c88e93cb97 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 7 Mar 2025 10:14:06 +0700 Subject: [PATCH 058/154] Fix (dis)chargeable handler filters not allowing to extract invalid items --- .../kotlin/ru/dbotthepony/mc/otm/container/HandlerFilter.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/HandlerFilter.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/HandlerFilter.kt index dbe17de88..7f1cb3421 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/HandlerFilter.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/HandlerFilter.kt @@ -93,7 +93,7 @@ interface HandlerFilter { } override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return stack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { !it.canExtract() || it.extractEnergy(Int.MAX_VALUE, true) <= 0 } ?: false + return stack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { !it.canExtract() || it.extractEnergy(Int.MAX_VALUE, true) <= 0 } ?: true } } @@ -103,7 +103,7 @@ interface HandlerFilter { } override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return stack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { !it.canReceive() || it.receiveEnergy(Int.MAX_VALUE, true) <= 0 } ?: false + return stack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { !it.canReceive() || it.receiveEnergy(Int.MAX_VALUE, true) <= 0 } ?: true } } From d88da8f2442f85af31cec18c2fc7d1ead9c72279 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 7 Mar 2025 10:15:53 +0700 Subject: [PATCH 059/154] Automation-forbidden slots are now prohibited to be extracted from --- .../mc/otm/container/IFilteredAutomatedContainerSlot.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredAutomatedContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredAutomatedContainerSlot.kt index b61234064..a94f6ba05 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredAutomatedContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredAutomatedContainerSlot.kt @@ -1,9 +1,14 @@ package ru.dbotthepony.mc.otm.container import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items interface IFilteredAutomatedContainerSlot : IFilteredContainerSlot, IAutomatedContainerSlot { override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { return super.canAutomationPlaceItem(itemStack) && testSlotFilter(itemStack) } + + override fun canAutomationTakeItem(desired: Int): Boolean { + return super.canAutomationTakeItem(desired) && (filter == null || filter !== Items.AIR) + } } From 51be2c89f43c61ca7b64557301ca5f4b52389cfd Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 7 Mar 2025 10:24:50 +0700 Subject: [PATCH 060/154] Make battery slot be filterable --- .../mc/otm/block/entity/MatteryPoweredBlockEntity.kt | 2 +- .../kotlin/ru/dbotthepony/mc/otm/menu/MatteryPoweredMenu.kt | 2 +- src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryPoweredBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryPoweredBlockEntity.kt index 7455987c3..592b64844 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryPoweredBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryPoweredBlockEntity.kt @@ -12,7 +12,7 @@ import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.Decimal abstract class MatteryPoweredBlockEntity(p_155228_: BlockEntityType<*>, p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(p_155228_, p_155229_, p_155230_) { - val batteryContainer = SlottedContainer.simple(1, AutomationFilters.DISCHARGABLE.simpleProvider, ::markDirtyFast).also(::addDroppableContainer) + val batteryContainer = SlottedContainer.simple(1, AutomationFilters.DISCHARGABLE.filteredProvider, ::markDirtyFast).also(::addDroppableContainer) open val energy: IMatteryEnergyStorage? get() = null diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryPoweredMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryPoweredMenu.kt index 2774dca95..a8853c826 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryPoweredMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryPoweredMenu.kt @@ -16,7 +16,7 @@ abstract class MatteryPoweredMenu protected constructor( tile: MatteryPoweredBlockEntity? = null ) : MatteryMenu(menuType, containerID, inventory, tile) { val energyWidget = LevelGaugeWidget(this, tile?.energy) - val batterySlot = BatteryMenuSlot(tile?.batteryContainer ?: SlottedContainer.simple(1), 0) + val batterySlot = BatteryMenuSlot(tile?.batteryContainer ?: SlottedContainer.filtered(1), 0) val redstoneConfig = EnumInputWithFeedback(this) init { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt index f14232d0e..c657e90bc 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt @@ -140,7 +140,7 @@ open class OutputMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = } } -open class BatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatteryMenuSlot(container, index, x, y) { +open class BatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : UserFilteredMenuSlot(container, index, x, y) { override fun mayPlace(itemStack: ItemStack): Boolean { return super.mayPlace(itemStack) && (itemStack.energy?.canExtract() ?: false) } From b4977ea6ae34dcf0a6a43acd85c1d62423f98947 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 7 Mar 2025 10:26:09 +0700 Subject: [PATCH 061/154] Move Battery bank to slotted container --- .../entity/tech/BatteryBankBlockEntity.kt | 34 +++++++++++++------ .../mc/otm/menu/tech/BatteryBankMenu.kt | 5 +-- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/BatteryBankBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/BatteryBankBlockEntity.kt index cd5940b7b..1707800d2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/BatteryBankBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/BatteryBankBlockEntity.kt @@ -21,6 +21,9 @@ import ru.dbotthepony.mc.otm.capability.maxEnergyStoredMattery import ru.dbotthepony.mc.otm.capability.transcieveEnergy import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.otmRandom @@ -33,22 +36,31 @@ class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte var gaugeLevel by syncher.float() private set - // 6 на 2 - val container: MatteryContainer = object : MatteryContainer(::setChanged, CAPACITY) { - override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { - super.setChanged(slot, new, old) - batteryStatus[slot].value = new.getCapability(Capabilities.EnergyStorage.ITEM) != null + private inner class Slot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) { + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + return super.canAutomationPlaceItem(itemStack) && itemStack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { it.canExtract() && it.extractEnergy(Int.MAX_VALUE, true) > 0 } == true + } + + override fun canAutomationTakeItem(desired: Int): Boolean { + return super.canAutomationTakeItem(desired) && item.getCapability(Capabilities.EnergyStorage.ITEM)?.let { !it.canExtract() || it.extractEnergy(Int.MAX_VALUE, true) <= 0 } != false + } + + override fun notifyChanged(old: ItemStack) { + super.notifyChanged(old) + + batteryStatus[slot].value = item.getCapability(Capabilities.EnergyStorage.ITEM) != null gaugeLevel = batteryLevel.percentage(maxBatteryLevel) } - override fun getMaxStackSize(): Int = 1 - }.also(::addDroppableContainer) - - val batteryStatus = immutableList(CAPACITY) { - syncher.boolean(false) + override val maxStackSize: Int + get() = 1 } - val itemConfig = ConfigurableItemHandler(inputOutput = container.handler(HandlerFilter.Dischargeable)) + // 6 на 2 + val container = SlottedContainer.simple(CAPACITY, ::Slot, ::markDirtyFast).also(::addDroppableContainer) + val batteryStatus = immutableList(CAPACITY) { syncher.boolean(false) } + + val itemConfig = ConfigurableItemHandler(inputOutput = container) init { savetables.stateful(::container, INVENTORY_KEY) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/BatteryBankMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/BatteryBankMenu.kt index 36a469139..0c35515f1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/BatteryBankMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/BatteryBankMenu.kt @@ -5,6 +5,7 @@ import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.block.entity.tech.BatteryBankBlockEntity import net.minecraft.world.SimpleContainer import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.menu.BatteryMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryMenu @@ -21,7 +22,7 @@ class BatteryBankMenu( tile: BatteryBankBlockEntity? = null, ) : MatteryMenu(MMenus.BATTERY_BANK, p_38852_, inventory, tile) { val powerLevel = ProfiledLevelGaugeWidget(this, tile?.energyConfig?.energy) - val storageSlots: List + val storageSlots: List val redstone = EnumInputWithFeedback(this, RedstoneSetting::class.java) val energyConfig = EnergyConfigPlayerInput(this, allowPull = false, allowPush = true) val itemConfig = ItemConfigPlayerInput(this, allowPull = false, allowPush = false) @@ -33,7 +34,7 @@ class BatteryBankMenu( itemConfig.with(tile.itemConfig) } - val container: Container = tile?.container ?: SimpleContainer(BatteryBankBlockEntity.CAPACITY) + val container = tile?.container ?: SlottedContainer.filtered(BatteryBankBlockEntity.CAPACITY) storageSlots = immutableList(BatteryBankBlockEntity.CAPACITY) { addStorageSlot(BatteryMenuSlot(container, it)) From ebc49b03c439d3677e0deb3ad4cadda432eefa20 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 7 Mar 2025 11:45:35 +0700 Subject: [PATCH 062/154] Replace shulker box gui --- .../otm/mixin/ShulkerBoxBlockEntityMixin.java | 16 +++++ .../mc/otm/OverdriveThatMatters.kt | 3 +- .../vanilla/AbstractVanillaChestMenu.kt | 30 ++++++++ .../mc/otm/compat/vanilla/MatteryChestMenu.kt | 72 ++++--------------- .../compat/vanilla/MatteryShulkerBoxMenu.kt | 32 +++++++++ ...ryChestScreen.kt => VanillaChestScreen.kt} | 4 +- .../mc/otm/compat/vanilla/VanillaMenuTypes.kt | 41 +++++++++++ .../overdrive_that_matters.mixins.json | 3 +- 8 files changed, 139 insertions(+), 62 deletions(-) create mode 100644 src/main/java/ru/dbotthepony/mc/otm/mixin/ShulkerBoxBlockEntityMixin.java create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/AbstractVanillaChestMenu.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryShulkerBoxMenu.kt rename src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/{MatteryChestScreen.kt => VanillaChestScreen.kt} (85%) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaMenuTypes.kt diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/ShulkerBoxBlockEntityMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/ShulkerBoxBlockEntityMixin.java new file mode 100644 index 000000000..5e44c483b --- /dev/null +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/ShulkerBoxBlockEntityMixin.java @@ -0,0 +1,16 @@ +package ru.dbotthepony.mc.otm.mixin; + +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import ru.dbotthepony.mc.otm.compat.vanilla.MatteryShulkerBoxMenu; + +@Mixin(ShulkerBoxBlockEntity.class) +public abstract class ShulkerBoxBlockEntityMixin { + @Overwrite(remap = false) + public AbstractContainerMenu createMenu(int p_59312_, Inventory p_59313_) { + return new MatteryShulkerBoxMenu(p_59312_, p_59313_, (ShulkerBoxBlockEntity) (Object) this); + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt index b020f9548..bcb33c4ef 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt @@ -44,6 +44,7 @@ import ru.dbotthepony.mc.otm.client.render.blockentity.MatterBatteryBankRenderer import ru.dbotthepony.mc.otm.compat.curios.isCuriosLoaded import ru.dbotthepony.mc.otm.compat.curios.onCuriosSlotModifiersUpdated import ru.dbotthepony.mc.otm.compat.vanilla.MatteryChestMenu +import ru.dbotthepony.mc.otm.compat.vanilla.VanillaMenuTypes import ru.dbotthepony.mc.otm.config.AndroidConfig import ru.dbotthepony.mc.otm.config.CablesConfig import ru.dbotthepony.mc.otm.config.ClientConfig @@ -127,7 +128,7 @@ object OverdriveThatMatters { MLootNumberProviders.register(MOD_BUS) StorageStack.register(MOD_BUS) - MatteryChestMenu.register(MOD_BUS) + VanillaMenuTypes.register(MOD_BUS) MCreativeTabs.initialize(MOD_BUS) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/AbstractVanillaChestMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/AbstractVanillaChestMenu.kt new file mode 100644 index 000000000..c67a3bc68 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/AbstractVanillaChestMenu.kt @@ -0,0 +1,30 @@ +package ru.dbotthepony.mc.otm.compat.vanilla + +import net.minecraft.world.Container +import net.minecraft.world.entity.player.Inventory +import net.minecraft.world.entity.player.Player +import net.minecraft.world.inventory.MenuType +import ru.dbotthepony.mc.otm.menu.MatteryMenu +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot + +abstract class AbstractVanillaChestMenu( + type: MenuType<*>, + containerId: Int, + inventory: Inventory, + val container: Container +) : MatteryMenu(type, containerId, inventory) { + abstract val rows: Int + abstract val columns: Int + + abstract val containerSlots: List + val sort = SortInput(container, playerSortSettings) + + override fun stillValid(player: Player): Boolean { + return container.stillValid(player) + } + + override fun removed(player: Player) { + super.removed(player) + container.stopOpen(player) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt index 231ef450d..25bb68fee 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt @@ -1,118 +1,74 @@ package ru.dbotthepony.mc.otm.compat.vanilla -import net.minecraft.core.registries.Registries 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 net.minecraft.world.flag.FeatureFlags import net.minecraft.world.inventory.MenuType -import net.neoforged.bus.api.IEventBus -import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent -import ru.dbotthepony.mc.otm.OverdriveThatMatters -import ru.dbotthepony.mc.otm.menu.MatteryMenu +import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.makeSlots -import ru.dbotthepony.mc.otm.registry.MDeferredRegister class MatteryChestMenu( type: MenuType<*>, containerId: Int, - inventory: Inventory, val rows: Int, val columns: Int, - val container: Container = SimpleContainer(rows * columns) -) : MatteryMenu(type, containerId, inventory) { - val chestSlots = makeSlots(container, ::MatteryMenuSlot) - val sort = SortInput(container, playerSortSettings) + inventory: Inventory, override val rows: Int, override val columns: Int, + container: Container = EnhancedContainer(rows * columns) +) : AbstractVanillaChestMenu(type, containerId, inventory, container) { + override val containerSlots = makeSlots(container, ::MatteryMenuSlot) init { require(rows * columns == container.containerSize) { "Provided container $container has different dimensions than specified rows x columns: ${container.containerSize} vs $rows x $columns (${rows * columns})" } container.startOpen(player) - addStorageSlot(chestSlots) + addStorageSlot(containerSlots) addInventorySlots() } - override fun stillValid(player: Player): Boolean { - return container.stillValid(player) - } - - override fun removed(player: Player) { - super.removed(player) - container.stopOpen(player) - } - companion object { - private val registrar = MDeferredRegister(Registries.MENU, OverdriveThatMatters.MOD_ID) - - private val GENERIC_9x1 by registrar.register("generic_9x1") { MenuType(::c9x1, FeatureFlags.VANILLA_SET) } - private val GENERIC_9x2 by registrar.register("generic_9x2") { MenuType(::c9x2, FeatureFlags.VANILLA_SET) } - private val GENERIC_9x3 by registrar.register("generic_9x3") { MenuType(::c9x3, FeatureFlags.VANILLA_SET) } - private val GENERIC_9x4 by registrar.register("generic_9x4") { MenuType(::c9x4, FeatureFlags.VANILLA_SET) } - private val GENERIC_9x5 by registrar.register("generic_9x5") { MenuType(::c9x5, FeatureFlags.VANILLA_SET) } - private val GENERIC_9x6 by registrar.register("generic_9x6") { MenuType(::c9x6, FeatureFlags.VANILLA_SET) } - private val GENERIC_3x3 by registrar.register("generic_3x3") { MenuType(::c3x3, FeatureFlags.VANILLA_SET) } - private val HOPPER by registrar.register("hopper") { MenuType(::hopper, FeatureFlags.VANILLA_SET) } - @JvmStatic @JvmOverloads fun c9x1(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(9)): MatteryChestMenu { - return MatteryChestMenu(GENERIC_9x1, containerId, inventory, 1, 9, container) + return MatteryChestMenu(VanillaMenuTypes.GENERIC_9x1, containerId, inventory, 1, 9, container) } @JvmStatic @JvmOverloads fun c9x2(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(9 * 2)): MatteryChestMenu { - return MatteryChestMenu(GENERIC_9x2, containerId, inventory, 2, 9, container) + return MatteryChestMenu(VanillaMenuTypes.GENERIC_9x2, containerId, inventory, 2, 9, container) } @JvmStatic @JvmOverloads fun c9x3(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(9 * 3)): MatteryChestMenu { - return MatteryChestMenu(GENERIC_9x3, containerId, inventory, 3, 9, container) + return MatteryChestMenu(VanillaMenuTypes.GENERIC_9x3, containerId, inventory, 3, 9, container) } @JvmStatic @JvmOverloads fun c9x4(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(9 * 4)): MatteryChestMenu { - return MatteryChestMenu(GENERIC_9x4, containerId, inventory, 4, 9, container) + return MatteryChestMenu(VanillaMenuTypes.GENERIC_9x4, containerId, inventory, 4, 9, container) } @JvmStatic @JvmOverloads fun c9x5(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(9 * 5)): MatteryChestMenu { - return MatteryChestMenu(GENERIC_9x5, containerId, inventory, 5, 9, container) + return MatteryChestMenu(VanillaMenuTypes.GENERIC_9x5, containerId, inventory, 5, 9, container) } @JvmStatic @JvmOverloads fun c9x6(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(9 * 6)): MatteryChestMenu { - return MatteryChestMenu(GENERIC_9x6, containerId, inventory, 6, 9, container) + return MatteryChestMenu(VanillaMenuTypes.GENERIC_9x6, containerId, inventory, 6, 9, container) } @JvmStatic @JvmOverloads fun c3x3(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(3 * 3)): MatteryChestMenu { - return MatteryChestMenu(GENERIC_3x3, containerId, inventory, 3, 3, container) + return MatteryChestMenu(VanillaMenuTypes.GENERIC_3x3, containerId, inventory, 3, 3, container) } @JvmStatic @JvmOverloads fun hopper(containerId: Int, inventory: Inventory, container: Container = SimpleContainer(5)): MatteryChestMenu { - return MatteryChestMenu(HOPPER, containerId, inventory, 1, 5, container) - } - - fun register(bus: IEventBus) { - registrar.register(bus) - bus.addListener(this::registerScreens) - } - - private fun registerScreens(event: RegisterMenuScreensEvent) { - event.register(GENERIC_9x1, ::MatteryChestScreen) - event.register(GENERIC_9x2, ::MatteryChestScreen) - event.register(GENERIC_9x3, ::MatteryChestScreen) - event.register(GENERIC_9x4, ::MatteryChestScreen) - event.register(GENERIC_9x5, ::MatteryChestScreen) - event.register(GENERIC_9x6, ::MatteryChestScreen) - event.register(GENERIC_3x3, ::MatteryChestScreen) - event.register(HOPPER, ::MatteryChestScreen) + return MatteryChestMenu(VanillaMenuTypes.HOPPER, containerId, inventory, 1, 5, container) } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryShulkerBoxMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryShulkerBoxMenu.kt new file mode 100644 index 000000000..01bd06a14 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryShulkerBoxMenu.kt @@ -0,0 +1,32 @@ +package ru.dbotthepony.mc.otm.compat.vanilla + +import net.minecraft.world.Container +import net.minecraft.world.entity.player.Inventory +import net.minecraft.world.item.ItemStack +import ru.dbotthepony.mc.otm.container.EnhancedContainer +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.makeSlots + +class MatteryShulkerBoxMenu( + containerId: Int, + inventory: Inventory, + container: Container = EnhancedContainer(27) +) : AbstractVanillaChestMenu(VanillaMenuTypes.SHULKER_BOX, containerId, inventory, container) { + override val containerSlots = makeSlots(container, ::Slot) + override val rows: Int + get() = 3 + override val columns: Int + get() = 9 + + init { + container.startOpen(player) + addStorageSlot(containerSlots) + addInventorySlots() + } + + class Slot(container: Container, slot: Int) : MatteryMenuSlot(container, slot) { + override fun mayPlace(stack: ItemStack): Boolean { + return super.mayPlace(stack) && stack.item.canFitInsideContainerItems() + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaChestScreen.kt similarity index 85% rename from src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestScreen.kt rename to src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaChestScreen.kt index 316a948c9..eaa1f0976 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaChestScreen.kt @@ -11,7 +11,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel -class MatteryChestScreen(menu: MatteryChestMenu, inventory: Inventory, title: Component) : MatteryScreen(menu, inventory, title) { +class VanillaChestScreen(menu: AbstractVanillaChestMenu, inventory: Inventory, title: Component) : MatteryScreen(menu, inventory, title) { override fun makeMainFrame(): FramePanel> { val frame = FramePanel.padded(this, AbstractSlotPanel.SIZE * menu.columns.coerceAtLeast(9), AbstractSlotPanel.SIZE * menu.rows + 4f, title) @@ -22,7 +22,7 @@ class MatteryChestScreen(menu: MatteryChestMenu, inventory: Inventory, title: Co grid.dock = Dock.FILL grid.gravity = RenderGravity.BOTTOM_CENTER - for (slot in menu.chestSlots) + for (slot in menu.containerSlots) SlotPanel(this, grid, slot) val controls = DeviceControls(this, frame) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaMenuTypes.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaMenuTypes.kt new file mode 100644 index 000000000..8e7c52865 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaMenuTypes.kt @@ -0,0 +1,41 @@ +package ru.dbotthepony.mc.otm.compat.vanilla + +import net.minecraft.core.registries.Registries +import net.minecraft.world.flag.FeatureFlags +import net.minecraft.world.inventory.MenuType +import net.neoforged.bus.api.IEventBus +import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent +import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.registry.MDeferredRegister + +object VanillaMenuTypes { + private val registrar = MDeferredRegister(Registries.MENU, OverdriveThatMatters.MOD_ID) + + val GENERIC_9x1 by registrar.register("generic_9x1") { MenuType(MatteryChestMenu::c9x1, FeatureFlags.VANILLA_SET) } + val GENERIC_9x2 by registrar.register("generic_9x2") { MenuType(MatteryChestMenu::c9x2, FeatureFlags.VANILLA_SET) } + val GENERIC_9x3 by registrar.register("generic_9x3") { MenuType(MatteryChestMenu::c9x3, FeatureFlags.VANILLA_SET) } + val GENERIC_9x4 by registrar.register("generic_9x4") { MenuType(MatteryChestMenu::c9x4, FeatureFlags.VANILLA_SET) } + val GENERIC_9x5 by registrar.register("generic_9x5") { MenuType(MatteryChestMenu::c9x5, FeatureFlags.VANILLA_SET) } + val GENERIC_9x6 by registrar.register("generic_9x6") { MenuType(MatteryChestMenu::c9x6, FeatureFlags.VANILLA_SET) } + val GENERIC_3x3 by registrar.register("generic_3x3") { MenuType(MatteryChestMenu::c3x3, FeatureFlags.VANILLA_SET) } + val HOPPER by registrar.register("hopper") { MenuType(MatteryChestMenu::hopper, FeatureFlags.VANILLA_SET) } + + val SHULKER_BOX by registrar.register("shulker_box") { MenuType(::MatteryShulkerBoxMenu, FeatureFlags.VANILLA_SET) } + + fun register(bus: IEventBus) { + registrar.register(bus) + bus.addListener(this::registerScreens) + } + + private fun registerScreens(event: RegisterMenuScreensEvent) { + event.register(GENERIC_9x1, ::VanillaChestScreen) + event.register(GENERIC_9x2, ::VanillaChestScreen) + event.register(GENERIC_9x3, ::VanillaChestScreen) + event.register(GENERIC_9x4, ::VanillaChestScreen) + event.register(GENERIC_9x5, ::VanillaChestScreen) + event.register(GENERIC_9x6, ::VanillaChestScreen) + event.register(GENERIC_3x3, ::VanillaChestScreen) + event.register(HOPPER, ::VanillaChestScreen) + event.register(SHULKER_BOX, ::VanillaChestScreen) + } +} diff --git a/src/main/resources/overdrive_that_matters.mixins.json b/src/main/resources/overdrive_that_matters.mixins.json index f317fa83a..8cc7a2020 100644 --- a/src/main/resources/overdrive_that_matters.mixins.json +++ b/src/main/resources/overdrive_that_matters.mixins.json @@ -19,7 +19,8 @@ "DispenserBlockEntityMixin", "GuiGraphicsMixin", "BlockStateBaseMixin", - "LevelMixin" + "LevelMixin", + "ShulkerBoxBlockEntityMixin" ], "client": [ "MixinGameRenderer", From 4107ec2313fde375e866544034f2f908c6dad55b Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 7 Mar 2025 18:33:29 +0700 Subject: [PATCH 063/154] Update Chemical generator to use SlottedContainer --- .../tech/ChemicalGeneratorBlockEntity.kt | 18 ++++++++---------- .../screen/tech/ChemicalGeneratorScreen.kt | 3 ++- .../mc/otm/menu/tech/ChemicalGeneratorMenu.kt | 10 ++++++---- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ChemicalGeneratorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ChemicalGeneratorBlockEntity.kt index 1c9214737..784e74320 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ChemicalGeneratorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ChemicalGeneratorBlockEntity.kt @@ -14,6 +14,8 @@ import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.tech.ChemicalGeneratorMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import ru.dbotthepony.mc.otm.core.math.Decimal @@ -23,20 +25,16 @@ class ChemicalGeneratorBlockEntity(pos: BlockPos, state: BlockState) : MatteryDe return ChemicalGeneratorMenu(containerID, inventory, this) } - val batteryContainer = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer) - val residueContainer = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer) - val fuelContainer = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer) - - val batteryItemHandler = batteryContainer.handler(HandlerFilter.Chargeable) - val residueItemHandler = residueContainer.handler(HandlerFilter.OnlyOut) - val fuelItemHandler = fuelContainer.handler(HandlerFilter.ChemicalFuel) + val batteryContainer = SlottedContainer.simple(1, AutomationFilters.DISCHARGABLE.filteredProvider, ::markDirtyFast).also(::addDroppableContainer) + val residueContainer = SlottedContainer.simple(1, AutomationFilters.ONLY_OUT.simpleProvider, ::markDirtyFast).also(::addDroppableContainer) + val fuelContainer = SlottedContainer.simple(1, AutomationFilters.CHEMICAL_FUEL.filteredProvider, ::markDirtyFast).also(::addDroppableContainer) val energy = ProfiledEnergyStorage(GeneratorEnergyStorage(::markDirtyFast, MachinesConfig.ChemicalGenerator.VALUES::energyCapacity, MachinesConfig.ChemicalGenerator.VALUES::energyThroughput)) val itemConfig = ConfigurableItemHandler( - input = fuelItemHandler, - output = residueItemHandler, - battery = batteryItemHandler, + input = fuelContainer, + output = residueContainer, + battery = batteryContainer, backDefault = ItemHandlerMode.BATTERY) val energyConfig = ConfigurableEnergy(energy) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/ChemicalGeneratorScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/ChemicalGeneratorScreen.kt index c56e2283c..2e631ddc0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/ChemicalGeneratorScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/ChemicalGeneratorScreen.kt @@ -9,6 +9,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel +import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.WideProfiledPowerGaugePanel import ru.dbotthepony.mc.otm.menu.tech.ChemicalGeneratorMenu @@ -35,7 +36,7 @@ class ChemicalGeneratorScreen(menu: ChemicalGeneratorMenu, inventory: Inventory, progress.setRecipeType { listOf(RecipeTypes.FUELING) } SlotPanel(this, frame, menu.residueSlot, 56f, PROGRESS_SLOT_TOP) - SlotPanel(this, frame, menu.fuelSlot, 104f, PROGRESS_SLOT_TOP) + UserFilteredSlotPanel(this, frame, menu.fuelSlot, 104f, PROGRESS_SLOT_TOP) makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, itemConfig = menu.itemConfig, energyConfig = menu.energyConfig) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ChemicalGeneratorMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ChemicalGeneratorMenu.kt index f5bffee67..3e2c08051 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ChemicalGeneratorMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ChemicalGeneratorMenu.kt @@ -1,6 +1,5 @@ package ru.dbotthepony.mc.otm.menu.tech -import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory import net.minecraft.world.item.ItemStack import net.neoforged.neoforge.capabilities.Capabilities @@ -8,8 +7,11 @@ import ru.dbotthepony.kommons.util.getValue import ru.dbotthepony.kommons.util.setValue import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.block.entity.tech.ChemicalGeneratorBlockEntity +import ru.dbotthepony.mc.otm.container.EnhancedContainer +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput @@ -30,19 +32,19 @@ class ChemicalGeneratorMenu @JvmOverloads constructor(id: Int, inv: Inventory, t } } - val fuelSlot = object : MatteryMenuSlot(tile?.fuelContainer ?: SimpleContainer(1), 0) { + val fuelSlot = object : UserFilteredMenuSlot(tile?.fuelContainer ?: SlottedContainer.filtered(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.getBurnTime(null) > 0 } } - val residueSlot = object : MatteryMenuSlot(tile?.residueContainer ?: SimpleContainer(1), 0) { + val residueSlot = object : MatteryMenuSlot(tile?.residueContainer ?: EnhancedContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return false } } - val batterySlot = object : MatteryMenuSlot(tile?.batteryContainer ?: SimpleContainer(1), 0) { + val batterySlot = object : UserFilteredMenuSlot(tile?.batteryContainer ?: SlottedContainer.filtered(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.getCapability(Capabilities.EnergyStorage.ITEM)?.canReceive() ?: false } From 762926d2cc118800b7f5050cc0f2e3f566c6913d Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 7 Mar 2025 18:48:52 +0700 Subject: [PATCH 064/154] Update Cobblestone generator to use SlottedContainer --- .../mc/otm/block/entity/tech/CobblerBlockEntity.kt | 6 ++++-- .../ru/dbotthepony/mc/otm/menu/tech/CobblerMenu.kt | 10 ++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/CobblerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/CobblerBlockEntity.kt index a54b1a092..b575ae8dd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/CobblerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/CobblerBlockEntity.kt @@ -13,6 +13,8 @@ import ru.dbotthepony.mc.otm.block.entity.JobStatus import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.tech.CobblerMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities @@ -22,8 +24,8 @@ class CobblerBlockEntity(blockPos: BlockPos, blockState: BlockState) return CobblerMenu(containerID, inventory, this) } - val container = MatteryContainer(this::itemContainerUpdated, CONTAINER_SIZE).also(::addDroppableContainer) - val itemConfig = ConfigurableItemHandler(output = container.handler(HandlerFilter.OnlyOut)) + val container = SlottedContainer.simple(CONTAINER_SIZE, AutomationFilters.ONLY_OUT.simpleProvider, ::itemContainerUpdated).also(::addDroppableContainer) + val itemConfig = ConfigurableItemHandler(output = container) init { savetables.stateful(::container, INVENTORY_KEY) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/CobblerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/CobblerMenu.kt index 272fcc3cb..a7258ace0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/CobblerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/CobblerMenu.kt @@ -1,29 +1,31 @@ package ru.dbotthepony.mc.otm.menu.tech -import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.block.entity.tech.CobblerBlockEntity -import ru.dbotthepony.mc.otm.core.immutableList +import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.menu.OutputMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput +import ru.dbotthepony.mc.otm.menu.makeSlots import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget import ru.dbotthepony.mc.otm.registry.game.MMenus -class CobblerMenu @JvmOverloads constructor( +class CobblerMenu( p_38852_: Int, inventory: Inventory, tile: CobblerBlockEntity? = null ) : MatteryMenu(MMenus.COBBLESTONE_GENERATOR, p_38852_, inventory, tile) { - val storageSlots = (tile?.container ?: SimpleContainer(CobblerBlockEntity.CONTAINER_SIZE)).let { c -> immutableList(c.containerSize) { addStorageSlot(OutputMenuSlot(c, it)) } } + val storageSlots = makeSlots(tile?.container ?: EnhancedContainer(CobblerBlockEntity.CONTAINER_SIZE), ::OutputMenuSlot) val redstone = EnumInputWithFeedback(this) val itemConfig = ItemConfigPlayerInput(this) val progress = ProgressGaugeWidget(this) init { + addStorageSlot(storageSlots) + if (tile != null) { progress.with(tile.jobEventLoops[0]) redstone.with(tile.redstoneControl::redstoneSetting) From 54c2964debd26efffb059a0e4d0ad60da008dcda Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 7 Mar 2025 19:17:34 +0700 Subject: [PATCH 065/154] Update Energy servo to use SlottedContainer, merge EnergyContainerInputMenuSlot into BatteryMenuSlot --- .../block/entity/tech/EnergyHatchBlockEntity.kt | 15 ++++++++------- .../kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt | 14 ++++++-------- .../mc/otm/menu/tech/EnergyHatchMenu.kt | 13 ++++++++----- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyHatchBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyHatchBlockEntity.kt index 4e6dfd6ca..d9a8c7517 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyHatchBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyHatchBlockEntity.kt @@ -18,6 +18,8 @@ import ru.dbotthepony.mc.otm.config.EnergyBalanceValues import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.RelativeSide import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag import ru.dbotthepony.mc.otm.menu.tech.EnergyHatchMenu @@ -32,13 +34,12 @@ class EnergyHatchBlockEntity( ) : MatteryDeviceBlockEntity(type, blockPos, blockState) { val energy = ProfiledEnergyStorage(BlockEnergyStorageImpl(this::markDirtyFast, FlowDirection.input(isInput), capacity)) - val container = object : MatteryContainer(::markDirtyFast, CAPACITY) { - override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int { - return 1 - } - }.also(::addDroppableContainer) + val container = SlottedContainer.simple( + CAPACITY, + if (isInput) AutomationFilters.DISCHARGABLE.limitedFilteredProvider else AutomationFilters.CHARGEABLE.limitedFilteredProvider, + ::markDirtyFast + ).also(::addDroppableContainer) - val itemHandler = container.handler(if (isInput) HandlerFilter.Dischargeable else HandlerFilter.Chargeable) private val neighbours = ArrayList>() init { @@ -47,7 +48,7 @@ class EnergyHatchBlockEntity( // it would cause a lot of frustration if hatches accept stuff only though one face exposeEnergyGlobally(energy) - exposeGlobally(Capabilities.ItemHandler.BLOCK, itemHandler) + exposeGlobally(Capabilities.ItemHandler.BLOCK, container) if (!isInput) { for (side in RelativeSide.entries) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt index c657e90bc..9042393d5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt @@ -140,9 +140,13 @@ open class OutputMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = } } -open class BatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : UserFilteredMenuSlot(container, index, x, y) { +open class BatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = 0, val direction: FlowDirection = FlowDirection.BI_DIRECTIONAL) : UserFilteredMenuSlot(container, index, x, y) { override fun mayPlace(itemStack: ItemStack): Boolean { - return super.mayPlace(itemStack) && (itemStack.energy?.canExtract() ?: false) + if (!super.mayPlace(itemStack)) + return false + + val energy = itemStack.energy ?: return false + return direction.test(FlowDirection.of(energy.canReceive(), energy.canExtract())) } } @@ -158,12 +162,6 @@ open class ChargeMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = } } -open class EnergyContainerInputMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = 0, val direction: FlowDirection = FlowDirection.BI_DIRECTIONAL) : MatteryMenuSlot(container, index, x, y) { - override fun mayPlace(itemStack: ItemStack): Boolean { - return super.mayPlace(itemStack) && (itemStack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { direction.test(FlowDirection.of(it.canReceive(), it.canExtract())) } ?: false) - } -} - open class MatterContainerInputMenuSlot( container: Container, index: Int, diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyHatchMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyHatchMenu.kt index 4a97d460f..e4f8c4c0e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyHatchMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyHatchMenu.kt @@ -1,12 +1,12 @@ package ru.dbotthepony.mc.otm.menu.tech -import net.minecraft.world.Container -import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.block.entity.tech.EnergyHatchBlockEntity import ru.dbotthepony.mc.otm.capability.FlowDirection -import ru.dbotthepony.mc.otm.menu.EnergyContainerInputMenuSlot +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer +import ru.dbotthepony.mc.otm.menu.BatteryMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.makeSlots @@ -19,10 +19,13 @@ class EnergyHatchMenu( inventory: Inventory, tile: EnergyHatchBlockEntity? = null ) : MatteryMenu(if (isInput) MMenus.ENERGY_INPUT_HATCH else MMenus.ENERGY_OUTPUT_HATCH, containerId, inventory, tile) { - val container: Container = tile?.container ?: SimpleContainer(EnergyHatchBlockEntity.CAPACITY) + val container = tile?.container ?: SlottedContainer.simple( + EnergyHatchBlockEntity.CAPACITY, + if (isInput) AutomationFilters.DISCHARGABLE.limitedFilteredProvider else AutomationFilters.CHARGEABLE.limitedFilteredProvider + ) val inputSlots = makeSlots(container) { a, b -> - EnergyContainerInputMenuSlot(a, b, direction = FlowDirection.input(isInput)) + BatteryMenuSlot(a, b, direction = FlowDirection.input(isInput)) } val gauge = ProfiledLevelGaugeWidget(this, tile?.energy) From 101bf52113e001810c0dcb2719a2436e57ac7ecd Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 7 Mar 2025 19:53:09 +0700 Subject: [PATCH 066/154] Update Energy servo to use SlottedContainer, as well as make it behave better with automation --- .../entity/tech/EnergyServoBlockEntity.kt | 14 +++++------ .../mc/otm/menu/tech/EnergyServoMenu.kt | 23 +++++-------------- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyServoBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyServoBlockEntity.kt index 4cf96e086..67a707821 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyServoBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyServoBlockEntity.kt @@ -17,13 +17,17 @@ import ru.dbotthepony.mc.otm.capability.maxEnergyStoredMattery import ru.dbotthepony.mc.otm.capability.receiveEnergy import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters +import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer +import ru.dbotthepony.mc.otm.container.slotted.and import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.menu.tech.EnergyServoMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities class EnergyServoBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.ENERGY_SERVO, blockPos, blockState) { - val discharge = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer) - val charge = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer) + val discharge = SlottedContainer.simple(1, AutomationFilters.DISCHARGABLE.filteredProvider, ::markDirtyFast).also(::addDroppableContainer) + val charge = SlottedContainer.simple(1, AutomationFilters.CHARGEABLE.filteredProvider, ::markDirtyFast).also(::addDroppableContainer) val energy: ProfiledEnergyStorage = ProfiledEnergyStorage(object : IMatteryEnergyStorage { override val energyFlow: FlowDirection get() { @@ -61,11 +65,7 @@ class EnergyServoBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte }) val energyConfig = ConfigurableEnergy(energy, possibleModes = FlowDirection.BI_DIRECTIONAL) - - val itemConfig = ConfigurableItemHandler( - input = charge.handler(HandlerFilter.OnlyIn.and(HandlerFilter.Chargeable)), - output = discharge.handler(HandlerFilter.OnlyOut.and(HandlerFilter.Dischargeable)) - ) + val itemConfig = ConfigurableItemHandler(input = charge, output = discharge) init { savetables.stateful(::charge) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyServoMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyServoMenu.kt index 73b7568d3..61cdd9018 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyServoMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyServoMenu.kt @@ -1,36 +1,25 @@ package ru.dbotthepony.mc.otm.menu.tech -import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory -import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.block.entity.tech.EnergyServoBlockEntity -import ru.dbotthepony.mc.otm.capability.energy +import ru.dbotthepony.mc.otm.capability.FlowDirection +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer +import ru.dbotthepony.mc.otm.menu.BatteryMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryMenu -import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.registry.game.MMenus -class EnergyServoMenu @JvmOverloads constructor( +class EnergyServoMenu( p_38852_: Int, inventory: Inventory, tile: EnergyServoBlockEntity? = null ) : MatteryMenu(MMenus.ENERGY_SERVO, p_38852_, inventory, tile) { - val dischargeSlot = object : MatteryMenuSlot(tile?.discharge ?: SimpleContainer(1), 0) { - override fun mayPlace(itemStack: ItemStack): Boolean { - return super.mayPlace(itemStack) && (itemStack.energy?.canExtract() ?: false) - } - } - - val chargeSlot = object : MatteryMenuSlot(tile?.charge ?: SimpleContainer(1), 0) { - override fun mayPlace(itemStack: ItemStack): Boolean { - return super.mayPlace(itemStack) && (itemStack.energy?.canReceive() ?: false) - } - } - + val dischargeSlot = BatteryMenuSlot(tile?.discharge ?: SlottedContainer.filtered(1), 0, direction = FlowDirection.OUTPUT) + val chargeSlot = BatteryMenuSlot(tile?.charge ?: SlottedContainer.filtered(1), 0, direction = FlowDirection.INPUT) val equipment = makeEquipmentSlots(mapMoveToExternal = true) val powerGauge = ProfiledLevelGaugeWidget(this, tile?.energy) From 847ec819287e97628f926199c943e92e58452883 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Mon, 10 Mar 2025 09:58:42 +0700 Subject: [PATCH 067/154] Use moveEnergy in Energy Servo --- .../block/entity/tech/EnergyServoBlockEntity.kt | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyServoBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyServoBlockEntity.kt index 67a707821..b40910235 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyServoBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyServoBlockEntity.kt @@ -14,6 +14,7 @@ import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energyStoredMattery import ru.dbotthepony.mc.otm.capability.extractEnergy import ru.dbotthepony.mc.otm.capability.maxEnergyStoredMattery +import ru.dbotthepony.mc.otm.capability.moveEnergy import ru.dbotthepony.mc.otm.capability.receiveEnergy import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter @@ -89,19 +90,7 @@ class EnergyServoBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte val chargeEnergy = charge.energy ?: return val dischargeEnergy = discharge.energy ?: return - val extracted = dischargeEnergy.extractEnergy(Decimal.LONG_MAX_VALUE, true) - - if (extracted.isPositive) { - val received = chargeEnergy.receiveEnergy(extracted, true) - - if (received.isPositive) { - val extracted2 = dischargeEnergy.extractEnergy(received, false) - - if (extracted2 == received) { - chargeEnergy.receiveEnergy(dischargeEnergy.extractEnergy(received, false), false) - } - } - } + moveEnergy(source = dischargeEnergy, destination = chargeEnergy, amount = Decimal.LONG_MAX_VALUE, simulate = false) } } } From 17e4856b100d9b9a5148a40b30e2f98a13a60c6e Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Mon, 10 Mar 2025 15:29:50 +0700 Subject: [PATCH 068/154] Use SlottedContainer in Essense Storage --- .../entity/tech/EssenceStorageBlockEntity.kt | 47 +++++++++++-------- .../screen/tech/EssenceStorageScreen.kt | 5 +- .../mc/otm/container/EnhancedContainer.kt | 9 ++++ .../mc/otm/menu/tech/EssenceStorageMenu.kt | 9 ++-- 4 files changed, 46 insertions(+), 24 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt index 9695e8dea..22db89523 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt @@ -23,8 +23,12 @@ import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.block.tech.EssenceStorageBlock import ru.dbotthepony.mc.otm.capability.item.CombinedItemHandler import ru.dbotthepony.mc.otm.config.MachinesConfig +import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.getEntitiesInEllipsoid import ru.dbotthepony.mc.otm.core.lookupOrThrow import ru.dbotthepony.mc.otm.core.math.Vector @@ -45,9 +49,29 @@ class EssenceStorageBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma markDirtyFast() } - val capsuleContainer = MatteryContainer(::markDirtyFast, 1) - val servoContainer = MatteryContainer(::markDirtyFast, 1) - val mendingContainer = MatteryContainer(::markDirtyFast, 1).also(::addDroppableContainer) + private class CapsuleSlot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) { + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + return super.canAutomationPlaceItem(itemStack) && itemStack.item is EssenceCapsuleItem + } + + override fun canAutomationTakeItem(desired: Int): Boolean { + return false + } + } + + private inner class MendingSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) { + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + return super.canAutomationPlaceItem(itemStack) && itemStack.isDamaged && itemStack.getEnchantmentLevel(mending!!) > 0 + } + + override fun canAutomationTakeItem(desired: Int): Boolean { + return super.canAutomationTakeItem(desired) && (!item.isDamaged || experienceStored <= 0) + } + } + + val capsuleContainer = SlottedContainer.simple(1, ::CapsuleSlot, ::markDirtyFast) + val servoContainer = EnhancedContainer.withListener(1, ::markDirtyFast) + val mendingContainer = SlottedContainer.simple(1, ::MendingSlot, ::markDirtyFast).also(::addDroppableContainer) private var mending: Holder? = null @@ -63,22 +87,7 @@ class EssenceStorageBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma } val itemConfig = ConfigurableItemHandler( - inputOutput = CombinedItemHandler( - capsuleContainer.handler(HandlerFilter.OnlyIn.and(object : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return stack.item is EssenceCapsuleItem - } - })), - mendingContainer.handler(object : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return stack.isDamaged && stack.getEnchantmentLevel(mending!!) > 0 - } - - override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return !stack.isDamaged || experienceStored <= 0 - } - }) - ) + inputOutput = CombinedItemHandler(capsuleContainer, mendingContainer) ) override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/EssenceStorageScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/EssenceStorageScreen.kt index 3bab0a1a5..46a1d4ed4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/EssenceStorageScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/EssenceStorageScreen.kt @@ -21,6 +21,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.button.ButtonPanel import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls import ru.dbotthepony.mc.otm.client.screen.panels.input.TextInputPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel +import ru.dbotthepony.mc.otm.client.screen.panels.slot.UserFilteredSlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.util.HorizontalStripPanel import ru.dbotthepony.mc.otm.core.ResourceLocation import ru.dbotthepony.mc.otm.core.TextComponent @@ -279,7 +280,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title get() = SET_EXACT override fun onClick(mouseButton: Int) { - val player = minecraft!!.player!! ?: return + val player = minecraft!!.player!! if (player.experienceLevel == customDispense) { if (player.experienceProgress > 0f) { @@ -297,7 +298,7 @@ class EssenceStorageScreen(menu: EssenceStorageMenu, inventory: Inventory, title set(_) {} } - SlotPanel(this, inputs, menu.mendingSlot).also { + UserFilteredSlotPanel(this, inputs, menu.mendingSlot).also { it.dock = Dock.LEFT it.tooltips.add(TranslatableComponent("enchantment.minecraft.mending").withStyle(ChatFormatting.GRAY)) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt index f3a4defd5..5f2f6c508 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt @@ -186,5 +186,14 @@ open class EnhancedContainer(private val size: Int) : IEnhancedContainer, INBTSe companion object { private val LOGGER = LogManager.getLogger() + + fun withListener(slots: Int, listener: Runnable): EnhancedContainer { + return object : EnhancedContainer(slots) { + override fun notifySlotChanged(slot: Int, old: ItemStack) { + super.notifySlotChanged(slot, old) + listener.run() + } + } + } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EssenceStorageMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EssenceStorageMenu.kt index a80d14515..f3c4258fd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EssenceStorageMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EssenceStorageMenu.kt @@ -9,11 +9,14 @@ import net.minecraft.world.item.enchantment.EnchantmentHelper import ru.dbotthepony.kommons.util.getValue import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.block.entity.tech.EssenceStorageBlockEntity +import ru.dbotthepony.mc.otm.container.EnhancedContainer +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.util.getTotalXpRequiredForLevel import ru.dbotthepony.mc.otm.item.consumables.EssenceCapsuleItem import ru.dbotthepony.mc.otm.item.EssenceServoItem import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.FluidConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.ItemConfigPlayerInput @@ -31,19 +34,19 @@ class EssenceStorageMenu( val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig) val fluidConfig = FluidConfigPlayerInput(this, tile?.fluidConfig) - val capsuleSlot = object : MatteryMenuSlot(tile?.capsuleContainer ?: SimpleContainer(1), 0) { + val capsuleSlot = object : MatteryMenuSlot(tile?.capsuleContainer ?: EnhancedContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.item is EssenceCapsuleItem && super.mayPlace(itemStack) } } - val servoSlot = object : MatteryMenuSlot(tile?.servoContainer ?: SimpleContainer(1), 0) { + val servoSlot = object : MatteryMenuSlot(tile?.servoContainer ?: EnhancedContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.item == MItems.ESSENCE_SERVO && super.mayPlace(itemStack) } } - val mendingSlot = object : MatteryMenuSlot(tile?.mendingContainer ?: SimpleContainer(1), 0) { + val mendingSlot = object : UserFilteredMenuSlot(tile?.mendingContainer ?: SlottedContainer.filtered(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.isDamaged && EnchantmentHelper.has(itemStack, EnchantmentEffectComponents.REPAIR_WITH_XP) } From 5e1ae7e77d60c553bcccac03ab0603b40b45e23f Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Mon, 10 Mar 2025 15:30:50 +0700 Subject: [PATCH 069/154] Handle negative experience stored in essence capsules --- .../mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt index 22db89523..5f21b8da5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt @@ -40,6 +40,7 @@ import ru.dbotthepony.mc.otm.menu.tech.EssenceStorageMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import ru.dbotthepony.mc.otm.registry.game.MDataComponentTypes import ru.dbotthepony.mc.otm.registry.game.MFluids +import kotlin.math.max class EssenceStorageBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.ESSENCE_STORAGE, blockPos, blockState), IFluidHandler { var experienceStored = 0L @@ -169,7 +170,7 @@ class EssenceStorageBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma val capsule = capsuleContainer[0] if (!capsule.isEmpty && capsule.has(MDataComponentTypes.EXPERIENCE)) { - experienceStored += capsule.get(MDataComponentTypes.EXPERIENCE)!! * capsule.count + experienceStored += max(capsule.get(MDataComponentTypes.EXPERIENCE)!! * capsule.count, 0L) capsuleContainer.clearContent() } From 1f8cd2cfe39c88ab7dab212d4496cb5dddbe8c35 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Tue, 11 Mar 2025 16:50:48 +0700 Subject: [PATCH 070/154] Update Plate press to use SlottedContainer --- .../block/entity/tech/ItemHatchBlockEntity.kt | 7 +-- .../entity/tech/PlatePressBlockEntity.kt | 48 ++++++++++++++++--- .../mc/otm/menu/tech/PlatePressMenu.kt | 6 ++- 3 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ItemHatchBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ItemHatchBlockEntity.kt index 8ebffbb02..2f40e9a0b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ItemHatchBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ItemHatchBlockEntity.kt @@ -11,6 +11,8 @@ import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag import ru.dbotthepony.mc.otm.menu.tech.ItemHatchMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities @@ -21,12 +23,11 @@ class ItemHatchBlockEntity( blockPos: BlockPos, blockState: BlockState ) : MatteryDeviceBlockEntity(type, blockPos, blockState) { - val container = MatteryContainer(this::markDirtyFast, CAPACITY).also(::addDroppableContainer) - val itemHandler = container.handler(if (isInput) HandlerFilter.OnlyIn else HandlerFilter.OnlyOut) + val container = SlottedContainer.simple(CAPACITY, if (isInput) AutomationFilters.ONLY_IN.filteredProvider else AutomationFilters.ONLY_OUT.filteredProvider, this::markDirtyFast).also(::addDroppableContainer) init { savetables.stateful(::container, INVENTORY_KEY) - exposeGlobally(Capabilities.ItemHandler.BLOCK, itemHandler) + exposeGlobally(Capabilities.ItemHandler.BLOCK, container) } override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt index bc8c6e1aa..934eb8cb9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt @@ -5,6 +5,8 @@ import net.minecraft.core.BlockPos import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player import net.minecraft.world.inventory.AbstractContainerMenu +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.crafting.SingleRecipeInput import net.minecraft.world.level.block.state.BlockState import net.neoforged.neoforge.capabilities.Capabilities import ru.dbotthepony.mc.otm.block.entity.ExperienceStorage @@ -19,12 +21,20 @@ import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.balance +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters +import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer +import ru.dbotthepony.mc.otm.core.SimpleCache +import ru.dbotthepony.mc.otm.core.collect.any import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.collect.maybe import ru.dbotthepony.mc.otm.core.otmRandom +import ru.dbotthepony.mc.otm.core.util.ItemStackKey +import ru.dbotthepony.mc.otm.core.util.asKey import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import ru.dbotthepony.mc.otm.registry.game.MRecipes +import java.time.Duration class PlatePressBlockEntity( blockPos: BlockPos, @@ -33,14 +43,36 @@ class PlatePressBlockEntity( ) : MatteryWorkerBlockEntity(if (isTwin) MBlockEntities.TWIN_PLATE_PRESS else MBlockEntities.PLATE_PRESS, blockPos, blockState, ItemJob.CODEC, if (isTwin) 2 else 1) { override val upgrades = makeUpgrades(if (isTwin) 4 else 3, UpgradeType.BASIC_PROCESSING) override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyLevelUpdated, upgrades.transform(MachinesConfig.PLATE_PRESS))) - val inputContainer = MatteryContainer(this::itemContainerUpdated, if (isTwin) 2 else 1).also(::addDroppableContainer) - val outputContainer = MatteryContainer(this::itemContainerUpdated, if (isTwin) 2 else 1).also(::addDroppableContainer) + + private inner class InputSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) { + override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { + if (!super.canAutomationPlaceItem(itemStack)) + return false + + val level = level ?: return true + val input = SingleRecipeInput(itemStack) + + return cache.get(itemStack.asKey()) { + return@get level.recipeManager + .byType(MRecipes.PLATE_PRESS) + .any { it.value.matches(input, level) } + } + } + + override fun canAutomationTakeItem(desired: Int): Boolean { + return false + } + } + + val inputContainer = SlottedContainer.simple(if (isTwin) 2 else 1, ::InputSlot, this::itemContainerUpdated).also(::addDroppableContainer) + val outputContainer = SlottedContainer.simple(if (isTwin) 2 else 1, AutomationFilters.ONLY_OUT.simpleProvider, this::itemContainerUpdated).also(::addDroppableContainer) val experience = ExperienceStorage(MachinesConfig.PLATE_PRESS::maxExperienceStored).also(::addNeighbourListener) val energyConfig = ConfigurableEnergy(energy) + val itemConfig = ConfigurableItemHandler( - input = inputContainer.handler(HandlerFilter.OnlyIn), - output = outputContainer.handler(HandlerFilter.OnlyOut), + input = inputContainer, + output = outputContainer, ) init { @@ -76,9 +108,7 @@ class PlatePressBlockEntity( val recipe = level.recipeManager .byType(MRecipes.PLATE_PRESS) - .iterator() - .filter { it.value.matches(inputContainer, id) } - .maybe()?.value ?: return JobContainer.noItem() + .firstOrNull { it.value.matches(inputContainer, id) }?.value ?: return JobContainer.noItem() val toProcess = inputContainer[id].count.coerceAtMost(1 + upgrades.processingItems) @@ -100,4 +130,8 @@ class PlatePressBlockEntity( super.tick() } + + companion object { + private val cache = SimpleCache(16384L, Duration.ofMinutes(1L)) + } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PlatePressMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PlatePressMenu.kt index e18661ad1..052984a6c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PlatePressMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PlatePressMenu.kt @@ -7,6 +7,8 @@ import net.minecraft.world.entity.player.Inventory import net.minecraft.world.inventory.MenuType import ru.dbotthepony.mc.otm.block.entity.tech.PlatePressBlockEntity import ru.dbotthepony.mc.otm.compat.jei.PlatePressRecipeCategory +import ru.dbotthepony.mc.otm.container.EnhancedContainer +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.menu.OutputMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot @@ -28,8 +30,8 @@ class PlatePressMenu( tile: PlatePressBlockEntity? = null, isTwin: Boolean ) : AbstractProcessingMachineMenu(type, containerID, inventory, tile) { - val inputSlots = makeSlots(tile?.inputContainer ?: SimpleContainer(if (isTwin) 2 else 1), ::MatteryMenuSlot) - val outputSlots = makeSlots(tile?.outputContainer ?: SimpleContainer(if (isTwin) 2 else 1)) { a, b -> OutputMenuSlot(a, b) { tile?.experience?.popExperience(player as ServerPlayer) } } + val inputSlots = makeSlots(tile?.inputContainer ?: SlottedContainer.filtered(if (isTwin) 2 else 1), ::MatteryMenuSlot) + val outputSlots = makeSlots(tile?.outputContainer ?: EnhancedContainer(if (isTwin) 2 else 1)) { a, b -> OutputMenuSlot(a, b) { tile?.experience?.popExperience(player as ServerPlayer) } } val gauges = immutableList(if (isTwin) 2 else 1) { ProgressGaugeWidget(this, tile?.jobEventLoops?.get(it)) } override val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig, allowPush = true) From c08ea8a43d2913691d0369d6e8cf6267dd8a35e5 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Tue, 11 Mar 2025 20:50:59 +0700 Subject: [PATCH 071/154] Update Driver Rack to use SlottedContainer --- .../block/entity/storage/DriveRackBlockEntity.kt | 14 +++++++++----- .../mc/otm/menu/storage/DriveRackMenu.kt | 3 ++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt index 877a2d08a..aa10846f0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt @@ -15,6 +15,8 @@ import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.storage.DriveRackMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import ru.dbotthepony.mc.otm.storage.optics.priority @@ -45,19 +47,21 @@ class DriveRackBlockEntity(blockPos: BlockPos, blockState: BlockState) : Mattery markDirtyFast() } - val container: MatteryContainer = object : MatteryContainer(::markDirtyFast, 4) { - override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { - super.setChanged(slot, new, old) + private inner class Slot(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) { + override fun notifyChanged(old: ItemStack) { + super.notifyChanged(old) old.getCapability(MatteryCapability.CONDENSATION_DRIVE)?.let { cell.removeStorageComponent(it.priority(::insertPriority, ::extractPriority).powered(energy).flow(::mode)) } - new.getCapability(MatteryCapability.CONDENSATION_DRIVE)?.let { + item.getCapability(MatteryCapability.CONDENSATION_DRIVE)?.let { cell.addStorageComponent(it.priority(::insertPriority, ::extractPriority).powered(energy).flow(::mode)) } } - }.also(::addDroppableContainer) + } + + val container = SlottedContainer.simple(4, ::Slot, ::markDirtyFast).also(::addDroppableContainer) init { savetables.stateful(::energy, ENERGY_KEY) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveRackMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveRackMenu.kt index 9855f5b58..2fc33a8f0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveRackMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveRackMenu.kt @@ -4,6 +4,7 @@ import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.block.entity.storage.DriveRackBlockEntity import ru.dbotthepony.mc.otm.capability.FlowDirection +import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.menu.DriveMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput @@ -18,7 +19,7 @@ class DriveRackMenu @JvmOverloads constructor( inventory: Inventory, tile: DriveRackBlockEntity? = null ) : MatteryPoweredMenu(MMenus.DRIVE_RACK, containerId, inventory, tile) { - val storageSlots = makeSlots(tile?.container ?: SimpleContainer(4), ::DriveMenuSlot) + val storageSlots = makeSlots(tile?.container ?: EnhancedContainer(4), ::DriveMenuSlot) val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget) val insertPriority = IntInputWithFeedback(this, tile?.let { it::insertPriority }) From 566538f8a70f7f895b3a40a635b7769b1390ab58 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Tue, 11 Mar 2025 20:59:11 +0700 Subject: [PATCH 072/154] Update Drive Viewer to use EnhancedContainer --- .../otm/block/entity/storage/DriveViewerBlockEntity.kt | 10 ++++++---- .../dbotthepony/mc/otm/menu/storage/DriveViewerMenu.kt | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt index 91b4f661b..c1c23799e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt @@ -17,6 +17,7 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.config.MachinesConfig +import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.core.get import ru.dbotthepony.mc.otm.core.math.Decimal @@ -29,15 +30,16 @@ class DriveViewerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyUpdated, MachinesConfig.DRIVE_VIEWER)) val energyConfig = ConfigurableEnergy(energy) - val container: MatteryContainer = object : MatteryContainer(::markDirtyFast, 1) { - override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { - super.setChanged(slot, new, old) + val container: EnhancedContainer = object : EnhancedContainer(1) { + override fun notifySlotChanged(slot: Int, old: ItemStack) { + super.notifySlotChanged(slot, old) + markDirtyFast() val level = level if (level is ServerLevel) { tickList.once { - val isPresent = new.getCapability(MatteryCapability.CONDENSATION_DRIVE) != null + val isPresent = get(slot).getCapability(MatteryCapability.CONDENSATION_DRIVE) != null var state = this@DriveViewerBlockEntity.blockState.setValue(DriveViewerBlock.DRIVE_PRESENT, isPresent) if (!isPresent) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveViewerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveViewerMenu.kt index 8d9121892..d7390009d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveViewerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveViewerMenu.kt @@ -12,6 +12,7 @@ import ru.dbotthepony.mc.otm.block.entity.storage.DriveViewerBlockEntity import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage +import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.ItemFilter import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.util.ItemStorageStackSorter @@ -36,7 +37,7 @@ class DriveViewerMenu( ) : MatteryPoweredMenu(MMenus.DRIVE_VIEWER, containerID, inventory, tile), INetworkedItemViewProvider { override val networkedItemView = NetworkedItemView(inventory.player, this, tile == null) - val driveSlot = object : MatteryMenuSlot(tile?.container ?: SimpleContainer(1), 0) { + val driveSlot = object : MatteryMenuSlot(tile?.container ?: EnhancedContainer(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.getCapability(MatteryCapability.CONDENSATION_DRIVE) != null } From 1455e12da3907504f48f9c9e113cee8e72562a9a Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Tue, 11 Mar 2025 21:08:31 +0700 Subject: [PATCH 073/154] Fix TooltipList not using proper container class --- src/main/kotlin/ru/dbotthepony/mc/otm/core/TooltipList.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/TooltipList.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/TooltipList.kt index ea819668e..4ee84e841 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/TooltipList.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/TooltipList.kt @@ -24,6 +24,7 @@ import ru.dbotthepony.mc.otm.client.isShiftDown import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.config.ClientConfig import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.nbt.map import ru.dbotthepony.mc.otm.core.nbt.mapPresent @@ -112,7 +113,7 @@ class TooltipList { val registry = context.registries() if (registry != null) { - val container = MatteryContainer(1) + val container = SlottedContainer.filtered(1) tag.map(batteryKey) { it: Tag -> container.deserializeNBT(registry, it) } if (!container[0].isEmpty) { From 55c3c161724a52a86f46acc4b0e6f4d2d7e6c2d7 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Tue, 11 Mar 2025 21:10:19 +0700 Subject: [PATCH 074/154] Update Energy Interface to use SlottedContainer --- .../entity/tech/EnergyInterfaceBlockEntity.kt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyInterfaceBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyInterfaceBlockEntity.kt index 8a74c8afd..b99eda066 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyInterfaceBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyInterfaceBlockEntity.kt @@ -20,6 +20,8 @@ import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.moveEnergy import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.RelativeSide import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag import ru.dbotthepony.mc.otm.core.multiblock.IMultiblockAccess @@ -56,13 +58,11 @@ class EnergyInterfaceBlockEntity( targets.invalidate() } - val container = object : MatteryContainer(::markDirtyFast, CAPACITY) { - override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int { - return 1 - } - }.also(::addDroppableContainer) + val container = SlottedContainer.simple( + CAPACITY, + if (isInput) AutomationFilters.DISCHARGABLE.limitedFilteredProvider else AutomationFilters.CHARGEABLE.limitedFilteredProvider, + ::markDirtyFast).also(::addDroppableContainer) - val itemHandler = container.handler(if (isInput) HandlerFilter.Dischargeable else HandlerFilter.Chargeable) private val neighbours = ArrayList>() override fun setRemoved() { @@ -75,7 +75,7 @@ class EnergyInterfaceBlockEntity( // it would cause a lot of frustration if hatches accept stuff only though one face exposeEnergyGlobally(energy) - exposeGlobally(Capabilities.ItemHandler.BLOCK, itemHandler) + exposeGlobally(Capabilities.ItemHandler.BLOCK, container) if (!isInput) { for (side in RelativeSide.entries) { From 4dad60dfbb18dc7d7a7a5dfef380ef812cd66159 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 12 Mar 2025 16:47:45 +0700 Subject: [PATCH 075/154] Move Matter Hatch to Slotted Container --- .../block/entity/tech/MatterHatchBlockEntity.kt | 17 ++++------------- .../kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt | 2 +- .../mc/otm/menu/tech/MatterHatchMenu.kt | 4 +++- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/MatterHatchBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/MatterHatchBlockEntity.kt index f03a7aaf7..7a85e84e0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/MatterHatchBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/MatterHatchBlockEntity.kt @@ -17,6 +17,8 @@ import ru.dbotthepony.mc.otm.capability.moveMatter import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.MatteryContainer +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag import ru.dbotthepony.mc.otm.menu.tech.MatterHatchMenu @@ -28,26 +30,15 @@ class MatterHatchBlockEntity( blockPos: BlockPos, blockState: BlockState ) : MatteryDeviceBlockEntity(type, blockPos, blockState) { - val container = object : MatteryContainer(::markDirtyFast, CAPACITY) { - override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int { - return 1 - } - }.also(::addDroppableContainer) - + val container = SlottedContainer.simple(CAPACITY, if (isInput) AutomationFilters.MATTER_PROVIDERS.limitedFilteredProvider else AutomationFilters.MATTER_CONSUMERS.limitedFilteredProvider, ::markDirtyFast).also(::addDroppableContainer) val matter = ProfiledMatterStorage(MatterStorageImpl(this::markDirtyFast, FlowDirection.input(isInput), MachinesConfig::MATTER_HATCH)) - val itemHandler = if (isInput) { - container.handler(HandlerFilter.MatterProviders) - } else { - container.handler(HandlerFilter.MatterConsumers) - } - init { savetables.stateful(::container, INVENTORY_KEY) savetables.stateful(::matter, MATTER_STORAGE_KEY) // it would cause a lot of frustration if hatches accept stuff only though one face - exposeGlobally(Capabilities.ItemHandler.BLOCK, itemHandler) + exposeGlobally(Capabilities.ItemHandler.BLOCK, container) exposeGlobally(MatteryCapability.MATTER_BLOCK, matter) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt index 9042393d5..807822264 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt @@ -168,7 +168,7 @@ open class MatterContainerInputMenuSlot( x: Int = 0, y: Int = 0, val direction: FlowDirection = FlowDirection.BI_DIRECTIONAL -) : MatteryMenuSlot(container, index, x, y) { +) : UserFilteredMenuSlot(container, index, x, y) { override fun mayPlace(itemStack: ItemStack): Boolean { val handler = itemStack.getCapability(MatteryCapability.MATTER_ITEM) return handler != null && super.mayPlace(itemStack) && this.direction.test(handler.matterFlow) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/MatterHatchMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/MatterHatchMenu.kt index db04cf5ea..f61088744 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/MatterHatchMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/MatterHatchMenu.kt @@ -6,6 +6,8 @@ import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.block.entity.tech.MatterHatchBlockEntity import ru.dbotthepony.mc.otm.capability.FlowDirection +import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.MatterContainerInputMenuSlot import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback @@ -19,7 +21,7 @@ class MatterHatchMenu( inventory: Inventory, tile: MatterHatchBlockEntity? = null ) : MatteryMenu(if (isInput) MMenus.MATTER_INPUT_HATCH else MMenus.MATTER_OUTPUT_HATCH, containerId, inventory, tile) { - val container: Container = tile?.container ?: SimpleContainer(MatterHatchBlockEntity.CAPACITY) + val container: Container = tile?.container ?: SlottedContainer.simple(MatterHatchBlockEntity.CAPACITY, if (isInput) AutomationFilters.MATTER_PROVIDERS.limitedFilteredProvider else AutomationFilters.MATTER_CONSUMERS.limitedFilteredProvider) val inputSlots = makeSlots(container) { a, b -> MatterContainerInputMenuSlot(a, b, direction = FlowDirection.input(isInput)) From e699147f9f15b2280a47d255ff0b282e8f97baef Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 12 Mar 2025 16:49:19 +0700 Subject: [PATCH 076/154] Merge ChargeMenuSlot into BatteryMenuSlot --- src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt | 5 +++-- src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt | 8 ++------ 2 files changed, 5 insertions(+), 8 deletions(-) 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 65a2b9de4..52f526131 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt @@ -33,6 +33,7 @@ import ru.dbotthepony.kommons.util.Delegate import ru.dbotthepony.kommons.util.getValue import ru.dbotthepony.kommons.util.setValue import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.capability.FlowDirection import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.compat.cos.cosmeticArmorSlots @@ -311,10 +312,10 @@ abstract class MatteryMenu( } if (mattery.hasExopack) { - _exopackChargeSlots.add(BatteryMenuSlot(mattery.exopackEnergy.parent, 0).also { mapQuickMoveToExternal(it); mapQuickMoveToInventory(it); addSlot(it) }) + _exopackChargeSlots.add(BatteryMenuSlot(mattery.exopackEnergy.parent, 0, direction = FlowDirection.OUTPUT).also { mapQuickMoveToExternal(it); mapQuickMoveToInventory(it); addSlot(it) }) for (i in 0 until mattery.exopackChargeSlots.containerSize) - _exopackChargeSlots.add(ChargeMenuSlot(mattery.exopackChargeSlots, i).also { mapQuickMoveToExternal(it); mapQuickMoveToInventory(it); addSlot(it) }) + _exopackChargeSlots.add(BatteryMenuSlot(mattery.exopackChargeSlots, i, direction = FlowDirection.INPUT).also { mapQuickMoveToExternal(it); mapQuickMoveToInventory(it); addSlot(it) }) } sortInventoryInput = SortInput(mattery.inventoryAndExopackNoHotbar, playerSortSettings) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt index 807822264..871d36bb3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt @@ -16,6 +16,7 @@ import ru.dbotthepony.mc.otm.capability.IMatteryUpgrade import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.UpgradeType import ru.dbotthepony.mc.otm.capability.energy +import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.IEnhancedContainer @@ -146,6 +147,7 @@ open class BatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int return false val energy = itemStack.energy ?: return false + if (energy is IMatteryEnergyStorage) return direction.test(energy.energyFlow) return direction.test(FlowDirection.of(energy.canReceive(), energy.canExtract())) } } @@ -156,12 +158,6 @@ open class ChemicalFuelMenuSlot(container: Container, index: Int, x: Int = 0, y: } } -open class ChargeMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatteryMenuSlot(container, index, x, y) { - override fun mayPlace(itemStack: ItemStack): Boolean { - return super.mayPlace(itemStack) && (itemStack.energy?.canReceive() ?: false) - } -} - open class MatterContainerInputMenuSlot( container: Container, index: Int, From ade2c0499dde8603a5325cc1c22e0c0f537a5c59 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 12 Mar 2025 18:42:04 +0700 Subject: [PATCH 077/154] Move Item Monitor to new container API --- .../entity/storage/ItemMonitorBlockEntity.kt | 27 +++++++++---------- .../mc/otm/container/IEnhancedContainer.kt | 10 +++++++ .../mc/otm/core/nbt/CompoundTagExt.kt | 10 +++++++ 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt index 41f92f2e7..946bc3551 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt @@ -29,12 +29,15 @@ import ru.dbotthepony.mc.otm.client.render.UVWindingOrder import ru.dbotthepony.mc.otm.client.render.Widgets8 import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.CombinedContainer +import ru.dbotthepony.mc.otm.container.EnhancedContainer +import ru.dbotthepony.mc.otm.container.IEnhancedCraftingContainer import ru.dbotthepony.mc.otm.container.MatteryCraftingContainer import ru.dbotthepony.mc.otm.container.util.slotIterator import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.collect.map import ru.dbotthepony.mc.otm.core.collect.toList import ru.dbotthepony.mc.otm.core.isNotEmpty +import ru.dbotthepony.mc.otm.core.nbt.map import ru.dbotthepony.mc.otm.core.nbt.mapString import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.util.ItemStorageStackSorter @@ -216,17 +219,13 @@ class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte fun howMuchPlayerCrafted(ply: Player): Int = craftingAmount.getInt(ply) fun lastCraftingRecipe(ply: Player) = lastCraftingRecipe[ply] - // a lot of code is hardcoded to take CraftingContainer as it's input - // hence we are forced to work around this by providing proxy container - val craftingGrid = object : MatteryCraftingContainer(::markDirtyFast, 3, 3) { - override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { - markDirtyFast() + val craftingGrid = IEnhancedCraftingContainer.Wrapper(EnhancedContainer.withListener(3 * 3) { + markDirtyFast() - if (!inProcessOfCraft) { - scanCraftingGrid(false) - } + if (!inProcessOfCraft) { + scanCraftingGrid(false) } - }.also(::addDroppableContainer) + }, 3, 3).also(::addDroppableContainer) private fun scanCraftingGrid(justCheckForRecipeChange: Boolean): Boolean { val level = level ?: return false @@ -346,8 +345,8 @@ class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte check(residue.size == craftingGrid.containerSize) { "Container and residue list sizes mismatch: ${residue.size} != ${craftingGrid.containerSize}" } - val combinedInventory = craftingPlayer.matteryPlayer?.inventoryAndExopack - val copy = craftingGrid.iterator(false).map { it.copy() }.toList() + val combinedInventory = craftingPlayer.matteryPlayer.inventoryAndExopack + val copy = craftingGrid.parent.copyToList() // удаляем по одному предмету из сетки крафта for (slot in 0 until craftingGrid.containerSize) { @@ -381,7 +380,7 @@ class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte remaining = poweredView?.insertStack(ItemStorageStack(remaining), false)?.toItemStack() ?: remaining } - remaining = combinedInventory?.addItem(remaining, false) ?: remaining + remaining = combinedInventory.addItem(remaining, false) if (remaining.isNotEmpty) { craftingPlayer.spawnAtLocation(remaining) @@ -425,7 +424,7 @@ class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte } }) - nbt["crafting_grid"] = craftingGrid.serializeNBT(registry) + nbt["crafting_grid"] = craftingGrid.parent.serializeNBT(registry) } override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) { @@ -438,7 +437,7 @@ class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte check(this.settings.put(UUID.fromString(key), ItemMonitorPlayerSettings().also { it.deserializeNBT(registry, settings.getCompound(key)) }) == null) } - craftingGrid.deserializeNBT(registry, nbt["crafting_grid"]) + nbt.map("crafting_grid", craftingGrid.parent::deserializeNBT, registry) } fun getSettings(ply: ServerPlayer): ItemMonitorPlayerSettings { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt index 1c2a1994b..795e2e481 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt @@ -216,6 +216,16 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable, Sta return list } + fun copyToList(): MutableList { + val list = ArrayList(containerSize) + + for (i in 0 until containerSize) { + list.add(this[i].copy()) + } + + return list + } + fun addItem(stack: ItemStack, simulate: Boolean, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null): ItemStack { if (stack.isEmpty || slots.isEmpty()) return stack diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/nbt/CompoundTagExt.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/nbt/CompoundTagExt.kt index 9387c88e2..0370d3536 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/nbt/CompoundTagExt.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/nbt/CompoundTagExt.kt @@ -59,6 +59,16 @@ inline fun CompoundTag.map(key: String, consumer: (T) -> R return null } +inline fun CompoundTag.map(key: String, consumer: (A0, T) -> R, arg0: A0): R? { + val tag = get(key) + + if (tag is T) { + return consumer(arg0, tag) + } + + return null +} + inline fun CompoundTag.mapPresent(key: String, consumer: (T) -> R): R? { val tag = get(key) From a2263c57258cf90388bb936217b00513613a0656 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 14 Mar 2025 18:11:39 +0700 Subject: [PATCH 078/154] Update MatteryPlayer to use Enhanced containers instead of Mattery containers --- .../mc/otm/container/IAutomatedContainer.kt | 4 +- .../mc/otm/container/ISlottedContainer.kt | 12 ++- .../otm/container/slotted/SlottedContainer.kt | 4 +- .../mc/otm/player/ExopackContainer.kt | 21 ++++ .../mc/otm/player/IPlayerInventorySlot.kt | 7 ++ .../mc/otm/player/MatteryPlayer.kt | 100 +++++++----------- .../mc/otm/player/PlayerInventoryWrapper.kt | 73 +++++++++++++ 7 files changed, 156 insertions(+), 65 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/player/IPlayerInventorySlot.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/player/PlayerInventoryWrapper.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt index 2a703741f..f143f30a2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt @@ -10,9 +10,7 @@ import net.neoforged.neoforge.items.IItemHandlerModifiable * Reinforced [ISlottedContainer] which slots are [IAutomatedContainerSlot]s, which * subsequently allow this container to implement [IItemHandler] */ -interface IAutomatedContainer : ISlottedContainer, IItemHandlerModifiable { - override fun containerSlot(slot: Int): IAutomatedContainerSlot - +interface IAutomatedContainer : ISlottedContainer, IItemHandlerModifiable { override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean { return containerSlot(slot).canAutomationPlaceItem(itemStack) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt index 8e2442836..020c2d6d3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt @@ -8,7 +8,17 @@ import ru.dbotthepony.kommons.collect.any /** * Skeletal implementation for containers which revolve around [IContainerSlot] */ -interface ISlottedContainer : IEnhancedContainer { +interface ISlottedContainer : IEnhancedContainer { + override fun containerSlot(slot: Int): S + + override fun slotIterator(): Iterator { + return super.slotIterator() as Iterator + } + + override fun nonEmptySlotIterator(): Iterator { + return super.nonEmptySlotIterator() as Iterator + } + override fun setChanged(slot: Int) { containerSlot(slot).setChanged() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt index ca04ebf0b..1b5a66420 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt @@ -40,7 +40,7 @@ class SlottedContainer( slots: Collection>, private val stillValid: Predicate, private val globalChangeListeners: Array -) : IAutomatedContainer, INBTSerializable { +) : IAutomatedContainer, INBTSerializable { interface ISlotGroup : List { /** * @see IAutomatedContainer.addItem @@ -140,7 +140,7 @@ class SlottedContainer( } } - override fun containerSlot(slot: Int): IAutomatedContainerSlot { + override fun containerSlot(slot: Int): ContainerSlot { return slots[slot] } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt new file mode 100644 index 000000000..eb71b2c80 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt @@ -0,0 +1,21 @@ +package ru.dbotthepony.mc.otm.player + +import net.minecraft.world.item.Item +import ru.dbotthepony.mc.otm.container.EnhancedContainer +import ru.dbotthepony.mc.otm.container.IContainerSlot + +class ExopackContainer(size: Int, val player: MatteryPlayer) : EnhancedContainer(size) { + private inner class Slot(slot: Int) : IContainerSlot.Simple(slot, this@ExopackContainer), IPlayerInventorySlot { + override var shouldCharge: Boolean + get() = (PlayerInventoryWrapper.SLOTS + slot) in player.slotsChargeFlag + set(value) { if (value) player.slotsChargeFlag.add(PlayerInventoryWrapper.SLOTS + slot) else player.slotsChargeFlag.remove(PlayerInventoryWrapper.SLOTS + slot) } + + override var filter: Item? + get() = player.slotFilters[PlayerInventoryWrapper.SLOTS + slot] + set(value) { if (value == null) player.slotFilters.remove(PlayerInventoryWrapper.SLOTS + slot) else player.slotFilters[PlayerInventoryWrapper.SLOTS + slot] = value } + } + + override fun containerSlot(slot: Int): IPlayerInventorySlot { + return Slot(slot) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/IPlayerInventorySlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/IPlayerInventorySlot.kt new file mode 100644 index 000000000..6719c2fb2 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/IPlayerInventorySlot.kt @@ -0,0 +1,7 @@ +package ru.dbotthepony.mc.otm.player + +import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot + +interface IPlayerInventorySlot : IFilteredContainerSlot { + var shouldCharge: Boolean +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt index 4dd651770..48c6b88e3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt @@ -2,6 +2,9 @@ package ru.dbotthepony.mc.otm.player import com.mojang.blaze3d.systems.RenderSystem import com.mojang.blaze3d.vertex.PoseStack +import com.mojang.serialization.Codec +import com.mojang.serialization.codecs.RecordCodecBuilder +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap import it.unimi.dsi.fastutil.ints.IntAVLTreeSet import it.unimi.dsi.fastutil.ints.IntSet import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap @@ -12,6 +15,7 @@ import net.minecraft.core.HolderLookup import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.ListTag +import net.minecraft.nbt.NbtOps import net.minecraft.nbt.StringTag import net.minecraft.network.chat.Component import net.minecraft.network.protocol.common.custom.CustomPacketPayload @@ -76,12 +80,16 @@ import ru.dbotthepony.mc.otm.config.PlayerConfig import ru.dbotthepony.mc.otm.config.ExopackConfig import ru.dbotthepony.mc.otm.container.CombinedContainer import ru.dbotthepony.mc.otm.container.DynamicallyProxiedContainer +import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.IContainer import ru.dbotthepony.mc.otm.container.IContainerSlot +import ru.dbotthepony.mc.otm.container.IEnhancedContainer import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot import ru.dbotthepony.mc.otm.container.IMatteryContainer import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.get +import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot +import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.container.util.slotIterator import ru.dbotthepony.mc.otm.container.vanishCursedItems import ru.dbotthepony.mc.otm.core.* @@ -95,6 +103,7 @@ import ru.dbotthepony.mc.otm.core.nbt.getStringList import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.util.Savetables import ru.dbotthepony.mc.otm.core.util.TickList +import ru.dbotthepony.mc.otm.data.codec.minRange import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu import ru.dbotthepony.mc.otm.menu.IItemStackSortingSettings import ru.dbotthepony.mc.otm.network.* @@ -158,10 +167,10 @@ class MatteryPlayer(val ply: Player) { val level: Level get() = capability.ply.level() } - private inner class PlayerMatteryContainer(size: Int) : MatteryContainer(size) { - override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { + private inner class PlayerMatteryContainer(size: Int) : EnhancedContainer(size) { + override fun notifySlotChanged(slot: Int, old: ItemStack) { if (ply is ServerPlayer) { - val item = new.copy() + val item = this[slot].copy() tickList.once { MatteryInventoryChangeTrigger.trigger(ply, combinedInventory, item) @@ -249,22 +258,20 @@ class MatteryPlayer(val ply: Player) { * If you want to properly extend Exopack suit capacity, add your value into this map */ val exopackSlotModifier = UUIDIntModifiersMap(observer = observer@{ - if (it < 0) { - exopackContainer = PlayerMatteryContainer(0) - } else { - exopackContainer = PlayerMatteryContainer(it) - } + exopackContainer = ExopackContainer(it.coerceAtLeast(0), this) }, backingMap = this.exopackSlotModifierMap.delegate) - val regularSlotFilters = immutableList(Inventory.INVENTORY_SIZE) { - syncher.add(null, StreamCodecs.ITEM_TYPE.nullable()) - } - val slotsChargeFlag = syncher.set( backing = ListenableSet(IntAVLTreeSet()), codec = StreamCodecs.VAR_INT, ).delegate + val slotFilters = syncher.map( + backing = ListenableMap(Int2ObjectOpenHashMap()), + keyCodec = StreamCodecs.VAR_INT, + valueCodec = StreamCodecs.ITEM_TYPE + ).delegate + private fun slotChargeToDefault() { // броня slotsChargeFlag.add(36) @@ -277,15 +284,12 @@ class MatteryPlayer(val ply: Player) { slotChargeToDefault() } - private var exopackContainerSynchedFilters: List = listOf() - /** * Exopack container, which actually store items inside Exopack */ - var exopackContainer: MatteryContainer = PlayerMatteryContainer(0) + var exopackContainer: ExopackContainer = ExopackContainer(0, this) private set(value) { _exoPackMenu = null - exopackContainerSynchedFilters.forEach { it.close() } @Suppress("SENSELESS_COMPARISON") // false positive - fields of player can easily be nulls, despite annotations saying otherwise if (ply.containerMenu != null && (ply !is ServerPlayer || ply.connection != null)) { @@ -300,7 +304,6 @@ class MatteryPlayer(val ply: Player) { } value.deserializeNBT(ply.level().registryAccess(), field.serializeNBT(ply.level().registryAccess())) - exopackContainerSynchedFilters = value.synchableFilters.map { syncher.add0(it) } field = value _combinedInventory = null @@ -312,34 +315,9 @@ class MatteryPlayer(val ply: Player) { private var _combinedInventory2: CombinedContainer? = null private var _combinedInventory3: CombinedContainer? = null - val wrappedInventory: IMatteryContainer = object : IMatteryContainer, IContainer by DynamicallyProxiedContainer(ply::getInventory) { - override fun getSlotFilter(slot: Int): Item? { - return regularSlotFilters.getOrNull(slot)?.get() - } + val wrappedInventory = PlayerInventoryWrapper(this) - override fun setSlotFilter(slot: Int, filter: Item?): Boolean { - regularSlotFilters.getOrNull(slot)?.accept(filter) - return true - } - - override fun setChanged(slot: Int) { - ply.inventory.setChanged() - } - - override fun clearSlotFilters() { - regularSlotFilters.forEach { it.accept(null) } - } - - override fun containerSlot(slot: Int): IFilteredContainerSlot { - return object : IContainerSlot.Simple(slot, this), IFilteredContainerSlot { - override var filter: Item? - get() = regularSlotFilters.getOrNull(slot)?.get() - set(value) { regularSlotFilters.getOrNull(slot)?.accept(value) } - } - } - } - - val wrappedItemInventory: IMatteryContainer = object : IMatteryContainer by wrappedInventory { + val wrappedItemInventory: IEnhancedContainer = object : IEnhancedContainer by wrappedInventory { override fun getContainerSize(): Int { return 36 } @@ -955,11 +933,8 @@ class MatteryPlayer(val ply: Player) { } } - tag["regularSlotFilters"] = ListTag().also { - for (filter in regularSlotFilters) { - it.add(StringTag.valueOf(filter.value?.registryName?.toString() ?: "")) - } - } + tag["slotFilters"] = filtersCodec.encodeStart(registry.createSerializationContext(NbtOps.INSTANCE), slotFilters.entries.map { it.key to it.value }) + .getOrThrow { IllegalStateException("Unable to serialize slot filters: $it") } tag.putIntArray("slotsChargeFlag", slotsChargeFlag.toIntArray()) return tag @@ -977,18 +952,16 @@ class MatteryPlayer(val ply: Player) { ExopackSlotsExpandedTrigger.trigger(ply, 0, exopackContainer.containerSize) } - for (filter in regularSlotFilters) { - filter.value = null - } - + slotFilters.clear() slotsChargeFlag.clear() - val regularSlotFilters = tag.getStringList("regularSlotFilters") - - for (i in 0 until regularSlotFilters.size.coerceAtMost(this.regularSlotFilters.size)) { - val path = regularSlotFilters[i].asString - if (path == "") continue - this.regularSlotFilters[i].value = BuiltInRegistries.ITEM.get(ResourceLocation.tryParse(path) ?: continue) + if ("slotFilters" in tag) { + filtersCodec.decode(registry.createSerializationContext(NbtOps.INSTANCE), tag["slotFilters"]) + .ifError { LOGGER.error("Unable to deserialize slot filters: ${it.message()}") } + .resultOrPartial() + .ifPresent { + it.first.forEach { (a, b) -> slotFilters[a] = b } + } } if ("slotsChargeFlag" in tag) { @@ -1341,6 +1314,15 @@ class MatteryPlayer(val ply: Player) { @Suppress("unused") companion object { + private val filtersCodec: Codec>> = Codec.list( + RecordCodecBuilder.create { + it.group( + Codec.INT.minRange(0).fieldOf("slot").forGetter { it.first }, + BuiltInRegistries.ITEM.byNameCodec().fieldOf("filter").forGetter { it.second } + ).apply(it, ::Pair) + } + ) + private val offhandSlotRange = IntSet.of(40) init { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/PlayerInventoryWrapper.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/PlayerInventoryWrapper.kt new file mode 100644 index 000000000..35b15d786 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/PlayerInventoryWrapper.kt @@ -0,0 +1,73 @@ +package ru.dbotthepony.mc.otm.player + +import net.minecraft.world.entity.player.Inventory +import net.minecraft.world.entity.player.Player +import net.minecraft.world.item.Item +import net.minecraft.world.item.ItemStack +import ru.dbotthepony.mc.otm.container.ISlottedContainer +import ru.dbotthepony.mc.otm.container.get +import ru.dbotthepony.mc.otm.container.set + +class PlayerInventoryWrapper(val player: MatteryPlayer) : ISlottedContainer { + val inventory: Inventory + get() = player.ply.inventory + + private inner class Slot(val slot: Int) : IPlayerInventorySlot { + override fun setChanged() { + inventory.setChanged() + } + + override var filter: Item? + get() = player.slotFilters[slot] + set(value) { if (value == null) player.slotFilters.remove(slot) else player.slotFilters[slot] = value } + override var shouldCharge: Boolean + get() = slot in player.slotsChargeFlag + set(value) { if (value) player.slotsChargeFlag.add(slot) else player.slotsChargeFlag.remove(slot) } + override var item: ItemStack + get() = inventory[slot] + set(value) { inventory[slot] = value } + override val maxStackSize: Int + get() = inventory.maxStackSize + + override fun maxStackSize(item: ItemStack): Int { + return inventory.getMaxStackSize(item) + } + + override fun remove(): ItemStack { + return inventory.removeItemNoUpdate(slot) + } + + override fun remove(count: Int): ItemStack { + return inventory.removeItem(slot, count) + } + } + + private val slots = Array(SLOTS) { Slot(it) } + + override val hasFilterableSlots: Boolean + get() = true + + override fun containerSlot(slot: Int): IPlayerInventorySlot { + return slots[slot] + } + + override fun clearContent() { + slots.forEach { it.remove() } + } + + override fun setChanged() { + inventory.setChanged() + } + + override fun getContainerSize(): Int { + return slots.size + } + + override fun stillValid(player: Player): Boolean { + return inventory.stillValid(player) + } + + companion object { + const val SLOTS = 41 + } +} From b076d295605ad70a715a3da53a720ffd3bd70da7 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 14 Mar 2025 18:29:51 +0700 Subject: [PATCH 079/154] Declare IEnhancedContainer as having generic parameter Slot --- .../entity/storage/DriveViewerBlockEntity.kt | 2 +- .../entity/storage/ItemMonitorBlockEntity.kt | 2 +- .../entity/tech/EssenceStorageBlockEntity.kt | 2 +- .../mc/otm/compat/vanilla/MatteryChestMenu.kt | 2 +- .../compat/vanilla/MatteryShulkerBoxMenu.kt | 2 +- .../mc/otm/container/CombinedContainer.kt | 18 +++++------ .../mc/otm/container/EnhancedContainer.kt | 32 +++++++++---------- .../mc/otm/container/IEnhancedContainer.kt | 20 ++++++------ .../container/IEnhancedCraftingContainer.kt | 4 +-- .../mc/otm/container/IMatteryContainer.kt | 2 +- .../mc/otm/container/ISlottedContainer.kt | 12 +------ .../mc/otm/container/UpgradeContainer.kt | 2 +- .../mc/otm/container/util/Iterators.kt | 10 +++--- .../mc/otm/item/matter/MatterDustItem.kt | 2 +- .../ru/dbotthepony/mc/otm/menu/Slots.kt | 10 +++--- .../mc/otm/menu/matter/MatterRecyclerMenu.kt | 2 +- .../otm/menu/matter/MatterReplicatorMenu.kt | 2 +- .../mc/otm/menu/matter/MatterScannerMenu.kt | 2 +- .../mc/otm/menu/matter/PatternStorageMenu.kt | 2 +- .../mc/otm/menu/storage/DriveRackMenu.kt | 2 +- .../mc/otm/menu/storage/DriveViewerMenu.kt | 2 +- .../mc/otm/menu/tech/ChemicalGeneratorMenu.kt | 2 +- .../mc/otm/menu/tech/CobblerMenu.kt | 2 +- .../mc/otm/menu/tech/EssenceStorageMenu.kt | 4 +-- .../mc/otm/menu/tech/PlatePressMenu.kt | 2 +- .../mc/otm/menu/tech/PoweredFurnaceMenu.kt | 2 +- .../mc/otm/player/ExopackContainer.kt | 3 +- .../mc/otm/player/MatteryPlayer.kt | 4 +-- 28 files changed, 73 insertions(+), 80 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt index c1c23799e..40f4eabd7 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt @@ -30,7 +30,7 @@ class DriveViewerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::energyUpdated, MachinesConfig.DRIVE_VIEWER)) val energyConfig = ConfigurableEnergy(energy) - val container: EnhancedContainer = object : EnhancedContainer(1) { + val container: EnhancedContainer.Simple = object : EnhancedContainer.Simple(1) { override fun notifySlotChanged(slot: Int, old: ItemStack) { super.notifySlotChanged(slot, old) markDirtyFast() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt index d872ac632..3c44eabd5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt @@ -219,7 +219,7 @@ class ItemMonitorBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matte fun howMuchPlayerCrafted(ply: Player): Int = craftingAmount.getInt(ply) fun lastCraftingRecipe(ply: Player) = lastCraftingRecipe[ply] - val craftingGrid = IEnhancedCraftingContainer.Wrapper(EnhancedContainer.withListener(3 * 3) { + val craftingGrid = IEnhancedCraftingContainer.Wrapper(EnhancedContainer.WithListener(3 * 3) { markDirtyFast() if (!inProcessOfCraft) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt index 0cd0feeda..e5221721c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt @@ -71,7 +71,7 @@ class EssenceStorageBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma } val capsuleContainer = SlottedContainer.simple(1, ::CapsuleSlot, ::markDirtyFast) - val servoContainer = EnhancedContainer.withListener(1, ::markDirtyFast) + val servoContainer = EnhancedContainer.WithListener(1, ::markDirtyFast) val mendingContainer = SlottedContainer.simple(1, ::MendingSlot, ::markDirtyFast).also(::addDroppableContainer) private var mending: Holder? = null diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt index 25bb68fee..038854f22 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt @@ -11,7 +11,7 @@ import ru.dbotthepony.mc.otm.menu.makeSlots class MatteryChestMenu( type: MenuType<*>, containerId: Int, inventory: Inventory, override val rows: Int, override val columns: Int, - container: Container = EnhancedContainer(rows * columns) + container: Container = EnhancedContainer.Simple(rows * columns) ) : AbstractVanillaChestMenu(type, containerId, inventory, container) { override val containerSlots = makeSlots(container, ::MatteryMenuSlot) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryShulkerBoxMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryShulkerBoxMenu.kt index 01bd06a14..9ebc6d65e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryShulkerBoxMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryShulkerBoxMenu.kt @@ -10,7 +10,7 @@ import ru.dbotthepony.mc.otm.menu.makeSlots class MatteryShulkerBoxMenu( containerId: Int, inventory: Inventory, - container: Container = EnhancedContainer(27) + container: Container = EnhancedContainer.Simple(27) ) : AbstractVanillaChestMenu(VanillaMenuTypes.SHULKER_BOX, containerId, inventory, container) { override val containerSlots = makeSlots(container, ::Slot) override val rows: Int diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt index 456f87cde..5f495f997 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt @@ -23,9 +23,9 @@ import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.stream import java.util.stream.Stream -class CombinedContainer(containers: Stream>>) : ISlottedContainer, IMatteryContainer { - constructor(vararg containers: IEnhancedContainer) : this(containers.stream().map { it to (0 until it.containerSize) }) - constructor(containers: Collection) : this(containers.stream().map { it to (0 until it.containerSize) }) +class CombinedContainer(containers: Stream, Iterable>>) : ISlottedContainer, IMatteryContainer { + constructor(vararg containers: IEnhancedContainer<*>) : this(containers.stream().map { it to (0 until it.containerSize) }) + constructor(containers: Collection>) : this(containers.stream().map { it to (0 until it.containerSize) }) private val slots: ImmutableList private val slotsMap: ImmutableMap> @@ -145,7 +145,7 @@ class CombinedContainer(containers: Stream>>() + private val values = ArrayList, Iterable>>() fun add(container: Container): Builder { return add(IEnhancedContainer.wrap(container)) @@ -167,27 +167,27 @@ class CombinedContainer(containers: Stream): Builder { values.add(container to container.slotRange) return this } - fun add(container: IEnhancedContainer, slots: Iterator): Builder { + fun add(container: IEnhancedContainer<*>, slots: Iterator): Builder { values.add(container to IntArrayList(slots)) return this } - fun add(container: IEnhancedContainer, slot: Int): Builder { + fun add(container: IEnhancedContainer<*>, slot: Int): Builder { values.add(container to intArrayOf(slot).asIterable()) return this } - fun add(container: IEnhancedContainer, from: Int, to: Int): Builder { + fun add(container: IEnhancedContainer<*>, from: Int, to: Int): Builder { values.add(container to (from .. to)) return this } - fun add(container: IEnhancedContainer, slots: Iterable): Builder { + fun add(container: IEnhancedContainer<*>, slots: Iterable): Builder { values.add(container to slots) return this } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt index 5f2f6c508..fe1aa25d8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt @@ -23,15 +23,9 @@ import ru.dbotthepony.mc.otm.core.nbt.set * This is supposed to be counterpart to [SimpleContainer] of Minecraft itself, with more features * and improved performance (inside [IEnhancedContainer] defined methods). */ -open class EnhancedContainer(private val size: Int) : IEnhancedContainer, INBTSerializable { +abstract class EnhancedContainer(private val size: Int) : IEnhancedContainer, INBTSerializable { private val items = Array(size) { ItemStack.EMPTY } private val observedItems = Array(size) { ItemStack.EMPTY } - private val slots by lazy(LazyThreadSafetyMode.PUBLICATION) { Array(size) { IContainerSlot.Simple(it, this) } } - - // can be safely overridden in subclasses, very little memory will be wasted - override fun containerSlot(slot: Int): IContainerSlot { - return slots[slot] - } protected open fun notifySlotChanged(slot: Int, old: ItemStack) {} @@ -184,16 +178,22 @@ open class EnhancedContainer(private val size: Int) : IEnhancedContainer, INBTSe } } - companion object { - private val LOGGER = LogManager.getLogger() + open class Simple(size: Int) : EnhancedContainer(size) { + private val slots by lazy(LazyThreadSafetyMode.PUBLICATION) { Array(size) { IContainerSlot.Simple(it, this) } } - fun withListener(slots: Int, listener: Runnable): EnhancedContainer { - return object : EnhancedContainer(slots) { - override fun notifySlotChanged(slot: Int, old: ItemStack) { - super.notifySlotChanged(slot, old) - listener.run() - } - } + override fun containerSlot(slot: Int): IContainerSlot { + return slots[slot] } } + + open class WithListener(size: Int, private val listener: Runnable) : Simple(size) { + override fun notifySlotChanged(slot: Int, old: ItemStack) { + super.notifySlotChanged(slot, old) + listener.run() + } + } + + companion object { + private val LOGGER = LogManager.getLogger() + } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt index 795e2e481..8a9fd2fac 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt @@ -24,7 +24,7 @@ import java.util.stream.StreamSupport * This is useful because it allows to interact with actually enhanced and regular containers through unified interface, * and actual implementations of this interface are likely to provide efficient method implementations in place of derived/emulated ones. */ -interface IEnhancedContainer : IContainer, RecipeInput, Iterable, StackedContentsCompatible { +interface IEnhancedContainer : IContainer, RecipeInput, Iterable, StackedContentsCompatible { // provide non-ambiguous get and set operators operator fun get(slot: Int): ItemStack { return getItem(slot) @@ -34,9 +34,7 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable, Sta setItem(slot, value) } - fun containerSlot(slot: Int): IContainerSlot { - return IContainerSlot.Simple(slot, this) - } + fun containerSlot(slot: Int): S override fun fillStackedContents(contents: StackedContents) { forEach { contents.accountStack(it) } @@ -45,11 +43,11 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable, Sta /** * Returns iterator over **all** slots this container has */ - fun slotIterator(): Iterator { + fun slotIterator(): Iterator { return (0 until containerSize).iterator().map { containerSlot(it) } } - fun nonEmptySlotIterator(): Iterator { + fun nonEmptySlotIterator(): Iterator { return slotIterator().filter { it.isNotEmpty } } @@ -307,7 +305,11 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable, Sta return StreamSupport.stream(spliterator(), false) } - private class Wrapper(private val parent: Container) : IEnhancedContainer { + private class Wrapper(private val parent: Container) : IEnhancedContainer { + override fun containerSlot(slot: Int): IContainerSlot { + return IContainerSlot.Simple(slot, parent) + } + override fun clearContent() { return parent.clearContent() } @@ -378,8 +380,8 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable, Sta } companion object { - fun wrap(other: Container): IEnhancedContainer { - if (other is IEnhancedContainer) + fun wrap(other: Container): IEnhancedContainer<*> { + if (other is IEnhancedContainer<*>) return other return Wrapper(other) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedCraftingContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedCraftingContainer.kt index 61dc89142..e7e10a0dd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedCraftingContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedCraftingContainer.kt @@ -4,7 +4,7 @@ import net.minecraft.world.entity.player.StackedContents import net.minecraft.world.inventory.CraftingContainer import net.minecraft.world.item.ItemStack -interface IEnhancedCraftingContainer : IEnhancedContainer, CraftingContainer { +interface IEnhancedCraftingContainer : IEnhancedContainer, CraftingContainer { override fun getItems(): MutableList { return toList() } @@ -13,7 +13,7 @@ interface IEnhancedCraftingContainer : IEnhancedContainer, CraftingContainer { forEach { contents.accountSimpleStack(it) } } - class Wrapper(val parent: C, private val width: Int, private val height: Int) : IEnhancedCraftingContainer, IEnhancedContainer by parent { + class Wrapper, S : IContainerSlot>(val parent: C, private val width: Int, private val height: Int) : IEnhancedCraftingContainer, IEnhancedContainer by parent { init { require(width * height == parent.containerSize) { "Crafting container dimensions ($width x $height) do not match container size provided (${parent.containerSize})" } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt index b41c5f2eb..7d383f010 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt @@ -9,7 +9,7 @@ import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.collect.map import ru.dbotthepony.mc.otm.core.isNotEmpty -interface IMatteryContainer : IEnhancedContainer { +interface IMatteryContainer : IEnhancedContainer { fun getSlotFilter(slot: Int): Item? /** diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt index 020c2d6d3..d6bf3cda9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt @@ -8,17 +8,7 @@ import ru.dbotthepony.kommons.collect.any /** * Skeletal implementation for containers which revolve around [IContainerSlot] */ -interface ISlottedContainer : IEnhancedContainer { - override fun containerSlot(slot: Int): S - - override fun slotIterator(): Iterator { - return super.slotIterator() as Iterator - } - - override fun nonEmptySlotIterator(): Iterator { - return super.nonEmptySlotIterator() as Iterator - } - +interface ISlottedContainer : IEnhancedContainer { override fun setChanged(slot: Int) { containerSlot(slot).setChanged() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt index 544f81a47..e18a3d427 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt @@ -17,7 +17,7 @@ class UpgradeContainer( val allowedUpgrades: Set = UpgradeType.ALL, val shouldLockUpgradeSlots: BooleanSupplier = BooleanSupplier { false }, private val listener: Runnable = Runnable {} -) : EnhancedContainer(slotCount), IMatteryUpgrade { +) : EnhancedContainer.Simple(slotCount), IMatteryUpgrade { override fun notifySlotChanged(slot: Int, old: ItemStack) { super.notifySlotChanged(slot, old) listener.run() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/util/Iterators.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/util/Iterators.kt index 9160415c9..39101d4cd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/util/Iterators.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/util/Iterators.kt @@ -13,7 +13,7 @@ import ru.dbotthepony.mc.otm.core.collect.map import ru.dbotthepony.mc.otm.core.isNotEmpty fun Container.containerSlot(slot: Int): IContainerSlot { - if (this is IEnhancedContainer) { + if (this is IEnhancedContainer<*>) { return containerSlot(slot) } else { return IContainerSlot.Simple(slot, this) @@ -24,7 +24,7 @@ fun Container.containerSlot(slot: Int): IContainerSlot { * Returns [IContainerSlot] only if this container is [IEnhancedContainer] */ fun Container.containerSlotOrNull(slot: Int): IContainerSlot? { - if (this is IEnhancedContainer) { + if (this is IEnhancedContainer<*>) { return containerSlot(slot) } else { return null @@ -40,7 +40,7 @@ fun Slot.containerSlotOrNull(): IContainerSlot? { } operator fun Container.iterator(): Iterator { - if (this is IEnhancedContainer) { + if (this is IEnhancedContainer<*>) { return iterator() } else { return (0 until containerSize).iterator().map { this[it] }.filter { it.isNotEmpty } @@ -48,7 +48,7 @@ operator fun Container.iterator(): Iterator { } fun Container.slotIterator(): Iterator { - if (this is IEnhancedContainer) { + if (this is IEnhancedContainer<*>) { return slotIterator() } else { return (0 until containerSize).iterator().map { IContainerSlot.Simple(it, this) } @@ -56,7 +56,7 @@ fun Container.slotIterator(): Iterator { } fun Container.nonEmptySlotIterator(): Iterator { - if (this is IEnhancedContainer) { + if (this is IEnhancedContainer<*>) { return nonEmptySlotIterator() } else { return (0 until containerSize).iterator().filter { this[it].isNotEmpty }.map { IContainerSlot.Simple(it, this) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/matter/MatterDustItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/matter/MatterDustItem.kt index 717524447..e8060499d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/matter/MatterDustItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/matter/MatterDustItem.kt @@ -66,7 +66,7 @@ class MatterDustItem : Item(Properties().stacksTo(64)), IMatterItem { return MatterValue(value, 1.0) } - fun moveIntoContainer(matterValue: Decimal, container: IEnhancedContainer, mainSlot: Int, stackingSlot: Int): Decimal { + fun moveIntoContainer(matterValue: Decimal, container: IEnhancedContainer<*>, mainSlot: Int, stackingSlot: Int): Decimal { @Suppress("name_shadowing") var matterValue = matterValue diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt index 871d36bb3..a41dad0c2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt @@ -65,8 +65,8 @@ open class MatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int } override fun setChanged() { - if (container is IEnhancedContainer) { - (container as IEnhancedContainer).setChanged(containerSlot) + if (container is IEnhancedContainer<*>) { + (container as IEnhancedContainer<*>).setChanged(containerSlot) } else { super.setChanged() } @@ -83,7 +83,7 @@ open class MatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int override fun getMaxStackSize(): Int { val container = container - if (container is IEnhancedContainer) { + if (container is IEnhancedContainer<*>) { return container.getMaxStackSize(slotIndex, ItemStack.EMPTY) } else { return super.getMaxStackSize() @@ -93,7 +93,7 @@ open class MatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int override fun getMaxStackSize(itemStack: ItemStack): Int { val container = container - if (container is IEnhancedContainer) { + if (container is IEnhancedContainer<*>) { return container.getMaxStackSize(slotIndex, itemStack) } else { return super.getMaxStackSize(itemStack) @@ -278,7 +278,7 @@ fun MatteryMenu.makeUpgradeSlots(count: Int, container: UpgradeContainer?): Upgr allowedTypes[value] = BooleanSupplier { b.get() } } - val syncContainer = container ?: EnhancedContainer(count) + val syncContainer = container ?: EnhancedContainer.Simple(count) val isOpen = InstantBooleanInput(this) return UpgradeSlots( diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterRecyclerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterRecyclerMenu.kt index 8a7b3f2b4..011aeb2fb 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterRecyclerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterRecyclerMenu.kt @@ -21,7 +21,7 @@ class MatterRecyclerMenu @JvmOverloads constructor( inventory: Inventory, tile: MatterRecyclerBlockEntity? = null ) : MatteryPoweredMenu(MMenus.MATTER_RECYCLER, containerID, inventory, tile) { - val input = object : MatteryMenuSlot(tile?.container ?: EnhancedContainer(1), 0) { + val input = object : MatteryMenuSlot(tile?.container ?: EnhancedContainer.Simple(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.item is MatterDustItem && (itemStack.item as MatterDustItem).getMatterValue(itemStack) != null } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReplicatorMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReplicatorMenu.kt index d1956e505..a4824823a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReplicatorMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterReplicatorMenu.kt @@ -35,7 +35,7 @@ class MatterReplicatorMenu @JvmOverloads constructor( val upgrades = makeUpgradeSlots(3, tile?.upgrades) init { - val container = CombinedContainer(tile?.outputContainer ?: EnhancedContainer(3), tile?.dustContainer ?: EnhancedContainer(2)) + val container = CombinedContainer(tile?.outputContainer ?: EnhancedContainer.Simple(3), tile?.dustContainer ?: EnhancedContainer.Simple(2)) storageSlots = immutableList(5) { addStorageSlot(OutputMenuSlot(container, it, onTake = { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterScannerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterScannerMenu.kt index 005e774c1..85157fb8d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterScannerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterScannerMenu.kt @@ -31,7 +31,7 @@ class MatterScannerMenu( val upgrades = makeUpgradeSlots(2, tile?.upgrades) init { - val container = tile?.container ?: EnhancedContainer(1) + val container = tile?.container ?: EnhancedContainer.Simple(1) input = object : MatteryMenuSlot(container, 0, 64, 38) { override fun mayPlace(itemStack: ItemStack) = MatterManager.canDecompose(itemStack) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/PatternStorageMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/PatternStorageMenu.kt index 920899dec..2ddc1a530 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/PatternStorageMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/PatternStorageMenu.kt @@ -32,7 +32,7 @@ class PatternStorageMenu @JvmOverloads constructor( }) } - val patterns = tile?.container ?: EnhancedContainer(2 * 4) + val patterns = tile?.container ?: EnhancedContainer.Simple(2 * 4) storageSlots = immutableList(patterns.containerSize) { addStorageSlot(PatternMenuSlot(patterns, it)) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveRackMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveRackMenu.kt index 2fc33a8f0..e0e8c4b40 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveRackMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveRackMenu.kt @@ -19,7 +19,7 @@ class DriveRackMenu @JvmOverloads constructor( inventory: Inventory, tile: DriveRackBlockEntity? = null ) : MatteryPoweredMenu(MMenus.DRIVE_RACK, containerId, inventory, tile) { - val storageSlots = makeSlots(tile?.container ?: EnhancedContainer(4), ::DriveMenuSlot) + val storageSlots = makeSlots(tile?.container ?: EnhancedContainer.Simple(4), ::DriveMenuSlot) val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget) val insertPriority = IntInputWithFeedback(this, tile?.let { it::insertPriority }) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveViewerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveViewerMenu.kt index d7390009d..1f0a190c0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveViewerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveViewerMenu.kt @@ -37,7 +37,7 @@ class DriveViewerMenu( ) : MatteryPoweredMenu(MMenus.DRIVE_VIEWER, containerID, inventory, tile), INetworkedItemViewProvider { override val networkedItemView = NetworkedItemView(inventory.player, this, tile == null) - val driveSlot = object : MatteryMenuSlot(tile?.container ?: EnhancedContainer(1), 0) { + val driveSlot = object : MatteryMenuSlot(tile?.container ?: EnhancedContainer.Simple(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.getCapability(MatteryCapability.CONDENSATION_DRIVE) != null } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ChemicalGeneratorMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ChemicalGeneratorMenu.kt index 3e2c08051..445d5433d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ChemicalGeneratorMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ChemicalGeneratorMenu.kt @@ -38,7 +38,7 @@ class ChemicalGeneratorMenu @JvmOverloads constructor(id: Int, inv: Inventory, t } } - val residueSlot = object : MatteryMenuSlot(tile?.residueContainer ?: EnhancedContainer(1), 0) { + val residueSlot = object : MatteryMenuSlot(tile?.residueContainer ?: EnhancedContainer.Simple(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return false } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/CobblerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/CobblerMenu.kt index a7258ace0..1bbc3b4e8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/CobblerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/CobblerMenu.kt @@ -17,7 +17,7 @@ class CobblerMenu( inventory: Inventory, tile: CobblerBlockEntity? = null ) : MatteryMenu(MMenus.COBBLESTONE_GENERATOR, p_38852_, inventory, tile) { - val storageSlots = makeSlots(tile?.container ?: EnhancedContainer(CobblerBlockEntity.CONTAINER_SIZE), ::OutputMenuSlot) + val storageSlots = makeSlots(tile?.container ?: EnhancedContainer.Simple(CobblerBlockEntity.CONTAINER_SIZE), ::OutputMenuSlot) val redstone = EnumInputWithFeedback(this) val itemConfig = ItemConfigPlayerInput(this) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EssenceStorageMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EssenceStorageMenu.kt index f3c4258fd..1c362f84d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EssenceStorageMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EssenceStorageMenu.kt @@ -34,13 +34,13 @@ class EssenceStorageMenu( val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig) val fluidConfig = FluidConfigPlayerInput(this, tile?.fluidConfig) - val capsuleSlot = object : MatteryMenuSlot(tile?.capsuleContainer ?: EnhancedContainer(1), 0) { + val capsuleSlot = object : MatteryMenuSlot(tile?.capsuleContainer ?: EnhancedContainer.Simple(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.item is EssenceCapsuleItem && super.mayPlace(itemStack) } } - val servoSlot = object : MatteryMenuSlot(tile?.servoContainer ?: EnhancedContainer(1), 0) { + val servoSlot = object : MatteryMenuSlot(tile?.servoContainer ?: EnhancedContainer.Simple(1), 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return itemStack.item == MItems.ESSENCE_SERVO && super.mayPlace(itemStack) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PlatePressMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PlatePressMenu.kt index 052984a6c..ed4eccf7c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PlatePressMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PlatePressMenu.kt @@ -31,7 +31,7 @@ class PlatePressMenu( isTwin: Boolean ) : AbstractProcessingMachineMenu(type, containerID, inventory, tile) { val inputSlots = makeSlots(tile?.inputContainer ?: SlottedContainer.filtered(if (isTwin) 2 else 1), ::MatteryMenuSlot) - val outputSlots = makeSlots(tile?.outputContainer ?: EnhancedContainer(if (isTwin) 2 else 1)) { a, b -> OutputMenuSlot(a, b) { tile?.experience?.popExperience(player as ServerPlayer) } } + val outputSlots = makeSlots(tile?.outputContainer ?: EnhancedContainer.Simple(if (isTwin) 2 else 1)) { a, b -> OutputMenuSlot(a, b) { tile?.experience?.popExperience(player as ServerPlayer) } } val gauges = immutableList(if (isTwin) 2 else 1) { ProgressGaugeWidget(this, tile?.jobEventLoops?.get(it)) } override val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig, allowPush = true) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PoweredFurnaceMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PoweredFurnaceMenu.kt index f66e42b08..024b854c1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PoweredFurnaceMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/PoweredFurnaceMenu.kt @@ -40,7 +40,7 @@ class PoweredFurnaceMenu( // we can't make these slots to reject non-smeltable items // since mods may add obscure recipes/ingredients which never test true on client val inputSlots = makeSlots(tile?.inputs ?: SlottedContainer.filtered(2), ::UserFilteredMenuSlot) - val outputSlots = makeSlots(tile?.outputs ?: EnhancedContainer(2)) { c, s -> OutputMenuSlot(c, s) { tile?.experience?.popExperience(player as ServerPlayer) } } + val outputSlots = makeSlots(tile?.outputs ?: EnhancedContainer.Simple(2)) { c, s -> OutputMenuSlot(c, s) { tile?.experience?.popExperience(player as ServerPlayer) } } val progressGauge = immutableList(2) { ProgressGaugeWidget(this, tile?.jobEventLoops?.get(it)) } override val itemConfig = ItemConfigPlayerInput(this, tile?.itemConfig, allowPush = true) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt index eb71b2c80..c3b7c9f9d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt @@ -3,8 +3,9 @@ package ru.dbotthepony.mc.otm.player import net.minecraft.world.item.Item import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.IContainerSlot +import ru.dbotthepony.mc.otm.container.IEnhancedContainer -class ExopackContainer(size: Int, val player: MatteryPlayer) : EnhancedContainer(size) { +class ExopackContainer(size: Int, val player: MatteryPlayer) : EnhancedContainer(size) { private inner class Slot(slot: Int) : IContainerSlot.Simple(slot, this@ExopackContainer), IPlayerInventorySlot { override var shouldCharge: Boolean get() = (PlayerInventoryWrapper.SLOTS + slot) in player.slotsChargeFlag diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt index 48c6b88e3..2ce22ab3f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt @@ -167,7 +167,7 @@ class MatteryPlayer(val ply: Player) { val level: Level get() = capability.ply.level() } - private inner class PlayerMatteryContainer(size: Int) : EnhancedContainer(size) { + private inner class PlayerMatteryContainer(size: Int) : EnhancedContainer.Simple(size) { override fun notifySlotChanged(slot: Int, old: ItemStack) { if (ply is ServerPlayer) { val item = this[slot].copy() @@ -317,7 +317,7 @@ class MatteryPlayer(val ply: Player) { val wrappedInventory = PlayerInventoryWrapper(this) - val wrappedItemInventory: IEnhancedContainer = object : IEnhancedContainer by wrappedInventory { + val wrappedItemInventory: IEnhancedContainer = object : IEnhancedContainer by wrappedInventory { override fun getContainerSize(): Int { return 36 } From 05bdff6a3734f1c4a166e2a280e6ea846dbd57ef Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 14 Mar 2025 18:31:01 +0700 Subject: [PATCH 080/154] Remove unused class --- .../ru/dbotthepony/mc/otm/player/MatteryPlayer.kt | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt index 2ce22ab3f..b730e9b4a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt @@ -167,18 +167,6 @@ class MatteryPlayer(val ply: Player) { val level: Level get() = capability.ply.level() } - private inner class PlayerMatteryContainer(size: Int) : EnhancedContainer.Simple(size) { - override fun notifySlotChanged(slot: Int, old: ItemStack) { - if (ply is ServerPlayer) { - val item = this[slot].copy() - - tickList.once { - MatteryInventoryChangeTrigger.trigger(ply, combinedInventory, item) - } - } - } - } - /** * For fields that need to be synchronized only to owning player * From d0904da1db2ec53295d83778d3ae4de7d7a6e2a4 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 14 Mar 2025 18:32:28 +0700 Subject: [PATCH 081/154] Remove remaining MatteryContainer usages --- .../kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt index b730e9b4a..c8bc3e8df 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt @@ -509,8 +509,8 @@ class MatteryPlayer(val ply: Player) { } } - val input = MatteryContainer(Runnable { notify(IdleReason.ITEM) }, 1) - val output = MatteryContainer(Runnable { notify(IdleReason.ITEM) }, 1) + val input = EnhancedContainer.WithListener(1) { notify(IdleReason.ITEM) } + val output = EnhancedContainer.WithListener(1) { notify(IdleReason.ITEM) } init { savetables.stateful(::input, "exopack_smelter_input_$index") @@ -539,7 +539,7 @@ class MatteryPlayer(val ply: Player) { */ val exopackEnergy = ProfiledEnergyStorage(BatteryBackedEnergyStorage(ply, syncher, Decimal.ZERO, ExopackConfig.ENERGY_CAPACITY, false, onChange = { for (v in smelters) v.notify(MachineJobEventLoop.IdleReason.POWER) })) - val exopackChargeSlots = MatteryContainer(4) + val exopackChargeSlots = EnhancedContainer.Simple(4) var acceptExopackChargeFromWirelessCharger = true init { From 621661c9fed695012ec8a48ac3d7c37fef0bab8a Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 14 Mar 2025 18:33:44 +0700 Subject: [PATCH 082/154] Remove MatteryCraftingContainer usage --- .../entity/storage/ItemMonitorBlockEntity.kt | 1 - .../otm/container/MatteryCraftingContainer.kt | 21 ------------------- .../mc/otm/matter/MatterManager.kt | 5 +++-- 3 files changed, 3 insertions(+), 24 deletions(-) delete mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryCraftingContainer.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt index 3c44eabd5..3098460df 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt @@ -31,7 +31,6 @@ import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.CombinedContainer import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.IEnhancedCraftingContainer -import ru.dbotthepony.mc.otm.container.MatteryCraftingContainer import ru.dbotthepony.mc.otm.container.util.slotIterator import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.collect.map diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryCraftingContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryCraftingContainer.kt deleted file mode 100644 index 036e7bc27..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryCraftingContainer.kt +++ /dev/null @@ -1,21 +0,0 @@ -package ru.dbotthepony.mc.otm.container - -import net.minecraft.world.inventory.CraftingContainer -import net.minecraft.world.item.ItemStack - -open class MatteryCraftingContainer(listener: ContainerListener, private val width: Int, private val height: Int) : MatteryContainer(listener, width * height), CraftingContainer { - constructor(listener: () -> Unit, width: Int, height: Int) : this({ _, _, _ -> listener.invoke() }, width, height) - constructor(width: Int, height: Int) : this(EmptyListener, width, height) - - final override fun getWidth(): Int { - return width - } - - final override fun getHeight(): Int { - return height - } - - final override fun getItems(): MutableList { - return toList() - } -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterManager.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterManager.kt index 176860e2c..1c732a29e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterManager.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/MatterManager.kt @@ -77,7 +77,8 @@ import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive import ru.dbotthepony.mc.otm.client.isShiftDown import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.config.ClientConfig -import ru.dbotthepony.mc.otm.container.MatteryCraftingContainer +import ru.dbotthepony.mc.otm.container.EnhancedContainer +import ru.dbotthepony.mc.otm.container.IEnhancedCraftingContainer import ru.dbotthepony.mc.otm.container.util.stream import ru.dbotthepony.mc.otm.core.ResourceLocation import ru.dbotthepony.mc.otm.core.TextComponent @@ -500,7 +501,7 @@ object MatterManager { height = it.value.ingredients.size.coerceAtLeast(height) } - val container = MatteryCraftingContainer(width, height) + val container = IEnhancedCraftingContainer.Wrapper(EnhancedContainer.Simple(width * height), width, height) val realIngredients = ArrayList>() for (c in it.value.ingredients.indices) { From bdeb740df02c88183b78b2843de13650bccc2be7 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 14 Mar 2025 18:35:22 +0700 Subject: [PATCH 083/154] Remove ShadowContainer and MatteryContainer --- .../decorative/CargoCrateBlockEntity.kt | 1 - .../entity/decorative/FluidTankBlockEntity.kt | 1 - .../entity/decorative/PainterBlockEntity.kt | 1 - .../entity/matter/MatterBottlerBlockEntity.kt | 1 - .../matter/MatterCapacitorBankBlockEntity.kt | 1 - .../matter/MatterDecomposerBlockEntity.kt | 1 - .../matter/MatterReplicatorBlockEntity.kt | 1 - .../entity/matter/MatterScannerBlockEntity.kt | 1 - .../entity/storage/DriveRackBlockEntity.kt | 1 - .../entity/storage/DriveViewerBlockEntity.kt | 1 - .../entity/tech/BatteryBankBlockEntity.kt | 1 - .../tech/ChemicalGeneratorBlockEntity.kt | 1 - .../block/entity/tech/CobblerBlockEntity.kt | 1 - .../entity/tech/EnergyHatchBlockEntity.kt | 1 - .../entity/tech/EnergyInterfaceBlockEntity.kt | 1 - .../entity/tech/EnergyServoBlockEntity.kt | 1 - .../entity/tech/EssenceStorageBlockEntity.kt | 1 - .../block/entity/tech/ItemHatchBlockEntity.kt | 1 - .../entity/tech/MatterHatchBlockEntity.kt | 1 - .../entity/tech/PlatePressBlockEntity.kt | 1 - .../mc/otm/container/MatteryContainer.kt | 498 ------------------ .../mc/otm/container/ShadowContainer.kt | 47 -- .../otm/container/ShadowCraftingContainer.kt | 33 -- .../ru/dbotthepony/mc/otm/core/TooltipList.kt | 1 - .../mc/otm/menu/decorative/GrillMenu.kt | 1 - .../mc/otm/menu/decorative/PainterMenu.kt | 1 - .../mc/otm/player/MatteryPlayer.kt | 1 - 27 files changed, 602 deletions(-) delete mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt delete mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/ShadowContainer.kt delete mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/ShadowCraftingContainer.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt index 20f3f0319..eeb688851 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt @@ -29,7 +29,6 @@ import net.minecraft.world.phys.Vec3 import net.neoforged.neoforge.capabilities.Capabilities import ru.dbotthepony.mc.otm.block.decorative.CargoCrateBlock import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/FluidTankBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/FluidTankBlockEntity.kt index 8f8a2a83d..deeea262e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/FluidTankBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/FluidTankBlockEntity.kt @@ -19,7 +19,6 @@ import ru.dbotthepony.mc.otm.capability.fluid.BlockMatteryFluidHandler import ru.dbotthepony.mc.otm.capability.moveFluid import ru.dbotthepony.mc.otm.config.ItemsConfig import ru.dbotthepony.mc.otm.container.HandlerFilter -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.get import ru.dbotthepony.mc.otm.container.slotted.AutomationFilter import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/PainterBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/PainterBlockEntity.kt index 8078b8dbf..2e1c5679f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/PainterBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/PainterBlockEntity.kt @@ -19,7 +19,6 @@ import net.neoforged.neoforge.fluids.FluidStack import net.neoforged.neoforge.fluids.capability.IFluidHandler import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.container.HandlerFilter -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.immutableList diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt index 485fea8b9..d105cc7b1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt @@ -21,7 +21,6 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage import ru.dbotthepony.mc.otm.config.MachinesConfig -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.UpgradeContainer import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt index d5193ae07..f0c2fa62d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt @@ -17,7 +17,6 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage import ru.dbotthepony.mc.otm.container.HandlerFilter -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.immutableList diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt index d12f61704..4db7331f6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt @@ -22,7 +22,6 @@ import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.HandlerFilter -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt index 3f3c67d79..7cc732dca 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt @@ -26,7 +26,6 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.* import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.HandlerFilter -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.Decimal diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt index 26a120f93..2698b997b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt @@ -20,7 +20,6 @@ import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.PatternState import ru.dbotthepony.mc.otm.config.MachinesConfig -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt index aa10846f0..5f76987db 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveRackBlockEntity.kt @@ -14,7 +14,6 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.config.MachinesConfig -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.storage.DriveRackMenu diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt index 40f4eabd7..2e01e7368 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/DriveViewerBlockEntity.kt @@ -18,7 +18,6 @@ import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.EnhancedContainer -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.core.get import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.util.ItemStorageStackSorter diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/BatteryBankBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/BatteryBankBlockEntity.kt index fc816a029..ce692be8a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/BatteryBankBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/BatteryBankBlockEntity.kt @@ -20,7 +20,6 @@ import ru.dbotthepony.mc.otm.capability.matteryEnergy import ru.dbotthepony.mc.otm.capability.maxEnergyStoredMattery import ru.dbotthepony.mc.otm.capability.transcieveEnergy import ru.dbotthepony.mc.otm.container.HandlerFilter -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ChemicalGeneratorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ChemicalGeneratorBlockEntity.kt index 784e74320..d0ab00ab4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ChemicalGeneratorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ChemicalGeneratorBlockEntity.kt @@ -12,7 +12,6 @@ import ru.dbotthepony.mc.otm.capability.* import ru.dbotthepony.mc.otm.capability.energy.GeneratorEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.config.MachinesConfig -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/CobblerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/CobblerBlockEntity.kt index b575ae8dd..f8ed9261c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/CobblerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/CobblerBlockEntity.kt @@ -11,7 +11,6 @@ import ru.dbotthepony.mc.otm.block.entity.ItemJob import ru.dbotthepony.mc.otm.block.entity.JobContainer import ru.dbotthepony.mc.otm.block.entity.JobStatus import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyHatchBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyHatchBlockEntity.kt index d9a8c7517..da9d414d6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyHatchBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyHatchBlockEntity.kt @@ -17,7 +17,6 @@ import ru.dbotthepony.mc.otm.capability.moveEnergy import ru.dbotthepony.mc.otm.config.EnergyBalanceValues import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.HandlerFilter -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.RelativeSide diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyInterfaceBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyInterfaceBlockEntity.kt index ab84548ff..feb34a081 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyInterfaceBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyInterfaceBlockEntity.kt @@ -19,7 +19,6 @@ import ru.dbotthepony.mc.otm.capability.energy.CombinedProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.moveEnergy import ru.dbotthepony.mc.otm.container.HandlerFilter -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.RelativeSide diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyServoBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyServoBlockEntity.kt index b40910235..627227a9a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyServoBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyServoBlockEntity.kt @@ -16,7 +16,6 @@ import ru.dbotthepony.mc.otm.capability.extractEnergy import ru.dbotthepony.mc.otm.capability.maxEnergyStoredMattery import ru.dbotthepony.mc.otm.capability.moveEnergy import ru.dbotthepony.mc.otm.capability.receiveEnergy -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt index e5221721c..35f4e5b7c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt @@ -25,7 +25,6 @@ import ru.dbotthepony.mc.otm.capability.item.CombinedItemHandler import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.HandlerFilter -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ItemHatchBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ItemHatchBlockEntity.kt index 2f40e9a0b..c6cab62b0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ItemHatchBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ItemHatchBlockEntity.kt @@ -10,7 +10,6 @@ import net.neoforged.neoforge.capabilities.Capabilities import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity import ru.dbotthepony.mc.otm.container.HandlerFilter -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/MatterHatchBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/MatterHatchBlockEntity.kt index 7a85e84e0..b493464c8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/MatterHatchBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/MatterHatchBlockEntity.kt @@ -16,7 +16,6 @@ import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage import ru.dbotthepony.mc.otm.capability.moveMatter import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.HandlerFilter -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.Decimal diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt index ff5f4e31c..ac4949ce1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt @@ -18,7 +18,6 @@ import ru.dbotthepony.mc.otm.capability.UpgradeType import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.config.MachinesConfig -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.balance import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt deleted file mode 100644 index fc9c3d58d..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/MatteryContainer.kt +++ /dev/null @@ -1,498 +0,0 @@ -package ru.dbotthepony.mc.otm.container - -import com.mojang.serialization.Codec -import com.mojang.serialization.codecs.RecordCodecBuilder -import it.unimi.dsi.fastutil.ints.IntAVLTreeSet -import it.unimi.dsi.fastutil.ints.IntArrayList -import it.unimi.dsi.fastutil.ints.IntComparators -import it.unimi.dsi.fastutil.ints.IntSpliterator -import it.unimi.dsi.fastutil.objects.ObjectSpliterators -import net.minecraft.core.HolderLookup -import net.minecraft.core.registries.BuiltInRegistries -import net.minecraft.world.item.ItemStack -import net.minecraft.nbt.CompoundTag -import net.minecraft.nbt.NbtOps -import net.minecraft.nbt.Tag -import net.minecraft.world.Container -import net.minecraft.world.entity.player.Player -import net.minecraft.world.entity.player.StackedContents -import net.minecraft.world.inventory.StackedContentsCompatible -import net.minecraft.world.item.Item -import net.minecraft.world.item.Items -import net.neoforged.neoforge.common.util.INBTSerializable -import org.apache.logging.log4j.LogManager -import ru.dbotthepony.kommons.util.Delegate -import ru.dbotthepony.mc.otm.core.addSorted -import ru.dbotthepony.mc.otm.core.collect.any -import ru.dbotthepony.mc.otm.core.collect.count -import ru.dbotthepony.mc.otm.core.collect.emptyIterator -import ru.dbotthepony.mc.otm.core.collect.filter -import ru.dbotthepony.mc.otm.core.collect.map -import ru.dbotthepony.mc.otm.core.collect.toList -import ru.dbotthepony.mc.otm.core.immutableList -import ru.dbotthepony.mc.otm.core.isNotEmpty -import ru.dbotthepony.mc.otm.data.codec.minRange -import ru.dbotthepony.mc.otm.network.StreamCodecs -import ru.dbotthepony.mc.otm.network.syncher.ISynchable -import ru.dbotthepony.mc.otm.network.syncher.SynchableObservedDelegate -import java.util.* -import java.util.function.Consumer -import java.util.function.Predicate -import java.util.function.Supplier -import java.util.stream.Stream -import java.util.stream.StreamSupport -import kotlin.collections.ArrayList - -@Suppress("UNUSED") -open class MatteryContainer(var listener: ContainerListener, private val size: Int) : IMatteryContainer, INBTSerializable, StackedContentsCompatible { - constructor(watcher: Runnable, size: Int) : this({ _, _, _ -> watcher.run() }, size) - constructor(size: Int) : this(EmptyListener, size) - - fun interface ContainerListener { - fun setChanged(slot: Int, new: ItemStack, old: ItemStack) - } - - object EmptyListener : ContainerListener { - override fun setChanged(slot: Int, new: ItemStack, old: ItemStack) {} - } - - init { - require(size >= 0) { "Invalid container size $size" } - } - - private val slots = Array(size) { ItemStack.EMPTY } - private val nonEmptyFlags = BitSet() - private var nonEmptyIndices = IntArrayList() - private var indicesReferenced = false - private data class Update(val slot: Int, val new: ItemStack, val old: ItemStack) - private val queuedUpdates = ArrayList() - private var queueUpdates = false - - private fun cowIndices() { - if (indicesReferenced) { - nonEmptyIndices = IntArrayList(nonEmptyIndices) - indicesReferenced = false - } - } - - private val trackedSlots: Array = Array(size) { ItemStack.EMPTY } - private val filters: Array = arrayOfNulls(size) - - var changeset = 0 - private set - - override fun clearSlotFilters() { - Arrays.fill(filters, null) - } - - val synchableFilters by lazy { - immutableList { - for (i in 0 until size) { - accept(SynchableObservedDelegate(Delegate.Of({ filters[i] }, { filters[i] = it }), StreamCodecs.ITEM_TYPE_NULLABLE)) - } - } - } - - final override fun setSlotFilter(slot: Int, filter: Item?): Boolean { - filters[slot] = filter - return true - } - - final override fun getSlotFilter(slot: Int) = filters[slot] - final override fun hasSlotFilter(slot: Int) = filters[slot] !== null - final override fun isSlotForbiddenForAutomation(slot: Int) = filters[slot] === Items.AIR - - final override fun testSlotFilter(slot: Int, itemStack: ItemStack): Boolean { - return testSlotFilter(slot, itemStack.item) - } - - final override fun testSlotFilter(slot: Int, item: Item): Boolean { - if (filters[slot] == null) { - return true - } else { - return filters[slot] === item - } - } - - final override fun getContainerSize() = size - protected open fun startedIgnoringUpdates() {} - protected open fun stoppedIgnoringUpdates() {} - - private data class SerializedItem(val item: ItemStack, val slot: Int) { - companion object { - val CODEC: Codec = RecordCodecBuilder.create { - it.group( - ItemStack.OPTIONAL_CODEC.fieldOf("item").forGetter { it.item }, - Codec.INT.minRange(0).fieldOf("slot").forGetter { it.slot }, - ).apply(it, ::SerializedItem) - } - } - } - - private data class SerializedFilter(val item: Item, val slot: Int) { - companion object { - val CODEC: Codec = RecordCodecBuilder.create { - it.group( - BuiltInRegistries.ITEM.byNameCodec().fieldOf("item").forGetter { it.item }, - Codec.INT.minRange(0).fieldOf("slot").forGetter { it.slot }, - ).apply(it, ::SerializedFilter) - } - } - } - - private data class SerializedState( - val items: List, - val filters: List - ) { - companion object { - val CODEC: Codec = RecordCodecBuilder.create { - it.group( - Codec.list(SerializedItem.CODEC).fieldOf("items").forGetter { it.items }, - Codec.list(SerializedFilter.CODEC).fieldOf("filters").forGetter { it.filters }, - ).apply(it, ::SerializedState) - } - } - } - - override fun deserializeNBT(registries: HolderLookup.Provider, tag: Tag?) { - Arrays.fill(slots, ItemStack.EMPTY) - Arrays.fill(filters, null) - nonEmptyFlags.clear() - nonEmptyIndices = IntArrayList() - - if (tag != null) { - SerializedState.CODEC.parse(registries.createSerializationContext(NbtOps.INSTANCE), tag) - .resultOrPartial { LOGGER.error("Error deserializing container: $it") } - .ifPresent { - val freeSlots = IntAVLTreeSet() - - for (i in 0 until size) - freeSlots.add(i) - - for ((item, slotID) in it.items) { - if (item.isEmpty) - continue - - if (freeSlots.remove(slotID)) { - slots[slotID] = item - // trackedSlots[slotID] = item.copy() - } else if (freeSlots.isEmpty()) { - break - } else { - val slotID = freeSlots.firstInt() - freeSlots.remove(slotID) - slots[slotID] = item - // trackedSlots[slotID] = item.copy() - } - } - - for ((item, index) in it.filters) { - if (index in 0 until size) - filters[index] = item - } - - setChanged() - } - } - } - - private fun internalSetChanged(slot: Int, new: ItemStack, old: ItemStack) { - if (queueUpdates) { - queuedUpdates.add(Update(slot, new, old)) - } else { - setChanged(slot, new, old) - } - } - - private fun runUpdates() { - for ((slot, new, old) in queuedUpdates) { - setChanged(slot, new, old) - } - - queuedUpdates.clear() - } - - protected open fun setChanged(slot: Int, new: ItemStack, old: ItemStack) { - listener.setChanged(slot, new, old) - } - - override fun serializeNBT(registries: HolderLookup.Provider): CompoundTag { - val state = SerializedState( - slotIterator(true).map { SerializedItem(it.item, it.slot) }.toList(size), - filters.withIndex().iterator().filter { it.value != null }.map { SerializedFilter(it.value!!, it.index) }.toList() - ) - - return SerializedState.CODEC.encodeStart(registries.createSerializationContext(NbtOps.INSTANCE), state) - .resultOrPartial { throw RuntimeException("Failed to encode container contents: $it") }.get() as CompoundTag - } - - final override fun isEmpty(): Boolean { - return nonEmptyIndices.isEmpty - } - - operator fun contains(other: ItemStack): Boolean { - for (i in 0 until size) { - if (ItemStack.isSameItemSameComponents(this[i], other)) { - return true - } - } - - return false - } - - final override fun getItem(slot: Int): ItemStack { - val item = slots[slot] - - if (item.isEmpty) { - if (nonEmptyFlags[slot]) { - setChanged(slot) - } - - return ItemStack.EMPTY - } else { - if (!nonEmptyFlags[slot]) { - setChanged(slot) - } - - return item - } - } - - override fun fillStackedContents(contents: StackedContents) { - for (item in iterator()) { - contents.accountStack(item) - } - } - - final override fun removeItem(slot: Int, amount: Int): ItemStack { - if (amount <= 0 || slot < 0 || slot >= size || slots[slot].isEmpty) - return ItemStack.EMPTY - - val old = slots[slot].copy() - val split = slots[slot].split(amount) - trackedSlots[slot] = slots[slot].copy() - changeset++ - updateEmptyFlag(slot) - internalSetChanged(slot, if (slots[slot].isEmpty) ItemStack.EMPTY else slots[slot], old) - - return split - } - - final override fun removeItemNoUpdate(slot: Int): ItemStack { - val old = slots[slot] - slots[slot] = ItemStack.EMPTY - trackedSlots[slot] = ItemStack.EMPTY - - if (old.isNotEmpty) { - updateEmptyFlag(slot) - changeset++ - } - - return old - } - - final override fun setItem(slot: Int, itemStack: ItemStack) { - if (slots[slot].isEmpty && itemStack.isEmpty || itemStack === slots[slot]) - return - - val old = slots[slot] - slots[slot] = if (itemStack.isEmpty) ItemStack.EMPTY else itemStack - trackedSlots[slot] = if (itemStack.isEmpty) ItemStack.EMPTY else itemStack.copy() - - updateEmptyFlag(slot) - changeset++ - internalSetChanged(slot, itemStack, old) - } - - final override fun setChanged() { - queueUpdates = true - - try { - for (slot in 0 until size) { - setChanged(slot) - } - - runUpdates() - } finally { - queuedUpdates.clear() - queueUpdates = false - } - } - - final override fun setChanged(slot: Int) { - if (!ItemStack.isSameItemSameComponents(slots[slot], trackedSlots[slot])) { - trackedSlots[slot] = slots[slot].copy() - updateEmptyFlag(slot) - changeset++ - internalSetChanged(slot, slots[slot], trackedSlots[slot]) - // mojang соси))0)0))0)))))0) - } - } - - private fun updateEmptyFlag(slot: Int) { - if (slots[slot].isEmpty) { - if (nonEmptyFlags[slot]) { - nonEmptyFlags[slot] = false - cowIndices() - nonEmptyIndices.rem(slot) - } - } else { - if (!nonEmptyFlags[slot]) { - nonEmptyFlags[slot] = true - cowIndices() - nonEmptyIndices.addSorted(slot, IntComparators.NATURAL_COMPARATOR) - } - } - } - - override fun stillValid(player: Player): Boolean { - return true - } - - final override fun clearContent() { - nonEmptyFlags.clear() - nonEmptyIndices = IntArrayList() - - Arrays.fill(trackedSlots, ItemStack.EMPTY) - - for (slot in 0 until size) { - if (!slots[slot].isEmpty) { - val old = slots[slot] - slots[slot] = ItemStack.EMPTY - internalSetChanged(slot, ItemStack.EMPTY, old) - } - } - } - - private inner class Iterator : kotlin.collections.Iterator { - init { - indicesReferenced = true - } - - private val parent = nonEmptyIndices.intIterator() - private var lastIndex = -1 - - override fun hasNext(): Boolean { - return parent.hasNext() - } - - override fun next(): ItemStack { - lastIndex = parent.nextInt() - return getItem(lastIndex) - } - } - - private inner class Spliterator(private val parent: IntSpliterator) : java.util.Spliterator { - override fun tryAdvance(action: Consumer): Boolean { - return parent.tryAdvance { - action.accept(getItem(it)) - } - } - - override fun trySplit(): java.util.Spliterator? { - return parent.trySplit()?.let(::Spliterator) - } - - override fun estimateSize(): Long { - return parent.estimateSize() - } - - override fun characteristics(): Int { - return parent.characteristics() - } - } - - final override fun iterator(): kotlin.collections.Iterator { - if (isEmpty) { - return emptyIterator() - } - - return Iterator() - } - - final override fun iterator(nonEmpty: Boolean): kotlin.collections.Iterator { - if (!nonEmpty) { - return (0 until size).iterator().map { slots[it] } - } else if (isEmpty) { - return emptyIterator() - } else { - return Iterator() - } - } - - inner class Slot(val slot: Int) : IFilteredContainerSlot { - override var item: ItemStack - get() = this@MatteryContainer[slot] - set(value) { this@MatteryContainer[slot] = value } - override val maxStackSize: Int - get() = this@MatteryContainer.maxStackSize - - override fun remove(): ItemStack { - return removeItemNoUpdate(slot) - } - - override fun remove(count: Int): ItemStack { - return removeItem(slot, count) - } - - override var filter: Item? - get() = getSlotFilter(slot) - set(value) { setSlotFilter(slot, value) } - - override val isForbiddenForAutomation: Boolean - get() = isSlotForbiddenForAutomation(slot) - - override fun maxStackSize(item: ItemStack): Int { - return getMaxStackSize(slot, item) - } - - override fun setChanged() { - setChanged(slot) - } - } - - final override fun slotIterator(): kotlin.collections.Iterator { - indicesReferenced = true - return nonEmptyIndices.iterator().map { Slot(it) } - } - - final override fun slotIterator(nonEmpty: Boolean): kotlin.collections.Iterator { - if (!nonEmpty) { - return (0 until size).iterator().map { Slot(it) } - } else if (isEmpty) { - return emptyIterator() - } else { - indicesReferenced = true - return nonEmptyIndices.iterator().map { Slot(it) } - } - } - - final override fun containerSlot(slot: Int): Slot { - return Slot(slot) - } - - final override fun countItem(item: Item): Int { - return iterator().filter { it.item == item }.count().toInt() - } - - final override fun hasAnyOf(items: Set): Boolean { - return iterator().any { it.item in items } - } - - final override fun hasAnyMatching(predicate: Predicate): Boolean { - return iterator().any(predicate) - } - - final override fun spliterator(): java.util.Spliterator { - if (isEmpty) { - return ObjectSpliterators.emptySpliterator() - } - - indicesReferenced = true - return Spliterator(nonEmptyIndices.intSpliterator()) - } - - companion object { - private val LOGGER = LogManager.getLogger() - } -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ShadowContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ShadowContainer.kt deleted file mode 100644 index 93c85355e..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ShadowContainer.kt +++ /dev/null @@ -1,47 +0,0 @@ -package ru.dbotthepony.mc.otm.container - -import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap -import net.minecraft.world.Container -import net.minecraft.world.item.ItemStack - -class ShadowContainer(private val parent: Container) : IContainer by IContainer.wrap(parent) { - private val shadowed = Int2ObjectArrayMap(0) - - override fun clearContent() { - shadowed.clear() - parent.clearContent() - } - - override fun isEmpty(): Boolean { - return parent.isEmpty && shadowed.isEmpty() - } - - override fun getItem(slot: Int): ItemStack { - return shadowed[slot] ?: parent.getItem(slot) - } - - override fun removeItem(slot: Int, count: Int): ItemStack { - val shadow = shadowed[slot] ?: return parent.removeItem(slot, count) - val copy = shadow.copyWithCount(shadow.count.coerceAtLeast(count)) - shadow.split(count) - if (shadow.isEmpty) shadowed[slot] = ItemStack.EMPTY - return copy - } - - override fun removeItemNoUpdate(slot: Int): ItemStack { - shadowed[slot] ?: return parent.removeItemNoUpdate(slot) - val old = shadowed[slot] - shadowed[slot] = ItemStack.EMPTY - return old!! - } - - override fun setItem(slot: Int, item: ItemStack) { - shadowed[slot] = item - } - - companion object { - fun shadow(container: Container, slot: Int, itemStack: ItemStack): Container { - return ShadowContainer(container).also { it[slot] = itemStack } - } - } -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ShadowCraftingContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ShadowCraftingContainer.kt deleted file mode 100644 index 95123a710..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ShadowCraftingContainer.kt +++ /dev/null @@ -1,33 +0,0 @@ -package ru.dbotthepony.mc.otm.container - -import net.minecraft.world.entity.player.StackedContents -import net.minecraft.world.inventory.CraftingContainer -import net.minecraft.world.item.ItemStack -import ru.dbotthepony.mc.otm.container.util.iterator -import ru.dbotthepony.mc.otm.core.collect.toList - -class ShadowCraftingContainer(private val parent: CraftingContainer) : IContainer by ShadowContainer(parent), CraftingContainer { - override fun fillStackedContents(contents: StackedContents) { - for (item in iterator()) { - contents.accountStack(item) - } - } - - override fun getWidth(): Int { - return parent.width - } - - override fun getHeight(): Int { - return parent.height - } - - override fun getItems(): MutableList { - return iterator().toList() - } - - companion object { - fun shadow(container: CraftingContainer, slot: Int, itemStack: ItemStack): CraftingContainer { - return ShadowCraftingContainer(container).also { it[slot] = itemStack } - } - } -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/TooltipList.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/TooltipList.kt index 4ee84e841..0ab1d1033 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/TooltipList.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/TooltipList.kt @@ -23,7 +23,6 @@ import ru.dbotthepony.mc.otm.client.ShiftPressedCond import ru.dbotthepony.mc.otm.client.isShiftDown import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.config.ClientConfig -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.nbt.map diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/GrillMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/GrillMenu.kt index 644d81902..57a021e42 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/GrillMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/GrillMenu.kt @@ -10,7 +10,6 @@ import net.minecraft.world.item.crafting.RecipeType import net.minecraft.world.item.crafting.SingleRecipeInput import ru.dbotthepony.kommons.util.getValue import ru.dbotthepony.mc.otm.block.entity.decorative.GrillBlockEntity -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.immutableList diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/PainterMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/PainterMenu.kt index bff6b40eb..ec7eec0dc 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/PainterMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/decorative/PainterMenu.kt @@ -16,7 +16,6 @@ import ru.dbotthepony.kommons.util.getValue import ru.dbotthepony.kommons.util.setValue import ru.dbotthepony.mc.otm.block.entity.decorative.PainterBlockEntity import ru.dbotthepony.mc.otm.player.matteryPlayer -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.set import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.addAll diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt index c8bc3e8df..c8d12575e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt @@ -86,7 +86,6 @@ import ru.dbotthepony.mc.otm.container.IContainerSlot import ru.dbotthepony.mc.otm.container.IEnhancedContainer import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot import ru.dbotthepony.mc.otm.container.IMatteryContainer -import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.get import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer From 59eab74b4404fd66ae0d4d5b26c2da893c499328 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 14 Mar 2025 18:38:28 +0700 Subject: [PATCH 084/154] Remove IMatteryContainer --- .../capability/item/CombinedItemHandler.kt | 3 +- .../mc/otm/container/CombinedContainer.kt | 26 +-- .../mc/otm/container/ContainerHandler.kt | 89 -------- .../mc/otm/container/IMatteryContainer.kt | 203 ------------------ .../mc/otm/container/util/Iterators.kt | 1 - .../ru/dbotthepony/mc/otm/menu/Slots.kt | 1 - .../mc/otm/player/MatteryPlayer.kt | 1 - 7 files changed, 6 insertions(+), 318 deletions(-) delete mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerHandler.kt delete mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/item/CombinedItemHandler.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/item/CombinedItemHandler.kt index cd21d7221..1cd762f2e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/item/CombinedItemHandler.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/item/CombinedItemHandler.kt @@ -3,7 +3,6 @@ package ru.dbotthepony.mc.otm.capability.item import com.google.common.collect.ImmutableList import net.minecraft.world.item.ItemStack import net.neoforged.neoforge.items.IItemHandler -import ru.dbotthepony.mc.otm.container.ContainerHandler import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import java.util.stream.Stream @@ -12,7 +11,7 @@ class CombinedItemHandler(val handlers: ImmutableList) : IItemHand constructor(handlers: Collection) : this(ImmutableList.copyOf(handlers)) constructor(vararg handlers: IItemHandler) : this(ImmutableList.copyOf(handlers)) - private val needsChecking = handlers.any { it !is ContainerHandler && it !is SlottedContainer } + private val needsChecking = handlers.any { it !is SlottedContainer } private val lastSizes = IntArray(this.handlers.size) private var totalSize = 0 private val mappings = ArrayList() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt index 5f495f997..199414482 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt @@ -23,7 +23,7 @@ import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.stream import java.util.stream.Stream -class CombinedContainer(containers: Stream, Iterable>>) : ISlottedContainer, IMatteryContainer { +class CombinedContainer(containers: Stream, Iterable>>) : ISlottedContainer { constructor(vararg containers: IEnhancedContainer<*>) : this(containers.stream().map { it to (0 until it.containerSize) }) constructor(containers: Collection>) : this(containers.stream().map { it to (0 until it.containerSize) }) @@ -116,28 +116,12 @@ class CombinedContainer(containers: Stream, Iterable< ) } - override fun slotIterator(): Iterator { - return slots.iterator().map { - if (it is IFilteredContainerSlot) it else IFilteredContainerSlot.Dummy(it) - } + override fun slotIterator(): Iterator { + return slots.iterator() } - override fun containerSlot(slot: Int): IFilteredContainerSlot { - val getSlot = slots[slot] - if (getSlot is IFilteredContainerSlot) return getSlot - return IFilteredContainerSlot.Dummy(getSlot) - } - - override fun getMaxStackSize(slot: Int, itemStack: ItemStack): Int { - return super.getMaxStackSize(slot, itemStack) - } - - override fun getSlotFilter(slot: Int): Item? { - return containerSlot(slot).filter - } - - override fun clearSlotFilters() { - + override fun containerSlot(slot: Int): IContainerSlot { + return slots[slot] } override fun setChanged(slot: Int) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerHandler.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerHandler.kt deleted file mode 100644 index f3c21eb2d..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerHandler.kt +++ /dev/null @@ -1,89 +0,0 @@ -package ru.dbotthepony.mc.otm.container - -import net.minecraft.world.item.ItemStack -import net.neoforged.neoforge.items.IItemHandler - -class ContainerHandler( - private val container: IMatteryContainer, - private val filter: HandlerFilter = HandlerFilter.Both, -) : IItemHandler { - override fun getSlots() = container.containerSize - override fun getStackInSlot(slot: Int) = container[slot] - - override fun insertItem(slot: Int, stack: ItemStack, simulate: Boolean): ItemStack { - if (!container.testSlotFilter(slot, stack) || !filter.canInsert(slot, stack)) - return stack - - filter.preInsert(slot, stack, simulate) - - val localStack = container[slot] - var amount = filter.modifyInsertCount(slot, stack, localStack, simulate) - - if (amount <= 0) - return stack - - if (localStack.isEmpty) { - amount = stack.count.coerceAtMost(container.getMaxStackSize(slot, stack)).coerceAtMost(amount) - - if (!simulate) { - container.setItem(slot, stack.copyWithCount(amount)) - } - - if (stack.count <= amount) { - return ItemStack.EMPTY - } else { - return stack.copyWithCount(stack.count - amount) - } - } else if (localStack.isStackable && container.getMaxStackSize(slot, localStack) > localStack.count && ItemStack.isSameItemSameComponents(localStack, stack)) { - val newCount = container.getMaxStackSize(slot, localStack).coerceAtMost(localStack.count + stack.count.coerceAtMost(amount)) - val diff = newCount - localStack.count - - if (diff != 0) { - if (!simulate) { - localStack.grow(diff) - container.setChanged(slot) - } - - val copy = stack.copy() - copy.shrink(diff) - return copy - } - } - - return stack - } - - override fun extractItem(slot: Int, amount: Int, simulate: Boolean): ItemStack { - if (amount <= 0 || container.isSlotForbiddenForAutomation(slot)) - return ItemStack.EMPTY - - val localStack = container.getItem(slot) - if (localStack.isEmpty) return ItemStack.EMPTY - - @Suppress("name_shadowing") - val amount = filter.modifyExtractCount(slot, amount, simulate) - if (amount <= 0) return ItemStack.EMPTY - if (!filter.canExtract(slot, amount, localStack)) return ItemStack.EMPTY - - filter.preExtract(slot, amount, simulate) - - val minimal = amount.coerceAtMost(localStack.count) - val copy = localStack.copy() - copy.count = minimal - - if (!simulate) { - localStack.shrink(minimal) - container.setChanged(slot) - } - - return copy - } - - override fun getSlotLimit(slot: Int): Int { - return container.maxStackSize - } - - override fun isItemValid(slot: Int, stack: ItemStack): Boolean { - return container.testSlotFilter(slot, stack) && filter.canInsert(slot, stack) - } -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt deleted file mode 100644 index 7d383f010..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IMatteryContainer.kt +++ /dev/null @@ -1,203 +0,0 @@ -package ru.dbotthepony.mc.otm.container - -import it.unimi.dsi.fastutil.ints.IntIterable -import net.minecraft.world.item.Item -import net.minecraft.world.item.ItemStack -import net.minecraft.world.item.Items -import net.minecraft.world.item.crafting.RecipeInput -import ru.dbotthepony.mc.otm.core.collect.filter -import ru.dbotthepony.mc.otm.core.collect.map -import ru.dbotthepony.mc.otm.core.isNotEmpty - -interface IMatteryContainer : IEnhancedContainer { - fun getSlotFilter(slot: Int): Item? - - /** - * @return whenever the filter was set. Returns false only if container can't be filtered. - */ - fun setSlotFilter(slot: Int, filter: Item? = null): Boolean { - return false - } - - fun clearSlotFilters() - - override fun isEmpty(): Boolean - - override fun size(): Int { - return containerSize - } - - /** - * Iterates over non-empty itemstacks of this container - */ - override fun iterator(): Iterator { - return iterator(true) - } - - /** - * Iterates non-empty slots of this container - */ - override fun slotIterator(): Iterator { - return slotIterator(true) - } - - fun iterator(nonEmpty: Boolean): Iterator { - if (nonEmpty) { - return (0 until containerSize).iterator().map { this[it] }.filter { it.isNotEmpty } - } else { - return (0 until containerSize).iterator().map { this[it] } - } - } - - /** - * Iterates either non-empty slots of container or all slots of container - */ - fun slotIterator(nonEmpty: Boolean): Iterator { - if (nonEmpty) { - return (0 until containerSize).iterator().filter { this[it].isNotEmpty }.map { containerSlot(it) } - } else { - return (0 until containerSize).iterator().map { containerSlot(it) } - } - } - - override fun containerSlot(slot: Int): IFilteredContainerSlot - - fun hasSlotFilter(slot: Int) = getSlotFilter(slot) !== null - fun isSlotForbiddenForAutomation(slot: Int) = getSlotFilter(slot) === Items.AIR - - fun testSlotFilter(slot: Int, itemStack: ItemStack): Boolean { - return testSlotFilter(slot, itemStack.item) - } - - fun testSlotFilter(slot: Int, item: Item): Boolean { - if (getSlotFilter(slot) == null) { - return true - } else { - return getSlotFilter(slot) === item - } - } - - override fun getMaxStackSize(slot: Int, itemStack: ItemStack) = maxStackSize.coerceAtMost(itemStack.maxStackSize) - - private fun addItem(stack: ItemStack, simulate: Boolean, filterPass: Boolean, slots: IntIterable, onlyIntoExisting: Boolean, popTime: Int?, ignoreFilters: Boolean): ItemStack { - if (stack.isEmpty) - return stack - - // двигаем в одинаковые слоты - var i = slots.intIterator() - - while (i.hasNext()) { - val slot = i.nextInt() - - if ( - (ignoreFilters || !isSlotForbiddenForAutomation(slot)) && - ItemStack.isSameItemSameComponents(getItem(slot), stack) && - (ignoreFilters || !filterPass && !hasSlotFilter(slot) || filterPass && hasSlotFilter(slot) && testSlotFilter(slot, stack)) - ) { - val slotStack = getItem(slot) - val slotLimit = getMaxStackSize(slot, slotStack) - - if (slotStack.count < slotLimit) { - val newCount = (slotStack.count + stack.count).coerceAtMost(slotLimit) - val diff = newCount - slotStack.count - - if (!simulate) { - slotStack.count = newCount - setChanged(slot) - - if (popTime != null) { - slotStack.popTime = popTime - } - } - - stack.shrink(diff) - - if (stack.isEmpty) { - return stack - } - } - } - } - - if (!onlyIntoExisting) { - i = slots.intIterator() - - // двигаем в пустые слоты - while (i.hasNext()) { - val slot = i.nextInt() - - if ( - getItem(slot).isEmpty && - (ignoreFilters || !isSlotForbiddenForAutomation(slot)) && - (ignoreFilters || !filterPass && !hasSlotFilter(slot) || filterPass && hasSlotFilter(slot) && testSlotFilter(slot, stack)) - ) { - val diff = stack.count.coerceAtMost(getMaxStackSize(slot, stack)) - - if (!simulate) { - val copyToPut = stack.copy() - copyToPut.count = diff - setItem(slot, copyToPut) - - if (popTime != null) { - copyToPut.popTime = popTime - } - } - - stack.shrink(diff) - - if (stack.isEmpty) { - return stack - } - } - } - } - - return stack - } - - fun addItem(stack: ItemStack, simulate: Boolean, slots: IntIterable = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean = false): ItemStack { - if (stack.isEmpty) - return stack - - if (ignoreFilters) { - return addItem(stack.copy(), simulate, true, slots, onlyIntoExisting, popTime, true) - } else { - var copy = addItem(stack.copy(), simulate, true, slots, onlyIntoExisting, popTime, false) - copy = addItem(copy, simulate, false, slots, onlyIntoExisting, popTime, false) - return copy - } - } - - fun handler(filter: HandlerFilter = HandlerFilter.Both): ContainerHandler { - return ContainerHandler(this, filter) - } - - /** - * Unlike [addItem], modifies original [stack] - * - * @return Whenever [stack] was modified - */ - fun consumeItem(stack: ItemStack, simulate: Boolean, slots: IntIterable = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean = false): Boolean { - if (stack.isEmpty) - return false - - val result = addItem(stack, simulate, slots, onlyIntoExisting, popTime, ignoreFilters) - - if (result.count != stack.count) { - if (!simulate) { - stack.count = result.count - } - - return true - } - - return false - } - - fun fullyAddItem(stack: ItemStack, slots: IntIterable = slotRange, ignoreFilters: Boolean = false): Boolean { - if (!addItem(stack, true, slots, ignoreFilters).isEmpty) - return false - - return addItem(stack, false, slots, ignoreFilters).isEmpty - } -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/util/Iterators.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/util/Iterators.kt index 39101d4cd..c5af49249 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/util/Iterators.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/util/Iterators.kt @@ -6,7 +6,6 @@ import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.container.IContainerSlot import ru.dbotthepony.mc.otm.container.IEnhancedContainer -import ru.dbotthepony.mc.otm.container.IMatteryContainer import ru.dbotthepony.mc.otm.container.get import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.collect.map diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt index a41dad0c2..b881d0172 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt @@ -21,7 +21,6 @@ import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.IEnhancedContainer import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot -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.util.containerSlotOrNull diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt index c8d12575e..5dbc065d0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt @@ -85,7 +85,6 @@ import ru.dbotthepony.mc.otm.container.IContainer import ru.dbotthepony.mc.otm.container.IContainerSlot import ru.dbotthepony.mc.otm.container.IEnhancedContainer import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot -import ru.dbotthepony.mc.otm.container.IMatteryContainer import ru.dbotthepony.mc.otm.container.get import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer From c43be6eb6200b10ad0e345c9df75d23f01d26f35 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 14 Mar 2025 18:40:10 +0700 Subject: [PATCH 085/154] Remove IContainer --- .../container/DynamicallyProxiedContainer.kt | 81 ---------------- .../mc/otm/container/IContainer.kt | 95 ------------------- .../mc/otm/container/IEnhancedContainer.kt | 33 ++++++- .../mc/otm/player/MatteryPlayer.kt | 2 - 4 files changed, 31 insertions(+), 180 deletions(-) delete mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/DynamicallyProxiedContainer.kt delete mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/IContainer.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/DynamicallyProxiedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/DynamicallyProxiedContainer.kt deleted file mode 100644 index b2e400392..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/DynamicallyProxiedContainer.kt +++ /dev/null @@ -1,81 +0,0 @@ -package ru.dbotthepony.mc.otm.container - -import net.minecraft.world.Container -import net.minecraft.world.entity.player.Player -import net.minecraft.world.item.Item -import net.minecraft.world.item.ItemStack -import java.util.function.Predicate -import java.util.function.Supplier - -/** - * because mods tend to do crazy shit - */ -class DynamicallyProxiedContainer(private val toProxy: Supplier) : IContainer { - override fun clearContent() { - return toProxy.get().clearContent() - } - - override fun getContainerSize(): Int { - return toProxy.get().containerSize - } - - override fun isEmpty(): Boolean { - return toProxy.get().isEmpty - } - - override fun getItem(slot: Int): ItemStack { - return toProxy.get().getItem(slot) - } - - override fun removeItem(slot: Int, amount: Int): ItemStack { - return toProxy.get().removeItem(slot, amount) - } - - override fun removeItemNoUpdate(slot: Int): ItemStack { - return toProxy.get().removeItemNoUpdate(slot) - } - - override fun setItem(slot: Int, itemStack: ItemStack) { - return toProxy.get().setItem(slot, itemStack) - } - - override fun setChanged() { - return toProxy.get().setChanged() - } - - override fun stillValid(player: Player): Boolean { - return toProxy.get().stillValid(player) - } - - override fun getMaxStackSize(): Int { - return toProxy.get().getMaxStackSize() - } - - override fun startOpen(player: Player) { - toProxy.get().startOpen(player) - } - - override fun stopOpen(player: Player) { - toProxy.get().stopOpen(player) - } - - override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean { - return toProxy.get().canPlaceItem(slot, itemStack) - } - - override fun canTakeItem(container: Container, slot: Int, itemStack: ItemStack): Boolean { - return toProxy.get().canTakeItem(container, slot, itemStack) - } - - override fun countItem(item: Item): Int { - return toProxy.get().countItem(item) - } - - override fun hasAnyOf(items: Set): Boolean { - return toProxy.get().hasAnyOf(items) - } - - override fun hasAnyMatching(predicate: Predicate): Boolean { - return toProxy.get().hasAnyMatching(predicate) - } -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IContainer.kt deleted file mode 100644 index 3afa4ab72..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IContainer.kt +++ /dev/null @@ -1,95 +0,0 @@ -package ru.dbotthepony.mc.otm.container - -import net.minecraft.world.Container -import net.minecraft.world.entity.player.Player -import net.minecraft.world.item.Item -import net.minecraft.world.item.ItemStack -import java.util.function.Predicate - -// passthrough all default methods to fix Kotlin bug related to implementation delegation not properly working on Java interfaces -// and also to give params proper names -// https://youtrack.jetbrains.com/issue/KT-55080/Change-the-behavior-of-inheritance-delegation-to-delegates-implementing-Java-interfaces-with-default-methods -interface IContainer : Container { - override fun getMaxStackSize(): Int { - return super.getMaxStackSize() - } - - override fun startOpen(player: Player) { - super.startOpen(player) - } - - override fun stopOpen(player: Player) { - super.stopOpen(player) - } - - override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean { - return super.canPlaceItem(slot, itemStack) - } - - override fun canTakeItem(container: Container, slot: Int, itemStack: ItemStack): Boolean { - return super.canTakeItem(container, slot, itemStack) - } - - override fun countItem(item: Item): Int { - return super.countItem(item) - } - - override fun hasAnyOf(items: Set): Boolean { - return super.hasAnyOf(items) - } - - override fun hasAnyMatching(predicate: Predicate): Boolean { - return super.hasAnyMatching(predicate) - } - - override fun clearContent() - override fun getContainerSize(): Int - override fun isEmpty(): Boolean - override fun getItem(slot: Int): ItemStack - override fun removeItem(slot: Int, amount: Int): ItemStack - override fun removeItemNoUpdate(slot: Int): ItemStack - override fun setItem(slot: Int, itemStack: ItemStack) - override fun setChanged() - - override fun stillValid(player: Player): Boolean - companion object { - fun wrap(container: Container): IContainer { - if (container is IContainer) - return container - else - return object : IContainer, Container by container { - override fun getMaxStackSize(): Int { - return container.getMaxStackSize() - } - - override fun startOpen(player: Player) { - container.startOpen(player) - } - - override fun stopOpen(player: Player) { - container.stopOpen(player) - } - - override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean { - return container.canPlaceItem(slot, itemStack) - } - - override fun canTakeItem(container: Container, slot: Int, itemStack: ItemStack): Boolean { - return container.canTakeItem(container, slot, itemStack) - } - - override fun countItem(item: Item): Int { - return container.countItem(item) - } - - override fun hasAnyOf(items: Set): Boolean { - return container.hasAnyOf(items) - } - - override fun hasAnyMatching(predicate: Predicate): Boolean { - return container.hasAnyMatching(predicate) - } - } - } - } -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt index 8a9fd2fac..f6560d196 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt @@ -19,12 +19,41 @@ import java.util.stream.Stream import java.util.stream.StreamSupport /** - * "Backward-compatible" enhanced container interface, where all methods can be derived/emulated from existing [IContainer] ([Container]) code + * "Backward-compatible" enhanced container interface, where all methods can be derived/emulated from existing [Container] code * * This is useful because it allows to interact with actually enhanced and regular containers through unified interface, * and actual implementations of this interface are likely to provide efficient method implementations in place of derived/emulated ones. */ -interface IEnhancedContainer : IContainer, RecipeInput, Iterable, StackedContentsCompatible { +interface IEnhancedContainer : Container, RecipeInput, Iterable, StackedContentsCompatible { + // https://youtrack.jetbrains.com/issue/KT-55080/Change-the-behavior-of-inheritance-delegation-to-delegates-implementing-Java-interfaces-with-default-methods + override fun getMaxStackSize(): Int { + return super.getMaxStackSize() + } + + override fun startOpen(player: Player) { + super.startOpen(player) + } + + override fun stopOpen(player: Player) { + super.stopOpen(player) + } + + override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean { + return super.canPlaceItem(slot, itemStack) + } + + override fun canTakeItem(container: Container, slot: Int, itemStack: ItemStack): Boolean { + return super.canTakeItem(container, slot, itemStack) + } + + override fun clearContent() + override fun getContainerSize(): Int + override fun getItem(slot: Int): ItemStack + override fun removeItem(slot: Int, amount: Int): ItemStack + override fun removeItemNoUpdate(slot: Int): ItemStack + override fun setItem(slot: Int, itemStack: ItemStack) + override fun setChanged() + // provide non-ambiguous get and set operators operator fun get(slot: Int): ItemStack { return getItem(slot) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt index 5dbc065d0..83c7d95bc 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt @@ -79,9 +79,7 @@ import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.config.PlayerConfig import ru.dbotthepony.mc.otm.config.ExopackConfig import ru.dbotthepony.mc.otm.container.CombinedContainer -import ru.dbotthepony.mc.otm.container.DynamicallyProxiedContainer import ru.dbotthepony.mc.otm.container.EnhancedContainer -import ru.dbotthepony.mc.otm.container.IContainer import ru.dbotthepony.mc.otm.container.IContainerSlot import ru.dbotthepony.mc.otm.container.IEnhancedContainer import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot From 90a22a093dbc298e2da0aa2a9602a6828d73e80a Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 14 Mar 2025 18:57:14 +0700 Subject: [PATCH 086/154] Don't create filter syncher for IPlayerInventorySlot --- src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt index b881d0172..b3644e38c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt @@ -30,6 +30,7 @@ import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.InstantBooleanInput import ru.dbotthepony.mc.otm.network.StreamCodecs +import ru.dbotthepony.mc.otm.player.IPlayerInventorySlot import ru.dbotthepony.mc.otm.runOnClient import java.util.* import java.util.function.BooleanSupplier @@ -58,7 +59,7 @@ open class MatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int open fun setupNetworkControls(menu: MatteryMenu) { val slot = containerSlotOrNull() - if (slot is IFilteredContainerSlot) { + if (slot is IFilteredContainerSlot && slot !is IPlayerInventorySlot) { menu.mSynchronizer.add(Delegate.Of(slot::filter), StreamCodecs.ITEM_TYPE_NULLABLE) } } From 2943026dd571d15f2407649a74ab5ce834b5fd6f Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 14 Mar 2025 19:06:49 +0700 Subject: [PATCH 087/154] Add generic param to CombinedContainer --- .../entity/storage/ItemMonitorBlockEntity.kt | 12 ++--- .../mc/otm/container/CombinedContainer.kt | 50 +++++++++---------- .../mc/otm/container/EnhancedContainer.kt | 2 +- .../mc/otm/container/IAutomatedContainer.kt | 2 +- .../mc/otm/container/IEnhancedContainer.kt | 2 +- .../container/IEnhancedCraftingContainer.kt | 4 +- .../mc/otm/container/ISlottedContainer.kt | 2 +- .../ru/dbotthepony/mc/otm/menu/MatteryMenu.kt | 20 ++++---- .../mc/otm/player/MatteryPlayer.kt | 14 +++--- 9 files changed, 53 insertions(+), 55 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt index 3098460df..26d051e29 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt @@ -96,42 +96,42 @@ class ItemMonitorPlayerSettings : INBTSerializable, IItemMonitorPla enum class IngredientPriority(override val component: Component, icon: Lazy, override val winding: UVWindingOrder = UVWindingOrder.NORMAL) : Setting { // Refill everything from system SYSTEM(TranslatableComponent("otm.gui.item_monitor.refill_source.system"), lazy { Widgets8.WHITE_ARROW_DOWN }, UVWindingOrder.FLIP) { - override fun takeOne(item: ItemStack, view: IStorageProvider?, inventory: CombinedContainer?, id: UUID?): Boolean { + override fun takeOne(item: ItemStack, view: IStorageProvider?, inventory: CombinedContainer<*>?, id: UUID?): Boolean { return takeOne(id, view) } }, // Refill everything from player's inventory INVENTORY(TranslatableComponent("otm.gui.item_monitor.refill_source.inventory"), lazy { Widgets8.WHITE_ARROW_DOWN }) { - override fun takeOne(item: ItemStack, view: IStorageProvider?, inventory: CombinedContainer?, id: UUID?): Boolean { + override fun takeOne(item: ItemStack, view: IStorageProvider?, inventory: CombinedContainer<*>?, id: UUID?): Boolean { return takeOne(inventory, item) } }, // Refill everything from system, if can't refill from player's inventory SYSTEM_FIRST(TranslatableComponent("otm.gui.item_monitor.refill_source.system_first"), lazy { Widgets8.ARROW_SIDEWAYS }, UVWindingOrder.FLIP) { - override fun takeOne(item: ItemStack, view: IStorageProvider?, inventory: CombinedContainer?, id: UUID?): Boolean { + override fun takeOne(item: ItemStack, view: IStorageProvider?, inventory: CombinedContainer<*>?, id: UUID?): Boolean { return takeOne(id, view) || takeOne(inventory, item) } }, // Refill everything from player's inventory, if can't refill from system INVENTORY_FIRST(TranslatableComponent("otm.gui.item_monitor.refill_source.inventory_first"), lazy { Widgets8.ARROW_SIDEWAYS }) { - override fun takeOne(item: ItemStack, view: IStorageProvider?, inventory: CombinedContainer?, id: UUID?): Boolean { + override fun takeOne(item: ItemStack, view: IStorageProvider?, inventory: CombinedContainer<*>?, id: UUID?): Boolean { return takeOne(inventory, item) || takeOne(id, view) } }, // Do not refill (?) DO_NOT(TranslatableComponent("otm.gui.item_monitor.refill_source.do_not"), lazy { Widgets8.MINUS }) { - override fun takeOne(item: ItemStack, view: IStorageProvider?, inventory: CombinedContainer?, id: UUID?): Boolean { + override fun takeOne(item: ItemStack, view: IStorageProvider?, inventory: CombinedContainer<*>?, id: UUID?): Boolean { return false } }; override val icon: IGUIRenderable by icon - abstract fun takeOne(item: ItemStack, view: IStorageProvider?, inventory: CombinedContainer?, id: UUID?): Boolean + abstract fun takeOne(item: ItemStack, view: IStorageProvider?, inventory: CombinedContainer<*>?, id: UUID?): Boolean } enum class ResultTarget(override val component: Component, icon: Lazy, override val winding: UVWindingOrder = UVWindingOrder.NORMAL) : Setting { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt index 199414482..0c658349b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt @@ -23,20 +23,20 @@ import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.stream import java.util.stream.Stream -class CombinedContainer(containers: Stream, Iterable>>) : ISlottedContainer { - constructor(vararg containers: IEnhancedContainer<*>) : this(containers.stream().map { it to (0 until it.containerSize) }) - constructor(containers: Collection>) : this(containers.stream().map { it to (0 until it.containerSize) }) +class CombinedContainer(containers: Stream, Iterable>>) : ISlottedContainer { + constructor(vararg containers: IEnhancedContainer) : this(containers.stream().map { it to (0 until it.containerSize) }) + constructor(containers: Collection>) : this(containers.stream().map { it to (0 until it.containerSize) }) - private val slots: ImmutableList - private val slotsMap: ImmutableMap> + private val slots: ImmutableList + private val slotsMap: ImmutableMap> private val containers: ImmutableSet private val fullCoverage: ImmutableList - private val notFullCoverage: ImmutableMap> + private val notFullCoverage: ImmutableMap> init { - val list = ImmutableList.Builder() + val list = ImmutableList.Builder() val validationMap = Reference2ObjectOpenHashMap() - val slotsMap = Reference2ObjectOpenHashMap>() + val slotsMap = Reference2ObjectOpenHashMap>() var i = 0 for ((container, slots) in containers) { @@ -116,11 +116,11 @@ class CombinedContainer(containers: Stream, Iterable< ) } - override fun slotIterator(): Iterator { + override fun slotIterator(): Iterator { return slots.iterator() } - override fun containerSlot(slot: Int): IContainerSlot { + override fun containerSlot(slot: Int): S { return slots[slot] } @@ -128,62 +128,62 @@ class CombinedContainer(containers: Stream, Iterable< slots[slot].setChanged() } - class Builder { - private val values = ArrayList, Iterable>>() + class Builder { + private val values = ArrayList, Iterable>>() - fun add(container: Container): Builder { + fun add(container: Container): Builder { return add(IEnhancedContainer.wrap(container)) } - fun add(container: Container, slots: Iterator): Builder { + fun add(container: Container, slots: Iterator): Builder { return add(IEnhancedContainer.wrap(container), slots) } - fun add(container: Container, slot: Int): Builder { + fun add(container: Container, slot: Int): Builder { return add(IEnhancedContainer.wrap(container), slot) } - fun add(container: Container, from: Int, to: Int): Builder { + fun add(container: Container, from: Int, to: Int): Builder { return add(IEnhancedContainer.wrap(container), from, to) } - fun add(container: Container, slots: Iterable): Builder { + fun add(container: Container, slots: Iterable): Builder { return add(IEnhancedContainer.wrap(container), slots) } - fun add(container: IEnhancedContainer<*>): Builder { + fun add(container: IEnhancedContainer): Builder { values.add(container to container.slotRange) return this } - fun add(container: IEnhancedContainer<*>, slots: Iterator): Builder { + fun add(container: IEnhancedContainer, slots: Iterator): Builder { values.add(container to IntArrayList(slots)) return this } - fun add(container: IEnhancedContainer<*>, slot: Int): Builder { + fun add(container: IEnhancedContainer, slot: Int): Builder { values.add(container to intArrayOf(slot).asIterable()) return this } - fun add(container: IEnhancedContainer<*>, from: Int, to: Int): Builder { + fun add(container: IEnhancedContainer, from: Int, to: Int): Builder { values.add(container to (from .. to)) return this } - fun add(container: IEnhancedContainer<*>, slots: Iterable): Builder { + fun add(container: IEnhancedContainer, slots: Iterable): Builder { values.add(container to slots) return this } - fun build(): CombinedContainer { + fun build(): CombinedContainer { return CombinedContainer(values.stream()) } } companion object { - fun fromMenuSlots(slots: Iterator): CombinedContainer { - val builder = Builder() + fun fromMenuSlots(slots: Iterator): CombinedContainer { + val builder = Builder() for (slot in slots) { builder.add(slot.container, slot.slotIndex) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt index fe1aa25d8..f012f130b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt @@ -23,7 +23,7 @@ import ru.dbotthepony.mc.otm.core.nbt.set * This is supposed to be counterpart to [SimpleContainer] of Minecraft itself, with more features * and improved performance (inside [IEnhancedContainer] defined methods). */ -abstract class EnhancedContainer(private val size: Int) : IEnhancedContainer, INBTSerializable { +abstract class EnhancedContainer(private val size: Int) : IEnhancedContainer, INBTSerializable { private val items = Array(size) { ItemStack.EMPTY } private val observedItems = Array(size) { ItemStack.EMPTY } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt index f143f30a2..529512d22 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IAutomatedContainer.kt @@ -10,7 +10,7 @@ import net.neoforged.neoforge.items.IItemHandlerModifiable * Reinforced [ISlottedContainer] which slots are [IAutomatedContainerSlot]s, which * subsequently allow this container to implement [IItemHandler] */ -interface IAutomatedContainer : ISlottedContainer, IItemHandlerModifiable { +interface IAutomatedContainer : ISlottedContainer, IItemHandlerModifiable { override fun canPlaceItem(slot: Int, itemStack: ItemStack): Boolean { return containerSlot(slot).canAutomationPlaceItem(itemStack) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt index f6560d196..d42d54a9b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt @@ -24,7 +24,7 @@ import java.util.stream.StreamSupport * This is useful because it allows to interact with actually enhanced and regular containers through unified interface, * and actual implementations of this interface are likely to provide efficient method implementations in place of derived/emulated ones. */ -interface IEnhancedContainer : Container, RecipeInput, Iterable, StackedContentsCompatible { +interface IEnhancedContainer : Container, RecipeInput, Iterable, StackedContentsCompatible { // https://youtrack.jetbrains.com/issue/KT-55080/Change-the-behavior-of-inheritance-delegation-to-delegates-implementing-Java-interfaces-with-default-methods override fun getMaxStackSize(): Int { return super.getMaxStackSize() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedCraftingContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedCraftingContainer.kt index e7e10a0dd..0866e8172 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedCraftingContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedCraftingContainer.kt @@ -4,7 +4,7 @@ import net.minecraft.world.entity.player.StackedContents import net.minecraft.world.inventory.CraftingContainer import net.minecraft.world.item.ItemStack -interface IEnhancedCraftingContainer : IEnhancedContainer, CraftingContainer { +interface IEnhancedCraftingContainer : IEnhancedContainer, CraftingContainer { override fun getItems(): MutableList { return toList() } @@ -13,7 +13,7 @@ interface IEnhancedCraftingContainer : IEnhancedContainer forEach { contents.accountSimpleStack(it) } } - class Wrapper, S : IContainerSlot>(val parent: C, private val width: Int, private val height: Int) : IEnhancedCraftingContainer, IEnhancedContainer by parent { + class Wrapper, out S : IContainerSlot>(val parent: C, private val width: Int, private val height: Int) : IEnhancedCraftingContainer, IEnhancedContainer by parent { init { require(width * height == parent.containerSize) { "Crafting container dimensions ($width x $height) do not match container size provided (${parent.containerSize})" } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt index d6bf3cda9..e3befae6a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt @@ -8,7 +8,7 @@ import ru.dbotthepony.kommons.collect.any /** * Skeletal implementation for containers which revolve around [IContainerSlot] */ -interface ISlottedContainer : IEnhancedContainer { +interface ISlottedContainer : IEnhancedContainer { override fun setChanged(slot: Int) { containerSlot(slot).setChanged() } 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 4c2a36e34..eb29aaa04 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt @@ -39,6 +39,7 @@ import ru.dbotthepony.mc.otm.player.matteryPlayer import ru.dbotthepony.mc.otm.compat.cos.cosmeticArmorSlots import ru.dbotthepony.mc.otm.compat.curios.curiosSlots import ru.dbotthepony.mc.otm.compat.curios.isCurioSlot +import ru.dbotthepony.mc.otm.container.IEnhancedContainer import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot import ru.dbotthepony.mc.otm.container.computeSortedIndices import ru.dbotthepony.mc.otm.container.sortWithIndices @@ -59,6 +60,7 @@ import ru.dbotthepony.mc.otm.network.readByteListUnbounded import ru.dbotthepony.mc.otm.network.syncher.SynchableGroup import ru.dbotthepony.mc.otm.network.wrap import ru.dbotthepony.mc.otm.network.writeByteListUnbounded +import ru.dbotthepony.mc.otm.player.IPlayerInventorySlot import java.util.* import java.util.function.BooleanSupplier import java.util.function.Consumer @@ -225,7 +227,7 @@ abstract class MatteryMenu( protected var inventorySlotIndexStart = 0 protected var inventorySlotIndexEnd = 0 - open inner class InventorySlot(container: Container, index: Int) : UserFilteredMenuSlot(container, index, 0, 0) { + open inner class InventorySlot(container: IEnhancedContainer, index: Int) : UserFilteredMenuSlot(container, index, 0, 0) { override fun mayPlace(itemStack: ItemStack): Boolean { return !isInventorySlotLocked(index) && super.mayPlace(itemStack) } @@ -238,19 +240,15 @@ abstract class MatteryMenu( private set init { - val mattery = player.matteryPlayer - - if (mattery.hasExopack) { - chargeFlag = Delegate.Of( - getter = { slotIndex in mattery.slotsChargeFlag }, - setter = booleanInput(true) { if (mattery.hasExopack) { if (it) mattery.slotsChargeFlag.add(slotIndex) else mattery.slotsChargeFlag.remove(slotIndex) } }::accept - ) + if (player.matteryPlayer.hasExopack) { + val slot = container.containerSlot(index) + chargeFlag = Delegate.Of(slot::shouldCharge) } } } - open inner class EquipmentMenuSlot(container: Container, index: Int, val type: net.minecraft.world.entity.EquipmentSlot) : InventorySlot(container, index) { - constructor(type: net.minecraft.world.entity.EquipmentSlot) : this(inventory, 34 + type.ordinal, type) + open inner class EquipmentMenuSlot(container: IEnhancedContainer, index: Int, val type: net.minecraft.world.entity.EquipmentSlot) : InventorySlot(container, index) { + constructor(type: net.minecraft.world.entity.EquipmentSlot) : this(player.matteryPlayer.wrappedInventory, 34 + type.ordinal, type) override fun setByPlayer(newItem: ItemStack, oldItem: ItemStack) { inventory.player.onEquipItem(type, oldItem, newItem) @@ -280,7 +278,7 @@ abstract class MatteryMenu( autoCreateInventoryFrame = autoFrame - offhandSlot = object : InventorySlot(inventory, 40) { + offhandSlot = object : InventorySlot(player.matteryPlayer.wrappedInventory, 40) { override fun setByPlayer(newItem: ItemStack, oldItem: ItemStack) { inventory.player.onEquipItem(net.minecraft.world.entity.EquipmentSlot.OFFHAND, oldItem, newItem) super.setByPlayer(newItem, oldItem) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt index 83c7d95bc..f0353e071 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt @@ -295,9 +295,9 @@ class MatteryPlayer(val ply: Player) { _combinedInventory3 = null } - private var _combinedInventory: CombinedContainer? = null - private var _combinedInventory2: CombinedContainer? = null - private var _combinedInventory3: CombinedContainer? = null + private var _combinedInventory: CombinedContainer? = null + private var _combinedInventory2: CombinedContainer? = null + private var _combinedInventory3: CombinedContainer? = null val wrappedInventory = PlayerInventoryWrapper(this) @@ -307,7 +307,7 @@ class MatteryPlayer(val ply: Player) { } } - val combinedInventory: CombinedContainer + val combinedInventory: CombinedContainer get() { if (_combinedInventory == null) _combinedInventory = CombinedContainer(wrappedInventory, exopackContainer) @@ -315,7 +315,7 @@ class MatteryPlayer(val ply: Player) { return _combinedInventory!! } - val inventoryAndExopack: CombinedContainer + val inventoryAndExopack: CombinedContainer get() { if (_combinedInventory2 == null) _combinedInventory2 = CombinedContainer(wrappedItemInventory, exopackContainer) @@ -323,10 +323,10 @@ class MatteryPlayer(val ply: Player) { return _combinedInventory2!! } - val inventoryAndExopackNoHotbar: CombinedContainer + val inventoryAndExopackNoHotbar: CombinedContainer get() { if (_combinedInventory3 == null) - _combinedInventory3 = CombinedContainer.Builder() + _combinedInventory3 = CombinedContainer.Builder() .add(wrappedItemInventory, 9 .. 35) .add(exopackContainer).build() From 4ab667b37eb510ad50c8b3df458727db6b11c363 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 14 Mar 2025 19:32:04 +0700 Subject: [PATCH 088/154] Ooprs!!1 --- .../kotlin/ru/dbotthepony/mc/otm/core/collect/IntRange2Set.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/IntRange2Set.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/IntRange2Set.kt index fccb08844..7e1588613 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/IntRange2Set.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/IntRange2Set.kt @@ -87,7 +87,7 @@ class IntRange2Set private constructor(private val first: Int, private val last: } override fun isEmpty(): Boolean { - return last > first + return last < first } override fun toArray(a: IntArray?): IntArray { @@ -158,7 +158,7 @@ class IntRange2Set private constructor(private val first: Int, private val last: } override val size: Int - get() = if (last > first) 0 else last - first + 1 + get() = if (last < first) 0 else last - first + 1 override fun toString(): String { if (isEmpty()) From 3a5f37bd7634b93a594ff32a071100d20443f454 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 14 Mar 2025 19:32:17 +0700 Subject: [PATCH 089/154] Specify argument names explicitly --- .../mc/otm/container/ISlottedContainer.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt index e3befae6a..59307ad96 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt @@ -141,16 +141,16 @@ interface ISlottedContainer : IEnhancedContainer { if (stack.isEmpty) return false - val result = addItem(stack, simulate, slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = ignoreFilters) + val result = addItem(stack, simulate = simulate, slots = slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = ignoreFilters) if (!simulate) stack.count = result.count return result.count != stack.count } fun fullyAddItem(stack: ItemStack, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean): Boolean { - if (!addItem(stack, true, slots, popTime = popTime, onlyIntoExisting = onlyIntoExisting, ignoreFilters = ignoreFilters).isEmpty) + if (!addItem(stack, simulate = true, slots = slots, popTime = popTime, onlyIntoExisting = onlyIntoExisting, ignoreFilters = ignoreFilters).isEmpty) return false - return addItem(stack, false, slots, popTime = popTime, onlyIntoExisting = onlyIntoExisting, ignoreFilters = ignoreFilters).isEmpty + return addItem(stack, simulate = false, slots = slots, popTime = popTime, onlyIntoExisting = onlyIntoExisting, ignoreFilters = ignoreFilters).isEmpty } override fun addItem( @@ -160,7 +160,7 @@ interface ISlottedContainer : IEnhancedContainer { onlyIntoExisting: Boolean, popTime: Int? ): ItemStack { - return addItem(stack, simulate, slots, onlyIntoExisting, popTime, ignoreFilters = false) + return addItem(stack, simulate = simulate, slots = slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = false) } override fun consumeItem( @@ -170,10 +170,10 @@ interface ISlottedContainer : IEnhancedContainer { onlyIntoExisting: Boolean, popTime: Int? ): Boolean { - return consumeItem(stack, simulate, slots, onlyIntoExisting, popTime, ignoreFilters = false) + return consumeItem(stack, simulate = simulate, slots = slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = false) } override fun fullyAddItem(stack: ItemStack, slots: IntCollection, onlyIntoExisting: Boolean, popTime: Int?): Boolean { - return fullyAddItem(stack, slots, onlyIntoExisting, popTime, ignoreFilters = false) + return fullyAddItem(stack, slots = slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = false) } } From 01215d647cb70be68037d00cc942010c32dc5524 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 14 Mar 2025 19:40:01 +0700 Subject: [PATCH 090/154] Cache hasFilterableSlots in CombinedContainer --- .../kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt index 0c658349b..ee5065ed5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/CombinedContainer.kt @@ -76,6 +76,8 @@ class CombinedContainer(containers: Stream Date: Fri, 14 Mar 2025 19:45:28 +0700 Subject: [PATCH 091/154] Always use slotted addItem implementation in containers --- .../mc/otm/container/IEnhancedContainer.kt | 111 +++++++++----- .../mc/otm/container/ISlottedContainer.kt | 145 +----------------- .../mc/otm/player/ExopackContainer.kt | 3 + 3 files changed, 80 insertions(+), 179 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt index d42d54a9b..2eb1774fe 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt @@ -1,7 +1,6 @@ package ru.dbotthepony.mc.otm.container import it.unimi.dsi.fastutil.ints.IntCollection -import it.unimi.dsi.fastutil.ints.IntSet import net.minecraft.world.Container import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.StackedContents @@ -253,60 +252,102 @@ interface IEnhancedContainer : Container, RecipeInput, I return list } - fun addItem(stack: ItemStack, simulate: Boolean, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null): ItemStack { + private fun addItem(stack: ItemStack, simulate: Boolean, filterPass: Boolean, slots: IntCollection, onlyIntoExisting: Boolean, popTime: Int?, ignoreFilters: Boolean): ItemStack { if (stack.isEmpty || slots.isEmpty()) return stack - val copy = stack.copy() - // двигаем в одинаковые слоты - for (slot in slotWithItemIterator(stack.item, slots)) { - if (ItemStack.isSameItemSameComponents(this[slot], copy)) { - val slotStack = this[slot] - val slotLimit = getMaxStackSize(slot, slotStack) + for (i in slotWithItemIterator(stack.item, slots)) { + val slot = containerSlot(i) - if (slotStack.count < slotLimit) { - val newCount = (slotStack.count + copy.count).coerceAtMost(slotLimit) - val diff = newCount - slotStack.count + val condition: Boolean + + if (slot is IFilteredContainerSlot) { + condition = (ignoreFilters || !slot.isForbiddenForAutomation) && + ItemStack.isSameItemSameComponents(slot.item, stack) && + (ignoreFilters || !filterPass && !slot.hasFilter || filterPass && slot.hasFilter && slot.testSlotFilter(stack)) + } else { + condition = (ignoreFilters || !filterPass) && ItemStack.isSameItemSameComponents(slot.item, stack) + } + + if (condition) { + val slotLimit = slot.maxStackSize(slot.item) + + if (slot.item.count < slotLimit) { + val newCount = (slot.item.count + stack.count).coerceAtMost(slotLimit) + val diff = newCount - slot.item.count if (!simulate) { - slotStack.count = newCount - setChanged(slot) + slot.item.count = newCount + slot.setChanged() if (popTime != null) { - slotStack.popTime = popTime + slot.item.popTime = popTime } } - copy.shrink(diff) + stack.shrink(diff) - if (copy.isEmpty) { + if (stack.isEmpty) return ItemStack.EMPTY - } } } } if (!onlyIntoExisting) { - // двигаем в пустые слоты - for (slot in emptySlotIndexIterator(slots)) { - val diff = copy.count.coerceAtMost(getMaxStackSize(slot, stack)) + for (i in emptySlotIndexIterator(slots)) { + val slot = containerSlot(i) - if (!simulate) { - val copyToPut = copy.copy() - copyToPut.count = diff - this[slot] = copyToPut - setChanged() + val condition: Boolean + + if (slot is IFilteredContainerSlot) { + condition = (ignoreFilters || !slot.isForbiddenForAutomation) && + (ignoreFilters || !filterPass && !slot.hasFilter || filterPass && slot.hasFilter && slot.testSlotFilter(stack)) + } else { + condition = ignoreFilters || !filterPass } - copy.shrink(diff) + if (condition) { + val diff = stack.count.coerceAtMost(slot.maxStackSize(stack)) - if (copy.isEmpty) - return ItemStack.EMPTY + if (!simulate) { + val copyToPut = stack.copy() + copyToPut.count = diff + slot.item = copyToPut + + if (popTime != null) { + copyToPut.popTime = popTime + } + } + + stack.shrink(diff) + + if (stack.isEmpty) + return ItemStack.EMPTY + } } } - return copy + return stack + } + + /** + * Hint used internally by [IEnhancedContainer] to potentially speed up default method implementations + */ + val hasFilterableSlots: Boolean + get() = false + + fun addItem(stack: ItemStack, simulate: Boolean, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean = false): ItemStack { + if (stack.isEmpty || slots.isEmpty()) + return stack + + if (ignoreFilters || !hasFilterableSlots) { + return addItem(stack.copy(), simulate, filterPass = true, slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = true) + } else { + var copy = addItem(stack.copy(), simulate, filterPass = true, slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = false) + copy = addItem(copy, simulate, filterPass = false, slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = false) + return copy + } } /** @@ -314,20 +355,20 @@ interface IEnhancedContainer : Container, RecipeInput, I * * @return Whenever [stack] was modified */ - fun consumeItem(stack: ItemStack, simulate: Boolean, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null): Boolean { - if (stack.isEmpty || slots.isEmpty()) + fun consumeItem(stack: ItemStack, simulate: Boolean, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean = false): Boolean { + if (stack.isEmpty) return false - val result = addItem(stack, simulate, slots, onlyIntoExisting, popTime) + val result = addItem(stack, simulate = simulate, slots = slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = ignoreFilters) if (!simulate) stack.count = result.count return result.count != stack.count } - fun fullyAddItem(stack: ItemStack, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null): Boolean { - if (!addItem(stack, true, slots, onlyIntoExisting, popTime).isEmpty) + fun fullyAddItem(stack: ItemStack, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean = false): Boolean { + if (!addItem(stack, simulate = true, slots = slots, popTime = popTime, onlyIntoExisting = onlyIntoExisting, ignoreFilters = ignoreFilters).isEmpty) return false - return addItem(stack, false, slots, onlyIntoExisting, popTime).isEmpty + return addItem(stack, simulate = false, slots = slots, popTime = popTime, onlyIntoExisting = onlyIntoExisting, ignoreFilters = ignoreFilters).isEmpty } fun stream(): Stream { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt index 59307ad96..5a39fbd8a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ISlottedContainer.kt @@ -1,7 +1,5 @@ package ru.dbotthepony.mc.otm.container -import it.unimi.dsi.fastutil.ints.IntCollection -import it.unimi.dsi.fastutil.ints.IntSet import net.minecraft.world.item.ItemStack import ru.dbotthepony.kommons.collect.any @@ -33,147 +31,6 @@ interface ISlottedContainer : IEnhancedContainer { containerSlot(slot).item = itemStack } - private fun addItem(stack: ItemStack, simulate: Boolean, filterPass: Boolean, slots: IntCollection, onlyIntoExisting: Boolean, popTime: Int?, ignoreFilters: Boolean): ItemStack { - if (stack.isEmpty || slots.isEmpty()) - return stack - - // двигаем в одинаковые слоты - for (i in slotWithItemIterator(stack.item, slots)) { - val slot = containerSlot(i) - - val condition: Boolean - - if (slot is IFilteredContainerSlot) { - condition = (ignoreFilters || !slot.isForbiddenForAutomation) && - ItemStack.isSameItemSameComponents(slot.item, stack) && - (ignoreFilters || !filterPass && !slot.hasFilter || filterPass && slot.hasFilter && slot.testSlotFilter(stack)) - } else { - condition = (ignoreFilters || !filterPass) && ItemStack.isSameItemSameComponents(slot.item, stack) - } - - if (condition) { - val slotLimit = slot.maxStackSize(slot.item) - - if (slot.item.count < slotLimit) { - val newCount = (slot.item.count + stack.count).coerceAtMost(slotLimit) - val diff = newCount - slot.item.count - - if (!simulate) { - slot.item.count = newCount - slot.setChanged() - - if (popTime != null) { - slot.item.popTime = popTime - } - } - - stack.shrink(diff) - - if (stack.isEmpty) - return ItemStack.EMPTY - } - } - } - - if (!onlyIntoExisting) { - for (i in emptySlotIndexIterator(slots)) { - val slot = containerSlot(i) - - val condition: Boolean - - if (slot is IFilteredContainerSlot) { - condition = (ignoreFilters || !slot.isForbiddenForAutomation) && - (ignoreFilters || !filterPass && !slot.hasFilter || filterPass && slot.hasFilter && slot.testSlotFilter(stack)) - } else { - condition = ignoreFilters || !filterPass - } - - if (condition) { - val diff = stack.count.coerceAtMost(slot.maxStackSize(stack)) - - if (!simulate) { - val copyToPut = stack.copy() - copyToPut.count = diff - slot.item = copyToPut - - if (popTime != null) { - copyToPut.popTime = popTime - } - } - - stack.shrink(diff) - - if (stack.isEmpty) - return ItemStack.EMPTY - } - } - } - - return stack - } - - /** - * Hint used internally by [ISlottedContainer] to potentially speed up default method implementations - */ - val hasFilterableSlots: Boolean + override val hasFilterableSlots: Boolean get() = slotIterator().any { it is IFilteredContainerSlot } - - fun addItem(stack: ItemStack, simulate: Boolean, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean): ItemStack { - if (stack.isEmpty || slots.isEmpty()) - return stack - - if (ignoreFilters || !hasFilterableSlots) { - return addItem(stack.copy(), simulate, filterPass = true, slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = true) - } else { - var copy = addItem(stack.copy(), simulate, filterPass = true, slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = false) - copy = addItem(copy, simulate, filterPass = false, slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = false) - return copy - } - } - - - /** - * Unlike [addItem], modifies original [stack] - * - * @return Whenever [stack] was modified - */ - fun consumeItem(stack: ItemStack, simulate: Boolean, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean): Boolean { - if (stack.isEmpty) - return false - - val result = addItem(stack, simulate = simulate, slots = slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = ignoreFilters) - if (!simulate) stack.count = result.count - return result.count != stack.count - } - - fun fullyAddItem(stack: ItemStack, slots: IntCollection = slotRange, onlyIntoExisting: Boolean = false, popTime: Int? = null, ignoreFilters: Boolean): Boolean { - if (!addItem(stack, simulate = true, slots = slots, popTime = popTime, onlyIntoExisting = onlyIntoExisting, ignoreFilters = ignoreFilters).isEmpty) - return false - - return addItem(stack, simulate = false, slots = slots, popTime = popTime, onlyIntoExisting = onlyIntoExisting, ignoreFilters = ignoreFilters).isEmpty - } - - override fun addItem( - stack: ItemStack, - simulate: Boolean, - slots: IntCollection, - onlyIntoExisting: Boolean, - popTime: Int? - ): ItemStack { - return addItem(stack, simulate = simulate, slots = slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = false) - } - - override fun consumeItem( - stack: ItemStack, - simulate: Boolean, - slots: IntCollection, - onlyIntoExisting: Boolean, - popTime: Int? - ): Boolean { - return consumeItem(stack, simulate = simulate, slots = slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = false) - } - - override fun fullyAddItem(stack: ItemStack, slots: IntCollection, onlyIntoExisting: Boolean, popTime: Int?): Boolean { - return fullyAddItem(stack, slots = slots, onlyIntoExisting = onlyIntoExisting, popTime = popTime, ignoreFilters = false) - } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt index c3b7c9f9d..f7c86e5b2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt @@ -19,4 +19,7 @@ class ExopackContainer(size: Int, val player: MatteryPlayer) : EnhancedContainer override fun containerSlot(slot: Int): IPlayerInventorySlot { return Slot(slot) } + + override val hasFilterableSlots: Boolean + get() = true } From 54012cf136972a0e2dff617b683e7ef2801104e5 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 14 Mar 2025 21:06:23 +0700 Subject: [PATCH 092/154] Bump kommons --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index face01890..ef09c8011 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,7 +22,7 @@ mixin_version=0.8.5 neogradle.subsystems.parchment.minecraftVersion=1.21.1 neogradle.subsystems.parchment.mappingsVersion=2024.11.17 -kommons_version=3.5.2 +kommons_version=3.6.0 caffeine_cache_version=3.1.5 jei_version=19.16.4.171 From 448041fe2e27b1c8b1c51f41dbeec90c607adcd7 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 14 Mar 2025 22:09:32 +0700 Subject: [PATCH 093/154] More specialized versions of iterators in IEnhancedContainer --- .../mc/otm/container/IEnhancedContainer.kt | 56 ++++++++++++++----- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt index 2eb1774fe..9e1d5bb60 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt @@ -76,10 +76,22 @@ interface IEnhancedContainer : Container, RecipeInput, I } fun nonEmptySlotIterator(): Iterator { - return slotIterator().filter { it.isNotEmpty } + return nonEmptySlotIndexIterator().map { containerSlot(it) } } - private fun slotIterator(allowedSlots: IntCollection, predicate: Predicate): IntIterator { + fun emptySlotIterator(): Iterator { + return emptySlotIndexIterator().map { containerSlot(it) } + } + + fun nonEmptySlotIterator(allowedSlots: IntCollection): Iterator { + return nonEmptySlotIndexIterator(allowedSlots).map { containerSlot(it) } + } + + fun emptySlotIterator(allowedSlots: IntCollection): Iterator { + return emptySlotIndexIterator(allowedSlots).map { containerSlot(it) } + } + + private fun slotIndexWalker(allowedSlots: IntCollection, predicate: Predicate): IntIterator { return object : IntIterator() { private val parent = allowedSlots.intIterator() private var foundNext = false @@ -120,6 +132,14 @@ interface IEnhancedContainer : Container, RecipeInput, I } } + fun emptySlotIndexIterator(allowedSlots: IntCollection): IntIterator { + return slotIndexWalker(allowedSlots) { it.isEmpty } + } + + fun nonEmptySlotIndexIterator(allowedSlots: IntCollection): IntIterator { + return slotIndexWalker(allowedSlots) { it.isNotEmpty } + } + fun emptySlotIndexIterator(): IntIterator { return emptySlotIndexIterator(slotRange) } @@ -128,20 +148,30 @@ interface IEnhancedContainer : Container, RecipeInput, I return nonEmptySlotIndexIterator(slotRange) } - fun emptySlotIndexIterator(allowedSlots: IntCollection): IntIterator { - return slotIterator(allowedSlots) { it.isEmpty } + fun slotIndexWithItemIterator(item: Item): IntIterator { + return slotIndexWithItemIterator(item, slotRange) } - fun nonEmptySlotIndexIterator(allowedSlots: IntCollection): IntIterator { - return slotIterator(allowedSlots) { it.isNotEmpty } + fun slotIndexWithItemIterator(item: Item, allowedSlots: IntCollection): IntIterator { + val parent = nonEmptySlotIndexIterator(allowedSlots).filter { this[it].isNotEmpty && this[it].item === item } + + return object : IntIterator() { + override fun nextInt(): Int { + return parent.next() + } + + override fun hasNext(): Boolean { + return parent.hasNext() + } + } } - fun slotWithItemIterator(item: Item): IntIterator { + fun slotWithItemIterator(item: Item): Iterator { return slotWithItemIterator(item, slotRange) } - fun slotWithItemIterator(item: Item, allowedSlots: IntCollection): IntIterator { - return slotIterator(allowedSlots) { it.isNotEmpty && it.item === item } + fun slotWithItemIterator(item: Item, allowedSlots: IntCollection): Iterator { + return slotIndexWithItemIterator(item, allowedSlots).map { containerSlot(it) } } fun nextEmptySlot(startIndex: Int): Int { @@ -257,9 +287,7 @@ interface IEnhancedContainer : Container, RecipeInput, I return stack // двигаем в одинаковые слоты - for (i in slotWithItemIterator(stack.item, slots)) { - val slot = containerSlot(i) - + for (slot in slotWithItemIterator(stack.item, slots)) { val condition: Boolean if (slot is IFilteredContainerSlot) { @@ -295,9 +323,7 @@ interface IEnhancedContainer : Container, RecipeInput, I } if (!onlyIntoExisting) { - for (i in emptySlotIndexIterator(slots)) { - val slot = containerSlot(i) - + for (slot in emptySlotIterator(slots)) { val condition: Boolean if (slot is IFilteredContainerSlot) { From 69d9aaab50e1c28170510070524a503902719d27 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 14 Mar 2025 22:14:05 +0700 Subject: [PATCH 094/154] Fast implementation of some methods in EnhancedContainer --- .../mc/otm/container/EnhancedContainer.kt | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt index f012f130b..f504d831c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt @@ -1,5 +1,6 @@ package ru.dbotthepony.mc.otm.container +import it.unimi.dsi.fastutil.ints.IntCollection import it.unimi.dsi.fastutil.ints.IntOpenHashSet import net.minecraft.core.HolderLookup.Provider import net.minecraft.nbt.CompoundTag @@ -12,9 +13,14 @@ import net.minecraft.world.entity.player.Player import net.minecraft.world.item.ItemStack import net.neoforged.neoforge.common.util.INBTSerializable import org.apache.logging.log4j.LogManager +import ru.dbotthepony.kommons.collect.iterateClearBits +import ru.dbotthepony.kommons.collect.iterateSetBits import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer +import ru.dbotthepony.mc.otm.core.collect.IntRange2Set +import ru.dbotthepony.mc.otm.core.collect.map import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.nbt.set +import java.util.BitSet /** * Flexible base implementation of [IEnhancedContainer], designed to be inherited, or used as-is @@ -26,6 +32,55 @@ import ru.dbotthepony.mc.otm.core.nbt.set abstract class EnhancedContainer(private val size: Int) : IEnhancedContainer, INBTSerializable { private val items = Array(size) { ItemStack.EMPTY } private val observedItems = Array(size) { ItemStack.EMPTY } + private val bitmap = BitSet(size) + + final override fun isEmpty(): Boolean { + return bitmap.isEmpty + } + + final override fun nextEmptySlot(startIndex: Int): Int { + if (startIndex >= size) + return -1 + else if (startIndex < 0) + return bitmap.nextClearBit(0) + else + return bitmap.nextClearBit(startIndex) + } + + final override fun nextNonEmptySlot(startIndex: Int): Int { + if (startIndex >= size) + return -1 + else if (startIndex < 0) + return bitmap.nextSetBit(0) + else + return bitmap.nextSetBit(startIndex) + } + + final override fun iterator(): Iterator { + return bitmap.iterateSetBits(size).map { this[it] } + } + + final override fun nonEmptySlotIndexIterator(): IntIterator { + return bitmap.iterateSetBits(size) + } + + final override fun emptySlotIndexIterator(): IntIterator { + return bitmap.iterateClearBits(size) + } + + final override fun emptySlotIndexIterator(allowedSlots: IntCollection): IntIterator { + if (allowedSlots is IntRange2Set && allowedSlots.isNotEmpty()) + return bitmap.iterateClearBits(allowedSlots.firstInt(), allowedSlots.lastInt() + 1) + + return super.emptySlotIndexIterator(allowedSlots) + } + + final override fun nonEmptySlotIndexIterator(allowedSlots: IntCollection): IntIterator { + if (allowedSlots is IntRange2Set && allowedSlots.isNotEmpty()) + return bitmap.iterateSetBits(allowedSlots.firstInt(), allowedSlots.lastInt() + 1) + + return super.nonEmptySlotIndexIterator(allowedSlots) + } protected open fun notifySlotChanged(slot: Int, old: ItemStack) {} @@ -36,9 +91,11 @@ abstract class EnhancedContainer(private val size: Int) if (items[slot].isEmpty) { items[slot] = ItemStack.EMPTY observedItems[slot] = ItemStack.EMPTY + bitmap[slot] = false } else { notifySlotChanged(slot, observedItems[slot]) observedItems[slot] = items[slot].copy() + bitmap[slot] = true } } } @@ -50,6 +107,7 @@ abstract class EnhancedContainer(private val size: Int) override fun clearContent() { items.fill(ItemStack.EMPTY) observedItems.fill(ItemStack.EMPTY) + bitmap.clear() } override fun setChanged() { @@ -146,6 +204,7 @@ abstract class EnhancedContainer(private val size: Int) val copy = observedItems.copyOf() items.fill(ItemStack.EMPTY) observedItems.fill(ItemStack.EMPTY) + bitmap.clear() val seenSlots = IntOpenHashSet() val ops = provider.createSerializationContext(NbtOps.INSTANCE) @@ -166,6 +225,7 @@ abstract class EnhancedContainer(private val size: Int) if (it.isNotEmpty) { items[slot] = it observedItems[slot] = it.copy() + bitmap[slot] = true if (it.count != copy[slot].count || !ItemStack.isSameItemSameComponents(it, copy[slot])) notifySlotChanged(slot, copy[slot]) From 8b38504a26e1f7d25734f2b5494c1b45c07d24f7 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 14 Mar 2025 23:10:25 +0700 Subject: [PATCH 095/154] Derive hasEmptySlots, isEmpty, countItem from other methods --- .../mc/otm/container/IEnhancedContainer.kt | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt index 9e1d5bb60..af2b978fe 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt @@ -219,17 +219,11 @@ interface IEnhancedContainer : Container, RecipeInput, I } override fun isEmpty(): Boolean { - return super.isEmpty() + return nextNonEmptySlot(0) != -1 } val hasEmptySlots: Boolean get() { - for (i in 0 until containerSize) { - if (this[i].isEmpty) { - return true - } - } - - return false + return nextEmptySlot(0) != -1 } override fun size(): Int { @@ -239,11 +233,8 @@ interface IEnhancedContainer : Container, RecipeInput, I override fun countItem(item: Item): Int { var count = 0 - for (stack in this) { - if (stack.item === item) { - count += stack.count - } - } + for (slot in slotWithItemIterator(item)) + count += slot.item.count return count } From 0efc5207826d19df901e45bc444acfe87ab94653 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 15 Mar 2025 00:18:02 +0700 Subject: [PATCH 096/154] Implement faster lookup methods for Slotted Container as well --- .../otm/container/BitmapTrackingContainer.kt | 61 +++++++++++++++++++ .../mc/otm/container/EnhancedContainer.kt | 51 +--------------- .../mc/otm/container/slotted/ContainerSlot.kt | 4 +- .../otm/container/slotted/SlottedContainer.kt | 11 +++- 4 files changed, 74 insertions(+), 53 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/BitmapTrackingContainer.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/BitmapTrackingContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/BitmapTrackingContainer.kt new file mode 100644 index 000000000..136990472 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/BitmapTrackingContainer.kt @@ -0,0 +1,61 @@ +package ru.dbotthepony.mc.otm.container + +import it.unimi.dsi.fastutil.ints.IntCollection +import net.minecraft.world.item.ItemStack +import ru.dbotthepony.kommons.collect.iterateClearBits +import ru.dbotthepony.kommons.collect.iterateSetBits +import ru.dbotthepony.mc.otm.core.collect.IntRange2Set +import ru.dbotthepony.mc.otm.core.collect.map +import java.util.* + +abstract class BitmapTrackingContainer : IEnhancedContainer { + protected val bitmap = BitSet() + + final override fun isEmpty(): Boolean { + return bitmap.isEmpty + } + + final override fun nextEmptySlot(startIndex: Int): Int { + if (startIndex >= containerSize) + return -1 + else if (startIndex < 0) + return bitmap.nextClearBit(0) + else + return bitmap.nextClearBit(startIndex) + } + + final override fun nextNonEmptySlot(startIndex: Int): Int { + if (startIndex >= containerSize) + return -1 + else if (startIndex < 0) + return bitmap.nextSetBit(0) + else + return bitmap.nextSetBit(startIndex) + } + + final override fun iterator(): Iterator { + return bitmap.iterateSetBits(containerSize).map { this[it] } + } + + final override fun nonEmptySlotIndexIterator(): IntIterator { + return bitmap.iterateSetBits(containerSize) + } + + final override fun emptySlotIndexIterator(): IntIterator { + return bitmap.iterateClearBits(containerSize) + } + + final override fun emptySlotIndexIterator(allowedSlots: IntCollection): IntIterator { + if (allowedSlots is IntRange2Set && allowedSlots.isNotEmpty()) + return bitmap.iterateClearBits(allowedSlots.firstInt(), allowedSlots.lastInt() + 1) + + return super.emptySlotIndexIterator(allowedSlots) + } + + final override fun nonEmptySlotIndexIterator(allowedSlots: IntCollection): IntIterator { + if (allowedSlots is IntRange2Set && allowedSlots.isNotEmpty()) + return bitmap.iterateSetBits(allowedSlots.firstInt(), allowedSlots.lastInt() + 1) + + return super.nonEmptySlotIndexIterator(allowedSlots) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt index f504d831c..6ce4277a9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt @@ -29,58 +29,9 @@ import java.util.BitSet * This is supposed to be counterpart to [SimpleContainer] of Minecraft itself, with more features * and improved performance (inside [IEnhancedContainer] defined methods). */ -abstract class EnhancedContainer(private val size: Int) : IEnhancedContainer, INBTSerializable { +abstract class EnhancedContainer(private val size: Int) : BitmapTrackingContainer(), INBTSerializable { private val items = Array(size) { ItemStack.EMPTY } private val observedItems = Array(size) { ItemStack.EMPTY } - private val bitmap = BitSet(size) - - final override fun isEmpty(): Boolean { - return bitmap.isEmpty - } - - final override fun nextEmptySlot(startIndex: Int): Int { - if (startIndex >= size) - return -1 - else if (startIndex < 0) - return bitmap.nextClearBit(0) - else - return bitmap.nextClearBit(startIndex) - } - - final override fun nextNonEmptySlot(startIndex: Int): Int { - if (startIndex >= size) - return -1 - else if (startIndex < 0) - return bitmap.nextSetBit(0) - else - return bitmap.nextSetBit(startIndex) - } - - final override fun iterator(): Iterator { - return bitmap.iterateSetBits(size).map { this[it] } - } - - final override fun nonEmptySlotIndexIterator(): IntIterator { - return bitmap.iterateSetBits(size) - } - - final override fun emptySlotIndexIterator(): IntIterator { - return bitmap.iterateClearBits(size) - } - - final override fun emptySlotIndexIterator(allowedSlots: IntCollection): IntIterator { - if (allowedSlots is IntRange2Set && allowedSlots.isNotEmpty()) - return bitmap.iterateClearBits(allowedSlots.firstInt(), allowedSlots.lastInt() + 1) - - return super.emptySlotIndexIterator(allowedSlots) - } - - final override fun nonEmptySlotIndexIterator(allowedSlots: IntCollection): IntIterator { - if (allowedSlots is IntRange2Set && allowedSlots.isNotEmpty()) - return bitmap.iterateSetBits(allowedSlots.firstInt(), allowedSlots.lastInt() + 1) - - return super.nonEmptySlotIndexIterator(allowedSlots) - } protected open fun notifySlotChanged(slot: Int, old: ItemStack) {} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt index 62780ee8c..7d4821597 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt @@ -56,12 +56,12 @@ open class ContainerSlot( notifyChanged(observedItem) observedItem = ItemStack.EMPTY _item = ItemStack.EMPTY - container.notifyChanged() + container.notifyChanged(slot) return true } else if (observedItem.count != item.count || !ItemStack.isSameItemSameComponents(item, observedItem)) { notifyChanged(observedItem) observedItem = item.copy() - container.notifyChanged() + container.notifyChanged(slot) return true } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt index 1b5a66420..2f013f4d6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt @@ -17,6 +17,7 @@ import net.minecraft.world.item.ItemStack import net.neoforged.neoforge.common.util.INBTSerializable import org.apache.logging.log4j.LogManager import ru.dbotthepony.kommons.util.Either +import ru.dbotthepony.mc.otm.container.BitmapTrackingContainer import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.IAutomatedContainer import ru.dbotthepony.mc.otm.container.IAutomatedContainerSlot @@ -25,6 +26,7 @@ import ru.dbotthepony.mc.otm.container.balance import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.data.codec.minRange +import java.util.BitSet import java.util.function.Predicate import kotlin.reflect.KClass @@ -40,7 +42,7 @@ class SlottedContainer( slots: Collection>, private val stillValid: Predicate, private val globalChangeListeners: Array -) : IAutomatedContainer, INBTSerializable { +) : BitmapTrackingContainer(), IAutomatedContainer, INBTSerializable { interface ISlotGroup : List { /** * @see IAutomatedContainer.addItem @@ -130,6 +132,7 @@ class SlottedContainer( private var suppressListeners = false override fun clearContent() { + bitmap.clear() suppressListeners = true try { @@ -149,6 +152,11 @@ class SlottedContainer( globalChangeListeners.forEach { it.run() } } + fun notifyChanged(slot: Int) { + notifyChanged() + bitmap[slot] = slots[slot].isNotEmpty + } + // called by outside code (vanilla and other unaware mods) override fun setChanged() { suppressListeners = true @@ -253,6 +261,7 @@ class SlottedContainer( override fun deserializeNBT(provider: HolderLookup.Provider, nbt: Tag) { lostItems.clear() slots.forEach { it.clear() } + bitmap.clear() if (nbt is CompoundTag) { // legacy container From fd9960bd860b1c636402c47eb4fd43670afad2a9 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 15 Mar 2025 11:38:26 +0700 Subject: [PATCH 097/154] Remove HandlerFilter --- .../block/entity/MatteryPoweredBlockEntity.kt | 1 - .../decorative/CargoCrateBlockEntity.kt | 1 - .../entity/decorative/FluidTankBlockEntity.kt | 1 - .../entity/decorative/PainterBlockEntity.kt | 1 - .../entity/matter/MatterBottlerBlockEntity.kt | 1 - .../matter/MatterCapacitorBankBlockEntity.kt | 1 - .../matter/MatterDecomposerBlockEntity.kt | 1 - .../matter/MatterReconstructorBlockEntity.kt | 1 - .../matter/MatterReplicatorBlockEntity.kt | 1 - .../entity/matter/MatterScannerBlockEntity.kt | 1 - .../entity/tech/BatteryBankBlockEntity.kt | 1 - .../tech/ChemicalGeneratorBlockEntity.kt | 1 - .../block/entity/tech/CobblerBlockEntity.kt | 1 - .../entity/tech/EnergyHatchBlockEntity.kt | 1 - .../entity/tech/EnergyInterfaceBlockEntity.kt | 1 - .../entity/tech/EnergyServoBlockEntity.kt | 1 - .../entity/tech/EssenceStorageBlockEntity.kt | 1 - .../block/entity/tech/ItemHatchBlockEntity.kt | 1 - .../entity/tech/MatterHatchBlockEntity.kt | 1 - .../entity/tech/PlatePressBlockEntity.kt | 1 - .../mc/otm/container/HandlerFilter.kt | 153 ------------------ 21 files changed, 173 deletions(-) delete mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/HandlerFilter.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryPoweredBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryPoweredBlockEntity.kt index 592b64844..1f53db539 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryPoweredBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryPoweredBlockEntity.kt @@ -6,7 +6,6 @@ import net.minecraft.world.level.block.state.BlockState import ru.dbotthepony.mc.otm.capability.energy import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage import ru.dbotthepony.mc.otm.capability.extractEnergy -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.Decimal diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt index c48b765f6..4530adaef 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt @@ -29,7 +29,6 @@ import net.minecraft.world.phys.Vec3 import net.neoforged.neoforge.capabilities.Capabilities import ru.dbotthepony.mc.otm.block.decorative.CargoCrateBlock import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.TranslatableComponent diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/FluidTankBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/FluidTankBlockEntity.kt index deeea262e..ffa775373 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/FluidTankBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/FluidTankBlockEntity.kt @@ -18,7 +18,6 @@ import ru.dbotthepony.mc.otm.capability.item.CombinedItemHandler import ru.dbotthepony.mc.otm.capability.fluid.BlockMatteryFluidHandler import ru.dbotthepony.mc.otm.capability.moveFluid import ru.dbotthepony.mc.otm.config.ItemsConfig -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.get import ru.dbotthepony.mc.otm.container.slotted.AutomationFilter import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/PainterBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/PainterBlockEntity.kt index 2e1c5679f..321fe0f6d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/PainterBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/PainterBlockEntity.kt @@ -18,7 +18,6 @@ import net.neoforged.neoforge.capabilities.Capabilities import net.neoforged.neoforge.fluids.FluidStack import net.neoforged.neoforge.fluids.capability.IFluidHandler import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.immutableList diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt index d105cc7b1..f7b6a186a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt @@ -21,7 +21,6 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage import ru.dbotthepony.mc.otm.config.MachinesConfig -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.UpgradeContainer import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt index f0c2fa62d..60f2383a9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt @@ -16,7 +16,6 @@ import ru.dbotthepony.mc.otm.capability.FlowDirection import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.matter.IMatterStorage import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.immutableList diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt index 63f16a11b..8594476ad 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterDecomposerBlockEntity.kt @@ -21,7 +21,6 @@ import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage import ru.dbotthepony.mc.otm.config.MachinesConfig -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReconstructorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReconstructorBlockEntity.kt index 8f0f47ddd..49ef44425 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReconstructorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReconstructorBlockEntity.kt @@ -24,7 +24,6 @@ import ru.dbotthepony.mc.otm.capability.matter.PatternState import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage import ru.dbotthepony.mc.otm.config.MachinesConfig -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.UpgradeContainer import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt index 3f6a943b6..d472058ae 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterReplicatorBlockEntity.kt @@ -25,7 +25,6 @@ import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.* import ru.dbotthepony.mc.otm.config.MachinesConfig -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.Decimal diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt index 2698b997b..be8473c8c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterScannerBlockEntity.kt @@ -20,7 +20,6 @@ import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.capability.matter.PatternState import ru.dbotthepony.mc.otm.config.MachinesConfig -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.matter.MatterScannerMenu diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/BatteryBankBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/BatteryBankBlockEntity.kt index cb8b00784..d50def635 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/BatteryBankBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/BatteryBankBlockEntity.kt @@ -19,7 +19,6 @@ import ru.dbotthepony.mc.otm.capability.energyStoredMattery import ru.dbotthepony.mc.otm.capability.matteryEnergy import ru.dbotthepony.mc.otm.capability.maxEnergyStoredMattery import ru.dbotthepony.mc.otm.capability.transcieveEnergy -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ChemicalGeneratorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ChemicalGeneratorBlockEntity.kt index d0ab00ab4..f37b9ff4d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ChemicalGeneratorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ChemicalGeneratorBlockEntity.kt @@ -12,7 +12,6 @@ import ru.dbotthepony.mc.otm.capability.* import ru.dbotthepony.mc.otm.capability.energy.GeneratorEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.config.MachinesConfig -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.tech.ChemicalGeneratorMenu diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/CobblerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/CobblerBlockEntity.kt index f8ed9261c..fe27531b7 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/CobblerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/CobblerBlockEntity.kt @@ -11,7 +11,6 @@ import ru.dbotthepony.mc.otm.block.entity.ItemJob import ru.dbotthepony.mc.otm.block.entity.JobContainer import ru.dbotthepony.mc.otm.block.entity.JobStatus import ru.dbotthepony.mc.otm.block.entity.MatteryWorkerBlockEntity -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.tech.CobblerMenu diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyHatchBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyHatchBlockEntity.kt index da9d414d6..733cdb3ea 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyHatchBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyHatchBlockEntity.kt @@ -16,7 +16,6 @@ import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.moveEnergy import ru.dbotthepony.mc.otm.config.EnergyBalanceValues import ru.dbotthepony.mc.otm.config.MachinesConfig -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.RelativeSide diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyInterfaceBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyInterfaceBlockEntity.kt index ec801380d..8b8185fdd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyInterfaceBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyInterfaceBlockEntity.kt @@ -18,7 +18,6 @@ import ru.dbotthepony.mc.otm.capability.FlowDirection import ru.dbotthepony.mc.otm.capability.energy.CombinedProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.moveEnergy -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.RelativeSide diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyServoBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyServoBlockEntity.kt index 627227a9a..0e60cf388 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyServoBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyServoBlockEntity.kt @@ -16,7 +16,6 @@ import ru.dbotthepony.mc.otm.capability.extractEnergy import ru.dbotthepony.mc.otm.capability.maxEnergyStoredMattery import ru.dbotthepony.mc.otm.capability.moveEnergy import ru.dbotthepony.mc.otm.capability.receiveEnergy -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt index eb68e886b..f30aece84 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EssenceStorageBlockEntity.kt @@ -24,7 +24,6 @@ import ru.dbotthepony.mc.otm.block.tech.EssenceStorageBlock import ru.dbotthepony.mc.otm.capability.item.CombinedItemHandler import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.EnhancedContainer -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ItemHatchBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ItemHatchBlockEntity.kt index c6cab62b0..848bb0138 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ItemHatchBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/ItemHatchBlockEntity.kt @@ -9,7 +9,6 @@ import net.minecraft.world.level.block.state.BlockState import net.neoforged.neoforge.capabilities.Capabilities import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.multiblock.BlockEntityTag diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/MatterHatchBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/MatterHatchBlockEntity.kt index b493464c8..032d2685b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/MatterHatchBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/MatterHatchBlockEntity.kt @@ -15,7 +15,6 @@ import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage import ru.dbotthepony.mc.otm.capability.moveMatter import ru.dbotthepony.mc.otm.config.MachinesConfig -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.math.Decimal diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt index a32bc9bbc..16ec5cf96 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt @@ -18,7 +18,6 @@ import ru.dbotthepony.mc.otm.capability.UpgradeType import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.config.MachinesConfig -import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.container.balance import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/HandlerFilter.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/HandlerFilter.kt deleted file mode 100644 index 7f1cb3421..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/HandlerFilter.kt +++ /dev/null @@ -1,153 +0,0 @@ -package ru.dbotthepony.mc.otm.container - -import net.minecraft.world.item.ItemStack -import net.neoforged.neoforge.capabilities.Capabilities -import ru.dbotthepony.mc.otm.capability.MatteryCapability -import ru.dbotthepony.mc.otm.capability.fluid.stream -import ru.dbotthepony.mc.otm.core.isNotEmpty -import ru.dbotthepony.mc.otm.core.math.Decimal - -interface HandlerFilter { - fun canInsert(slot: Int, stack: ItemStack): Boolean { - return true - } - - fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return true - } - - fun preInsert(slot: Int, stack: ItemStack, simulate: Boolean) {} - fun preExtract(slot: Int, amount: Int, simulate: Boolean) {} - - fun modifyInsertCount(slot: Int, stack: ItemStack, existing: ItemStack, simulate: Boolean): Int { - return stack.count - } - - fun modifyExtractCount(slot: Int, amount: Int, simulate: Boolean): Int { - return amount - } - - fun and(other: HandlerFilter): HandlerFilter { - return object : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return this@HandlerFilter.canInsert(slot, stack) && other.canInsert(slot, stack) - } - - override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return this@HandlerFilter.canExtract(slot, amount, stack) && other.canExtract(slot, amount, stack) - } - - override fun preInsert(slot: Int, stack: ItemStack, simulate: Boolean) { - this@HandlerFilter.preInsert(slot, stack, simulate) - other.preInsert(slot, stack, simulate) - } - - override fun preExtract(slot: Int, amount: Int, simulate: Boolean) { - this@HandlerFilter.preExtract(slot, amount, simulate) - other.preExtract(slot, amount, simulate) - } - } - } - - object FluidContainers : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return stack.getCapability(Capabilities.FluidHandler.ITEM)?.let { it.tanks > 0 } ?: false - } - } - - object DrainableFluidContainers : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return stack.getCapability(Capabilities.FluidHandler.ITEM)?.let { it.stream().anyMatch { it.isNotEmpty } } ?: false - } - - override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return !canInsert(slot, stack) - } - } - - object OnlyIn : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return true - } - - override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return false - } - } - - object OnlyOut : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return false - } - - override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return true - } - } - - object Both : HandlerFilter - - object Dischargeable : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return stack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { it.canExtract() && it.extractEnergy(Int.MAX_VALUE, true) > 0 } ?: false - } - - override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return stack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { !it.canExtract() || it.extractEnergy(Int.MAX_VALUE, true) <= 0 } ?: true - } - } - - object Chargeable : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return stack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { it.canReceive() && it.receiveEnergy(Int.MAX_VALUE, true) > 0 } ?: false - } - - override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return stack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { !it.canReceive() || it.receiveEnergy(Int.MAX_VALUE, true) <= 0 } ?: true - } - } - - object ChemicalFuel : HandlerFilter { - override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return stack.getBurnTime(null) <= 0 - } - - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return stack.getBurnTime(null) > 0 - } - } - - object IsPattern : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return stack.getCapability(MatteryCapability.PATTERN_ITEM) != null - } - } - - object MatterProviders : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return stack.getCapability(MatteryCapability.MATTER_ITEM) - ?.let { it.matterFlow.output && it.extractMatterChecked(Decimal.POSITIVE_INFINITY, true) > Decimal.ZERO } - ?: false - } - - override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return stack.getCapability(MatteryCapability.MATTER_ITEM) - ?.let { !it.matterFlow.output || it.extractMatterChecked(Decimal.POSITIVE_INFINITY, true) <= Decimal.ZERO } - ?: false - } - } - - object MatterConsumers : HandlerFilter { - override fun canInsert(slot: Int, stack: ItemStack): Boolean { - return stack.getCapability(MatteryCapability.MATTER_ITEM) - ?.let { it.matterFlow.input && it.receiveMatterChecked(Decimal.POSITIVE_INFINITY, true) > Decimal.ZERO } - ?: false - } - - override fun canExtract(slot: Int, amount: Int, stack: ItemStack): Boolean { - return stack.getCapability(MatteryCapability.MATTER_ITEM) - ?.let { !it.matterFlow.input || it.receiveMatterChecked(Decimal.POSITIVE_INFINITY, true) <= Decimal.ZERO } - ?: false - } - } -} From cf32fd9d2a03c67f211b57230764f4358f9d77ea Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 15 Mar 2025 17:43:41 +0700 Subject: [PATCH 098/154] Extract moveItemStackToSlots static context --- .../ru/dbotthepony/mc/otm/menu/MatteryMenu.kt | 184 +++++++++--------- 1 file changed, 93 insertions(+), 91 deletions(-) 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 eb29aaa04..576fba7bb 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt @@ -469,7 +469,7 @@ abstract class MatteryMenu( if (target.any { it.any { it.containerSlotOrNull() is IFilteredContainerSlot } }) { for (collection in target) { - if (moveItemStackTo(slot, collection, onlyFiltered = true)) { + if (moveItemStackTo(ply, slot, collection, onlyFiltered = true)) { any = true if (!slot.hasItem()) { @@ -480,7 +480,7 @@ abstract class MatteryMenu( } for (collection in target) { - if (moveItemStackTo(slot, collection)) { + if (moveItemStackTo(ply, slot, collection)) { any = true if (!slot.hasItem()) { @@ -527,95 +527,6 @@ abstract class MatteryMenu( return true } - fun moveItemStackTo( - source: Slot, - slots: Collection, - onlyFiltered: Boolean = false - ): Boolean { - val remainder = moveItemStackToSlots(source.item, slots, onlyFiltered = onlyFiltered) - - if (remainder.count == source.item.count) { - return false - } - - val copy = source.item.copy() - - if (remainder.isEmpty) { - source.setByPlayer(ItemStack.EMPTY) - source.onTake(player, copy) - } else { - copy.count = source.item.count - remainder.count - source.item.count = remainder.count - source.onTake(player, copy) - } - - return true - } - - fun moveItemStackToSlots(item: ItemStack, slots: Collection, simulate: Boolean = false, onlyFiltered: Boolean = false): ItemStack { - if (item.isEmpty) { - return ItemStack.EMPTY - } - - val copy = item.copy() - - // first pass - stack with existing slots - if (copy.isStackable) { - for (slot in slots) { - if (onlyFiltered && slot.containerSlotOrNull().let { it !is IFilteredContainerSlot || it.filter == null || !it.testSlotFilter(item) }) { - continue - } else if (!onlyFiltered && slot.containerSlotOrNull().let { it is IFilteredContainerSlot && it.filter != null }) { - continue - } - - val limit = slot.getMaxStackSize(copy) - - if (limit > slot.item.count && slot.mayPlace(item) && ItemStack.isSameItemSameComponents(slot.item, copy)) { - val newCount = (slot.item.count + copy.count).coerceAtMost(limit) - val diff = newCount - slot.item.count - copy.count -= diff - - if (!simulate) { - slot.item.count += diff - slot.setChanged() - } - - if (copy.isEmpty) { - return copy - } - } - } - } - - // second pass - drop stack into first free slot - for (slot in slots) { - if (onlyFiltered && slot.containerSlotOrNull().let { it !is IFilteredContainerSlot || it.filter == null || !it.testSlotFilter(item) }) { - continue - } else if (!onlyFiltered && slot.containerSlotOrNull().let { it is IFilteredContainerSlot && it.filter != null }) { - continue - } - - val limit = slot.getMaxStackSize(copy) - - if (!slot.hasItem() && slot.mayPlace(item)) { - val newCount = copy.count.coerceAtMost(limit) - - if (!simulate) { - slot.setByPlayer(copy.copy().also { it.count = newCount }) - slot.setChanged() - } - - copy.count -= newCount - - if (copy.isEmpty) { - return copy - } - } - } - - return copy - } - fun moveItemStackToSlots(item: ItemStack, initialSlot: Int, finalSlot: Int, inverse: Boolean = false, simulate: Boolean = false): ItemStack { if (initialSlot > finalSlot) { return item @@ -717,5 +628,96 @@ abstract class MatteryMenu( InventoryMenu.EMPTY_ARMOR_SLOT_LEGGINGS, InventoryMenu.EMPTY_ARMOR_SLOT_CHESTPLATE, InventoryMenu.EMPTY_ARMOR_SLOT_HELMET) + + fun moveItemStackTo( + player: Player, + source: Slot, + slots: Collection, + onlyFiltered: Boolean = false + ): Boolean { + val remainder = moveItemStackToSlots(source.item, slots, onlyFiltered = onlyFiltered) + + if (remainder.count == source.item.count) { + return false + } + + val copy = source.item.copy() + + if (remainder.isEmpty) { + source.setByPlayer(ItemStack.EMPTY) + source.onTake(player, copy) + } else { + copy.count = source.item.count - remainder.count + source.item.count = remainder.count + source.onTake(player, copy) + } + + return true + } + + + fun moveItemStackToSlots(item: ItemStack, slots: Collection, simulate: Boolean = false, onlyFiltered: Boolean = false): ItemStack { + if (item.isEmpty) { + return ItemStack.EMPTY + } + + val copy = item.copy() + + // first pass - stack with existing slots + if (copy.isStackable) { + for (slot in slots) { + if (onlyFiltered && slot.containerSlotOrNull().let { it !is IFilteredContainerSlot || it.filter == null || !it.testSlotFilter(item) }) { + continue + } else if (!onlyFiltered && slot.containerSlotOrNull().let { it is IFilteredContainerSlot && it.filter != null }) { + continue + } + + val limit = slot.getMaxStackSize(copy) + + if (limit > slot.item.count && slot.mayPlace(item) && ItemStack.isSameItemSameComponents(slot.item, copy)) { + val newCount = (slot.item.count + copy.count).coerceAtMost(limit) + val diff = newCount - slot.item.count + copy.count -= diff + + if (!simulate) { + slot.item.count += diff + slot.setChanged() + } + + if (copy.isEmpty) { + return copy + } + } + } + } + + // second pass - drop stack into first free slot + for (slot in slots) { + if (onlyFiltered && slot.containerSlotOrNull().let { it !is IFilteredContainerSlot || it.filter == null || !it.testSlotFilter(item) }) { + continue + } else if (!onlyFiltered && slot.containerSlotOrNull().let { it is IFilteredContainerSlot && it.filter != null }) { + continue + } + + val limit = slot.getMaxStackSize(copy) + + if (!slot.hasItem() && slot.mayPlace(item)) { + val newCount = copy.count.coerceAtMost(limit) + + if (!simulate) { + slot.setByPlayer(copy.copy().also { it.count = newCount }) + slot.setChanged() + } + + copy.count -= newCount + + if (copy.isEmpty) { + return copy + } + } + } + + return copy + } } } From d5a9632c9764dbeea7d497fb28958ab35d27626d Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 15 Mar 2025 22:26:47 +0700 Subject: [PATCH 099/154] Move SortInput to upper level --- .../client/screen/panels/button/Buttons.kt | 4 ++-- .../vanilla/AbstractVanillaChestMenu.kt | 3 ++- .../mc/otm/menu/ExopackInventoryMenu.kt | 2 +- .../ru/dbotthepony/mc/otm/menu/MatteryMenu.kt | 17 +--------------- .../ru/dbotthepony/mc/otm/menu/SortInput.kt | 20 +++++++++++++++++++ .../mc/otm/menu/decorative/CargoCrateMenu.kt | 3 ++- .../menu/decorative/MinecartCargoCrateMenu.kt | 3 ++- .../mc/otm/menu/tech/ItemHatchMenu.kt | 3 ++- 8 files changed, 32 insertions(+), 23 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/menu/SortInput.kt 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 be92edf37..9847cf848 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 @@ -35,8 +35,8 @@ 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.util.getLevelFromXp -import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.SortInput import ru.dbotthepony.mc.otm.menu.UpgradeSlots import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput @@ -449,7 +449,7 @@ class DeviceControls>( return result } - fun sortingButtons(input: MatteryMenu.SortInput, unfoldableSettings: Boolean = true) { + fun sortingButtons(input: SortInput, unfoldableSettings: Boolean = true) { object : ButtonPanel(screen, this@DeviceControls, width = 18f, height = 18f) { var buttons: List>? = null diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/AbstractVanillaChestMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/AbstractVanillaChestMenu.kt index c67a3bc68..2281387e9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/AbstractVanillaChestMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/AbstractVanillaChestMenu.kt @@ -6,6 +6,7 @@ import net.minecraft.world.entity.player.Player import net.minecraft.world.inventory.MenuType import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.SortInput abstract class AbstractVanillaChestMenu( type: MenuType<*>, @@ -17,7 +18,7 @@ abstract class AbstractVanillaChestMenu( abstract val columns: Int abstract val containerSlots: List - val sort = SortInput(container, playerSortSettings) + val sort = SortInput(this, container, playerSortSettings) override fun stillValid(player: Player): Boolean { return container.stillValid(player) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt index 83510c0db..ebddaebac 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt @@ -135,7 +135,7 @@ class ExopackInventoryMenu(val capability: MatteryPlayer) : MatteryMenu(null, CO } } - sortEnderChest = SortInput(player.enderChestInventory, playerEnderSortSettings) + sortEnderChest = SortInput(this, player.enderChestInventory, playerEnderSortSettings) } else { enderChestSlots = listOf() sortEnderChest = null 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 576fba7bb..5e8c796d1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt @@ -3,8 +3,6 @@ package ru.dbotthepony.mc.otm.menu import com.google.common.collect.ImmutableList import com.mojang.datafixers.util.Pair import it.unimi.dsi.fastutil.bytes.ByteArrayList -import it.unimi.dsi.fastutil.ints.IntArrayList -import it.unimi.dsi.fastutil.ints.IntCollection import it.unimi.dsi.fastutil.objects.Reference2ObjectFunction import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap import it.unimi.dsi.fastutil.objects.ReferenceArrayList @@ -15,7 +13,6 @@ import net.minecraft.network.protocol.common.custom.CustomPacketPayload import net.minecraft.resources.ResourceLocation import net.minecraft.server.level.ServerPlayer import net.minecraft.util.RandomSource -import net.minecraft.world.Container import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player import net.minecraft.world.inventory.AbstractContainerMenu @@ -41,8 +38,6 @@ import ru.dbotthepony.mc.otm.compat.curios.curiosSlots import ru.dbotthepony.mc.otm.compat.curios.isCurioSlot import ru.dbotthepony.mc.otm.container.IEnhancedContainer import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot -import ru.dbotthepony.mc.otm.container.computeSortedIndices -import ru.dbotthepony.mc.otm.container.sortWithIndices import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull import ru.dbotthepony.mc.otm.core.ResourceLocation import ru.dbotthepony.mc.otm.core.collect.ConditionalSet @@ -165,16 +160,6 @@ abstract class MatteryMenu( } } - inner class SortInput(val container: Container, val settings: IItemStackSortingSettings) { - val input = PlayerInput(MatteryStreamCodec.Collection(StreamCodecs.VAR_INT, ::IntArrayList)) { - container.sortWithIndices(it) - } - - fun clientInput() { - input.accept(container.computeSortedIndices(settings.actualComparator)) - } - } - fun oneWayInput(allowSpectators: Boolean = false, handler: () -> Unit): PlayerInput { return PlayerInput(StreamCodecs.NOTHING, allowSpectators) { handler.invoke() @@ -316,7 +301,7 @@ abstract class MatteryMenu( _exopackChargeSlots.add(BatteryMenuSlot(mattery.exopackChargeSlots, i, direction = FlowDirection.INPUT).also { mapQuickMoveToExternal(it); mapQuickMoveToInventory(it); addSlot(it) }) } - sortInventoryInput = SortInput(mattery.inventoryAndExopackNoHotbar, playerSortSettings) + sortInventoryInput = SortInput(this, mattery.inventoryAndExopackNoHotbar, playerSortSettings) } private var broadcastOnce = false diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/SortInput.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/SortInput.kt new file mode 100644 index 000000000..2f5617f78 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/SortInput.kt @@ -0,0 +1,20 @@ +package ru.dbotthepony.mc.otm.menu + +import it.unimi.dsi.fastutil.ints.IntArrayList +import it.unimi.dsi.fastutil.ints.IntCollection +import net.minecraft.network.RegistryFriendlyByteBuf +import net.minecraft.world.Container +import ru.dbotthepony.mc.otm.container.computeSortedIndices +import ru.dbotthepony.mc.otm.container.sortWithIndices +import ru.dbotthepony.mc.otm.network.MatteryStreamCodec +import ru.dbotthepony.mc.otm.network.StreamCodecs + +class SortInput(menu: MatteryMenu, val container: Container, val settings: IItemStackSortingSettings) { + val input = menu.PlayerInput(MatteryStreamCodec.Collection(StreamCodecs.VAR_INT, ::IntArrayList)) { + container.sortWithIndices(it) + } + + fun clientInput() { + input.accept(container.computeSortedIndices(settings.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 723250b6c..90272457d 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,6 +5,7 @@ import net.minecraft.world.entity.player.Player import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.MatteryMenu +import ru.dbotthepony.mc.otm.menu.SortInput import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot import ru.dbotthepony.mc.otm.menu.makeSlots import ru.dbotthepony.mc.otm.registry.game.MMenus @@ -18,7 +19,7 @@ class CargoCrateMenu( val storageSlots = makeSlots(actualContainer, ::UserFilteredMenuSlot) private val trackedPlayerOpen = !inventory.player.isSpectator - val sort = SortInput(actualContainer, playerSortSettings) + val sort = SortInput(this, actualContainer, playerSortSettings) init { if (trackedPlayerOpen) { 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 c7869e695..613f24862 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 @@ -8,6 +8,7 @@ import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity import ru.dbotthepony.mc.otm.entity.MinecartCargoCrate import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.SortInput import ru.dbotthepony.mc.otm.menu.makeSlots import ru.dbotthepony.mc.otm.registry.game.MMenus @@ -21,7 +22,7 @@ class MinecartCargoCrateMenu( private val trackedPlayerOpen = !inventory.player.isSpectator - val sort = SortInput(actualContainer, playerSortSettings) + val sort = SortInput(this, actualContainer, playerSortSettings) init { if (trackedPlayerOpen) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ItemHatchMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ItemHatchMenu.kt index eae68b777..9ebd095cb 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ItemHatchMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/ItemHatchMenu.kt @@ -8,6 +8,7 @@ import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting import ru.dbotthepony.mc.otm.block.entity.tech.ItemHatchBlockEntity import ru.dbotthepony.mc.otm.menu.MatteryMenu +import ru.dbotthepony.mc.otm.menu.SortInput import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.makeSlots @@ -28,7 +29,7 @@ class ItemHatchMenu( } } - val sort = SortInput(actualContainer, playerSortSettings) + val sort = SortInput(this, actualContainer, playerSortSettings) val redstone = EnumInputWithFeedback(this) init { From ee4b12e687713c0acbd7640cfd7d675ef9987e1d Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 16 Mar 2025 23:41:33 +0700 Subject: [PATCH 100/154] Improved "quick move" code in menus --- .../mc/otm/core/util/ItemStackKey.kt | 22 +- .../mc/otm/menu/ExopackInventoryMenu.kt | 6 +- .../ru/dbotthepony/mc/otm/menu/MatteryMenu.kt | 126 +---------- .../dbotthepony/mc/otm/menu/QuickMoveInput.kt | 203 ++++++++++++++++++ .../ru/dbotthepony/mc/otm/menu/Slots.kt | 5 + .../mc/otm/menu/storage/ItemMonitorMenu.kt | 7 +- 6 files changed, 240 insertions(+), 129 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/ItemStackKey.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/ItemStackKey.kt index 875a6502c..0145c1988 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/ItemStackKey.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/ItemStackKey.kt @@ -2,12 +2,17 @@ package ru.dbotthepony.mc.otm.core.util import it.unimi.dsi.fastutil.HashCommon import net.minecraft.core.component.DataComponentMap +import net.minecraft.core.component.DataComponentPatch +import net.minecraft.core.component.PatchedDataComponentMap +import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack +import ru.dbotthepony.mc.otm.core.getHolder -class ItemStackKey(val item: Item, val components: DataComponentMap) { +class ItemStackKey(val item: Item, val components: DataComponentPatch) { // make copy of original itemstack because there is no copy() method on DataComponentMap, which is returned by ItemStack#getComponents - constructor(itemStack: ItemStack) : this(itemStack.item, itemStack.copy().components) + constructor(itemStack: ItemStack) : this(itemStack.item, itemStack.copy().componentsPatch) + constructor(item: Item) : this(item, DataComponentPatch.EMPTY) private var hashComputed = false private var hash = 0 @@ -25,6 +30,10 @@ class ItemStackKey(val item: Item, val components: DataComponentMap) { return hash } + fun asItemStack(count: Int = 1): ItemStack { + return ItemStack(BuiltInRegistries.ITEM.getHolder(item)!!, count, components) + } + override fun toString(): String { return "ItemStackKey[$item, $components]" } @@ -33,3 +42,12 @@ class ItemStackKey(val item: Item, val components: DataComponentMap) { fun ItemStack.asKey(): ItemStackKey { return ItemStackKey(this) } + +fun ItemStack.asKeyOrNull(): ItemStackKey? { + if (isEmpty) return null + return ItemStackKey(this) +} + +fun Item.asKey(): ItemStackKey { + return ItemStackKey(this) +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt index ebddaebac..74e068363 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt @@ -177,7 +177,7 @@ class ExopackInventoryMenu(val capability: MatteryPlayer) : MatteryMenu(null, CO if (!player.level().isClientSide) { for (slot in craftingGrid.slotIterator()) { - val leftover = moveItemStackToSlots(slot.item, playerInventorySlots) + val leftover = QuickMoveInput.moveItemStackToSlots(slot.item, playerInventorySlots) if (!leftover.isEmpty) { player.drop(leftover, true) @@ -205,11 +205,11 @@ class ExopackInventoryMenu(val capability: MatteryPlayer) : MatteryMenu(null, CO if (slotIndex == craftingResultSlot.index) { val item = craftingResultSlot.item - val leftover = moveItemStackToSlots(item, playerInventorySlots, simulate = true) + val leftover = QuickMoveInput.moveItemStackToSlots(item, playerInventorySlots, simulate = true) if (leftover.isEmpty) { val copy = item.copy() - moveItemStackToSlots(item, playerInventorySlots, simulate = false) + QuickMoveInput.moveItemStackToSlots(item, playerInventorySlots, simulate = false) item.count = 0 craftingResultSlot.onTake(ply, copy) return copy 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 5e8c796d1..0c3179bd0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt @@ -452,25 +452,10 @@ abstract class MatteryMenu( val copy = slot.item.copy() var any = false - if (target.any { it.any { it.containerSlotOrNull() is IFilteredContainerSlot } }) { - for (collection in target) { - if (moveItemStackTo(ply, slot, collection, onlyFiltered = true)) { - any = true - - if (!slot.hasItem()) { - return copy - } - } - } - } - for (collection in target) { - if (moveItemStackTo(ply, slot, collection)) { + if (QuickMoveInput.moveItemStackTo(ply, slot, collection)) { any = true - - if (!slot.hasItem()) { - return copy - } + if (!slot.hasItem()) return copy } } @@ -486,7 +471,7 @@ abstract class MatteryMenu( return stack } - return moveItemStackToSlots(stack, _playerInventorySlots, simulate = simulate) + return QuickMoveInput.moveItemStackToSlots(stack, _playerInventorySlots, simulate = simulate) } override fun canTakeItemForPickAll(itemStack: ItemStack, slot: Slot): Boolean { @@ -521,22 +506,12 @@ abstract class MatteryMenu( require(finalSlot < slots.size) { "Final slot $finalSlot is bigger than total size of array of ${slots.size}" } val slots = ArrayList(finalSlot - initialSlot + 1) - var filters = false for (i in (if (inverse) finalSlot downTo initialSlot else initialSlot .. finalSlot)) { - val slot = slots[i] - slots.add(slot) - - if (slot.containerSlotOrNull() is IFilteredContainerSlot) { - filters = true - } + slots.add(this.slots[i]) } - if (filters) { - return moveItemStackToSlots(moveItemStackToSlots(item, slots, simulate, onlyFiltered = true), slots, simulate, onlyFiltered = false) - } - - return moveItemStackToSlots(item, slots, simulate) + return QuickMoveInput.moveItemStackToSlots(item, slots, simulate) } private var armorSlots: ImmutableList>? = null @@ -613,96 +588,5 @@ abstract class MatteryMenu( InventoryMenu.EMPTY_ARMOR_SLOT_LEGGINGS, InventoryMenu.EMPTY_ARMOR_SLOT_CHESTPLATE, InventoryMenu.EMPTY_ARMOR_SLOT_HELMET) - - fun moveItemStackTo( - player: Player, - source: Slot, - slots: Collection, - onlyFiltered: Boolean = false - ): Boolean { - val remainder = moveItemStackToSlots(source.item, slots, onlyFiltered = onlyFiltered) - - if (remainder.count == source.item.count) { - return false - } - - val copy = source.item.copy() - - if (remainder.isEmpty) { - source.setByPlayer(ItemStack.EMPTY) - source.onTake(player, copy) - } else { - copy.count = source.item.count - remainder.count - source.item.count = remainder.count - source.onTake(player, copy) - } - - return true - } - - - fun moveItemStackToSlots(item: ItemStack, slots: Collection, simulate: Boolean = false, onlyFiltered: Boolean = false): ItemStack { - if (item.isEmpty) { - return ItemStack.EMPTY - } - - val copy = item.copy() - - // first pass - stack with existing slots - if (copy.isStackable) { - for (slot in slots) { - if (onlyFiltered && slot.containerSlotOrNull().let { it !is IFilteredContainerSlot || it.filter == null || !it.testSlotFilter(item) }) { - continue - } else if (!onlyFiltered && slot.containerSlotOrNull().let { it is IFilteredContainerSlot && it.filter != null }) { - continue - } - - val limit = slot.getMaxStackSize(copy) - - if (limit > slot.item.count && slot.mayPlace(item) && ItemStack.isSameItemSameComponents(slot.item, copy)) { - val newCount = (slot.item.count + copy.count).coerceAtMost(limit) - val diff = newCount - slot.item.count - copy.count -= diff - - if (!simulate) { - slot.item.count += diff - slot.setChanged() - } - - if (copy.isEmpty) { - return copy - } - } - } - } - - // second pass - drop stack into first free slot - for (slot in slots) { - if (onlyFiltered && slot.containerSlotOrNull().let { it !is IFilteredContainerSlot || it.filter == null || !it.testSlotFilter(item) }) { - continue - } else if (!onlyFiltered && slot.containerSlotOrNull().let { it is IFilteredContainerSlot && it.filter != null }) { - continue - } - - val limit = slot.getMaxStackSize(copy) - - if (!slot.hasItem() && slot.mayPlace(item)) { - val newCount = copy.count.coerceAtMost(limit) - - if (!simulate) { - slot.setByPlayer(copy.copy().also { it.count = newCount }) - slot.setChanged() - } - - copy.count -= newCount - - if (copy.isEmpty) { - return copy - } - } - } - - return copy - } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt new file mode 100644 index 000000000..e3d3bf1b1 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt @@ -0,0 +1,203 @@ +package ru.dbotthepony.mc.otm.menu + +import net.minecraft.world.entity.player.Player +import net.minecraft.world.inventory.Slot +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot +import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull +import ru.dbotthepony.mc.otm.core.isNotEmpty +import ru.dbotthepony.mc.otm.core.util.ItemStackKey +import ru.dbotthepony.mc.otm.core.util.asKey +import ru.dbotthepony.mc.otm.core.util.asKeyOrNull + +class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, val to: Collection, val mode: Mode) { + enum class Mode { + RESTOCK { + override fun move(from: Collection, to: Collection, player: Player) { + val (_, itemsFrom) = computeSlotLists(from, true) + val (_, itemsTo) = computeSlotLists(to, false) + + val intersect = if (itemsFrom.size < itemsTo.size) itemsFrom.keys.filter { it in itemsTo.keys } else itemsTo.keys.filter { it in itemsFrom.keys } + + for (key in intersect) { + val slotsTo = itemsTo[key]!! + itemsFrom[key]!!.forEach { moveItemStackTo(player, it, slotsTo) } + } + } + }, + + RESTOCK_WITH_MOVE { + override fun move(from: Collection, to: Collection, player: Player) { + val (_, itemsFrom) = computeSlotLists(from, true) + val (emptyTo, itemsTo) = computeSlotLists(to, false) + + val intersect = if (itemsFrom.size < itemsTo.size) itemsFrom.keys.filter { it in itemsTo.keys } else itemsTo.keys.filter { it in itemsFrom.keys } + + for (key in intersect) { + val slotsTo = prioritySortSlots(itemsTo[key]!!, key.asItemStack()) + val slotsFrom = itemsFrom[key]!! + slotsFrom.removeIf { moveItemStackTo(player, it, slotsTo, sort = false); it.item.isEmpty } + var moveAny = false + slotsFrom.forEach { moveAny = moveItemStackTo(player, it, emptyTo, sort = false) || moveAny } + if (moveAny) emptyTo.removeIf { it.item.isNotEmpty } + } + } + }, + + MOVE { + override fun move(from: Collection, to: Collection, player: Player) { + val toSorted = prioritySortSlots(to) + + from.forEach { + val slot = it.containerSlotOrNull() + + if (slot !is IFilteredContainerSlot || !slot.hasFilter) + moveItemStackTo(player, it, toSorted, sort = false) + } + } + }; + + abstract fun move(from: Collection, to: Collection, player: Player) + } + + private val input = menu.oneWayInput(handler = ::handle) + + fun trigger() { + input.accept(null) + } + + private fun handle() { + mode.move(from, to, menu.player) + } + + companion object { + private fun computeSlotLists(slots: Collection, skipFilteredSlots: Boolean): Pair, MutableMap>> { + val emptySlots = ArrayList() + val filledSlots = HashMap>() + + for (slot in slots) { + val underlyingSlot = slot.containerSlotOrNull() + + if (underlyingSlot is IFilteredContainerSlot && (underlyingSlot.filter == Items.AIR || underlyingSlot.filter != null && skipFilteredSlots)) + continue + + val key = slot.item.asKeyOrNull() ?: (underlyingSlot as? IFilteredContainerSlot)?.filter?.asKey() + + if (key == null) { + emptySlots.add(slot) + } else { + filledSlots.computeIfAbsent(key) { ArrayList() }.add(slot) + } + } + + return emptySlots to filledSlots + } + + fun moveItemStackTo( + player: Player, + source: Slot, + slots: Collection, + sort: Boolean = true + ): Boolean { + if (!source.mayPickup(player) || source.item.isEmpty || slots.isEmpty()) + return false + + val remainder = moveItemStackToSlots(source.item, slots, sort = sort) + + if (remainder.count == source.item.count) + return false + + val copy = source.item.copy() + + if (remainder.isEmpty) { + source.setByPlayer(ItemStack.EMPTY) + source.onTake(player, copy) + } else { + copy.count = source.item.count - remainder.count + source.item.count = remainder.count + source.onTake(player, copy) + } + + return true + } + + fun prioritySortSlots(slots: Collection, filterItem: ItemStack? = null): MutableList { + val sortedSlots = ArrayList(slots) + + sortedSlots.removeIf { + val slot = it.containerSlotOrNull() + it.isOverCapacity || filterItem != null && !it.mayPlace(filterItem) || slot is IFilteredContainerSlot && slot.isForbiddenForAutomation + } + + sortedSlots.sortWith { a, b -> + val hasItemA = a.item.isNotEmpty + val hasItemB = b.item.isNotEmpty + + if (hasItemA && hasItemB) + return@sortWith 0 + else if (hasItemA) + return@sortWith -1 + else if (hasItemB) + return@sortWith 1 + + val slotA = a.containerSlotOrNull() + val slotB = b.containerSlotOrNull() + + val hasFilterA = slotA is IFilteredContainerSlot && slotA.hasFilter + val hasFilterB = slotB is IFilteredContainerSlot && slotB.hasFilter + + if (hasFilterA && hasFilterB || !hasFilterA && !hasFilterB) + return@sortWith 0 + else if (hasFilterA) + return@sortWith -1 + else + return@sortWith 1 + } + + return sortedSlots + } + + fun moveItemStackToSlots(item: ItemStack, slots: Collection, simulate: Boolean = false, sort: Boolean = true): ItemStack { + if (item.isEmpty) + return ItemStack.EMPTY + else if (slots.isEmpty()) + return item.copy() + + val sortedSlots = if (sort) prioritySortSlots(slots, item) else slots + val copy = item.copy() + + for (slot in sortedSlots) { + val limit = slot.getMaxStackSize(copy) + + if (!slot.hasItem()) { + val newCount = copy.count.coerceAtMost(limit) + + if (!simulate) { + slot.setByPlayer(copy.copy().also { it.count = newCount }) + // slot.setChanged() + } + + copy.shrink(newCount) + + if (copy.isEmpty) + return ItemStack.EMPTY + } else if (limit > slot.item.count && ItemStack.isSameItemSameComponents(slot.item, copy)) { + val newCount = (slot.item.count + copy.count).coerceAtMost(limit) + val diff = newCount - slot.item.count + copy.count -= diff + + if (!simulate) { + slot.item.count += diff + slot.setChanged() + } + + if (copy.isEmpty) + return ItemStack.EMPTY + } + } + + return copy + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt index b3644e38c..2ad6091ee 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt @@ -26,6 +26,7 @@ import ru.dbotthepony.mc.otm.container.UpgradeContainer import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull import ru.dbotthepony.mc.otm.core.collect.ConditionalEnumSet import ru.dbotthepony.mc.otm.core.immutableList +import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.InstantBooleanInput @@ -242,6 +243,10 @@ fun MatteryMenu.addFilterControls(slots: KMutableProperty0?, amount: return addFilterControls(slots?.let { Delegate.Of(it) }, amount) } +val Slot.isOverCapacity: Boolean get() { + return item.isNotEmpty && getMaxStackSize(item) <= item.count +} + /** * [openState] **is clientside only**, attempting to use it on server will result * in classloading exceptions. diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/ItemMonitorMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/ItemMonitorMenu.kt index 54a2d1287..2bba0944a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/ItemMonitorMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/ItemMonitorMenu.kt @@ -17,6 +17,7 @@ import ru.dbotthepony.mc.otm.core.collect.reduce import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.QuickMoveInput import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewProvider import ru.dbotthepony.mc.otm.menu.data.NetworkedItemView import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback @@ -137,9 +138,9 @@ class ItemMonitorMenu( if (settings.resultTarget == ItemMonitorPlayerSettings.ResultTarget.ALL_SYSTEM) { remaining = view.insertStack(ItemStorageStack(itemStack), simulate).toItemStack() - remaining = moveItemStackToSlots(remaining, playerInventorySlots, simulate) + remaining = QuickMoveInput.moveItemStackToSlots(remaining, playerInventorySlots, simulate) } else { - remaining = moveItemStackToSlots(itemStack, playerInventorySlots, simulate) + remaining = QuickMoveInput.moveItemStackToSlots(itemStack, playerInventorySlots, simulate) remaining = view.insertStack(ItemStorageStack(remaining), simulate).toItemStack() } @@ -184,7 +185,7 @@ class ItemMonitorMenu( else -> {} } - remainder = moveItemStackToSlots(remainder, playerInventorySlots) + remainder = QuickMoveInput.moveItemStackToSlots(remainder, playerInventorySlots) slots[slotIndex].set(remainder) return if (remainder.count != item.count) item else ItemStack.EMPTY From d89d5b9672539708b02bca1921072708d263e6f4 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Mon, 17 Mar 2025 11:23:34 +0700 Subject: [PATCH 101/154] Add "quick move" to/from storage graphics --- .../mc/otm/client/render/WidgetLocation.kt | 2 +- .../mc/otm/client/render/Widgets18.kt | 8 +++++++- .../textures/gui/widgets/storage_controls.png | Bin 1071 -> 1371 bytes .../textures/gui/widgets/storage_controls.xcf | Bin 11478 -> 15956 bytes 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/WidgetLocation.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/WidgetLocation.kt index 76ca2623a..bbd38299b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/WidgetLocation.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/WidgetLocation.kt @@ -5,7 +5,7 @@ import ru.dbotthepony.mc.otm.client.render.sprites.MatteryAtlas import ru.dbotthepony.mc.otm.core.ResourceLocation object WidgetLocation { - val STORAGE_CONTROLS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/storage_controls.png"), 90f, 72f) + val STORAGE_CONTROLS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/storage_controls.png"), 90f, 90f) val WIDGET_18 = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/widget_18.png"), 72f, 72f) val WIDGET_15 = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/widget_15.png"), 60f, 60f) val WIDGET_8 = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/widget_8.png"), 64f, 32f) 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 06bab6193..21aa5a69c 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 @@ -6,7 +6,7 @@ import ru.dbotthepony.mc.otm.core.immutableMap import ru.dbotthepony.mc.otm.core.math.RelativeSide object Widgets18 { - private val storageGrid = WidgetLocation.STORAGE_CONTROLS.grid(rows = 4, columns = 5) + private val storageGrid = WidgetLocation.STORAGE_CONTROLS.grid(rows = 5, columns = 5) val SORT_DESCENDING = storageGrid.next() val SORT_ASCENDING = storageGrid.next() @@ -24,6 +24,12 @@ object Widgets18 { val PLAY = storageGrid.next() val STOP = storageGrid.next() val SORT_NOW = storageGrid.next() + val MOVE_EVERYTHING_TO_STORAGE = storageGrid.next() + val MOVE_EVERYTHING_FROM_STORAGE = storageGrid.next() + val RESTOCK_TO_STORAGE = storageGrid.next() + val RESTOCK_FROM_STORAGE = storageGrid.next() + val RESTOCK_WITH_MOVE_TO_STORAGE = storageGrid.next() + val RESTOCK_WITH_MOVE_FROM_STORAGE = storageGrid.next() private val miscGrid = WidgetLocation.WIDGET_18.grid(4, 4) diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/storage_controls.png b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/storage_controls.png index 0c33af3f2bb17a5f806efa7c82d70f66f9efde76..054f10becee5be6977e92b4c905e07d6cb286bcb 100644 GIT binary patch delta 1312 zcmV+*1>gFw2-^yf7YbSk1^@s6IH*Aaks%x&P!xqvQ>7x6B6bjU$WWc^q9Tr^ibb$c z+6t{Yn7ol&Ab#<}FMz%#=}Ha$-qCKgLwEO#+08!GV(aYRuy%6}JfE-Re3IIGn zxk5(IQ7cXdAe=?r8EJaJd5v zKk1SoIe(I$N+=eA_cQvYJTP<%^sl*dYoFuv0m#yTS z5r3&%o*JJMG5hgUdz5h;Tiok&Bj&sHV)juj4u%I}h%{X!DSo1cAXsyBr z1q%QG00000&_GL5O?D4@Se58d%^$lJL0UaV9CewbF4^lsS^*MAHE005x!8dJLTPCa*tx;VXFub_&#Uaz)y zsv{i7QqRJWJ}cwz@1N$^j}K#vF`wUm%;o;hmYz9hp*j9IiIb^H?`TZw^CMjDZ}VmT zU(7{O-%H8n_~WF`#vDt{fSgmM8WF8|s#H?^styrrQaXO+~b!j3_NA%Gy9+zxHG_%7Jde8|Xng&*fMf%_QdU*#~ zRxwAH>_oKaqIXMlsYOh>s3M}d`AYa7eGt*a>QbYmKZU%LMla<($TB5ahE4;4=AO2K4+Pb7{q-LQx^i03vfo%23%h?OOU_?&pkpbHW| za$R=$jdRIifoFz{Y&uRHA{I+sEO#+08!GWEaad6`%6}JfE-Re3IIGniARSlF3y8BgX=2P$4;f@IUz7TeCPb z?Is0dK<|rfe@p;@U7*#l?eAmTZk+)BXW&Zf_-jpI{*&}ZM++YTL)*Z`bw`u;fXf|V zwQCxAr+sAAl_NYWW5@I0Pn3l)dip?!NB6{ae%S z-w$G{}w{XfO3AvD5g{&M&U0 zcYph2j!`Lz=vuT}R++?JB^}Z%qxbSV`qvV4wpzN6S+jJcgOM&lsiv0nRYOwA&O)+< zr?{F-Xr#hIoW!R^I>ZGF#ffainWbabZ4J?0g%1S_000000JtERmZY@N{ldVf#ir!}Z*h*Gk=$(OVz^ET!gS(-j{&5x!* zbW4pcHTktfX#BLE)UX*kr*)bS&~-Ds6Nx4HJKB_1LmV;Sv*Ud)4Ln{s@bDu&Wx3?4 z!c!|i>F*H=eK%`!dIxm+O$iPF004OBk5~Cw6`M4b@gk|Ux83^TuKM7chLEeto_`@9 zb|w0(<}dvf!CFbJOt$65|E4J|JsUx*S9&fH{rCDQWczQ1chKTl#=6~QX)c}KdC9{H zWcQY`ZS@JPGRDoC$ZJj<{!QfSig8pR47=AcV`N*$WU-5PuKs5F@XH)!S^q7&;+_Ej z002A-UMCvBSb{_LAfh3AAkmOLfIDa^tAP;>*^NYN@a9nP}u-U_?Xq gKn+a diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/storage_controls.xcf b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/storage_controls.xcf index 894ea7b4b51d74b4b16bcdc5200851e7e5f64c4b..3dbdd5d0e433eb90145f6929a9148a7ce041b823 100644 GIT binary patch literal 15956 zcmeHOTWnlM8J@j+cfEElrgog9-B1VHN!{2Xc8wAf2^Ep{0aXGCRFG3QOOBgJ0x z*Vhg8(-G>vqWPox`SHUed&Ulq7W;a^y)c7wOwX4OjvXzI9o+Nm-f@;Vv~S<|-lIj6 z-=i%#Gc%vr3-QgCNfm9{khW>=vP}zb*>uH^Y`XfZHf?>#rfbgGblp#FTI{mvgHHdE z^_K7Yn@umf6A+#%hG(ID1xYcSfbeX1F1%Pe5uPa>E1lw92?z!nfFRI_ z8%XawhAV)ANI5IZIvR=kut%@+=$uCvJv#5vjUHX_=w{HYk1w|iF@wmudH;=$Mxr`M zYXqbZdb9xfdysh{@vO&)@pxZ^#7j0cSJ6@aW07~O)Kp$gPhEQV-Af?mFcj#i1R|AL z71PM8^`)tVPJxL{#k8JE8oI1VsAe5k1;hlDj7i<0q^AC%q5g7B9urklzt;VcH95t? zHC@*Fa=9jtiK@w{qu$9W=B-J?E)h{{*i1h_6CrIxs#P5MET2P}Mp&l_yy>gbHpJo1 zTLt|@cz!PIUuMhJ6WsYcwZNTz+Y9N>d5oCN!96`5p@S%WQskXzgsW%}cmkbPd7T7I zQ=TjX`UC3Ynxtf1JGW!Z=rXCP%nYp8SdG^!rl&mSHdk|b-u^N3Z8ig?O?baXptj%; zJR8yLB6|UQhV2R6YyoL5qI@74<&&Okp9^l|)9VS`1oi-8wZ7c+R+M)kyG=O|>h_Yq>FCMlAUmkPb_RjnAN=C2m4EG*=|2cwbg zOzZBnLiJSZ zy9L1yEY@Flhp$D zONiU#qSwMb^Ol)eX$oMEAto`2Ng$@3zLRYtZOBQ<<|vRa4R6iYs0HT7X^To&Ia#60 zCUP)e`KJgSL@WO(@?~#rml(2cxK(f6>42GbKutQ}64X(^#{CzZv&@-ww}!8Wlh_{ z`s0TFAW#8Vseq~is!j#%YWYEF)!S*&?dW$gM7wVj*Ez!{GzYO5Ht8Ci{<_j-n)^K| z^&hjvz-@igCAJf~3IRPODq-^*)`s!q8z*tW`ls$|yt7;d% zgDC5TwjPfW1GpaA_E>}tqP7u{ccVL?X#$O&no&9Q&{&WG78aXgCkW-@rnm84*G*R| zm@c*v8<=-bEyF4U5Y8WmX{`I>Z!h9j>)+%Hx*#TS;9g&z|3EJ~kn79qUu+8-uX_dHHj^2m z*kdX)CW2aKPxEB52)CK$qv_D&!Fy7jan7^(ne(EJYWX3>^uATAvEnK4JT z9T;>15huGr+|UK^1#S8nyy?AGab=u|X^yirtep2Ys%yr+lu=i}nA3zYhieDgP@?6< zj%Y}6wj7Jv!Z-N6L+Mm_fgeEBZ6_f9YUu=Ryg?;&?5NOXd$>-}@%acHL>-4kZaaZJ zujGoY(g7UcT?YWBp(VCCK-ptokQ_n?e>%>^!GF0*f?bXnBwZBX@0$&HGXk(>>&fSH z^~-Kr?drFcFH{Mgn=ABexOaXkLI+XjZjlr2VrxJ3JUrJGaQDW;n?(k8m$0ayi{}p0 zt-E;t{zBhv^)#w0;wK1Q=RM?;9d74{>t=cr_k9{}yL231tWAb*VZl7fkJ-WrHeEg8 znTy_9@Vr{EXw&X%9xub0bKjeM?28WBH*JwJU%+6AWvy}2bjsM>jA0XX8oQ+UelM>7 zZuUb}pHpQ+IuBZd$@A2#*kGNSKj^yvENV z0cMz6T_uVCbOiUl)0H#BgbHP1`XJj(8jWHdmFBd>%>}Nl;`)Gv`f^>f(Yz=d zqS2%siT4JB_s1S(Th^09muIXNHP z<$J=eVrQbXNk(vNyp>+0(d)^t@p<^P)gqDQys+(O9wSz8NZj_j2pvS*{wVSh%z(HE z`lL%i2P3K$sri0go`bE?Zd(JJKUhLcl)i~M6&Da^>#t?FBxb0#Wr#8_41C;U#3HU` z2A+)2K{RkgNgfBd`I|_d zqDjPlMAQn4s0qx`@ms0-o1KgQuNFrRBYbU!!Ee~qT*VG9&)^#oI+nR0@?muYYekjB z4haCo1rk5>Nm;4=VFMOSIKs6f4>NOpsqoQ_Jhj!qLCj~C#yxjqFm2{w zYTh~njxWj8Vg@Iuq#KOPyl>W!eBGR(%-bHK8O7$r-oxRmaAfB(3p!)m*qPFIO5a*C zvmm|+L$%1{?+d-Kz34GwC5O!IQTyM>zWuXOW)PpJ-^=n0P(`#8J|?T^qwH1v|l2fg-BIb0Zoz$XDOK#_b5WO2o#eSVoT1gun$ W^S>(jxWhtg85{QL);jF$RR0Clymbly delta 676 zcmcaob1ia$sFVi-1WW@`fDtX@(#lLsJgRWrJdR-9JdvBv%f>M?@$ZDo z@LvUM=YI>cJVvQ*^9w~UCMKbMFhz_)lP?O2GYNg#oT0LliAi)VOoB=DBuF=t=)=w7 z>a&=bBx>O@5;K8JamJ0C)wQ-WF-d2^C8XOxS~#WW!7Pl|%blE{mjl9^6ZDc8ndJQ7 ziseB1#F*roHviCMiqGdR&QbTgkN2NRR#BDf+=P}qnuX Date: Mon, 17 Mar 2025 21:07:30 +0700 Subject: [PATCH 102/154] Add take all, restock, full restock buttons --- .../mc/otm/datagen/lang/English.kt | 10 ++ .../mc/otm/datagen/lang/Russian.kt | 10 ++ .../screen/decorative/CargoCrateScreen.kt | 10 +- .../client/screen/panels/button/Buttons.kt | 157 ++++++++++++++---- .../vanilla/AbstractVanillaChestMenu.kt | 3 + .../mc/otm/compat/vanilla/MatteryChestMenu.kt | 4 + .../compat/vanilla/MatteryShulkerBoxMenu.kt | 4 + .../otm/compat/vanilla/VanillaChestScreen.kt | 9 + .../dbotthepony/mc/otm/menu/QuickMoveInput.kt | 37 ++++- .../mc/otm/menu/decorative/CargoCrateMenu.kt | 3 + 10 files changed, 207 insertions(+), 40 deletions(-) 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 67ead1708..f67f598c9 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 @@ -987,6 +987,16 @@ private fun androidFeatures(provider: MatteryLanguageProvider) { private fun gui(provider: MatteryLanguageProvider) { with(provider.english) { + gui("quickmove_from.restock", "Restock from storage") + gui("quickmove_from.restock_with_move", "Full restock from storage") + gui("quickmove_from.move", "Take all") + + gui("quickmove_to.restock", "Restock to storage") + gui("quickmove_to.restock_with_move", "Full restock to storage") + gui("quickmove_to.move", "Deposit all") + + gui("quickmove_hint", "Right click to show all variants") + gui("exopack.accept_wireless_charge", "Accept wireless charging") gui("exopack.dont_accept_wireless_charge", "Do not accept wireless charging") 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 cc3b3a7d4..3ca5d8e84 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 @@ -980,6 +980,16 @@ private fun androidFeatures(provider: MatteryLanguageProvider) { private fun gui(provider: MatteryLanguageProvider) { with(provider.russian) { + gui("quickmove_from.restock", "Быстрое пополнение из хранилища") + gui("quickmove_from.restock_with_move", "Быстрое перемещение из хранилища") + gui("quickmove_from.move", "Взять всё") + + gui("quickmove_to.restock", "Быстрое пополнение в хранилище") + gui("quickmove_to.restock_with_move", "Быстрое перемещение в хранилище") + gui("quickmove_to.move", "Переместить всё") + + gui("quickmove_hint", "Правый клик чтоб увидеть все варианты") + gui("exopack.accept_wireless_charge", "Принимать заряд от беспроводных зарядников") gui("exopack.dont_accept_wireless_charge", "Не принимать заряд от беспроводных зарядников") 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 974878362..1cae5b676 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 @@ -7,6 +7,7 @@ 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.UserFilteredSlotPanel +import ru.dbotthepony.mc.otm.menu.QuickMoveInput import ru.dbotthepony.mc.otm.menu.decorative.CargoCrateMenu class CargoCrateScreen(menu: CargoCrateMenu, inventory: Inventory, title: Component) : MatteryScreen(menu, inventory, title) { @@ -23,9 +24,16 @@ class CargoCrateScreen(menu: CargoCrateMenu, inventory: Inventory, title: Compon UserFilteredSlotPanel(this, grid, slot) val controls = DeviceControls(this, frame) - controls.sortingButtons(menu.sort) + val leftControls = DeviceControls(this, frame) + leftControls.dockOnLeft = true + leftControls.quickMoveButtons(menu.quickMoveFromStorage, QuickMoveInput.Mode.RESTOCK, true) + + val leftInventoryControls = DeviceControls(this, inventoryFrame!!) + leftInventoryControls.dockOnLeft = true + leftInventoryControls.quickMoveButtons(menu.quickMoveToStorage, QuickMoveInput.Mode.RESTOCK_WITH_MOVE, false) + return frame } } 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 9847cf848..08a000f1a 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 @@ -36,6 +36,7 @@ import ru.dbotthepony.mc.otm.core.math.RelativeSide import ru.dbotthepony.mc.otm.core.util.ItemStackSorter import ru.dbotthepony.mc.otm.core.util.getLevelFromXp import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.QuickMoveInput import ru.dbotthepony.mc.otm.menu.SortInput import ru.dbotthepony.mc.otm.menu.UpgradeSlots import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback @@ -385,13 +386,17 @@ class DeviceControls>( } fun

> addButton(button: P): P { - buttons.add(button) - button.parent = this - alignButtons() + if (button !in buttons) { + buttons.add(button) + button.parent = this + alignButtons() + } + return button } fun

> addButton(button: P, after: EditablePanel<*>): P { + buttons.remove(button) val index = buttons.indexOf(after) if (index == -1) throw NoSuchElementException("Unknown panel to add button after: $after") buttons.add(index + 1, button) @@ -401,9 +406,12 @@ class DeviceControls>( } fun

> prependButton(button: P): P { - buttons.add(0, button) - button.parent = this - alignButtons() + if (button !in buttons) { + buttons.add(0, button) + button.parent = this + alignButtons() + } + return button } @@ -449,9 +457,75 @@ class DeviceControls>( return result } + private abstract inner class FoldableButtonPanel() : ButtonPanel(screen, this@DeviceControls, width = 18f, height = 18f) { + init { + addButton(this) + } + + private var buttons: List>? = null + + + fun makeButtons() { + if (buttons == null) { + buttons = doMakeButtons().also { + it.forEach { addButton(it, this) } + } + } + } + + fun removeButtons() { + if (buttons != null) { + buttons!!.forEach { it.remove() } + buttons = null + } + } + + override fun test(value: Int): Boolean { + return value == InputConstants.MOUSE_BUTTON_LEFT || hasExtraButtons && value == InputConstants.MOUSE_BUTTON_RIGHT + } + + fun switchButtons() { + if (buttons == null) + makeButtons() + else + removeButtons() + } + + protected abstract val hasExtraButtons: Boolean + protected abstract fun performAction() + protected abstract fun doMakeButtons(): List> + + final override fun onClick(mouseButton: Int) { + if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) { + performAction() + } else { + switchButtons() + } + } + } + fun sortingButtons(input: SortInput, unfoldableSettings: Boolean = true) { - object : ButtonPanel(screen, this@DeviceControls, width = 18f, height = 18f) { - var buttons: List>? = null + object : FoldableButtonPanel() { + override fun performAction() { + input.clientInput() + } + + override var isDisabled: Boolean + get() { return !input.input.test(minecraft.player ?: return false) } + set(value) {} + + override val hasExtraButtons: Boolean + get() = unfoldableSettings + + override fun doMakeButtons(): List> { + return sortingButtons(Delegate.Of(input.settings::isAscending), Delegate.Of(input.settings::sorting), ItemStackSorter.DEFAULT) { + for (v in ItemStackSorter.entries) { + add(v, v.icon, v.title) + } + + finish() + } + } init { tooltips.add(TranslatableComponent("otm.gui.sorting.sort_now")) @@ -459,50 +533,67 @@ class DeviceControls>( if (unfoldableSettings) { tooltips.add(TextComponent("")) tooltips.add(TranslatableComponent("otm.gui.sorting.sort_settings").withStyle(ChatFormatting.GRAY)) - } - addButton(this) - - if (!unfoldableSettings) { + } else { makeButtons() } } override val icon: IGUIRenderable get() = Widgets18.SORT_NOW + } + } - override fun test(value: Int): Boolean { - return value == InputConstants.MOUSE_BUTTON_LEFT || unfoldableSettings && value == InputConstants.MOUSE_BUTTON_RIGHT + fun quickMoveButtons(buttons: Map, mainMode: QuickMoveInput.Mode, isFromStorage: Boolean, unfoldableSettings: Boolean = true) { + object : FoldableButtonPanel() { + private val input = buttons[mainMode]!! + + override fun performAction() { + input.clientInput() } override var isDisabled: Boolean get() { return !input.input.test(minecraft.player ?: return false) } set(value) {} - private fun makeButtons() { - buttons = sortingButtons(Delegate.Of(input.settings::isAscending), Delegate.Of(input.settings::sorting), ItemStackSorter.DEFAULT) { - for (v in ItemStackSorter.entries) { - add(v, v.icon, v.title) + override val hasExtraButtons: Boolean + get() = unfoldableSettings + + override fun doMakeButtons(): List> { + return buttons.entries + .stream() + .filter { (m, _) -> m != input.mode } + .map { (m, b) -> + square18( + screen, + this, + icon = if (isFromStorage) m.iconFromStorage else m.iconToStorage, + onPress = { b.clientInput() } + ).also { + if (isFromStorage) + it.tooltips.add(m.textFromStorage) + else + it.tooltips.add(m.textToStorage) + } } - - finish() - } - - buttons!!.forEach { removeButton(it) } - buttons!!.forEach { addButton(it as EditablePanel, this) } + .toList() } - override fun onClick(mouseButton: Int) { - if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) { - input.clientInput() + init { + if (isFromStorage) + tooltips.add(input.mode.textFromStorage) + else + tooltips.add(input.mode.textToStorage) + + if (unfoldableSettings) { + tooltips.add(TextComponent("")) + tooltips.add(TranslatableComponent("otm.gui.quickmove_hint").withStyle(ChatFormatting.GRAY)) } else { - if (buttons == null) { - makeButtons() - } else { - buttons!!.forEach { it.remove() } - buttons = null - } + makeButtons() } } + + override val icon: IGUIRenderable + get() = if (isFromStorage) input.mode.iconFromStorage else input.mode.iconToStorage } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/AbstractVanillaChestMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/AbstractVanillaChestMenu.kt index 2281387e9..f7ccd1eb7 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/AbstractVanillaChestMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/AbstractVanillaChestMenu.kt @@ -6,6 +6,7 @@ import net.minecraft.world.entity.player.Player import net.minecraft.world.inventory.MenuType import ru.dbotthepony.mc.otm.menu.MatteryMenu import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.QuickMoveInput import ru.dbotthepony.mc.otm.menu.SortInput abstract class AbstractVanillaChestMenu( @@ -18,6 +19,8 @@ abstract class AbstractVanillaChestMenu( abstract val columns: Int abstract val containerSlots: List + abstract val quickMoveToStorage: Map + abstract val quickMoveFromStorage: Map val sort = SortInput(this, container, playerSortSettings) override fun stillValid(player: Player): Boolean { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt index 038854f22..b9f17a670 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt @@ -6,6 +6,7 @@ import net.minecraft.world.entity.player.Inventory import net.minecraft.world.inventory.MenuType import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.QuickMoveInput import ru.dbotthepony.mc.otm.menu.makeSlots class MatteryChestMenu( @@ -22,6 +23,9 @@ class MatteryChestMenu( addInventorySlots() } + override val quickMoveToStorage = QuickMoveInput.create(this, playerCombinedInventorySlots, containerSlots) + override val quickMoveFromStorage = QuickMoveInput.create(this, containerSlots, playerInventorySlots) + companion object { @JvmStatic @JvmOverloads diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryShulkerBoxMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryShulkerBoxMenu.kt index 9ebc6d65e..e987c22b6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryShulkerBoxMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryShulkerBoxMenu.kt @@ -5,6 +5,7 @@ import net.minecraft.world.entity.player.Inventory import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.QuickMoveInput import ru.dbotthepony.mc.otm.menu.makeSlots class MatteryShulkerBoxMenu( @@ -24,6 +25,9 @@ class MatteryShulkerBoxMenu( addInventorySlots() } + override val quickMoveToStorage = QuickMoveInput.create(this, playerCombinedInventorySlots, containerSlots) + override val quickMoveFromStorage = QuickMoveInput.create(this, containerSlots, playerInventorySlots) + class Slot(container: Container, slot: Int) : MatteryMenuSlot(container, slot) { override fun mayPlace(stack: ItemStack): Boolean { return super.mayPlace(stack) && stack.item.canFitInsideContainerItems() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaChestScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaChestScreen.kt index eaa1f0976..5a990200d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaChestScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaChestScreen.kt @@ -10,6 +10,7 @@ import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.SlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.util.GridPanel +import ru.dbotthepony.mc.otm.menu.QuickMoveInput class VanillaChestScreen(menu: AbstractVanillaChestMenu, inventory: Inventory, title: Component) : MatteryScreen(menu, inventory, title) { override fun makeMainFrame(): FramePanel> { @@ -28,6 +29,14 @@ class VanillaChestScreen(menu: AbstractVanillaChestMenu, inventory: Inventory, t val controls = DeviceControls(this, frame) controls.sortingButtons(menu.sort) + val leftControls = DeviceControls(this, frame) + leftControls.dockOnLeft = true + leftControls.quickMoveButtons(menu.quickMoveFromStorage, QuickMoveInput.Mode.RESTOCK, true) + + val leftInventoryControls = DeviceControls(this, inventoryFrame!!) + leftInventoryControls.dockOnLeft = true + leftInventoryControls.quickMoveButtons(menu.quickMoveToStorage, QuickMoveInput.Mode.RESTOCK_WITH_MOVE, false) + return frame } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt index e3d3bf1b1..f57aaa260 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt @@ -1,19 +1,26 @@ package ru.dbotthepony.mc.otm.menu +import net.minecraft.network.chat.Component import net.minecraft.world.entity.player.Player import net.minecraft.world.inventory.Slot import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Items +import ru.dbotthepony.mc.otm.client.render.Widgets18 +import ru.dbotthepony.mc.otm.client.render.sprites.AbstractMatterySprite import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull +import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.util.ItemStackKey import ru.dbotthepony.mc.otm.core.util.asKey import ru.dbotthepony.mc.otm.core.util.asKeyOrNull class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, val to: Collection, val mode: Mode) { - enum class Mode { - RESTOCK { + enum class Mode(val iconFromStorage: AbstractMatterySprite, val iconToStorage: AbstractMatterySprite) { + RESTOCK( + Widgets18.RESTOCK_FROM_STORAGE, + Widgets18.RESTOCK_TO_STORAGE + ) { override fun move(from: Collection, to: Collection, player: Player) { val (_, itemsFrom) = computeSlotLists(from, true) val (_, itemsTo) = computeSlotLists(to, false) @@ -27,7 +34,10 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, } }, - RESTOCK_WITH_MOVE { + RESTOCK_WITH_MOVE( + Widgets18.RESTOCK_WITH_MOVE_FROM_STORAGE, + Widgets18.RESTOCK_WITH_MOVE_TO_STORAGE + ) { override fun move(from: Collection, to: Collection, player: Player) { val (_, itemsFrom) = computeSlotLists(from, true) val (emptyTo, itemsTo) = computeSlotLists(to, false) @@ -45,7 +55,10 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, } }, - MOVE { + MOVE( + Widgets18.MOVE_EVERYTHING_FROM_STORAGE, + Widgets18.MOVE_EVERYTHING_TO_STORAGE + ) { override fun move(from: Collection, to: Collection, player: Player) { val toSorted = prioritySortSlots(to) @@ -59,11 +72,19 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, }; abstract fun move(from: Collection, to: Collection, player: Player) + + val textFromStorage: Component get() { + return TranslatableComponent("otm.gui.quickmove_from.${name.lowercase()}") + } + + val textToStorage: Component get() { + return TranslatableComponent("otm.gui.quickmove_to.${name.lowercase()}") + } } - private val input = menu.oneWayInput(handler = ::handle) + val input = menu.oneWayInput(handler = ::handle) - fun trigger() { + fun clientInput() { input.accept(null) } @@ -72,6 +93,10 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, } companion object { + fun create(menu: MatteryMenu, from: Collection, to: Collection): Map { + return Mode.entries.associateWith { QuickMoveInput(menu, from, to, it) } + } + private fun computeSlotLists(slots: Collection, skipFilteredSlots: Boolean): Pair, MutableMap>> { val emptySlots = ArrayList() val filledSlots = HashMap>() 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 90272457d..5f46a3188 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,6 +5,7 @@ import net.minecraft.world.entity.player.Player import ru.dbotthepony.mc.otm.block.entity.decorative.CargoCrateBlockEntity import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.MatteryMenu +import ru.dbotthepony.mc.otm.menu.QuickMoveInput import ru.dbotthepony.mc.otm.menu.SortInput import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot import ru.dbotthepony.mc.otm.menu.makeSlots @@ -20,6 +21,8 @@ class CargoCrateMenu( private val trackedPlayerOpen = !inventory.player.isSpectator val sort = SortInput(this, actualContainer, playerSortSettings) + val quickMoveToStorage = QuickMoveInput.create(this, playerCombinedInventorySlots, storageSlots) + val quickMoveFromStorage = QuickMoveInput.create(this, storageSlots, playerInventorySlots) init { if (trackedPlayerOpen) { From a84df28cf875d69c6b899f113fc3aef92c964ad7 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Mon, 17 Mar 2025 22:28:02 +0700 Subject: [PATCH 103/154] Rearrange icons in quickmove --- .../textures/gui/widgets/storage_controls.png | Bin 1371 -> 1303 bytes .../textures/gui/widgets/storage_controls.xcf | Bin 15956 -> 16168 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/storage_controls.png b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/storage_controls.png index 054f10becee5be6977e92b4c905e07d6cb286bcb..d46201f5e4b8bb78105dec2c9e8c3a39eb5432a1 100644 GIT binary patch delta 847 zcmV-V1F-zt3YQA7x&aCQ0RI60puMM)lfwZae-9fayY%uP0009NNkl(>{z+s$g23{CA_WQ7od zf3?=G2Nb)`5wo;e%iVqE1tM~`JlDQNW47(7@+j>%vbf{(Big%VFk7vpXmn27C9{mu zo@F|yUPkTdx0TN&C^lQF_n9+wsGXrsL8?tn*;fupsdf^QB|Q1j%ml|&NQk4zl$Z{3 zz=Gg}Hsi#mW3k&DqO}4a1S|jm00000e?S9Yn&QsFy@MY;8PO#bj*<$AH1AwXPS+Z} zgx2eP0EhTgvOh&!>VFhDrAn29r;?>jJ|#W5PGiQ%;^d)oaySX1L)z$6lAlWiM^0&_ z28*GxTgQ0;RTsk}k(e@n+cv4$;P>coth}#f1GifaG~`gLEKRm5%o+hwfA^qJe|NDK zyLSN3ej@}200000ZU3>AoKfMZu8bB*rMd0W7uV{AI}RbO$?m})RwX(X^QVp?NF%9{ z$(HQ+cbw2tGZ8d;q^F|M54WF!Z2iUX2)4MFzPh7K&7s{pE%Pt}*|klX8+`zy^wCKj zc}~UQ(Lh>9jC(1fV)NE;=ehnEa_?45!Va=007`1$oa=q|5-~; zE&sjv3`HW)moBvLnCY9s2=Aee{g+@m-x(3=pi{(F=hTWlqZ|ML0AK*rszl6|E7|=F%UaeCl++tt%lz60Py!D1`SwIU5_@TSa4ZJlwY1TmJX3ME92eg+@c8q0vLScR&T85&-}} Z8h?d1Z`G{4zsmps002ovPDHLkV1gfOq=*0j delta 915 zcmV;E18n@43fl^>x&a9Q00000`9r&ZlfwZae*_UG)JLT8000A6Nkli%y&tj@``fc%>Df8Ifu_w8wo-Q8_Qmu0v>GWxGkRBB zf8KjTS5vg3B8lMv}`|(tJlyMwe-0O2A=DYP`_EAZR=v1^z zW*KEXD|Jv+M(OFdx6dUgG+T=M%$Yh=XQ)$l|xc&oP=ZvPj0j{!ATVo;wUyH zse@dwpg5t;IC1J&^EQWQt-=Qd3jhEBe*gdg&_GL5h z9nouPz1`=QbO^zy@wF0ERfA2t{ z?qV&LcK|PcqXY*40001O{n*ORs92~{MvJ7}z3to|uGJ5|a0qElb`N@3mFQ5-AG;Mn zT1kyew&cYB!YM5^H-bj5^i(4H@c1dn)?W-~$i=<*y38^)hn9C*>0t!2OQ*7B^a~ip z$3-gSIUR?i3u#?3)(V7b=Q?_fe{88wl5uY4>aV9CewbF4^lsS^*9-sv0HE?3Q@Zp{ zJ$H$^IK5u4po+O(ueOAL+Wt7IBOJ$4&%%&CE939)pXS$(4`YlmpWlDX<^Il=o;hcs zIsQ0_lc`GYXiVz!BV6up^JV^D%tcY(OUdT=mpVpqP1?kDH%bd`r|^XqKAl%-NPL#d^jnjMB$VAe)a*HYMU^LlTsy5Qfc_t zy$njpOz!8UW#ZY7BLe^cearyzCVs6>#H?^styrrQaXO+~bs|nj^wBOJmuy5dv%?a4 z&XR=s`HWbbAQ$$$SigOo|9Crn#IQ%PuOo?BPGmf4=!<=J(CK>ABr| zgP%$wZ~MWP6=AOQ#IDTRGM&86VBoowlTvtV?H!x4>L9l%!{V`4CY77b}?rA zRWIpt=NuXy9UbPK2Exp6bkcS@U5FdD!2khQH&+oYJ~t~urN7KQWm}9{bIE5V64oF2 zoX+{=8)Iy2_I!oa)0+|zJoEpPl#>^p#aZ_} zCWvvGD$1}qPp0wwlUZ_hXktAA*@CQRCex%`<-DMZ^+-SqaX#A|)W09l-1zgQXE|TS zZ&fhv%fom`S3%&dtb)KeZ3y%MWS!AY)^%9}S%aw>h@uQxbsU_{|EUrb%Gr+^T;0sY z@05!V^ho03j?R_#-(e@k6`js(*|xZLs`#DEiPB=$boopY5;8l$vcwfQ^+8j$nfYU+FA4%Fw;hfDUFgE+EUyPQ1(hY zWgnzd?xMwIj{qv4Xs2>SINr)nsf=w^M@W0sVe!%Ss(l!$Z|K3*A}$QoZ|JvJKH!hq zsPV~JY9gswZm#)3x72LMV4c*1tZOpbx<_Bv9>7o^)J}bsbm}+LgLOf`ak8T>SH7q5 uZee)ims9h0#COrmxEJsj9o!&JCJYTFbnE&_42?zFX>68G<8IQE82JgvESy3B delta 1412 zcmds!O=uHA6vy|yeAqN!jg3vSX-v{an>L9FZIZS&$w`nZXv9JV5fu*#77@LcdQd9Z zOLaU|5b=Z7iWZy%tvJX|PIdtVne}m)dksYV(*>UqY&XPHNi&so|K^4x_#|D9^DkQsW<` z?pu%_wX)?QL^}y)g$9zkWhRh>AXK zyQWA(2tv$f>3}#tX-NT$urnqVtykH*WD8m+dD%LPkRfO*)uG*XK}MqJHxSmXZtz6og|BQhAiGP zpWHQS!qz0w)*+&;XL-_p4pG&Js-KCfHLe9_5QC412FrD73oaW0^P{1|z)GPfd^&s{ zFw#e^$Z>K-E*dVD?il9_?S~Mfc``&#(D3MGp5HT%5GUAqkYML&9*<2UcC8WZ_7Uw) z@wM(3h>0rEq*@L z7rxFG*h032uV)(pbH%y|a_rcE*P=UeS9q~+Cu08uHTOTH=KlGO=1&7pd2at4K$z-- Zd3xpGFc0TzfQ1s#!YI+g4OS|yd Date: Mon, 17 Mar 2025 23:15:54 +0700 Subject: [PATCH 104/154] Change quickmove slot priority to consider hotbar slots last, to match vanilla behavior --- src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 0c3179bd0..37131c37e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt @@ -176,7 +176,7 @@ abstract class MatteryMenu( fun intInput(allowSpectators: Boolean = false, handler: (Int) -> Unit) = PlayerInput(StreamCodecs.INT, allowSpectators, handler) /** - * hotbar + inventory + Exopack (in this order) + * inventory + Exopack + hotbar (in this order) */ val playerInventorySlots: List = Collections.unmodifiableList(_playerInventorySlots) @@ -282,7 +282,7 @@ abstract class MatteryMenu( val slot = InventorySlot(mattery.combinedInventory, i) - _playerInventorySlots.add(slot) + // _playerInventorySlots.add(slot) if (i <= 8) _playerHotbarSlots.add(slot) @@ -294,6 +294,9 @@ abstract class MatteryMenu( addSlot(slot) } + _playerInventorySlots.addAll(_playerCombinedInventorySlots) + _playerInventorySlots.addAll(_playerHotbarSlots) + if (mattery.hasExopack) { _exopackChargeSlots.add(BatteryMenuSlot(mattery.exopackEnergy.parent, 0, direction = FlowDirection.OUTPUT).also { mapQuickMoveToExternal(it); mapQuickMoveToInventory(it); addSlot(it) }) From ef2602895b17e2dac0685262682502de2eed9b69 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Tue, 18 Mar 2025 18:41:09 +0700 Subject: [PATCH 105/154] Declare VanillaMenuTypes#register as internal --- .../ru/dbotthepony/mc/otm/compat/vanilla/VanillaMenuTypes.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaMenuTypes.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaMenuTypes.kt index 8e7c52865..d4b068d73 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaMenuTypes.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaMenuTypes.kt @@ -22,7 +22,7 @@ object VanillaMenuTypes { val SHULKER_BOX by registrar.register("shulker_box") { MenuType(::MatteryShulkerBoxMenu, FeatureFlags.VANILLA_SET) } - fun register(bus: IEventBus) { + internal fun register(bus: IEventBus) { registrar.register(bus) bus.addListener(this::registerScreens) } From c9dca768706118ecaf60408a1d75e38b47743923 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Tue, 18 Mar 2025 18:55:55 +0700 Subject: [PATCH 106/154] Provide Unit (singleton) codecs --- .../ru/dbotthepony/mc/otm/network/MatteryStreamCodec.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryStreamCodec.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryStreamCodec.kt index aff3394b6..a217ec302 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryStreamCodec.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryStreamCodec.kt @@ -35,6 +35,14 @@ interface MatteryStreamCodec : StreamCodec<@UnsafeVariance S, } } + class MUnit(val value: V) : MatteryStreamCodec { + override fun decode(stream: ByteBuf): V { + return value + } + + override fun encode(stream: ByteBuf, value: V) {} + } + abstract class AbstractPair(private val first: MatteryStreamCodec, private val second: MatteryStreamCodec) : MatteryStreamCodec { protected abstract fun getFirst(value: P): A protected abstract fun getSecond(value: P): B From f7a4623830d50c912bde5be161feebfabc9165b9 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Tue, 18 Mar 2025 18:56:23 +0700 Subject: [PATCH 107/154] Provide convenient unit packet registration --- .../kotlin/ru/dbotthepony/mc/otm/network/Ext.kt | 12 ++++++++++++ .../mc/otm/network/MatteryPlayerPackets.kt | 13 ------------- .../ru/dbotthepony/mc/otm/network/NetworkPackets.kt | 12 ++++++------ 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/Ext.kt index b9d4f2bad..fe32ada33 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/Ext.kt @@ -28,6 +28,18 @@ fun PayloadRegistrar.playToServer( handler: KFunction1 ): PayloadRegistrar = playToServer(type, codec) { _, context -> handler(context) } +fun PayloadRegistrar.playToClient( + type: CustomPacketPayload.Type, + value: T, + handler: KFunction1 +): PayloadRegistrar = playToClient(type, MatteryStreamCodec.MUnit(value)) { _, context -> handler(context) } + +fun PayloadRegistrar.playToServer( + type: CustomPacketPayload.Type, + value: T, + handler: KFunction1 +): PayloadRegistrar = playToServer(type, MatteryStreamCodec.MUnit(value)) { _, context -> handler(context) } + inline fun encodePayload(registry: RegistryAccess, block: (RegistryFriendlyByteBuf) -> Unit): ByteArrayList { val underlying = ByteBufAllocator.DEFAULT.buffer() val buf = RegistryFriendlyByteBuf(underlying, registry, ConnectionType.NEOFORGE) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt index 72b92aaf2..29bf837a9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt @@ -245,9 +245,6 @@ object ExopackMenuOpen : CustomPacketPayload { "exopack_menu_open" ) ) - - val CODEC: StreamCodec = - StreamCodec.ofMember({ _, _ -> }, { ExopackMenuOpen }) } class PickItemFromInventoryPacket( @@ -347,8 +344,6 @@ object DisplayExopackPacket : CustomPacketPayload { "display_exopack" ) ) - val CODEC: StreamCodec = - StreamCodec.ofMember({ _, _ -> }, { DisplayExopackPacket }) } object HideExopackPacket : CustomPacketPayload { @@ -366,8 +361,6 @@ object HideExopackPacket : CustomPacketPayload { "hide_exopack" ) ) - val CODEC: StreamCodec = - StreamCodec.ofMember({ _, _ -> }, { HideExopackPacket }) } object EnableExopackGlowPacket : CustomPacketPayload { @@ -385,8 +378,6 @@ object EnableExopackGlowPacket : CustomPacketPayload { "enable_exopack_glow" ) ) - val CODEC: StreamCodec = - StreamCodec.ofMember({ _, _ -> }, { EnableExopackGlowPacket }) } object DisableExopackGlowPacket : CustomPacketPayload { @@ -404,8 +395,6 @@ object DisableExopackGlowPacket : CustomPacketPayload { "disable_exopack_glow" ) ) - val CODEC: StreamCodec = - StreamCodec.ofMember({ _, _ -> }, { DisableExopackGlowPacket }) } object ResetExopackColorPacket : CustomPacketPayload { @@ -423,8 +412,6 @@ object ResetExopackColorPacket : CustomPacketPayload { "reset_exopack_color" ) ) - val CODEC: StreamCodec = - StreamCodec.ofMember({ _, _ -> }, { ResetExopackColorPacket }) } class ExopackSmokePacket(val player: UUID) : CustomPacketPayload { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/NetworkPackets.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/NetworkPackets.kt index b97728212..07d715fc8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/NetworkPackets.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/NetworkPackets.kt @@ -44,15 +44,15 @@ internal fun registerNetworkPackets(event: RegisterPayloadHandlersEvent) { .playToClient(ExopackSlotPacket.TYPE, ExopackSlotPacket.CODEC, ExopackSlotPacket::play) .playToClient(ExopackMenuInitPacket.TYPE, ExopackMenuInitPacket.CODEC, ExopackMenuInitPacket::play) .playToClient(ExopackSmokePacket.TYPE, ExopackSmokePacket.CODEC, ExopackSmokePacket::play) - .playToServer(ExopackMenuOpen.TYPE, ExopackMenuOpen.CODEC, ExopackMenuOpen::play) + .playToServer(ExopackMenuOpen.TYPE, ExopackMenuOpen, ExopackMenuOpen::play) .playToServer(PickItemFromInventoryPacket.TYPE, PickItemFromInventoryPacket.CODEC, PickItemFromInventoryPacket::play) - .playToServer(DisplayExopackPacket.TYPE, DisplayExopackPacket.CODEC, DisplayExopackPacket::play) - .playToServer(HideExopackPacket.TYPE, HideExopackPacket.CODEC, HideExopackPacket::play) - .playToServer(EnableExopackGlowPacket.TYPE, EnableExopackGlowPacket.CODEC, EnableExopackGlowPacket::play) - .playToServer(DisableExopackGlowPacket.TYPE, DisableExopackGlowPacket.CODEC, DisableExopackGlowPacket::play) - .playToServer(ResetExopackColorPacket.TYPE, ResetExopackColorPacket.CODEC, ResetExopackColorPacket::play) + .playToServer(DisplayExopackPacket.TYPE, DisplayExopackPacket, DisplayExopackPacket::play) + .playToServer(HideExopackPacket.TYPE, HideExopackPacket, HideExopackPacket::play) + .playToServer(EnableExopackGlowPacket.TYPE, EnableExopackGlowPacket, EnableExopackGlowPacket::play) + .playToServer(DisableExopackGlowPacket.TYPE, DisableExopackGlowPacket, DisableExopackGlowPacket::play) + .playToServer(ResetExopackColorPacket.TYPE, ResetExopackColorPacket, ResetExopackColorPacket::play) .playToServer(SetExopackColorPacket.TYPE, SetExopackColorPacket.CODEC, SetExopackColorPacket::play) // otm player general From d6f53946d948079aebf837ceb075299bb510609c Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Tue, 18 Mar 2025 22:37:44 +0700 Subject: [PATCH 108/154] "Quick stack to nearby chests" prototype --- .../mc/otm/capability/MatteryCapability.java | 5 +- .../decorative/CargoCrateBlockEntity.kt | 8 ++ .../mc/otm/capability/IQuickStackContainer.kt | 14 +++ .../client/screen/ExopackInventoryScreen.kt | 14 +++ .../client/screen/panels/button/Buttons.kt | 3 +- .../mc/otm/compat/vanilla/VanillaMenuTypes.kt | 30 ++++++ .../kotlin/ru/dbotthepony/mc/otm/core/Ext.kt | 5 + .../mc/otm/core/math/EuclidMath.kt | 8 ++ .../ru/dbotthepony/mc/otm/entity/Ext.kt | 6 ++ .../ru/dbotthepony/mc/otm/menu/MatteryMenu.kt | 8 +- .../mc/otm/network/MatteryPlayerPackets.kt | 94 +++++++++++++++++++ .../mc/otm/network/NetworkPackets.kt | 3 +- 12 files changed, 189 insertions(+), 9 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/capability/IQuickStackContainer.kt diff --git a/src/main/java/ru/dbotthepony/mc/otm/capability/MatteryCapability.java b/src/main/java/ru/dbotthepony/mc/otm/capability/MatteryCapability.java index 6f30afc7e..77b2c9f5e 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/capability/MatteryCapability.java +++ b/src/main/java/ru/dbotthepony/mc/otm/capability/MatteryCapability.java @@ -15,7 +15,6 @@ import ru.dbotthepony.mc.otm.capability.matter.IReplicationTaskProvider; import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage; import ru.dbotthepony.mc.otm.graph.matter.MatterNode; import ru.dbotthepony.mc.otm.graph.storage.StorageNode; -import ru.dbotthepony.mc.otm.storage.StorageStack; import javax.annotation.Nonnull; @@ -70,4 +69,8 @@ public class MatteryCapability { @Nonnull @NotNull public static final ItemCapability UPGRADE = ItemCapability.createVoid(ResourceLocation.fromNamespaceAndPath(OverdriveThatMatters.MOD_ID, "machine_upgrade"), IMatteryUpgrade.class); + + @Nonnull + @NotNull + public static final BlockCapability QUICK_STACK_CONTAINER = BlockCapability.createVoid(ResourceLocation.fromNamespaceAndPath(OverdriveThatMatters.MOD_ID, "quick_stack_container"), IQuickStackContainer.class); } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt index 4530adaef..020a1d5b5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/decorative/CargoCrateBlockEntity.kt @@ -29,11 +29,15 @@ import net.minecraft.world.phys.Vec3 import net.neoforged.neoforge.capabilities.Capabilities import ru.dbotthepony.mc.otm.block.decorative.CargoCrateBlock import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity +import ru.dbotthepony.mc.otm.capability.IQuickStackContainer +import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.otmRandom +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot import ru.dbotthepony.mc.otm.menu.decorative.CargoCrateMenu +import ru.dbotthepony.mc.otm.menu.makeSlots import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import ru.dbotthepony.mc.otm.registry.game.MSoundEvents @@ -57,6 +61,10 @@ class CargoCrateBlockEntity( .build() .also(::addDroppableContainer) + init { + exposeSideless(MatteryCapability.QUICK_STACK_CONTAINER, IQuickStackContainer.Simple(makeSlots(container, ::MatteryMenuSlot))) + } + private var interactingPlayers = 0 override fun beforeDroppingItems(oldBlockState: BlockState, level: Level, blockPos: BlockPos, newBlockState: BlockState, movedByPiston: Boolean) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/IQuickStackContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/IQuickStackContainer.kt new file mode 100644 index 000000000..cbf7209cc --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/IQuickStackContainer.kt @@ -0,0 +1,14 @@ +package ru.dbotthepony.mc.otm.capability + +import net.minecraft.server.level.ServerPlayer +import net.minecraft.world.inventory.Slot + +interface IQuickStackContainer { + fun getSlotsFor(player: ServerPlayer): Collection + + class Simple(private val slots: Collection) : IQuickStackContainer { + override fun getSlotsFor(player: ServerPlayer): Collection { + return slots + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt index d02636fa7..c6816f8e6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt @@ -25,8 +25,11 @@ import ru.dbotthepony.mc.otm.client.setMousePos import ru.dbotthepony.mc.otm.client.shouldOpenVanillaInventory import ru.dbotthepony.mc.otm.core.math.integerDivisionDown import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu +import ru.dbotthepony.mc.otm.menu.QuickMoveInput import ru.dbotthepony.mc.otm.network.ExopackMenuOpen +import ru.dbotthepony.mc.otm.network.QuickStackPacket import yalter.mousetweaks.api.MouseTweaksDisableWheelTweak +import java.util.function.IntConsumer @MouseTweaksDisableWheelTweak class ExopackInventoryScreen(menu: ExopackInventoryMenu) : MatteryScreen(menu, TranslatableComponent("otm.gui.exopack")) { @@ -283,6 +286,17 @@ class ExopackInventoryScreen(menu: ExopackInventoryMenu) : MatteryScreen>( return result } - private abstract inner class FoldableButtonPanel() : ButtonPanel(screen, this@DeviceControls, width = 18f, height = 18f) { + abstract inner class FoldableButtonPanel() : ButtonPanel(screen, this@DeviceControls, width = 18f, height = 18f) { init { addButton(this) } private var buttons: List>? = null - fun makeButtons() { if (buttons == null) { buttons = doMakeButtons().also { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaMenuTypes.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaMenuTypes.kt index d4b068d73..fbca57f62 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaMenuTypes.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaMenuTypes.kt @@ -1,11 +1,24 @@ package ru.dbotthepony.mc.otm.compat.vanilla +import net.minecraft.core.BlockPos import net.minecraft.core.registries.Registries +import net.minecraft.world.Container import net.minecraft.world.flag.FeatureFlags import net.minecraft.world.inventory.MenuType +import net.minecraft.world.level.Level +import net.minecraft.world.level.block.Blocks +import net.minecraft.world.level.block.entity.BlockEntity +import net.minecraft.world.level.block.entity.ChestBlockEntity +import net.minecraft.world.level.block.state.BlockState import net.neoforged.bus.api.IEventBus +import net.neoforged.neoforge.capabilities.IBlockCapabilityProvider +import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.capability.IQuickStackContainer +import ru.dbotthepony.mc.otm.capability.MatteryCapability +import ru.dbotthepony.mc.otm.menu.MatteryMenuSlot +import ru.dbotthepony.mc.otm.menu.makeSlots import ru.dbotthepony.mc.otm.registry.MDeferredRegister object VanillaMenuTypes { @@ -22,9 +35,26 @@ object VanillaMenuTypes { val SHULKER_BOX by registrar.register("shulker_box") { MenuType(::MatteryShulkerBoxMenu, FeatureFlags.VANILLA_SET) } + private fun provider(level: Level, pos: BlockPos, state: BlockState, blockEntity: BlockEntity?, context: Void?): IQuickStackContainer? { + val container = blockEntity as? Container ?: return null + return IQuickStackContainer.Simple(makeSlots(container, ::MatteryMenuSlot)) + } + + fun registerCapabilities(event: RegisterCapabilitiesEvent) { + event.registerBlock( + MatteryCapability.QUICK_STACK_CONTAINER, + ::provider, + Blocks.CHEST, + Blocks.TRAPPED_CHEST, + Blocks.SHULKER_BOX, + Blocks.BARREL, + ) + } + internal fun register(bus: IEventBus) { registrar.register(bus) bus.addListener(this::registerScreens) + bus.addListener(this::registerCapabilities) } private fun registerScreens(event: RegisterMenuScreensEvent) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt index 90966e14e..1c33b2955 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt @@ -72,6 +72,7 @@ import java.util.random.RandomGenerator import java.util.stream.Stream import java.util.stream.StreamSupport import kotlin.NoSuchElementException +import kotlin.enums.EnumEntries import kotlin.jvm.optionals.getOrNull import kotlin.math.ln import kotlin.math.sqrt @@ -301,6 +302,10 @@ fun OutputStream.writeItemType(value: Item) { writeVarIntLE(BuiltInRegistries.ITEM.getId(value)) } +fun > FriendlyByteBuf.readEnum(entries: EnumEntries): E { + return entries[readVarInt()] +} + fun FriendlyByteBuf.readType(registry: IdMap): T { val id = readInt() return registry.byId(id) ?: throw NoSuchElementException("No such entry with ID $id") diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/EuclidMath.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/EuclidMath.kt index 77d910401..574709d69 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/EuclidMath.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/EuclidMath.kt @@ -435,6 +435,14 @@ operator fun Vec3i.times(int: Int): Vec3i = this.multiply(int) operator fun Direction.times(int: Int): Vec3i = this.normal.multiply(int) operator fun Vec3i.times(double: Double): Vector = Vector(x * double, y * double, z * double) +operator fun Vector.plus(direction: Vec3i): Vector = Vector(x + direction.x, y + direction.y, z + direction.z) +operator fun Vector.plus(direction: Direction): Vector = plus(direction.normal) +operator fun Vector.minus(direction: Vec3i): Vector = Vector(x - direction.x, y - direction.y, z - direction.z) +operator fun Vector.minus(direction: Direction): Vector = minus(direction.normal) + +operator fun Vec3i.plus(direction: Vector): Vector = Vector(x + direction.x, y + direction.y, z + direction.z) +operator fun Vec3i.minus(direction: Vector): Vector = Vector(x - direction.x, y - direction.y, z - direction.z) + fun Vec3.toIntVector() = Vec3i(x.toInt(), y.toInt(), z.toInt()) fun Vec3.roundToIntVector() = Vec3i(x.roundToInt(), y.roundToInt(), z.roundToInt()) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/Ext.kt index f9ec9cdbf..3071cfeaf 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/Ext.kt @@ -1,8 +1,10 @@ package ru.dbotthepony.mc.otm.entity +import net.minecraft.core.BlockPos import net.minecraft.network.syncher.EntityDataAccessor import net.minecraft.network.syncher.SynchedEntityData import net.minecraft.world.entity.Entity +import net.minecraft.world.entity.player.Player import kotlin.properties.ReadWriteProperty import kotlin.reflect.KProperty @@ -17,3 +19,7 @@ class SynchedEntityDataDelegate(private val type: EntityDataAccessor, priv } fun SynchedEntityData.delegate(type: EntityDataAccessor) = SynchedEntityDataDelegate(type, this) + +fun Player.checkCanInteract(pos: BlockPos): Boolean { + return mayInteract(level(), pos) && canInteractWithBlock(pos, 1.0) +} 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 37131c37e..64051b166 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt @@ -42,6 +42,7 @@ import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull import ru.dbotthepony.mc.otm.core.ResourceLocation import ru.dbotthepony.mc.otm.core.collect.ConditionalSet import ru.dbotthepony.mc.otm.core.math.Decimal +import ru.dbotthepony.mc.otm.entity.checkCanInteract import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.network.MatteryStreamCodec @@ -346,13 +347,10 @@ abstract class MatteryMenu( override fun stillValid(player: Player): Boolean { if (tile == null) return true - if (player.level().getBlockEntity(tile.blockPos) !== tile) { + if (player.level().getBlockEntity(tile.blockPos) !== tile) return false - } - val pos = tile.blockPos - - return player.distanceToSqr(pos.x.toDouble() + 0.5, pos.y.toDouble() + 0.5, pos.z.toDouble() + 0.5) <= 64.0 + return player.checkCanInteract(tile.blockPos) } fun syncCarried() { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt index 29bf837a9..c1ff400fc 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt @@ -1,6 +1,7 @@ package ru.dbotthepony.mc.otm.network import it.unimi.dsi.fastutil.bytes.ByteArrayList +import net.minecraft.core.BlockPos import net.minecraft.core.particles.ParticleTypes import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.RegistryFriendlyByteBuf @@ -8,28 +9,47 @@ import net.minecraft.network.codec.StreamCodec import net.minecraft.network.protocol.common.custom.CustomPacketPayload import net.minecraft.network.protocol.game.ClientboundSetCarriedItemPacket import net.minecraft.server.level.ServerPlayer +import net.minecraft.world.entity.ai.attributes.Attributes import net.minecraft.world.entity.player.Inventory +import net.minecraft.world.inventory.Slot import net.minecraft.world.item.ItemStack +import net.minecraft.world.level.ChunkPos +import net.minecraft.world.level.ClipBlockStateContext +import net.minecraft.world.level.block.entity.BlockEntity +import net.minecraft.world.level.block.state.BlockState +import net.minecraft.world.phys.Vec3 +import net.neoforged.neoforge.common.NeoForgeMod import net.neoforged.neoforge.network.handling.IPayloadContext import org.apache.logging.log4j.LogManager import ru.dbotthepony.kommons.math.RGBAColor import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.capability.IQuickStackContainer +import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.player.MatteryPlayer import ru.dbotthepony.mc.otm.player.matteryPlayer import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.container.get import ru.dbotthepony.mc.otm.container.set import ru.dbotthepony.mc.otm.core.ResourceLocation +import ru.dbotthepony.mc.otm.core.getChunkNow +import ru.dbotthepony.mc.otm.core.math.Vector import ru.dbotthepony.mc.otm.core.math.component1 import ru.dbotthepony.mc.otm.core.math.component2 import ru.dbotthepony.mc.otm.core.math.component3 +import ru.dbotthepony.mc.otm.core.math.minus +import ru.dbotthepony.mc.otm.core.math.plus import ru.dbotthepony.mc.otm.core.math.toRadians import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.core.position +import ru.dbotthepony.mc.otm.core.readEnum import ru.dbotthepony.mc.otm.core.readItem import ru.dbotthepony.mc.otm.core.writeItem +import ru.dbotthepony.mc.otm.entity.checkCanInteract import ru.dbotthepony.mc.otm.menu.ExopackInventoryMenu +import ru.dbotthepony.mc.otm.menu.QuickMoveInput import java.util.* +import kotlin.collections.ArrayList +import kotlin.collections.HashSet class MatteryPlayerDataPacket(val bytes: ByteArrayList, val isPublic: Boolean, val target: UUID? = null) : CustomPacketPayload { fun write(buff: FriendlyByteBuf) { @@ -414,6 +434,80 @@ object ResetExopackColorPacket : CustomPacketPayload { ) } +// as separate packet so it can be put into non-mattery menus +class QuickStackPacket( + val mode: QuickMoveInput.Mode, + val fromExopack: Boolean +) : CustomPacketPayload { + fun play(context: IPayloadContext) { + val player = context.player() as ServerPlayer + if (player.isSpectator) return + val radius = player.blockInteractionRange() + + val minChunkPos = ChunkPos(BlockPos.containing(player.position - Vector(radius, 0.0, radius))) + val maxChunkPos = ChunkPos(BlockPos.containing(player.position + Vector(radius, 0.0, radius))) + + val findCaps = ArrayList>() + + for (x in minChunkPos.x .. maxChunkPos.x) { + for (z in minChunkPos.z .. maxChunkPos.z) { + val chunk = player.serverLevel().chunkSource.getChunkNow(x, z) ?: continue + + for (blockEntity in chunk.blockEntities.values) { + if (player.checkCanInteract(blockEntity.blockPos)) { + val cap = player.level().getCapability(MatteryCapability.QUICK_STACK_CONTAINER, blockEntity.blockPos) ?: continue + findCaps.add(blockEntity to cap) + } + } + } + } + + if (findCaps.isEmpty()) return + + val eyes = player.eyePosition + val ignoreBlockstates = HashSet() + findCaps.forEach { (b, _) -> ignoreBlockstates.add(b.blockState) } + + val slots = ArrayList() + + for ((blockEntity, cap) in findCaps) { + // don't interact through walls + val trace = player.serverLevel().isBlockInLine(ClipBlockStateContext(eyes, Vector.atCenterOf(blockEntity.blockPos)) { + !it.isAir && it !in ignoreBlockstates + }) + + if (trace.blockPos == blockEntity.blockPos) { + slots.addAll(cap.getSlotsFor(player)) + } + } + + if (slots.isEmpty()) return + + if (fromExopack) + mode.move(player.matteryPlayer.exoPackMenu.playerCombinedInventorySlots, slots, player) + else + mode.move(slots, player.matteryPlayer.exoPackMenu.playerInventorySlots, player) + } + + override fun type(): CustomPacketPayload.Type { + return TYPE + } + + fun write(buff: FriendlyByteBuf) { + buff.writeEnum(mode) + buff.writeBoolean(fromExopack) + } + + companion object { + val TYPE = CustomPacketPayload.Type(ResourceLocation(OverdriveThatMatters.MOD_ID, "quick_stack")) + val CODEC: StreamCodec = StreamCodec.ofMember(QuickStackPacket::write, ::read) + + fun read(buff: FriendlyByteBuf): QuickStackPacket { + return QuickStackPacket(buff.readEnum(QuickMoveInput.Mode.entries), buff.readBoolean()) + } + } +} + class ExopackSmokePacket(val player: UUID) : CustomPacketPayload { fun write(buff: FriendlyByteBuf) { buff.writeUUID(player) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/NetworkPackets.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/NetworkPackets.kt index 07d715fc8..d23aad15e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/NetworkPackets.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/NetworkPackets.kt @@ -20,7 +20,7 @@ import ru.dbotthepony.mc.otm.menu.matter.ReplicationRequestPacket import ru.dbotthepony.mc.otm.menu.matter.TasksChangePacket internal fun registerNetworkPackets(event: RegisterPayloadHandlersEvent) { - val r = event.registrar("1.5.0") + val r = event.registrar("1.5.1") // world r @@ -54,6 +54,7 @@ internal fun registerNetworkPackets(event: RegisterPayloadHandlersEvent) { .playToServer(DisableExopackGlowPacket.TYPE, DisableExopackGlowPacket, DisableExopackGlowPacket::play) .playToServer(ResetExopackColorPacket.TYPE, ResetExopackColorPacket, ResetExopackColorPacket::play) .playToServer(SetExopackColorPacket.TYPE, SetExopackColorPacket.CODEC, SetExopackColorPacket::play) + .playToServer(QuickStackPacket.TYPE, QuickStackPacket.CODEC, QuickStackPacket::play) // otm player general r From 06a621d3700f020bb29005dfdd4640ca392356ea Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Tue, 18 Mar 2025 22:47:26 +0700 Subject: [PATCH 109/154] Prioritize chests closer to player first --- .../ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt index c1ff400fc..697e01acb 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt @@ -464,6 +464,8 @@ class QuickStackPacket( if (findCaps.isEmpty()) return + findCaps.sortBy { it.first.blockPos.distToCenterSqr(player.position) } + val eyes = player.eyePosition val ignoreBlockstates = HashSet() findCaps.forEach { (b, _) -> ignoreBlockstates.add(b.blockState) } From 36f6a123953780a99900689a048c18c64c6260d5 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Tue, 18 Mar 2025 22:55:17 +0700 Subject: [PATCH 110/154] Fix quick move to nearby chests treating every chest equally and possibly creating situation where items of one type of one of chests go into empty slots of different (unrelated) chest(s) --- .../ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt | 3 +++ .../mc/otm/network/MatteryPlayerPackets.kt | 14 ++++---------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt index f57aaa260..2f9ed9df4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt @@ -22,6 +22,7 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, Widgets18.RESTOCK_TO_STORAGE ) { override fun move(from: Collection, to: Collection, player: Player) { + if (from.isEmpty() || to.isEmpty()) return val (_, itemsFrom) = computeSlotLists(from, true) val (_, itemsTo) = computeSlotLists(to, false) @@ -39,6 +40,7 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, Widgets18.RESTOCK_WITH_MOVE_TO_STORAGE ) { override fun move(from: Collection, to: Collection, player: Player) { + if (from.isEmpty() || to.isEmpty()) return val (_, itemsFrom) = computeSlotLists(from, true) val (emptyTo, itemsTo) = computeSlotLists(to, false) @@ -60,6 +62,7 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, Widgets18.MOVE_EVERYTHING_TO_STORAGE ) { override fun move(from: Collection, to: Collection, player: Player) { + if (from.isEmpty() || to.isEmpty()) return val toSorted = prioritySortSlots(to) from.forEach { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt index 697e01acb..6eb691ae9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt @@ -470,8 +470,6 @@ class QuickStackPacket( val ignoreBlockstates = HashSet() findCaps.forEach { (b, _) -> ignoreBlockstates.add(b.blockState) } - val slots = ArrayList() - for ((blockEntity, cap) in findCaps) { // don't interact through walls val trace = player.serverLevel().isBlockInLine(ClipBlockStateContext(eyes, Vector.atCenterOf(blockEntity.blockPos)) { @@ -479,16 +477,12 @@ class QuickStackPacket( }) if (trace.blockPos == blockEntity.blockPos) { - slots.addAll(cap.getSlotsFor(player)) + if (fromExopack) + mode.move(player.matteryPlayer.exoPackMenu.playerCombinedInventorySlots, cap.getSlotsFor(player), player) + else + mode.move(cap.getSlotsFor(player), player.matteryPlayer.exoPackMenu.playerInventorySlots, player) } } - - if (slots.isEmpty()) return - - if (fromExopack) - mode.move(player.matteryPlayer.exoPackMenu.playerCombinedInventorySlots, slots, player) - else - mode.move(slots, player.matteryPlayer.exoPackMenu.playerInventorySlots, player) } override fun type(): CustomPacketPayload.Type { From bd4622fc0d7982ce00f03ae5f2971ddf8588b271 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 19 Mar 2025 10:57:24 +0700 Subject: [PATCH 111/154] Ignore slot filters when taking from chests --- .../mc/otm/compat/vanilla/MatteryChestMenu.kt | 2 +- .../compat/vanilla/MatteryShulkerBoxMenu.kt | 2 +- .../dbotthepony/mc/otm/menu/QuickMoveInput.kt | 22 +++++++++---------- .../mc/otm/menu/decorative/CargoCrateMenu.kt | 2 +- .../mc/otm/network/MatteryPlayerPackets.kt | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt index b9f17a670..36c787e4e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryChestMenu.kt @@ -24,7 +24,7 @@ class MatteryChestMenu( } override val quickMoveToStorage = QuickMoveInput.create(this, playerCombinedInventorySlots, containerSlots) - override val quickMoveFromStorage = QuickMoveInput.create(this, containerSlots, playerInventorySlots) + override val quickMoveFromStorage = QuickMoveInput.create(this, containerSlots, playerInventorySlots, false) companion object { @JvmStatic diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryShulkerBoxMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryShulkerBoxMenu.kt index e987c22b6..df242a70a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryShulkerBoxMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/MatteryShulkerBoxMenu.kt @@ -26,7 +26,7 @@ class MatteryShulkerBoxMenu( } override val quickMoveToStorage = QuickMoveInput.create(this, playerCombinedInventorySlots, containerSlots) - override val quickMoveFromStorage = QuickMoveInput.create(this, containerSlots, playerInventorySlots) + override val quickMoveFromStorage = QuickMoveInput.create(this, containerSlots, playerInventorySlots, false) class Slot(container: Container, slot: Int) : MatteryMenuSlot(container, slot) { override fun mayPlace(stack: ItemStack): Boolean { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt index 2f9ed9df4..13d5d8bc8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt @@ -15,15 +15,15 @@ import ru.dbotthepony.mc.otm.core.util.ItemStackKey import ru.dbotthepony.mc.otm.core.util.asKey import ru.dbotthepony.mc.otm.core.util.asKeyOrNull -class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, val to: Collection, val mode: Mode) { +class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, val to: Collection, val mode: Mode, val dontTouchFilteredSlots: Boolean = true) { enum class Mode(val iconFromStorage: AbstractMatterySprite, val iconToStorage: AbstractMatterySprite) { RESTOCK( Widgets18.RESTOCK_FROM_STORAGE, Widgets18.RESTOCK_TO_STORAGE ) { - override fun move(from: Collection, to: Collection, player: Player) { + override fun move(from: Collection, to: Collection, player: Player, dontTouchFilteredSlots: Boolean) { if (from.isEmpty() || to.isEmpty()) return - val (_, itemsFrom) = computeSlotLists(from, true) + val (_, itemsFrom) = computeSlotLists(from, dontTouchFilteredSlots) val (_, itemsTo) = computeSlotLists(to, false) val intersect = if (itemsFrom.size < itemsTo.size) itemsFrom.keys.filter { it in itemsTo.keys } else itemsTo.keys.filter { it in itemsFrom.keys } @@ -39,9 +39,9 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, Widgets18.RESTOCK_WITH_MOVE_FROM_STORAGE, Widgets18.RESTOCK_WITH_MOVE_TO_STORAGE ) { - override fun move(from: Collection, to: Collection, player: Player) { + override fun move(from: Collection, to: Collection, player: Player, dontTouchFilteredSlots: Boolean) { if (from.isEmpty() || to.isEmpty()) return - val (_, itemsFrom) = computeSlotLists(from, true) + val (_, itemsFrom) = computeSlotLists(from, dontTouchFilteredSlots) val (emptyTo, itemsTo) = computeSlotLists(to, false) val intersect = if (itemsFrom.size < itemsTo.size) itemsFrom.keys.filter { it in itemsTo.keys } else itemsTo.keys.filter { it in itemsFrom.keys } @@ -61,20 +61,20 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, Widgets18.MOVE_EVERYTHING_FROM_STORAGE, Widgets18.MOVE_EVERYTHING_TO_STORAGE ) { - override fun move(from: Collection, to: Collection, player: Player) { + override fun move(from: Collection, to: Collection, player: Player, dontTouchFilteredSlots: Boolean) { if (from.isEmpty() || to.isEmpty()) return val toSorted = prioritySortSlots(to) from.forEach { val slot = it.containerSlotOrNull() - if (slot !is IFilteredContainerSlot || !slot.hasFilter) + if (!dontTouchFilteredSlots || slot !is IFilteredContainerSlot || !slot.hasFilter) moveItemStackTo(player, it, toSorted, sort = false) } } }; - abstract fun move(from: Collection, to: Collection, player: Player) + abstract fun move(from: Collection, to: Collection, player: Player, dontTouchFilteredSlots: Boolean = true) val textFromStorage: Component get() { return TranslatableComponent("otm.gui.quickmove_from.${name.lowercase()}") @@ -92,12 +92,12 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, } private fun handle() { - mode.move(from, to, menu.player) + mode.move(from, to, menu.player, dontTouchFilteredSlots) } companion object { - fun create(menu: MatteryMenu, from: Collection, to: Collection): Map { - return Mode.entries.associateWith { QuickMoveInput(menu, from, to, it) } + fun create(menu: MatteryMenu, from: Collection, to: Collection, dontTouchFilteredSlots: Boolean = true): Map { + return Mode.entries.associateWith { QuickMoveInput(menu, from, to, it, dontTouchFilteredSlots) } } private fun computeSlotLists(slots: Collection, skipFilteredSlots: Boolean): Pair, MutableMap>> { 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 5f46a3188..c718af908 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 @@ -22,7 +22,7 @@ class CargoCrateMenu( val sort = SortInput(this, actualContainer, playerSortSettings) val quickMoveToStorage = QuickMoveInput.create(this, playerCombinedInventorySlots, storageSlots) - val quickMoveFromStorage = QuickMoveInput.create(this, storageSlots, playerInventorySlots) + val quickMoveFromStorage = QuickMoveInput.create(this, storageSlots, playerInventorySlots, false) init { if (trackedPlayerOpen) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt index 6eb691ae9..ab82f1c57 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt @@ -480,7 +480,7 @@ class QuickStackPacket( if (fromExopack) mode.move(player.matteryPlayer.exoPackMenu.playerCombinedInventorySlots, cap.getSlotsFor(player), player) else - mode.move(cap.getSlotsFor(player), player.matteryPlayer.exoPackMenu.playerInventorySlots, player) + mode.move(cap.getSlotsFor(player), player.matteryPlayer.exoPackMenu.playerInventorySlots, player, false) } } } From 85c4aa4dc4a9ec180ff343bc90480a8308608607 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 19 Mar 2025 11:29:47 +0700 Subject: [PATCH 112/154] Prioritize non-filtered slots when taking items first --- .../dbotthepony/mc/otm/menu/QuickMoveInput.kt | 82 ++++++++++++------- 1 file changed, 53 insertions(+), 29 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt index 13d5d8bc8..563f9e93c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt @@ -16,6 +16,37 @@ import ru.dbotthepony.mc.otm.core.util.asKey import ru.dbotthepony.mc.otm.core.util.asKeyOrNull class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, val to: Collection, val mode: Mode, val dontTouchFilteredSlots: Boolean = true) { + object HasItemComparator : Comparator { + override fun compare(a: Slot, b: Slot): Int { + val hasItemA = a.item.isNotEmpty + val hasItemB = b.item.isNotEmpty + + if (hasItemA == hasItemB) + return 0 + else if (hasItemA) + return -1 + else + return 1 + } + } + + object HasFilterComparator : Comparator { + override fun compare(a: Slot, b: Slot): Int { + val slotA = a.containerSlotOrNull() + val slotB = b.containerSlotOrNull() + + val hasFilterA = slotA is IFilteredContainerSlot && slotA.hasFilter + val hasFilterB = slotB is IFilteredContainerSlot && slotB.hasFilter + + if (hasFilterA == hasFilterB) + return 0 + else if (hasFilterA) + return -1 + else + return 1 + } + } + enum class Mode(val iconFromStorage: AbstractMatterySprite, val iconToStorage: AbstractMatterySprite) { RESTOCK( Widgets18.RESTOCK_FROM_STORAGE, @@ -30,7 +61,14 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, for (key in intersect) { val slotsTo = itemsTo[key]!! - itemsFrom[key]!!.forEach { moveItemStackTo(player, it, slotsTo) } + val slotsFrom = itemsFrom[key]!! + + if (!dontTouchFilteredSlots) { + // touch filtered slots last + slotsFrom.sortWith(HasFilterComparator.reversed()) + } + + slotsFrom.forEach { moveItemStackTo(player, it, slotsTo) } } } }, @@ -49,6 +87,12 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, for (key in intersect) { val slotsTo = prioritySortSlots(itemsTo[key]!!, key.asItemStack()) val slotsFrom = itemsFrom[key]!! + + if (!dontTouchFilteredSlots) { + // touch filtered slots last + slotsFrom.sortWith(HasFilterComparator.reversed()) + } + slotsFrom.removeIf { moveItemStackTo(player, it, slotsTo, sort = false); it.item.isEmpty } var moveAny = false slotsFrom.forEach { moveAny = moveItemStackTo(player, it, emptyTo, sort = false) || moveAny } @@ -150,40 +194,20 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, return true } - fun prioritySortSlots(slots: Collection, filterItem: ItemStack? = null): MutableList { - val sortedSlots = ArrayList(slots) + private val itemFilterSlotComparator = HasItemComparator.thenComparing(HasFilterComparator) - sortedSlots.removeIf { + fun > prioritySortSlotsInPlace(slots: T, filterItem: ItemStack? = null): T { + slots.removeIf { val slot = it.containerSlotOrNull() it.isOverCapacity || filterItem != null && !it.mayPlace(filterItem) || slot is IFilteredContainerSlot && slot.isForbiddenForAutomation } - sortedSlots.sortWith { a, b -> - val hasItemA = a.item.isNotEmpty - val hasItemB = b.item.isNotEmpty + slots.sortWith(itemFilterSlotComparator) + return slots + } - if (hasItemA && hasItemB) - return@sortWith 0 - else if (hasItemA) - return@sortWith -1 - else if (hasItemB) - return@sortWith 1 - - val slotA = a.containerSlotOrNull() - val slotB = b.containerSlotOrNull() - - val hasFilterA = slotA is IFilteredContainerSlot && slotA.hasFilter - val hasFilterB = slotB is IFilteredContainerSlot && slotB.hasFilter - - if (hasFilterA && hasFilterB || !hasFilterA && !hasFilterB) - return@sortWith 0 - else if (hasFilterA) - return@sortWith -1 - else - return@sortWith 1 - } - - return sortedSlots + fun prioritySortSlots(slots: Collection, filterItem: ItemStack? = null): MutableList { + return prioritySortSlotsInPlace(ArrayList(slots), filterItem) } fun moveItemStackToSlots(item: ItemStack, slots: Collection, simulate: Boolean = false, sort: Boolean = true): ItemStack { From 5b1ae12f8551581cfa5d6098d7363ce401fe85d8 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 19 Mar 2025 16:50:43 +0700 Subject: [PATCH 113/154] Prioritize slots with filter or items across all chests --- .../dbotthepony/mc/otm/menu/QuickMoveInput.kt | 20 +++---- .../mc/otm/network/MatteryPlayerPackets.kt | 53 ++++++++++++------- 2 files changed, 43 insertions(+), 30 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt index 563f9e93c..7deac409c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt @@ -16,20 +16,21 @@ import ru.dbotthepony.mc.otm.core.util.asKey import ru.dbotthepony.mc.otm.core.util.asKeyOrNull class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, val to: Collection, val mode: Mode, val dontTouchFilteredSlots: Boolean = true) { + /** + * slots with items come first + */ object HasItemComparator : Comparator { override fun compare(a: Slot, b: Slot): Int { val hasItemA = a.item.isNotEmpty val hasItemB = b.item.isNotEmpty - if (hasItemA == hasItemB) - return 0 - else if (hasItemA) - return -1 - else - return 1 + return hasItemB.compareTo(hasItemA) } } + /** + * slots with filters come first + */ object HasFilterComparator : Comparator { override fun compare(a: Slot, b: Slot): Int { val slotA = a.containerSlotOrNull() @@ -38,12 +39,7 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, val hasFilterA = slotA is IFilteredContainerSlot && slotA.hasFilter val hasFilterB = slotB is IFilteredContainerSlot && slotB.hasFilter - if (hasFilterA == hasFilterB) - return 0 - else if (hasFilterA) - return -1 - else - return 1 + return hasFilterB.compareTo(hasFilterA) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt index ab82f1c57..bf17ce3bb 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt @@ -9,16 +9,12 @@ import net.minecraft.network.codec.StreamCodec import net.minecraft.network.protocol.common.custom.CustomPacketPayload import net.minecraft.network.protocol.game.ClientboundSetCarriedItemPacket import net.minecraft.server.level.ServerPlayer -import net.minecraft.world.entity.ai.attributes.Attributes import net.minecraft.world.entity.player.Inventory import net.minecraft.world.inventory.Slot import net.minecraft.world.item.ItemStack +import net.minecraft.world.level.BlockGetter import net.minecraft.world.level.ChunkPos -import net.minecraft.world.level.ClipBlockStateContext import net.minecraft.world.level.block.entity.BlockEntity -import net.minecraft.world.level.block.state.BlockState -import net.minecraft.world.phys.Vec3 -import net.neoforged.neoforge.common.NeoForgeMod import net.neoforged.neoforge.network.handling.IPayloadContext import org.apache.logging.log4j.LogManager import ru.dbotthepony.kommons.math.RGBAColor @@ -28,10 +24,11 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.player.MatteryPlayer import ru.dbotthepony.mc.otm.player.matteryPlayer import ru.dbotthepony.mc.otm.client.minecraft +import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot import ru.dbotthepony.mc.otm.container.get import ru.dbotthepony.mc.otm.container.set +import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull import ru.dbotthepony.mc.otm.core.ResourceLocation -import ru.dbotthepony.mc.otm.core.getChunkNow import ru.dbotthepony.mc.otm.core.math.Vector import ru.dbotthepony.mc.otm.core.math.component1 import ru.dbotthepony.mc.otm.core.math.component2 @@ -467,21 +464,41 @@ class QuickStackPacket( findCaps.sortBy { it.first.blockPos.distToCenterSqr(player.position) } val eyes = player.eyePosition - val ignoreBlockstates = HashSet() - findCaps.forEach { (b, _) -> ignoreBlockstates.add(b.blockState) } + val ignorePositions = HashSet() + findCaps.forEach { (b) -> ignorePositions.add(b.blockPos) } + val level = player.serverLevel() - for ((blockEntity, cap) in findCaps) { - // don't interact through walls - val trace = player.serverLevel().isBlockInLine(ClipBlockStateContext(eyes, Vector.atCenterOf(blockEntity.blockPos)) { - !it.isAir && it !in ignoreBlockstates - }) + // don't interact through walls + // but interact through chests + findCaps.removeIf { (b) -> + BlockGetter.traverseBlocks(eyes, Vector.atCenterOf(b.blockPos), null, { _, pos -> if (pos !in ignorePositions && !level.getBlockState(pos).isAir) true else null }, { false }) + } - if (trace.blockPos == blockEntity.blockPos) { - if (fromExopack) - mode.move(player.matteryPlayer.exoPackMenu.playerCombinedInventorySlots, cap.getSlotsFor(player), player) - else - mode.move(cap.getSlotsFor(player), player.matteryPlayer.exoPackMenu.playerInventorySlots, player, false) + if (fromExopack) { + val prioritySlots = ArrayList() + val regularSlots = ArrayList>() + + for ((_, cap) in findCaps) { + val slots = cap.getSlotsFor(player) + + slots.forEach { + val slot = it.containerSlotOrNull() + + if (it.hasItem() || slot is IFilteredContainerSlot && slot.hasFilter) + prioritySlots.add(it) + } + + regularSlots.add(slots) } + + mode.move(player.matteryPlayer.exoPackMenu.playerCombinedInventorySlots, prioritySlots, player) + + regularSlots.forEach { + mode.move(player.matteryPlayer.exoPackMenu.playerCombinedInventorySlots, it, player) + } + } else { + for ((_, cap) in findCaps) + mode.move(cap.getSlotsFor(player), player.matteryPlayer.exoPackMenu.playerInventorySlots, player, false) } } From dcff861e71f782fd0827a805c0ef7a22cbfa5140 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 21 Mar 2025 14:31:59 +0700 Subject: [PATCH 114/154] More quickstack controls --- .../client/screen/ExopackInventoryScreen.kt | 14 +- .../screen/panels/QuickStackControlsPanel.kt | 159 ++++++++++++++++++ 2 files changed, 164 insertions(+), 9 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/QuickStackControlsPanel.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt index c6816f8e6..e199b8e5b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt @@ -286,16 +286,12 @@ class ExopackInventoryScreen(menu: ExopackInventoryMenu) : MatteryScreen( + screen: S, + parent: EditablePanel<*>? = null, +) : EditablePanel(screen, parent, 0f, 0f, 18f, 18f) { + private val grid = GridPanel(screen, this, columns = 1, rows = 1) + private val buttons = ArrayList>() + + init { + grid.dock = Dock.FILL + grid.layout = GridPanel.Layout.TOP_LEFT + } + + private inner class MainButton : ButtonPanel(screen, grid, width = 18f, height = 18f) { + init { + dockMargin = DockProperty.left(1f) + childrenOrder = -100 + tooltips.add(QuickMoveInput.Mode.RESTOCK_WITH_MOVE.textToStorage) + tooltips.add(TextComponent("")) + tooltips.add(TranslatableComponent("otm.gui.quickmove_hint").withStyle(ChatFormatting.GRAY)) + } + + override var isDisabled: Boolean + get() = minecraft.player!!.isSpectator + set(value) {} + + override val icon: IGUIRenderable + get() = Widgets18.RESTOCK_WITH_MOVE_TO_STORAGE + + override fun test(value: Int): Boolean { + return value == InputConstants.MOUSE_BUTTON_LEFT || value == InputConstants.MOUSE_BUTTON_RIGHT + } + + override fun onClick(mouseButton: Int) { + if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) { + PacketDistributor.sendToServer(QuickStackPacket(QuickMoveInput.Mode.RESTOCK_WITH_MOVE, true)) + } else { + buttons.forEach { it.visible = !it.visible } + + if (buttons[0].visible) { + grid.columns = 2 + grid.rows = 3 + } else { + grid.columns = 1 + grid.rows = 1 + } + + this@QuickStackControlsPanel.sizeToContents() + } + } + } + + override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean { + return false + } + + override fun sizeToContents() { + val oldWidth = width + val oldHeight = height + super.sizeToContents() + + if (parent == null && dockNear == null) { + when (dock) { + Dock.LEFT -> x -= width - oldWidth + Dock.TOP -> y -= height - oldHeight + else -> {} // do nothing + } + } + } + + override fun onParented(parent: EditablePanel<*>) { + super.onParented(parent) + + dockNear = null + } + + var dockNear: EditablePanel<*>? = null + + override fun tickInner() { + super.tickInner() + + val dockNear = dockNear + + if (dockNear != null && parent == null && dock != Dock.NONE && dock != Dock.FILL) { + x = dockNear.absoluteX + y = dockNear.absoluteY + + when (dock) { + Dock.LEFT -> { + x -= width + dockMargin.right + y += dockMargin.top + } + + Dock.RIGHT -> { + x += width + dockMargin.left + y += dockMargin.top + } + + Dock.TOP -> { + y -= height + dockMargin.bottom + x += dockMargin.left + } + + Dock.BOTTOM -> { + y += height + dockMargin.top + x += dockMargin.left + } + + else -> throw RuntimeException("you w0t m8?") + } + } + } + + init { + for ((i, mode) in QuickMoveInput.Mode.entries.withIndex()) { + val button = ButtonPanel.square18( + screen, grid, + mode.iconFromStorage, + onPress = IntConsumer { PacketDistributor.sendToServer(QuickStackPacket(mode, false)) }) + + button.childrenOrder = QuickMoveInput.Mode.entries.size + i + button.dockMargin = DockProperty.left(1f) + button.visible = false + button.tooltips.add(mode.textFromStorage) + buttons.add(button) + } + + for ((i, mode) in QuickMoveInput.Mode.entries.filter { it != QuickMoveInput.Mode.RESTOCK_WITH_MOVE }.withIndex()) { + val button = ButtonPanel.square18( + screen, grid, + mode.iconToStorage, + onPress = IntConsumer { PacketDistributor.sendToServer(QuickStackPacket(mode, true)) }) + + button.childrenOrder = i + 1 + button.dockMargin = DockProperty.left(1f) + button.visible = false + button.tooltips.add(mode.textToStorage) + buttons.add(button) + } + + MainButton() + } +} From 07e0c734790336bcd56015496297702326796293 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 21 Mar 2025 15:19:07 +0700 Subject: [PATCH 115/154] Fixes for quick stack controls --- .../screen/panels/QuickStackControlsPanel.kt | 65 +++++++++++-------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/QuickStackControlsPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/QuickStackControlsPanel.kt index aa09cac38..2381c1cc4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/QuickStackControlsPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/QuickStackControlsPanel.kt @@ -24,7 +24,7 @@ class QuickStackControlsPanel( init { grid.dock = Dock.FILL - grid.layout = GridPanel.Layout.TOP_LEFT + grid.layout = GridPanel.Layout.TOP_RIGHT } private inner class MainButton : ButtonPanel(screen, grid, width = 18f, height = 18f) { @@ -70,31 +70,7 @@ class QuickStackControlsPanel( return false } - override fun sizeToContents() { - val oldWidth = width - val oldHeight = height - super.sizeToContents() - - if (parent == null && dockNear == null) { - when (dock) { - Dock.LEFT -> x -= width - oldWidth - Dock.TOP -> y -= height - oldHeight - else -> {} // do nothing - } - } - } - - override fun onParented(parent: EditablePanel<*>) { - super.onParented(parent) - - dockNear = null - } - - var dockNear: EditablePanel<*>? = null - - override fun tickInner() { - super.tickInner() - + private fun moveToDockedParent() { val dockNear = dockNear if (dockNear != null && parent == null && dock != Dock.NONE && dock != Dock.FILL) { @@ -127,6 +103,41 @@ class QuickStackControlsPanel( } } + override fun sizeToContents() { + val oldWidth = width + val oldHeight = height + super.sizeToContents() + + if (parent == null && dockNear == null) { + when (dock) { + Dock.LEFT -> x -= width - oldWidth + Dock.TOP -> y -= height - oldHeight + else -> {} // do nothing + } + } else { + moveToDockedParent() + } + } + + override fun onParented(parent: EditablePanel<*>) { + super.onParented(parent) + + dockNear = null + } + + var dockNear: EditablePanel<*>? = null + set(value) { + if (field != value) { + field = value + moveToDockedParent() + } + } + + override fun tickInner() { + super.tickInner() + moveToDockedParent() + } + init { for ((i, mode) in QuickMoveInput.Mode.entries.withIndex()) { val button = ButtonPanel.square18( @@ -147,7 +158,7 @@ class QuickStackControlsPanel( mode.iconToStorage, onPress = IntConsumer { PacketDistributor.sendToServer(QuickStackPacket(mode, true)) }) - button.childrenOrder = i + 1 + button.childrenOrder = i button.dockMargin = DockProperty.left(1f) button.visible = false button.tooltips.add(mode.textToStorage) From a6361f10f2a64f62fac4b3d1e99f2041a1967ab5 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 21 Mar 2025 18:35:25 +0700 Subject: [PATCH 116/154] Final improvements to quick stack controls --- .../client/screen/ExopackInventoryScreen.kt | 7 +- .../screen/panels/QuickStackControlsPanel.kt | 75 ++----------------- 2 files changed, 9 insertions(+), 73 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt index e199b8e5b..56a368fc0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt @@ -286,12 +286,7 @@ class ExopackInventoryScreen(menu: ExopackInventoryMenu) : MatteryScreen( screen: S, parent: EditablePanel<*>? = null, -) : EditablePanel(screen, parent, 0f, 0f, 18f, 18f) { + x: Float = 0f, + y: Float = 0f +) : EditablePanel(screen, parent, x, y, 18f, 18f) { private val grid = GridPanel(screen, this, columns = 1, rows = 1) private val buttons = ArrayList>() init { grid.dock = Dock.FILL grid.layout = GridPanel.Layout.TOP_RIGHT + grid.columnMajorOrder = true } private inner class MainButton : ButtonPanel(screen, grid, width = 18f, height = 18f) { init { - dockMargin = DockProperty.left(1f) + dockMargin = DockProperty.bottom(1f) childrenOrder = -100 tooltips.add(QuickMoveInput.Mode.RESTOCK_WITH_MOVE.textToStorage) tooltips.add(TextComponent("")) @@ -70,72 +73,10 @@ class QuickStackControlsPanel( return false } - private fun moveToDockedParent() { - val dockNear = dockNear - - if (dockNear != null && parent == null && dock != Dock.NONE && dock != Dock.FILL) { - x = dockNear.absoluteX - y = dockNear.absoluteY - - when (dock) { - Dock.LEFT -> { - x -= width + dockMargin.right - y += dockMargin.top - } - - Dock.RIGHT -> { - x += width + dockMargin.left - y += dockMargin.top - } - - Dock.TOP -> { - y -= height + dockMargin.bottom - x += dockMargin.left - } - - Dock.BOTTOM -> { - y += height + dockMargin.top - x += dockMargin.left - } - - else -> throw RuntimeException("you w0t m8?") - } - } - } - override fun sizeToContents() { val oldWidth = width - val oldHeight = height super.sizeToContents() - - if (parent == null && dockNear == null) { - when (dock) { - Dock.LEFT -> x -= width - oldWidth - Dock.TOP -> y -= height - oldHeight - else -> {} // do nothing - } - } else { - moveToDockedParent() - } - } - - override fun onParented(parent: EditablePanel<*>) { - super.onParented(parent) - - dockNear = null - } - - var dockNear: EditablePanel<*>? = null - set(value) { - if (field != value) { - field = value - moveToDockedParent() - } - } - - override fun tickInner() { - super.tickInner() - moveToDockedParent() + x -= width - oldWidth } init { @@ -146,7 +87,7 @@ class QuickStackControlsPanel( onPress = IntConsumer { PacketDistributor.sendToServer(QuickStackPacket(mode, false)) }) button.childrenOrder = QuickMoveInput.Mode.entries.size + i - button.dockMargin = DockProperty.left(1f) + button.dockMargin = DockProperty.bottomRight(1f) button.visible = false button.tooltips.add(mode.textFromStorage) buttons.add(button) @@ -159,7 +100,7 @@ class QuickStackControlsPanel( onPress = IntConsumer { PacketDistributor.sendToServer(QuickStackPacket(mode, true)) }) button.childrenOrder = i - button.dockMargin = DockProperty.left(1f) + button.dockMargin = DockProperty.bottom(1f) button.visible = false button.tooltips.add(mode.textToStorage) buttons.add(button) From 9413ae5f2ba39ce40daa5f4d770d702d84681860 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 21 Mar 2025 21:17:50 +0700 Subject: [PATCH 117/154] Shrink effect list panel so it no longer overlaps "quick stack" controls --- .../dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt | 2 +- .../dbotthepony/mc/otm/client/screen/panels/EffectListPanel.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt index 56a368fc0..5732aeeab 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/ExopackInventoryScreen.kt @@ -284,7 +284,7 @@ class ExopackInventoryScreen(menu: ExopackInventoryMenu) : MatteryScreen @JvmOverloads constructor( init { scroll.visible = false - //scissor = true + scissor = true } open inner class EffectSquare( From 01d3cbf7b214943cbca93c0258eb80a4f9aad108 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 21 Mar 2025 21:58:56 +0700 Subject: [PATCH 118/154] Add "Smart exchange" button to quickstack controls --- .../mc/otm/datagen/lang/English.kt | 6 ++- .../mc/otm/datagen/lang/Russian.kt | 6 ++- .../screen/decorative/CargoCrateScreen.kt | 5 +- .../screen/panels/QuickStackControlsPanel.kt | 23 ++++++--- .../client/screen/panels/button/Buttons.kt | 51 +++++++++++-------- .../otm/compat/vanilla/VanillaChestScreen.kt | 5 +- 6 files changed, 60 insertions(+), 36 deletions(-) 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 f67f598c9..582993b87 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 @@ -988,12 +988,14 @@ private fun androidFeatures(provider: MatteryLanguageProvider) { private fun gui(provider: MatteryLanguageProvider) { with(provider.english) { gui("quickmove_from.restock", "Restock from storage") - gui("quickmove_from.restock_with_move", "Full restock from storage") + gui("quickmove_from.restock_with_move", "Quickstack from storage") gui("quickmove_from.move", "Take all") gui("quickmove_to.restock", "Restock to storage") - gui("quickmove_to.restock_with_move", "Full restock to storage") + gui("quickmove_to.restock_with_move", "Quickstack to storage") gui("quickmove_to.move", "Deposit all") + gui("quickmove.exchange", "Smart exchange with storage") + gui("quickmove.exchange.desc", "Filtered slots get restocked, everything else gets quickstacked from Exopack") gui("quickmove_hint", "Right click to show all variants") 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 3ca5d8e84..dacdff815 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 @@ -981,12 +981,14 @@ private fun androidFeatures(provider: MatteryLanguageProvider) { private fun gui(provider: MatteryLanguageProvider) { with(provider.russian) { gui("quickmove_from.restock", "Быстрое пополнение из хранилища") - gui("quickmove_from.restock_with_move", "Быстрое перемещение из хранилища") + gui("quickmove_from.restock_with_move", "Быстрое складирование из хранилища") gui("quickmove_from.move", "Взять всё") gui("quickmove_to.restock", "Быстрое пополнение в хранилище") - gui("quickmove_to.restock_with_move", "Быстрое перемещение в хранилище") + gui("quickmove_to.restock_with_move", "Быстрое складирование в хранилище") gui("quickmove_to.move", "Переместить всё") + gui("quickmove.exchange", "Умный обмен с хранилищем") + gui("quickmove.exchange.desc", "Слоты с фильтрами заполняются до максимума, всё остальное быстро складируется из экзопака") gui("quickmove_hint", "Правый клик чтоб увидеть все варианты") 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 1cae5b676..557704aa8 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 @@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.client.screen.decorative import net.minecraft.network.chat.Component import net.minecraft.world.entity.player.Inventory +import ru.dbotthepony.kommons.util.Either 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 @@ -28,11 +29,11 @@ class CargoCrateScreen(menu: CargoCrateMenu, inventory: Inventory, title: Compon val leftControls = DeviceControls(this, frame) leftControls.dockOnLeft = true - leftControls.quickMoveButtons(menu.quickMoveFromStorage, QuickMoveInput.Mode.RESTOCK, true) + leftControls.quickMoveButtons(menu.quickMoveFromStorage) val leftInventoryControls = DeviceControls(this, inventoryFrame!!) leftInventoryControls.dockOnLeft = true - leftInventoryControls.quickMoveButtons(menu.quickMoveToStorage, QuickMoveInput.Mode.RESTOCK_WITH_MOVE, false) + leftInventoryControls.quickMoveButtons(menu.quickMoveToStorage, menu.quickMoveFromStorage) return frame } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/QuickStackControlsPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/QuickStackControlsPanel.kt index 9eed2bfd8..c0616b598 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/QuickStackControlsPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/QuickStackControlsPanel.kt @@ -22,19 +22,27 @@ class QuickStackControlsPanel( y: Float = 0f ) : EditablePanel(screen, parent, x, y, 18f, 18f) { private val grid = GridPanel(screen, this, columns = 1, rows = 1) - private val buttons = ArrayList>() + private val buttons = ArrayList>() init { grid.dock = Dock.FILL grid.layout = GridPanel.Layout.TOP_RIGHT grid.columnMajorOrder = true + + // so row with main button contains only that button (visibly) + val fill = EditablePanel(screen, grid, width = 18f, height = 18f) + fill.childrenOrder = 999 + fill.visible = false + fill.dockMargin = DockProperty.bottomRight(1f) + buttons.add(fill) } private inner class MainButton : ButtonPanel(screen, grid, width = 18f, height = 18f) { init { dockMargin = DockProperty.bottom(1f) - childrenOrder = -100 - tooltips.add(QuickMoveInput.Mode.RESTOCK_WITH_MOVE.textToStorage) + childrenOrder = -100000 + tooltips.add(TranslatableComponent("otm.gui.quickmove.exchange")) + tooltips.add(TranslatableComponent("otm.gui.quickmove.exchange.desc").withStyle(ChatFormatting.GRAY)) tooltips.add(TextComponent("")) tooltips.add(TranslatableComponent("otm.gui.quickmove_hint").withStyle(ChatFormatting.GRAY)) } @@ -44,7 +52,7 @@ class QuickStackControlsPanel( set(value) {} override val icon: IGUIRenderable - get() = Widgets18.RESTOCK_WITH_MOVE_TO_STORAGE + get() = Widgets18.SMART_STORAGE_EXCHANGE override fun test(value: Int): Boolean { return value == InputConstants.MOUSE_BUTTON_LEFT || value == InputConstants.MOUSE_BUTTON_RIGHT @@ -53,12 +61,13 @@ class QuickStackControlsPanel( override fun onClick(mouseButton: Int) { if (mouseButton == InputConstants.MOUSE_BUTTON_LEFT) { PacketDistributor.sendToServer(QuickStackPacket(QuickMoveInput.Mode.RESTOCK_WITH_MOVE, true)) + PacketDistributor.sendToServer(QuickStackPacket(QuickMoveInput.Mode.RESTOCK, false)) } else { buttons.forEach { it.visible = !it.visible } if (buttons[0].visible) { grid.columns = 2 - grid.rows = 3 + grid.rows = 4 } else { grid.columns = 1 grid.rows = 1 @@ -86,14 +95,14 @@ class QuickStackControlsPanel( mode.iconFromStorage, onPress = IntConsumer { PacketDistributor.sendToServer(QuickStackPacket(mode, false)) }) - button.childrenOrder = QuickMoveInput.Mode.entries.size + i + button.childrenOrder = 1000 + i button.dockMargin = DockProperty.bottomRight(1f) button.visible = false button.tooltips.add(mode.textFromStorage) buttons.add(button) } - for ((i, mode) in QuickMoveInput.Mode.entries.filter { it != QuickMoveInput.Mode.RESTOCK_WITH_MOVE }.withIndex()) { + for ((i, mode) in QuickMoveInput.Mode.entries.withIndex()) { val button = ButtonPanel.square18( screen, grid, mode.iconToStorage, 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 1df7a600b..d94a736cc 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 @@ -6,6 +6,7 @@ import net.minecraft.network.chat.Component import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Items import ru.dbotthepony.kommons.util.Delegate +import ru.dbotthepony.kommons.util.Either import ru.dbotthepony.kommons.util.value import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting @@ -542,33 +543,43 @@ class DeviceControls>( } } - fun quickMoveButtons(buttons: Map, mainMode: QuickMoveInput.Mode, isFromStorage: Boolean, unfoldableSettings: Boolean = true) { + fun quickMoveButtons( + buttons: Map, + fromStorage: Map? = null + ) { object : FoldableButtonPanel() { - private val input = buttons[mainMode]!! - override fun performAction() { - input.clientInput() + if (fromStorage == null) { + buttons[QuickMoveInput.Mode.MOVE]!!.clientInput() + } else { + buttons[QuickMoveInput.Mode.RESTOCK_WITH_MOVE]!!.clientInput() + fromStorage[QuickMoveInput.Mode.RESTOCK]!!.clientInput() + } } override var isDisabled: Boolean - get() { return !input.input.test(minecraft.player ?: return false) } + get() { return !buttons.values.first().input.test(minecraft.player ?: return false) } set(value) {} override val hasExtraButtons: Boolean - get() = unfoldableSettings + get() = true override fun doMakeButtons(): List> { - return buttons.entries + var stream = buttons.entries .stream() - .filter { (m, _) -> m != input.mode } + + if (fromStorage == null) + stream = stream.filter { (m) -> m != QuickMoveInput.Mode.MOVE } + + return stream .map { (m, b) -> square18( screen, this, - icon = if (isFromStorage) m.iconFromStorage else m.iconToStorage, + icon = if (fromStorage == null) m.iconFromStorage else m.iconToStorage, onPress = { b.clientInput() } ).also { - if (isFromStorage) + if (fromStorage == null) it.tooltips.add(m.textFromStorage) else it.tooltips.add(m.textToStorage) @@ -578,21 +589,19 @@ class DeviceControls>( } init { - if (isFromStorage) - tooltips.add(input.mode.textFromStorage) - else - tooltips.add(input.mode.textToStorage) - - if (unfoldableSettings) { - tooltips.add(TextComponent("")) - tooltips.add(TranslatableComponent("otm.gui.quickmove_hint").withStyle(ChatFormatting.GRAY)) - } else { - makeButtons() + if (fromStorage == null) + tooltips.add(QuickMoveInput.Mode.MOVE.textFromStorage) + else { + tooltips.add(TranslatableComponent("otm.gui.quickmove.exchange")) + tooltips.add(TranslatableComponent("otm.gui.quickmove.exchange.desc").withStyle(ChatFormatting.GRAY)) } + + tooltips.add(TextComponent("")) + tooltips.add(TranslatableComponent("otm.gui.quickmove_hint").withStyle(ChatFormatting.GRAY)) } override val icon: IGUIRenderable - get() = if (isFromStorage) input.mode.iconFromStorage else input.mode.iconToStorage + get() = if (fromStorage == null) QuickMoveInput.Mode.MOVE.iconFromStorage else Widgets18.SMART_STORAGE_EXCHANGE } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaChestScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaChestScreen.kt index 5a990200d..a782b0535 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaChestScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/vanilla/VanillaChestScreen.kt @@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.compat.vanilla import net.minecraft.network.chat.Component import net.minecraft.world.entity.player.Inventory +import ru.dbotthepony.kommons.util.Either import ru.dbotthepony.mc.otm.client.render.RenderGravity import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.panels.Dock @@ -31,11 +32,11 @@ class VanillaChestScreen(menu: AbstractVanillaChestMenu, inventory: Inventory, t val leftControls = DeviceControls(this, frame) leftControls.dockOnLeft = true - leftControls.quickMoveButtons(menu.quickMoveFromStorage, QuickMoveInput.Mode.RESTOCK, true) + leftControls.quickMoveButtons(menu.quickMoveFromStorage) val leftInventoryControls = DeviceControls(this, inventoryFrame!!) leftInventoryControls.dockOnLeft = true - leftInventoryControls.quickMoveButtons(menu.quickMoveToStorage, QuickMoveInput.Mode.RESTOCK_WITH_MOVE, false) + leftInventoryControls.quickMoveButtons(menu.quickMoveToStorage, menu.quickMoveFromStorage) return frame } From 6cf218a18488ceb421ee8d328069b7f049762891 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 22 Mar 2025 15:06:56 +0700 Subject: [PATCH 119/154] Considerably buff matter bottler --- .../kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt index 7b312c5ae..cd24dee29 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt @@ -60,7 +60,7 @@ object MachinesConfig : AbstractConfig("machines") { private val MATTER_BOTTLER = workerValues( MNames.MATTER_BOTTLER, energyStorage = Decimal(40_000), - energyConsumption = Decimal(10), + energyConsumption = Decimal(40), energyThroughput = Decimal(200), matterCapacity = Decimal(400), workTimeMultiplier = null @@ -85,7 +85,7 @@ object MachinesConfig : AbstractConfig("machines") { object MatterBottler { val VALUES by ::MATTER_BOTTLER - val RATE by builder.comment("Matter transferred per tick").defineDecimal("RATE", Decimal("2.0"), Decimal.ONE_TENTH) + val RATE by builder.comment("Matter transferred per tick").defineDecimal("RATE", Decimal("10.0"), Decimal.ONE_TENTH) } object MatterRecycler { From eed3b04555737652127faa793b4325e2c3ec589a Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 22 Mar 2025 15:07:05 +0700 Subject: [PATCH 120/154] Make matter bottler actually consume energy --- .../entity/matter/MatterBottlerBlockEntity.kt | 237 ++++++++++-------- 1 file changed, 132 insertions(+), 105 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt index f7b6a186a..91e8d4d20 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterBottlerBlockEntity.kt @@ -22,7 +22,6 @@ import ru.dbotthepony.mc.otm.capability.matter.MatterStorageImpl import ru.dbotthepony.mc.otm.capability.matter.ProfiledMatterStorage import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.UpgradeContainer -import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.menu.matter.MatterBottlerMenu @@ -35,7 +34,7 @@ import java.util.function.BooleanSupplier class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.MATTER_BOTTLER, blockPos, blockState) { - val upgrades = UpgradeContainer(3, UpgradeType.BASIC_MATTER, BooleanSupplier { blockState.getValue(WorkerState.SEMI_WORKER_STATE) !== WorkerState.IDLE }, ::markDirtyFast) + val upgrades = UpgradeContainer(3, UpgradeType.BASIC_MATTER, BooleanSupplier { this.blockState.getValue(WorkerState.SEMI_WORKER_STATE) !== WorkerState.IDLE }, ::markDirtyFast) override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::markDirtyFast, upgrades.transform(MachinesConfig.MatterBottler.VALUES))) val energyConfig = ConfigurableEnergy(energy) @@ -141,7 +140,7 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) : } if (state !== blockState) { - level.setBlock(blockPos, state, Block.UPDATE_CLIENTS) + level.setBlock(blockPos, state, Block.UPDATE_ALL) } } @@ -154,18 +153,143 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) : } private val workerState by countingLazy(blockStateChangesCounter) { - blockState.getValue(WorkerState.SEMI_WORKER_STATE) + this.blockState.getValue(WorkerState.SEMI_WORKER_STATE) } private fun blockstateToWorking() { if (workerState !== WorkerState.WORKING) { - level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING), Block.UPDATE_CLIENTS) + level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING), Block.UPDATE_ALL) } } private fun blockstateToIdle() { if (workerState !== WorkerState.IDLE) { - level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS) + level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_ALL) + } + } + + private fun tickBottling() { + var isWorking = false + var hasCapacitors = false + + for (slot in bottling.slotIterator()) { + val item = slot.item + val capability = item.getCapability(MatteryCapability.MATTER_ITEM) ?: continue + + if (!capability.receiveMatterChecked(Decimal.LONG_MAX_VALUE, true).isPositive) { + unbottling.consumeItem(item, false) + slot.setChanged() + continue + } + + hasCapacitors = true + initialCapacity = initialCapacity ?: capability.storedMatter + val rate = MachinesConfig.MatterBottler.RATE * (1.0 + upgrades.speedBonus) + val energyRate = MachinesConfig.MatterBottler.VALUES.energyConsumption * (1.0 + upgrades.speedBonus) + + if (matter.storedMatter < rate) { + val toExtract = matter.missingMatter + .coerceAtMost(rate * 200) + .coerceAtMost(capability.missingMatter - matter.storedMatter) + + matter.receiveMatter(matterNode.graph.extractMatter(toExtract, false), false) + } + + if (matter.storedMatter.isPositive) { + val energyRatio = if (energyRate <= Decimal.ZERO) Decimal.ONE else energy.extractEnergy(energyRate, true) / energyRate + val matterRatio = matter.extractMatter(capability.receiveMatter(rate.coerceAtMost(matter.storedMatter), true), true) / rate + + val minRatio = minOf(matterRatio, energyRatio) + + if (minRatio > Decimal.ZERO) { + isWorking = true + energy.extractEnergy(energyRate * minRatio, false) + matter.extractMatter(capability.receiveMatter(rate * minRatio, false), false) + workProgress = ((capability.storedMatter - initialCapacity!!) / capability.maxStoredMatter).toFloat() + slot.setChanged() + } + } else { + if (spitItemsWhenCantWork) { + unbottling.consumeItem(item, false) + slot.setChanged() + } + } + + break + } + + if (isWorking) { + blockstateToWorking() + } else { + blockstateToIdle() + } + + if (!hasCapacitors) { + matter.extractMatter(matterNode.graph.receiveMatter(matter.storedMatter, false), false) + initialCapacity = null + workProgress = 0f + } + } + + private fun tickUnbottling() { + matter.extractMatter(matterNode.graph.receiveMatter(matter.storedMatter, false), false) + + if (!matter.missingMatter.isPositive) { + if (spitItemsWhenCantWork) { + for (slot in unbottling.slotIterator()) { + bottling.consumeItem(slot.item, false) + slot.setChanged() + } + } + + blockstateToIdle() + return + } + + var any = false + var hasCapacitors = false + + for (slot in unbottling.slotIterator()) { + val item = slot.item + val it = item.getCapability(MatteryCapability.MATTER_ITEM) ?: continue + + if (!it.extractMatterChecked(Decimal.LONG_MAX_VALUE, true).isPositive) { + bottling.consumeItem(item, false) + slot.setChanged() + continue + } + + initialCapacity = initialCapacity ?: it.storedMatter + + hasCapacitors = true + val rate = MachinesConfig.MatterBottler.RATE * (1.0 + upgrades.speedBonus) + val energyRate = MachinesConfig.MatterBottler.VALUES.energyConsumption * (1.0 + upgrades.speedBonus) + + val energyRatio = if (energyRate <= Decimal.ZERO) Decimal.ONE else energy.extractEnergy(energyRate, true) / energyRate + val matterRatio = matter.receiveMatter(it.extractMatterChecked(rate, true), true) / rate + + val minRatio = minOf(energyRatio, matterRatio) + + if (minRatio > Decimal.ZERO) { + any = true + energy.extractEnergy(energyRate * energyRatio, false) + matter.receiveMatter(it.extractMatterChecked(rate * minRatio, false), false) + + workProgress = 1f - (it.storedMatter / initialCapacity!!).toFloat() + } + + break + } + + if (any) { + blockstateToWorking() + } else { + blockstateToIdle() + } + + if (!hasCapacitors) { + initialCapacity = null + workProgress = 0f } } @@ -178,106 +302,9 @@ class MatterBottlerBlockEntity(blockPos: BlockPos, blockState: BlockState) : } if (isBottling) { - var any = false - var idle = false - - for (slot in bottling.slotIterator()) { - val item = slot.item - - item.getCapability(MatteryCapability.MATTER_ITEM)?.let { - if (!it.missingMatter.isPositive) { - unbottling.consumeItem(item, false) - slot.setChanged() - } else { - any = true - initialCapacity = initialCapacity ?: it.storedMatter - val rate = MachinesConfig.MatterBottler.RATE * (1.0 + upgrades.speedBonus) - - if (matter.storedMatter < rate) { - matter.receiveMatter(matterNode.graph.extractMatter(matter.missingMatter - .coerceAtMost(rate * 200) - .coerceAtMost(it.missingMatter - matter.storedMatter), false), false) - } - - if (matter.storedMatter.isPositive) { - matter.extractMatter(it.receiveMatter(rate.coerceAtMost(matter.storedMatter), false), false) - - if (!it.missingMatter.isPositive) { - initialCapacity = null - workProgress = 0f - } else { - workProgress = ((it.storedMatter - initialCapacity!!) / it.maxStoredMatter).toFloat() - } - } else { - idle = true - - if (spitItemsWhenCantWork) { - unbottling.consumeItem(item, false) - slot.setChanged() - } - } - } - } - - if (any) { - break - } - } - - if (any && !idle) { - blockstateToWorking() - } else { - matter.extractMatter(matterNode.graph.receiveMatter(matter.storedMatter, false), false) - blockstateToIdle() - } + tickBottling() } else { - matter.extractMatter(matterNode.graph.receiveMatter(matter.storedMatter, false), false) - - if (!matter.missingMatter.isPositive) { - if (spitItemsWhenCantWork) { - for (slot in unbottling.slotIterator()) { - bottling.consumeItem(slot.item, false) - slot.setChanged() - } - } - - blockstateToIdle() - return - } - - var any = false - - for (slot in unbottling.slotIterator()) { - val item = slot.item - - item.getCapability(MatteryCapability.MATTER_ITEM)?.let { - if (!it.storedMatter.isPositive) { - bottling.consumeItem(item, false) - slot.setChanged() - } else { - any = true - initialCapacity = initialCapacity ?: it.storedMatter - matter.receiveMatter(it.extractMatter(MachinesConfig.MatterBottler.RATE, false), false) - - if (!it.storedMatter.isPositive) { - initialCapacity = null - workProgress = 0f - } else { - workProgress = 1f - (it.storedMatter / initialCapacity!!).toFloat() - } - } - } - - if (any) { - break - } - } - - if (any) { - blockstateToWorking() - } else { - blockstateToIdle() - } + tickUnbottling() } } } From d17e64f33516bbd2f73e484728f84f5dfe3ec0d3 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 22 Mar 2025 15:10:17 +0700 Subject: [PATCH 121/154] Fix slotted container has empty bitmap after deserialization --- .../ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt index 2f013f4d6..31a8b5795 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt @@ -274,6 +274,7 @@ class SlottedContainer( for ((item, slot) in items) { if (slot in 0 until containerSize) { slots[slot].item = item + bitmap[slot] = item.isNotEmpty } else if (item.isNotEmpty) { ItemStack.CODEC.encodeStart(provider.createSerializationContext(NbtOps.INSTANCE), item) .ifError { LOGGER.warn("Unable to serialize 'lost' item: ${it.message()}") } @@ -307,6 +308,7 @@ class SlottedContainer( if (i in 0 until containerSize) { slots[i].deserializeNBT(provider, element) + bitmap[i] = slots[i].isNotEmpty } else { lostItems.add(element) this.provider = provider From 17dfa953dbb95462067a31592c2d2c01b5dcfe82 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 22 Mar 2025 15:28:11 +0700 Subject: [PATCH 122/154] damn --- .../kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt index 6ce4277a9..ba96afded 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt @@ -98,6 +98,7 @@ abstract class EnhancedContainer(private val size: Int) items[slot] = ItemStack.EMPTY notifySlotChanged(slot, observedItems[slot]) observedItems[slot] = ItemStack.EMPTY + bitmap[slot] = false return item } @@ -107,6 +108,7 @@ abstract class EnhancedContainer(private val size: Int) items[slot] = itemStack notifySlotChanged(slot, observedItems[slot]) observedItems[slot] = itemStack.copy() + bitmap[slot] = itemStack.isNotEmpty } } From faba736bd7838301a47440470de2b459da168fc0 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 22 Mar 2025 17:10:26 +0700 Subject: [PATCH 123/154] Considerably improve upgrade container performance --- .../mc/otm/container/UpgradeContainer.kt | 82 +++++++++++++++---- 1 file changed, 68 insertions(+), 14 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt index e18a3d427..e3dae88f8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt @@ -26,28 +26,62 @@ class UpgradeContainer( override val upgradeTypes: Set get() = setOf() - private fun positiveDecimals(fn: (IMatteryUpgrade) -> Decimal, reducer: (Decimal, Decimal) -> Decimal): Decimal { + private inline fun positiveDecimals(fn: (IMatteryUpgrade) -> Decimal, reducer: (Decimal, Decimal) -> Decimal): Decimal { if (isEmpty) return Decimal.ZERO - return iterator() - .map { (it.getCapability(MatteryCapability.UPGRADE)?.let(fn) ?: Decimal.ZERO).moreThanZero() * it.count } - .reduce(Decimal.ZERO, reducer) + var result = Decimal.ZERO + + for (it in iterator()) { + val cap = it.getCapability(MatteryCapability.UPGRADE) ?: continue + val value = fn(cap) + + if (value > Decimal.ZERO) { + if (it.count == 1) { + result = reducer(result, value ) + } else { + result = reducer(result, value * it.count) + } + } + } + + return result } - private fun anyDecimals(fn: (IMatteryUpgrade) -> Decimal, reducer: (Decimal, Decimal) -> Decimal): Decimal { + private inline fun anyDecimals(fn: (IMatteryUpgrade) -> Decimal, reducer: (Decimal, Decimal) -> Decimal): Decimal { if (isEmpty) return Decimal.ZERO - return iterator() - .map { (it.getCapability(MatteryCapability.UPGRADE)?.let(fn) ?: Decimal.ZERO) * it.count } - .reduce(Decimal.ZERO, reducer) + var result = Decimal.ZERO + + for (it in iterator()) { + val cap = it.getCapability(MatteryCapability.UPGRADE) ?: continue + val value = fn(cap) + + if (it.count == 1) { + result = reducer(result, value) + } else { + result = reducer(result, value * it.count) + } + } + + return result + } + + override val speedBonus: Double get() { + if (isEmpty) + return 0.0 + + return sumOf { (it.getCapability(MatteryCapability.UPGRADE)?.speedBonus ?: 0.0) * it.count } + } + + override val processingItems: Int get() { + if (isEmpty) + return 0 + + return sumOf { (it.getCapability(MatteryCapability.UPGRADE)?.processingItems ?: 0).coerceAtLeast(0) * it.count } } - override val speedBonus: Double - get() = if (isEmpty) 0.0 else iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.speedBonus ?: 0.0) * it.count }.reduce(0.0) { a, b -> a + b } - override val processingItems: Int - get() = if (isEmpty) 0 else iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.processingItems ?: 0).coerceAtLeast(0) * it.count }.reduce(0) { a, b -> a + b } override val energyStorageFlat: Decimal get() = positiveDecimals(IMatteryUpgrade::energyStorageFlat, Decimal::plus) override val energyStorage: Decimal @@ -58,8 +92,28 @@ class UpgradeContainer( get() = positiveDecimals(IMatteryUpgrade::matterStorage, Decimal::plus) override val energyConsumed: Decimal get() = anyDecimals(IMatteryUpgrade::energyConsumed, Decimal::plus) - override val failureMultiplier: Double - get() = if (isEmpty) 1.0 else iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.failureMultiplier ?: 1.0).coerceAtLeast(0.0).pow(it.count.toDouble()) }.reduce(1.0) { a, b -> a * b } + + override val failureMultiplier: Double get() { + if (isEmpty) + return 1.0 + + var result = 1.0 + + for (it in iterator()) { + val cap = it.getCapability(MatteryCapability.UPGRADE) ?: continue + val chance = cap.failureMultiplier.coerceAtLeast(0.0) + + if (chance == 0.0) + return 0.0 + else if (it.count == 1) + result *= chance + else + result *= chance.pow(it.count) + } + + return result + } + override val energyThroughputFlat: Decimal get() = positiveDecimals(IMatteryUpgrade::energyThroughputFlat, Decimal::plus) override val energyThroughput: Decimal From 524c36aaded27749a28468ec1f6f34b89b2f69ec Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 22 Mar 2025 19:09:59 +0700 Subject: [PATCH 124/154] oops --- .../ru/dbotthepony/mc/otm/container/EnhancedContainer.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt index ba96afded..630016b90 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/EnhancedContainer.kt @@ -170,8 +170,8 @@ abstract class EnhancedContainer(private val size: Int) val slot = element.getInt("slot") if (!seenSlots.add(slot)) continue - if ("item" in nbt) { - ItemStack.OPTIONAL_CODEC.decode(ops, nbt["item"]) + if ("item" in element) { + ItemStack.OPTIONAL_CODEC.decode(ops, element["item"]) .map { it.first } .ifError { LOGGER.error("Failed to deserialize item stack in slot $slot: ${it.message()}") } .ifSuccess { From 9f8e7693a871993baf6064bf991639a3f47df3b5 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 23 Mar 2025 01:28:06 +0700 Subject: [PATCH 125/154] Add IEnhancedContainer specific optimization --- .../ru/dbotthepony/mc/otm/core/util/LootTableUtils.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LootTableUtils.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LootTableUtils.kt index ae0a0a1be..8821690ee 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LootTableUtils.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LootTableUtils.kt @@ -9,6 +9,7 @@ import net.minecraft.world.item.ItemStack import net.minecraft.world.level.storage.loot.LootParams import net.minecraft.world.level.storage.loot.LootTable import org.apache.logging.log4j.LogManager +import ru.dbotthepony.mc.otm.container.IEnhancedContainer import ru.dbotthepony.mc.otm.container.get import ru.dbotthepony.mc.otm.container.set import ru.dbotthepony.mc.otm.core.isNotEmpty @@ -105,9 +106,14 @@ private fun shuffle(items: MutableList, emptySlotCount: Int, random: fun LootTable.fill(params: LootParams, random: RandomSource, container: Container, rounds: Int = 1) { val emptySlots = IntArrayList() - for (i in 0 until container.containerSize) - if (container[i].isEmpty) + if (container is IEnhancedContainer<*>) { + for (i in container.emptySlotIndexIterator()) emptySlots.add(i) + } else { + for (i in 0 until container.containerSize) + if (container[i].isEmpty) + emptySlots.add(i) + } emptySlots.shuffle(random) From 4fc646a13a23ea025d61ce217f9ab26fe2c5cfae Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 26 Mar 2025 18:52:26 +0700 Subject: [PATCH 126/154] Energy counter "pull" mode --- .../ru/dbotthepony/mc/otm/datagen/lang/English.kt | 2 ++ .../ru/dbotthepony/mc/otm/datagen/lang/Russian.kt | 2 ++ .../block/entity/tech/EnergyCounterBlockEntity.kt | 13 ++++++++++--- .../otm/client/screen/tech/EnergyCounterScreen.kt | 14 +++++++++++++- .../mc/otm/menu/tech/EnergyCounterMenu.kt | 3 +++ 5 files changed, 30 insertions(+), 4 deletions(-) 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 67ead1708..33c067834 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 @@ -631,6 +631,8 @@ private fun blocks(provider: MatteryLanguageProvider) { add(MBlocks.ENERGY_COUNTER[null]!!, "switch", "Switch input facing") add(MBlocks.ENERGY_COUNTER[null]!!, "limit", "I/O Limit. -1 means no limit") add(MBlocks.ENERGY_COUNTER[null]!!, "display_this", "Display this information on block's screen") + add(MBlocks.ENERGY_COUNTER[null]!!, "do_pull", "Pull energy from input side and push to output") + add(MBlocks.ENERGY_COUNTER[null]!!, "dont_pull", "Don't pull energy") addBlock(MBlocks.CHEMICAL_GENERATOR.values, "Chemical Generator") addBlock(MBlocks.CHEMICAL_GENERATOR.values, "desc", "Generates power by burning solid fuels") 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 cc3b3a7d4..a79597b28 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 @@ -635,6 +635,8 @@ private fun blocks(provider: MatteryLanguageProvider) { add(MBlocks.ENERGY_COUNTER[null]!!, "switch", "Сменить сторону входа") add(MBlocks.ENERGY_COUNTER[null]!!, "limit", "Лимит ввода/вывода. -1 для отключения лимитов") add(MBlocks.ENERGY_COUNTER[null]!!, "display_this", "Отображать эти данные на экране блока") + add(MBlocks.ENERGY_COUNTER[null]!!, "do_pull", "Забирать энергию на входе и выталкивать её на выходе") + add(MBlocks.ENERGY_COUNTER[null]!!, "dont_pull", "Не забирать энергию на входе") addBlock(MBlocks.CHEMICAL_GENERATOR.values, "Химический генератор") addBlock(MBlocks.CHEMICAL_GENERATOR.values, "desc", "Генерирует энергию сжигая твёрдое топливо") diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyCounterBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyCounterBlockEntity.kt index 80b12d46f..790067c07 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyCounterBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyCounterBlockEntity.kt @@ -31,6 +31,7 @@ import ru.dbotthepony.mc.otm.registry.game.MBlockEntities class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.ENERGY_COUNTER, p_155229_, p_155230_) { var passed by syncher.decimal() + var pullEnergyFromInput by syncher.boolean() override val blockRotation: BlockRotation by countingLazy(blockStateChangesCounter) { BlockRotation.of(blockState[EnergyCounterBlock.INPUT_DIRECTION]) @@ -86,10 +87,8 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat savetables.stateful(::history1h) savetables.stateful(::history6h) savetables.stateful(::history24h) - } - override fun saveLevel(nbt: CompoundTag, registry: HolderLookup.Provider) { - super.saveLevel(nbt, registry) + savetablesConfig.bool(::pullEnergyFromInput) } override fun loadAdditional(nbt: CompoundTag, registry: HolderLookup.Provider) { @@ -267,6 +266,14 @@ class EnergyCounterBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Mat override fun tick() { super.tick() + if (pullEnergyFromInput) { + val input = inputCapability + val output = outputCapability + + if (input != null && output != null) + thisTick += moveEnergy(source = input, destination = output, simulate = false) + } + lastTick = thisTick charts.forEach { it.add(thisTick) } thisTick = Decimal.ZERO diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/EnergyCounterScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/EnergyCounterScreen.kt index b552b93a1..8ddd297a5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/EnergyCounterScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/EnergyCounterScreen.kt @@ -111,7 +111,19 @@ class EnergyCounterScreen(menu: EnergyCounterMenu, inventory: Inventory, title: } } - makeDeviceControls(this, frame, redstoneConfig = menu.redstone) + val controls = makeDeviceControls(this, frame, redstoneConfig = menu.redstone) + + controls.addButton( + BooleanButtonPanel.square18( + this, + controls, + menu.pullEnergyFromInput, + iconActive = Widgets18.LEFT_CONTROLS.push, + iconInactive = Widgets18.LEFT_CONTROLS.output, + tooltipActive = TranslatableComponent("block.overdrive_that_matters.energy_counter.do_pull"), + tooltipInactive = TranslatableComponent("block.overdrive_that_matters.energy_counter.dont_pull") + ) + ) return frame } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyCounterMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyCounterMenu.kt index 0f917784e..5849e82e4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyCounterMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyCounterMenu.kt @@ -12,6 +12,7 @@ import ru.dbotthepony.mc.otm.core.chart.DecimalHistoryChart import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.toDecimal import ru.dbotthepony.mc.otm.menu.MatteryMenu +import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.IntInputWithFeedback import ru.dbotthepony.mc.otm.registry.game.MMenus @@ -34,6 +35,8 @@ class EnergyCounterMenu( val history6h = tile?.history6h ?: DecimalHistoryChart(720 * 6, 100) val history24h = tile?.history24h ?: DecimalHistoryChart(720 * 24, 100) + val pullEnergyFromInput = BooleanInputWithFeedback(this, tile?.let { it::pullEnergyFromInput }) + init { mSynchronizer.add(history5s) mSynchronizer.add(history15s) From 85dde24e59e98e3b197a3b94c16c3375df98f866 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 26 Mar 2025 19:06:39 +0700 Subject: [PATCH 127/154] Update energy counter menu code --- .../mc/otm/menu/tech/EnergyCounterMenu.kt | 25 ++++--------------- .../mc/otm/network/syncher/SynchableGroup.kt | 4 +++ 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyCounterMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyCounterMenu.kt index 5849e82e4..e95e7e6e2 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyCounterMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/EnergyCounterMenu.kt @@ -17,15 +17,16 @@ import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.IntInputWithFeedback import ru.dbotthepony.mc.otm.registry.game.MMenus import java.math.BigDecimal +import java.util.function.Supplier class EnergyCounterMenu( p_38852_: Int, inventory: Inventory, tile: EnergyCounterBlockEntity? = null ) : MatteryMenu(MMenus.ENERGY_COUNTER, p_38852_, inventory, tile) { - var passed by mSynchronizer.decimal() - var lastTick by mSynchronizer.decimal() - var maxIO by mSynchronizer.decimal() + var passed by mSynchronizer.computedDecimal { tile?.passed ?: Decimal.ZERO } + var lastTick by mSynchronizer.computedDecimal { tile?.lastTick ?: Decimal.ZERO } + var maxIO by mSynchronizer.computedDecimal { tile?.ioLimit ?: Decimal.ZERO } val history5s = tile?.history5s ?: DecimalHistoryChart(1, 100) val history15s = tile?.history15s ?: DecimalHistoryChart(3, 100) @@ -62,7 +63,7 @@ class EnergyCounterMenu( } } - var inputDirection: Direction by mSynchronizer.enum(Direction.UP) + val inputDirection: Direction by mSynchronizer.computedEnum { tile?.blockState?.getValue(EnergyCounterBlock.INPUT_DIRECTION) ?: Direction.UP} val maxIOInput = decimalInput { if (tile is EnergyCounterBlockEntity) { @@ -73,20 +74,4 @@ class EnergyCounterMenu( } } } - - override fun beforeBroadcast() { - super.beforeBroadcast() - - if (tile is EnergyCounterBlockEntity) { - passed = tile.passed - lastTick = tile.lastTick - inputDirection = tile.blockState.getValue(EnergyCounterBlock.INPUT_DIRECTION) - - maxIO = tile.ioLimit?.toDecimal() ?: -Decimal.ONE - } - } - - companion object { - private val MINUS_ONE = -BigDecimal.ONE - } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/syncher/SynchableGroup.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/syncher/SynchableGroup.kt index 88813c500..9e7f0749c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/syncher/SynchableGroup.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/syncher/SynchableGroup.kt @@ -270,6 +270,10 @@ class SynchableGroup : Observer, ISynchable, Iterable { return add(ListenableDelegate.maskSmart(value, getter, setter), MatteryStreamCodec.Enum(value::class.java)) } + inline fun > computedEnum(value: Supplier): SynchableDelegate { + return computed(value, MatteryStreamCodec.Enum(E::class.java)) + } + fun decimal(value: Decimal = Decimal.ZERO, setter: DelegateSetter = DelegateSetter.passthrough(), getter: DelegateGetter = DelegateGetter.passthrough()): SynchableDelegate { return add(ListenableDelegate.maskSmart(value, getter, setter), StreamCodecs.DECIMAL) } From e93c766edb30f7b6f749de6cc1ac968cc04b0394 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 26 Mar 2025 19:16:30 +0700 Subject: [PATCH 128/154] Move stuff from "Decimal" to appropriate places --- .../entity/tech/EnergyCounterBlockEntity.kt | 2 +- .../energy/BatteryBackedEnergyStorage.kt | 2 +- .../jade/providers/MatterStorageProvider.kt | 4 +- .../jade/providers/MatteryEnergyProvider.kt | 4 +- .../mc/otm/config/AbstractConfig.kt | 1 - .../dbotthepony/mc/otm/config/CablesConfig.kt | 1 - .../mc/otm/config/DecimalConfigValue.kt | 58 +++++++++++++ .../mc/otm/config/ExopackConfig.kt | 1 - .../dbotthepony/mc/otm/config/ItemsConfig.kt | 1 - .../mc/otm/config/MachinesConfig.kt | 1 - .../dbotthepony/mc/otm/config/PlayerConfig.kt | 1 - .../dbotthepony/mc/otm/config/ServerConfig.kt | 1 - .../dbotthepony/mc/otm/core/math/Decimal.kt | 83 ------------------- .../mc/otm/core/nbt/CompoundTagExt.kt | 5 ++ .../mc/otm/core/util/FriendlyStreams.kt | 19 +++++ .../mc/otm/data/FlywheelMaterials.kt | 4 +- .../mc/otm/item/QuantumBatteryItem.kt | 7 +- .../mc/otm/item/weapon/EnergySwordItem.kt | 4 +- .../mc/otm/item/weapon/FallingSunItem.kt | 4 +- .../dbotthepony/mc/otm/matter/IMatterValue.kt | 4 +- .../mc/otm/network/StreamCodecs.kt | 4 +- .../mc/otm/player/MatteryFoodData.kt | 3 +- 22 files changed, 102 insertions(+), 112 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/config/DecimalConfigValue.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyCounterBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyCounterBlockEntity.kt index 790067c07..2b1bb16e0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyCounterBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/EnergyCounterBlockEntity.kt @@ -22,7 +22,7 @@ import ru.dbotthepony.mc.otm.core.chart.DecimalHistoryChart import ru.dbotthepony.mc.otm.core.math.BlockRotation import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.RelativeSide -import ru.dbotthepony.mc.otm.core.math.getDecimal +import ru.dbotthepony.mc.otm.core.nbt.getDecimal import ru.dbotthepony.mc.otm.core.nbt.mapPresent import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.util.countingLazy diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/energy/BatteryBackedEnergyStorage.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/energy/BatteryBackedEnergyStorage.kt index 256a66c80..b24020479 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/energy/BatteryBackedEnergyStorage.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/energy/BatteryBackedEnergyStorage.kt @@ -15,7 +15,7 @@ import ru.dbotthepony.mc.otm.capability.FlowDirection import ru.dbotthepony.mc.otm.capability.extractEnergy import ru.dbotthepony.mc.otm.capability.receiveEnergy import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.math.getDecimal +import ru.dbotthepony.mc.otm.core.nbt.getDecimal import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.registry.StatNames import ru.dbotthepony.mc.otm.triggers.AndroidBatteryTrigger diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/jade/providers/MatterStorageProvider.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/jade/providers/MatterStorageProvider.kt index 3c3b15906..5c2769876 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/jade/providers/MatterStorageProvider.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/jade/providers/MatterStorageProvider.kt @@ -13,8 +13,8 @@ import ru.dbotthepony.mc.otm.compat.jade.JadeUids import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.getCapability import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.math.getDecimal -import ru.dbotthepony.mc.otm.core.math.putDecimal +import ru.dbotthepony.mc.otm.core.nbt.getDecimal +import ru.dbotthepony.mc.otm.core.nbt.putDecimal import ru.dbotthepony.mc.otm.core.util.formatMatter import snownee.jade.api.BlockAccessor import snownee.jade.api.IBlockComponentProvider diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/jade/providers/MatteryEnergyProvider.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/jade/providers/MatteryEnergyProvider.kt index 56727d58a..d4291dbb6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/compat/jade/providers/MatteryEnergyProvider.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/compat/jade/providers/MatteryEnergyProvider.kt @@ -13,8 +13,8 @@ import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.kommons.math.RGBAColor import ru.dbotthepony.mc.otm.capability.IProfiledStorage import ru.dbotthepony.mc.otm.core.getCapability -import ru.dbotthepony.mc.otm.core.math.getDecimal -import ru.dbotthepony.mc.otm.core.math.putDecimal +import ru.dbotthepony.mc.otm.core.nbt.getDecimal +import ru.dbotthepony.mc.otm.core.nbt.putDecimal import ru.dbotthepony.mc.otm.core.util.formatPower import snownee.jade.api.* import snownee.jade.api.config.IPluginConfig diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/config/AbstractConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/config/AbstractConfig.kt index b76938fb9..a74463904 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/config/AbstractConfig.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/config/AbstractConfig.kt @@ -7,7 +7,6 @@ import ru.dbotthepony.kommons.util.Delegate import ru.dbotthepony.kommons.util.getValue import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.math.defineDecimal import ru.dbotthepony.mc.otm.core.util.WriteOnce abstract class AbstractConfig(private val configName: String, private val type: ModConfig.Type = ModConfig.Type.SERVER) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/config/CablesConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/config/CablesConfig.kt index fe5e269e3..ad00a469f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/config/CablesConfig.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/config/CablesConfig.kt @@ -3,7 +3,6 @@ package ru.dbotthepony.mc.otm.config import ru.dbotthepony.kommons.util.getValue import ru.dbotthepony.kommons.util.setValue import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.math.defineDecimal object CablesConfig : AbstractConfig("cables") { enum class E(throughput: Decimal) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/config/DecimalConfigValue.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/config/DecimalConfigValue.kt new file mode 100644 index 000000000..457e734c9 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/config/DecimalConfigValue.kt @@ -0,0 +1,58 @@ +package ru.dbotthepony.mc.otm.config + +import net.neoforged.neoforge.common.ModConfigSpec +import ru.dbotthepony.mc.otm.core.math.Decimal + +class DecimalConfigValue( + parent: ModConfigSpec.ConfigValue, + val minimum: Decimal? = null, + val maximum: Decimal? = null, +) : ObservedConfigValue(parent) { + override fun fromString(value: String): Decimal? { + try { + val parsed = Decimal(value) + + if (minimum != null && minimum > parsed) { + return minimum + } else if (maximum != null && maximum < parsed) { + return maximum + } + + return parsed + } catch (err: java.lang.NumberFormatException) { + return null + } + } + + override fun toString(value: Decimal): Pair { + if (minimum != null && minimum > value) { + return minimum.toString() to minimum + } else if (maximum != null && maximum < value) { + return maximum.toString() to maximum + } + + return value.toString() to value + } +} + +private fun ModConfigSpec.Builder.commentRange(minimum: Decimal?, maximum: Decimal?) { + if (minimum != null && maximum != null) { + comment("Range: $minimum ~ $maximum") + } else if (minimum != null) { + comment("Range: >= $minimum") + } else if (maximum != null) { + comment("Range: <= $maximum") + } +} + +fun ModConfigSpec.Builder.defineDecimal(path: String, defaultValue: Decimal, minimum: Decimal? = null, maximum: Decimal? = null): DecimalConfigValue { + commentRange(minimum, maximum) + comment("Default: $defaultValue") + return DecimalConfigValue(define(path, defaultValue.toString()), minimum, maximum) +} + +fun ModConfigSpec.Builder.defineDecimal(path: List, defaultValue: Decimal, minimum: Decimal? = null, maximum: Decimal? = null): DecimalConfigValue { + commentRange(minimum, maximum) + comment("Default: $defaultValue") + return DecimalConfigValue(define(path, defaultValue.toString()), minimum, maximum) +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/config/ExopackConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/config/ExopackConfig.kt index afe73a16a..99f6fc655 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/config/ExopackConfig.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/config/ExopackConfig.kt @@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.config import ru.dbotthepony.kommons.util.getValue import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.math.defineDecimal object ExopackConfig : AbstractConfig("exopack") { val ENERGY_CAPACITY by builder diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/config/ItemsConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/config/ItemsConfig.kt index efe4c77ee..84e8bdb68 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/config/ItemsConfig.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/config/ItemsConfig.kt @@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.config import ru.dbotthepony.kommons.util.getValue import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.math.defineDecimal import ru.dbotthepony.mc.otm.registry.MNames object ItemsConfig : AbstractConfig("items") { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt index 7b312c5ae..573c1d70f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt @@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.config import ru.dbotthepony.kommons.util.getValue import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.math.defineDecimal import ru.dbotthepony.mc.otm.registry.MNames object MachinesConfig : AbstractConfig("machines") { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/config/PlayerConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/config/PlayerConfig.kt index c9f907244..d903cad0e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/config/PlayerConfig.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/config/PlayerConfig.kt @@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.config import ru.dbotthepony.kommons.util.getValue import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.math.defineDecimal object PlayerConfig : AbstractConfig("player") { init { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/config/ServerConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/config/ServerConfig.kt index 0687260bb..df5193062 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/config/ServerConfig.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/config/ServerConfig.kt @@ -2,7 +2,6 @@ package ru.dbotthepony.mc.otm.config import ru.dbotthepony.kommons.util.getValue import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.math.defineDecimal object ServerConfig : AbstractConfig("misc") { val LABORATORY_LAMP_LIGHT_LENGTH: Int by builder.comment("In blocks").defineInRange("LABORATORY_LAMP_LIGHT_LENGTH", 6, 1, 128) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt index 4c4289757..18f0bb4e4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt @@ -1,17 +1,10 @@ package ru.dbotthepony.mc.otm.core.math import net.minecraft.nbt.ByteArrayTag -import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.StringTag import net.minecraft.nbt.Tag import net.minecraft.network.FriendlyByteBuf import net.minecraft.util.RandomSource -import net.neoforged.neoforge.common.ModConfigSpec -import ru.dbotthepony.mc.otm.config.ObservedConfigValue -import ru.dbotthepony.mc.otm.core.util.readVarIntLE -import ru.dbotthepony.mc.otm.core.util.writeVarIntLE -import java.io.InputStream -import java.io.OutputStream import java.math.BigDecimal import java.math.BigInteger import java.math.MathContext @@ -1603,28 +1596,6 @@ sealed class Decimal : Number(), Comparable { } } -fun FriendlyByteBuf.readDecimal() = Decimal.read(this) -fun FriendlyByteBuf.writeDecimal(value: Decimal) = value.write(this) - -fun InputStream.readDecimal(): Decimal { - val size = readVarIntLE() - require(size >= 0) { "Negative payload size: $size" } - val bytes = ByteArray(size) - read(bytes) - return Decimal.fromByteArray(bytes) -} - -fun OutputStream.writeDecimal(value: Decimal) { - val bytes = value.toByteArray() - writeVarIntLE(bytes.size) - write(bytes) -} - -fun CompoundTag.getDecimal(key: String) = Decimal.deserializeNBT(this[key]) -fun CompoundTag.putDecimal(key: String, value: Decimal) = put(key, value.serializeNBT()) - -operator fun CompoundTag.set(key: String, value: Decimal) = putDecimal(key, value) - fun Float.toDecimal() = Decimal(this) fun Double.toDecimal() = Decimal(this) fun Int.toDecimal() = Decimal(this) @@ -1633,60 +1604,6 @@ fun Short.toDecimal() = Decimal(this) fun Long.toDecimal() = Decimal(this) fun Decimal.toDecimal() = this -class DecimalConfigValue( - parent: ModConfigSpec.ConfigValue, - val minimum: Decimal? = null, - val maximum: Decimal? = null, -) : ObservedConfigValue(parent) { - override fun fromString(value: String): Decimal? { - try { - val parsed = Decimal(value) - - if (minimum != null && minimum > parsed) { - return minimum - } else if (maximum != null && maximum < parsed) { - return maximum - } - - return parsed - } catch (err: java.lang.NumberFormatException) { - return null - } - } - - override fun toString(value: Decimal): Pair { - if (minimum != null && minimum > value) { - return minimum.toString() to minimum - } else if (maximum != null && maximum < value) { - return maximum.toString() to maximum - } - - return value.toString() to value - } -} - -private fun ModConfigSpec.Builder.commentRange(minimum: Decimal?, maximum: Decimal?) { - if (minimum != null && maximum != null) { - comment("Range: $minimum ~ $maximum") - } else if (minimum != null) { - comment("Range: >= $minimum") - } else if (maximum != null) { - comment("Range: <= $maximum") - } -} - -fun ModConfigSpec.Builder.defineDecimal(path: String, defaultValue: Decimal, minimum: Decimal? = null, maximum: Decimal? = null): DecimalConfigValue { - commentRange(minimum, maximum) - comment("Default: $defaultValue") - return DecimalConfigValue(define(path, defaultValue.toString()), minimum, maximum) -} - -fun ModConfigSpec.Builder.defineDecimal(path: List, defaultValue: Decimal, minimum: Decimal? = null, maximum: Decimal? = null): DecimalConfigValue { - commentRange(minimum, maximum) - comment("Default: $defaultValue") - return DecimalConfigValue(define(path, defaultValue.toString()), minimum, maximum) -} - fun RandomSource.nextDecimal(min: Decimal, max: Decimal, round: Boolean = false): Decimal { val value = nextDouble() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/nbt/CompoundTagExt.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/nbt/CompoundTagExt.kt index 9387c88e2..6521c0cda 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/nbt/CompoundTagExt.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/nbt/CompoundTagExt.kt @@ -20,6 +20,7 @@ import net.minecraft.nbt.ShortTag import net.minecraft.nbt.StringTag import net.minecraft.nbt.Tag import net.minecraft.world.item.ItemStack +import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.util.readBinaryJson import ru.dbotthepony.mc.otm.core.util.writeBinaryJson import java.util.UUID @@ -115,3 +116,7 @@ fun CompoundTag.getJson(key: String, sizeLimit: NbtAccounter = NbtAccounter(1 sh fun CompoundTag.getBoolean(index: String, orElse: Boolean): Boolean { return (this[index] as? NumericTag)?.asInt?.let { it > 0 } ?: orElse } + +fun CompoundTag.getDecimal(key: String) = Decimal.deserializeNBT(this[key]) +fun CompoundTag.putDecimal(key: String, value: Decimal) = put(key, value.serializeNBT()) +operator fun CompoundTag.set(key: String, value: Decimal) = putDecimal(key, value) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/FriendlyStreams.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/FriendlyStreams.kt index c1aa44fc4..a97d9f517 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/FriendlyStreams.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/FriendlyStreams.kt @@ -5,12 +5,14 @@ import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.NbtAccounter import net.minecraft.nbt.NbtIo +import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.chat.Component import net.minecraft.resources.ResourceLocation import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import net.minecraft.world.level.material.Fluid import net.neoforged.neoforge.fluids.FluidStack +import ru.dbotthepony.mc.otm.core.math.Decimal import java.io.* import java.math.BigDecimal import java.math.BigInteger @@ -238,3 +240,20 @@ fun OutputStream.writeBinaryString(input: String) { writeVarIntLE(bytes.size) write(bytes) } + +fun FriendlyByteBuf.readDecimal() = Decimal.read(this) +fun FriendlyByteBuf.writeDecimal(value: Decimal) = value.write(this) + +fun InputStream.readDecimal(): Decimal { + val size = readVarIntLE() + require(size >= 0) { "Negative payload size: $size" } + val bytes = ByteArray(size) + read(bytes) + return Decimal.fromByteArray(bytes) +} + +fun OutputStream.writeDecimal(value: Decimal) { + val bytes = value.toByteArray() + writeVarIntLE(bytes.size) + write(bytes) +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/FlywheelMaterials.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/FlywheelMaterials.kt index c2cbf6141..50388d03a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/data/FlywheelMaterials.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/data/FlywheelMaterials.kt @@ -38,8 +38,8 @@ import ru.dbotthepony.mc.otm.core.ResourceLocation import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.math.readDecimal -import ru.dbotthepony.mc.otm.core.math.writeDecimal +import ru.dbotthepony.mc.otm.core.util.readDecimal +import ru.dbotthepony.mc.otm.core.util.writeDecimal import ru.dbotthepony.mc.otm.core.readBlockType import ru.dbotthepony.mc.otm.core.registryName import ru.dbotthepony.mc.otm.core.util.formatPower diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/QuantumBatteryItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/QuantumBatteryItem.kt index 5e2ba1f97..270b8ab3f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/QuantumBatteryItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/QuantumBatteryItem.kt @@ -38,11 +38,10 @@ import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.collect.filter import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.math.getDecimal -import ru.dbotthepony.mc.otm.core.math.readDecimal -import ru.dbotthepony.mc.otm.core.math.set -import ru.dbotthepony.mc.otm.core.math.writeDecimal +import ru.dbotthepony.mc.otm.core.nbt.getDecimal +import ru.dbotthepony.mc.otm.core.util.readDecimal import ru.dbotthepony.mc.otm.core.nbt.set +import ru.dbotthepony.mc.otm.core.util.writeDecimal import ru.dbotthepony.mc.otm.core.nextUUID import ru.dbotthepony.mc.otm.core.util.formatPower import ru.dbotthepony.mc.otm.isClientThread diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/EnergySwordItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/EnergySwordItem.kt index 666ffbac2..d9a00fd6b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/EnergySwordItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/EnergySwordItem.kt @@ -29,8 +29,8 @@ import ru.dbotthepony.mc.otm.player.matteryPlayer import ru.dbotthepony.mc.otm.core.ResourceLocation import ru.dbotthepony.mc.otm.core.damageType import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue -import ru.dbotthepony.mc.otm.core.math.defineDecimal +import ru.dbotthepony.mc.otm.config.DecimalConfigValue +import ru.dbotthepony.mc.otm.config.defineDecimal import ru.dbotthepony.mc.otm.core.math.nextVariance import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.core.util.WriteOnce diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/FallingSunItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/FallingSunItem.kt index d4f636c9e..0f3351298 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/FallingSunItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/FallingSunItem.kt @@ -29,8 +29,8 @@ import ru.dbotthepony.mc.otm.player.matteryPlayer import ru.dbotthepony.mc.otm.core.ResourceLocation import ru.dbotthepony.mc.otm.core.damageType import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.math.DecimalConfigValue -import ru.dbotthepony.mc.otm.core.math.defineDecimal +import ru.dbotthepony.mc.otm.config.DecimalConfigValue +import ru.dbotthepony.mc.otm.config.defineDecimal import ru.dbotthepony.mc.otm.core.math.nextVariance import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.core.util.WriteOnce diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/IMatterValue.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/IMatterValue.kt index 17fa4e5c2..5c87223a9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/matter/IMatterValue.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/matter/IMatterValue.kt @@ -2,8 +2,8 @@ package ru.dbotthepony.mc.otm.matter import net.minecraft.network.FriendlyByteBuf import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.math.readDecimal -import ru.dbotthepony.mc.otm.core.math.writeDecimal +import ru.dbotthepony.mc.otm.core.util.readDecimal +import ru.dbotthepony.mc.otm.core.util.writeDecimal import ru.dbotthepony.mc.otm.core.util.readDouble import ru.dbotthepony.mc.otm.core.util.writeDouble import java.io.InputStream diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt index 1e0b59ff9..8fffdd713 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt @@ -9,8 +9,8 @@ import net.minecraft.resources.ResourceLocation import net.minecraft.world.level.block.Block import net.minecraft.world.level.block.state.BlockState import ru.dbotthepony.kommons.math.RGBAColor -import ru.dbotthepony.mc.otm.core.math.readDecimal -import ru.dbotthepony.mc.otm.core.math.writeDecimal +import ru.dbotthepony.mc.otm.core.util.readDecimal +import ru.dbotthepony.mc.otm.core.util.writeDecimal import ru.dbotthepony.mc.otm.core.readBlockType import ru.dbotthepony.mc.otm.core.readItemType import ru.dbotthepony.mc.otm.core.writeBlockType diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryFoodData.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryFoodData.kt index 9f442d2df..cc547f8e6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryFoodData.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryFoodData.kt @@ -14,8 +14,7 @@ import ru.dbotthepony.mc.otm.config.IFoodRegenerationValues import ru.dbotthepony.mc.otm.config.PlayerConfig import ru.dbotthepony.mc.otm.core.damageType import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.math.getDecimal -import ru.dbotthepony.mc.otm.core.math.set +import ru.dbotthepony.mc.otm.core.nbt.getDecimal import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.registry.MDamageTypes import kotlin.math.max From 5663b262ebebb2b69064fd025922867464593550 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 26 Mar 2025 19:34:22 +0700 Subject: [PATCH 129/154] Move random extensions to RandomUtils file --- .../kotlin/ru/dbotthepony/mc/otm/core/Ext.kt | 97 ----------------- .../ru/dbotthepony/mc/otm/core/RandomUtils.kt | 103 ++++++++++++++++++ 2 files changed, 103 insertions(+), 97 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/core/RandomUtils.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt index e1e0b3427..3b1c6b88b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt @@ -10,7 +10,6 @@ import com.google.common.collect.ImmutableSet import com.google.gson.JsonElement import com.google.gson.JsonObject import com.google.gson.JsonPrimitive -import it.unimi.dsi.fastutil.ints.IntList import it.unimi.dsi.fastutil.objects.ObjectComparators import net.minecraft.Util import net.minecraft.core.BlockPos @@ -29,7 +28,6 @@ import net.minecraft.network.chat.contents.TranslatableContents import net.minecraft.resources.ResourceKey import net.minecraft.resources.ResourceLocation import net.minecraft.tags.TagKey -import net.minecraft.util.RandomSource import net.minecraft.world.entity.Entity import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack @@ -65,13 +63,10 @@ import java.util.concurrent.Callable import java.util.concurrent.Future import java.util.function.Consumer import java.util.function.Supplier -import java.util.random.RandomGenerator import java.util.stream.Stream import java.util.stream.StreamSupport import kotlin.NoSuchElementException import kotlin.jvm.optionals.getOrNull -import kotlin.math.ln -import kotlin.math.sqrt import kotlin.reflect.KProperty operator fun RecipeInput.get(index: Int): ItemStack = getItem(index) @@ -189,43 +184,6 @@ fun > T.prev(values: Array): T { return values[next] } -fun IntArray.shuffle(random: RandomSource): IntArray { - for (i in lastIndex downTo 1) { - val j = random.nextInt(i + 1) - val copy = this[i] - this[i] = this[j] - this[j] = copy - } - - return this -} - -fun L.shuffle(random: RandomSource): L { - for (i in lastIndex downTo 1) { - val j = random.nextInt(i + 1) - set(j, set(i, getInt(j))) - } - - return this -} - -fun > L.shuffle(random: RandomSource): L { - Util.shuffle(this, random) - return this -} - -fun List.random(random: RandomGenerator): T { - if (isEmpty()) - throw NoSuchElementException("This list is empty") - return get(random.nextInt(size)) -} - -fun List.random(random: RandomSource): T { - if (isEmpty()) - throw NoSuchElementException("This list is empty") - return get(random.nextInt(size)) -} - inline fun immutableList(size: Int, initializer: (index: Int) -> T): ImmutableList { require(size >= 0) { "Invalid list size $size" } @@ -635,58 +593,3 @@ infix fun FluidStack.isNotSameAs(other: FluidStack): Boolean { return !FluidStack.isSameFluidSameComponents(this, other) && amount == other.amount } -data class DoublePair(val first: Double, val second: Double) - -fun RandomSource.nextUUID(): UUID { - return UUID(nextLong(), nextLong()) -} - -// normal distribution via Marsaglia polar method -fun RandomGenerator.nextNormalDoubles(stddev: Double, mean: Double): DoublePair { - var rand1: Double - var rand2: Double - var distSqr: Double - - do { - rand1 = 2.0 * nextDouble() - 1.0 - rand2 = 2.0 * nextDouble() - 1.0 - distSqr = rand1 * rand1 + rand2 * rand2 - } while (distSqr >= 1.0 || distSqr == 0.0) - - val mapping = sqrt(-2.0 * ln(distSqr) / distSqr) - - return DoublePair( - rand1 * mapping * stddev + mean, - rand2 * mapping * stddev + mean - ) -} - -// All Mojang's random sources use MarsagliaPolarGaussian for generating normal distributed doubles -fun RandomSource.nextNormalDoubles(stddev: Double, mean: Double): DoublePair { - return DoublePair( - nextGaussian() * stddev + mean, - nextGaussian() * stddev + mean - ) -} - -fun RandomSource.nextNormalDouble(stddev: Double, mean: Double): Double { - return nextGaussian() * stddev + mean -} - -fun RandomSource.nextFloat(min: Float, max: Float): Float { - if (this is RandomGenerator) - return nextFloat(min, max) - - require(max >= min) { "Min is bigger than max: $min vs $max" } - if (min == max) return min - return min + nextFloat() * (max - min) -} - -fun RandomSource.nextDouble(min: Double, max: Double): Double { - if (this is RandomGenerator) - return nextDouble(min, max) - - require(max >= min) { "Min is bigger than max: $min vs $max" } - if (min == max) return min - return min + nextDouble() * (max - min) -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/RandomUtils.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/RandomUtils.kt new file mode 100644 index 000000000..a042c8d08 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/RandomUtils.kt @@ -0,0 +1,103 @@ +package ru.dbotthepony.mc.otm.core + +import it.unimi.dsi.fastutil.ints.IntList +import net.minecraft.Util +import net.minecraft.util.RandomSource +import java.util.* +import java.util.random.RandomGenerator +import kotlin.NoSuchElementException +import kotlin.math.ln +import kotlin.math.sqrt + +data class DoublePair(val first: Double, val second: Double) + +fun RandomSource.nextUUID(): UUID { + return UUID(nextLong(), nextLong()) +} + +// normal distribution via Marsaglia polar method +fun RandomGenerator.nextNormalDoubles(stddev: Double, mean: Double): DoublePair { + var rand1: Double + var rand2: Double + var distSqr: Double + + do { + rand1 = 2.0 * nextDouble() - 1.0 + rand2 = 2.0 * nextDouble() - 1.0 + distSqr = rand1 * rand1 + rand2 * rand2 + } while (distSqr >= 1.0 || distSqr == 0.0) + + val mapping = sqrt(-2.0 * ln(distSqr) / distSqr) + + return DoublePair( + rand1 * mapping * stddev + mean, + rand2 * mapping * stddev + mean + ) +} + +// All Mojang's random sources use MarsagliaPolarGaussian for generating normal distributed doubles +fun RandomSource.nextNormalDoubles(stddev: Double, mean: Double): DoublePair { + return DoublePair( + nextGaussian() * stddev + mean, + nextGaussian() * stddev + mean + ) +} + +fun RandomSource.nextNormalDouble(stddev: Double, mean: Double): Double { + return nextGaussian() * stddev + mean +} + +fun RandomSource.nextFloat(min: Float, max: Float): Float { + if (this is RandomGenerator) + return nextFloat(min, max) + + require(max >= min) { "Min is bigger than max: $min vs $max" } + if (min == max) return min + return min + nextFloat() * (max - min) +} + +fun RandomSource.nextDouble(min: Double, max: Double): Double { + if (this is RandomGenerator) + return nextDouble(min, max) + + require(max >= min) { "Min is bigger than max: $min vs $max" } + if (min == max) return min + return min + nextDouble() * (max - min) +} + +fun IntArray.shuffle(random: RandomSource): IntArray { + for (i in lastIndex downTo 1) { + val j = random.nextInt(i + 1) + val copy = this[i] + this[i] = this[j] + this[j] = copy + } + + return this +} + +fun L.shuffle(random: RandomSource): L { + for (i in lastIndex downTo 1) { + val j = random.nextInt(i + 1) + set(j, set(i, getInt(j))) + } + + return this +} + +fun > L.shuffle(random: RandomSource): L { + Util.shuffle(this, random) + return this +} + +fun List.random(random: RandomGenerator): T { + if (isEmpty()) + throw NoSuchElementException("This list is empty") + return get(random.nextInt(size)) +} + +fun List.random(random: RandomSource): T { + if (isEmpty()) + throw NoSuchElementException("This list is empty") + return get(random.nextInt(size)) +} From c965bcdc8254169f50919fd9d44a2a1ce1dd910f Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 26 Mar 2025 19:36:52 +0700 Subject: [PATCH 130/154] Move decimal sampling to random utils --- .../ru/dbotthepony/mc/otm/core/RandomUtils.kt | 15 +++++++++++++++ .../ru/dbotthepony/mc/otm/core/math/Decimal.kt | 14 -------------- .../mc/otm/data/world/DecimalProvider.kt | 2 +- .../mc/otm/item/weapon/EnergySwordItem.kt | 2 +- .../mc/otm/item/weapon/FallingSunItem.kt | 2 +- .../mc/otm/worldgen/feature/BlackHolePlacer.kt | 3 +-- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/RandomUtils.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/RandomUtils.kt index a042c8d08..62214303e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/RandomUtils.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/RandomUtils.kt @@ -3,6 +3,7 @@ package ru.dbotthepony.mc.otm.core import it.unimi.dsi.fastutil.ints.IntList import net.minecraft.Util import net.minecraft.util.RandomSource +import ru.dbotthepony.mc.otm.core.math.Decimal import java.util.* import java.util.random.RandomGenerator import kotlin.NoSuchElementException @@ -101,3 +102,17 @@ fun List.random(random: RandomSource): T { throw NoSuchElementException("This list is empty") return get(random.nextInt(size)) } + +fun RandomSource.nextDecimal(min: Decimal, max: Decimal, round: Boolean = false): Decimal { + val value = nextDouble() + + return if (round) { + Decimal((min + (max - min) * value).whole) + } else { + min + (max - min) * value + } +} + +fun RandomSource.nextVariance(value: Decimal, round: Boolean = false): Decimal { + return nextDecimal(-value / 2, value / 2, round) +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt index 18f0bb4e4..0a85c870a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt @@ -4,7 +4,6 @@ import net.minecraft.nbt.ByteArrayTag import net.minecraft.nbt.StringTag import net.minecraft.nbt.Tag import net.minecraft.network.FriendlyByteBuf -import net.minecraft.util.RandomSource import java.math.BigDecimal import java.math.BigInteger import java.math.MathContext @@ -1604,16 +1603,3 @@ fun Short.toDecimal() = Decimal(this) fun Long.toDecimal() = Decimal(this) fun Decimal.toDecimal() = this -fun RandomSource.nextDecimal(min: Decimal, max: Decimal, round: Boolean = false): Decimal { - val value = nextDouble() - - return if (round) { - Decimal((min + (max - min) * value).whole) - } else { - min + (max - min) * value - } -} - -fun RandomSource.nextVariance(value: Decimal, round: Boolean = false): Decimal { - return nextDecimal(-value / 2, value / 2, round) -} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/data/world/DecimalProvider.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/data/world/DecimalProvider.kt index 67a993e4e..fc733d3f3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/data/world/DecimalProvider.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/data/world/DecimalProvider.kt @@ -8,7 +8,7 @@ import net.minecraft.util.RandomSource import net.neoforged.bus.api.IEventBus import ru.dbotthepony.mc.otm.OverdriveThatMatters import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.math.nextDecimal +import ru.dbotthepony.mc.otm.core.nextDecimal import ru.dbotthepony.mc.otm.data.codec.DecimalCodec import ru.dbotthepony.mc.otm.registry.MBuiltInRegistries import ru.dbotthepony.mc.otm.registry.MDeferredRegister diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/EnergySwordItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/EnergySwordItem.kt index d9a00fd6b..bf4d16672 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/EnergySwordItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/EnergySwordItem.kt @@ -31,7 +31,7 @@ import ru.dbotthepony.mc.otm.core.damageType import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.config.DecimalConfigValue import ru.dbotthepony.mc.otm.config.defineDecimal -import ru.dbotthepony.mc.otm.core.math.nextVariance +import ru.dbotthepony.mc.otm.core.nextVariance import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.core.util.WriteOnce import ru.dbotthepony.mc.otm.item.MatteryItem diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/FallingSunItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/FallingSunItem.kt index 0f3351298..0b7042e3b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/FallingSunItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/FallingSunItem.kt @@ -31,7 +31,7 @@ import ru.dbotthepony.mc.otm.core.damageType import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.config.DecimalConfigValue import ru.dbotthepony.mc.otm.config.defineDecimal -import ru.dbotthepony.mc.otm.core.math.nextVariance +import ru.dbotthepony.mc.otm.core.nextVariance import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.core.util.WriteOnce import ru.dbotthepony.mc.otm.item.MatteryItem diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/feature/BlackHolePlacer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/feature/BlackHolePlacer.kt index 102d3eccf..9a687d100 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/feature/BlackHolePlacer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/worldgen/feature/BlackHolePlacer.kt @@ -1,6 +1,5 @@ package ru.dbotthepony.mc.otm.worldgen.feature -import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder import net.minecraft.world.level.levelgen.feature.Feature import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext @@ -8,7 +7,7 @@ import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfigur import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleBlockEntity import ru.dbotthepony.mc.otm.config.ServerConfig import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.math.nextDecimal +import ru.dbotthepony.mc.otm.core.nextDecimal import ru.dbotthepony.mc.otm.data.codec.DecimalCodec import ru.dbotthepony.mc.otm.registry.game.MBlocks From 1087e755ff46a5ba7ce66f1db6808afde18594b4 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 26 Mar 2025 22:06:39 +0700 Subject: [PATCH 131/154] And now, proper random decimals implementation --- .../ru/dbotthepony/mc/otm/core/RandomUtils.kt | 117 ++++++++++++++++-- .../dbotthepony/mc/otm/core/math/Decimal.kt | 13 +- 2 files changed, 122 insertions(+), 8 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/RandomUtils.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/RandomUtils.kt index 62214303e..38dd8b17e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/RandomUtils.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/RandomUtils.kt @@ -4,9 +4,10 @@ import it.unimi.dsi.fastutil.ints.IntList import net.minecraft.Util import net.minecraft.util.RandomSource import ru.dbotthepony.mc.otm.core.math.Decimal +import java.math.BigInteger import java.util.* import java.util.random.RandomGenerator -import kotlin.NoSuchElementException +import kotlin.experimental.and import kotlin.math.ln import kotlin.math.sqrt @@ -103,14 +104,116 @@ fun List.random(random: RandomSource): T { return get(random.nextInt(size)) } -fun RandomSource.nextDecimal(min: Decimal, max: Decimal, round: Boolean = false): Decimal { - val value = nextDouble() +class RandomByteSource(private val source: RandomSource) { + private val bytes = ByteArray(8) + private var i = 7 - return if (round) { - Decimal((min + (max - min) * value).whole) - } else { - min + (max - min) * value + fun next(): Byte { + if (++i == 8) { + i = 0 + + var generate = source.nextLong() + + for (i in 0 .. 7) { + bytes[i] = generate.toByte() + generate = generate ushr 8 + } + } + + return bytes[i] } + + fun next(bound: Int): Byte { + require(bound > 0) { "Bound must be positive" } + val m = bound - 1 + var r = next().toInt().and(0xFF) + + if (bound and m == 0) { + r = r and m + } else { + var u = r ushr 1 + + while (true) { + r = u % bound + + if (u + m - r < 0) { + u = next().toInt().and(0xFF).ushr(1) + } else { + break + } + } + } + + return r.toByte() + } + + fun next(bytes: ByteArray) { + for (i in bytes.indices) { + bytes[i] = next() + } + } +} + +/** + * Uniformely distributed [Decimal] value on [0,[bound]) range + * + * If [round] is `true`, will only return integers + */ +fun RandomSource.nextDecimal(bound: Decimal, round: Boolean = false): Decimal { + if (round) + require(bound > Decimal.ZERO) { "Bound must be positive, $bound given" } + else + require(bound >= Decimal.ONE) { "Bound must be 1 or bigger, $bound given" } + + require(bound.isFinite) { "Bound must be finite" } + + val bytes = RandomByteSource(this) + + if (round) { + val thisBytes = bound.whole.toByteArray() + val generateBytes = ByteArray(thisBytes.size) + bytes.next(generateBytes) + + generateBytes[0] = generateBytes[0].and(127) + + if (generateBytes[0] >= thisBytes[0]) { + generateBytes[0] = bytes.next(thisBytes[0].toInt().and(127)) + } + + return Decimal(BigInteger(generateBytes)) + } else { + val thisBytes = bound.mag.toByteArray() + val generateBytes = ByteArray(thisBytes.size) + bytes.next(generateBytes) + + generateBytes[0] = generateBytes[0].and(127) + + if (generateBytes[0] >= thisBytes[0]) { + generateBytes[0] = bytes.next(thisBytes[0].toInt().and(127)) + } + + return Decimal.raw(BigInteger(generateBytes)) + } +} + +/** + * Uniformely distributed [Decimal] value on [[origin],[bound]) range + * + * If [round] is `true`, will only return integers + */ +fun RandomSource.nextDecimal(origin: Decimal, bound: Decimal, round: Boolean = false): Decimal { + require(origin < bound) { "Origin must be less than bound: $origin < $bound" } + require(origin.isFinite) { "Origin must be finite" } + require(bound.isFinite) { "Bound must be finite" } + + return origin + nextDecimal(bound - origin, round) +} + +/** + * Uniformely distributed [Decimal] value on [0,1) range + */ +fun RandomSource.nextDecimal(): Decimal { + return nextDecimal(Decimal.ZERO, Decimal.ONE) } fun RandomSource.nextVariance(value: Decimal, round: Boolean = false): Decimal { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt index 0a85c870a..284cb53be 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt @@ -39,6 +39,8 @@ sealed class Decimal : Number(), Comparable { */ abstract val fractional: BigInteger + abstract internal val mag: BigInteger + /** * *Signed* normalized (-1,1) fractional part of this Decimal, as [Float] */ @@ -181,7 +183,7 @@ sealed class Decimal : Number(), Comparable { return toBigDecmial().divide(divisor.toBigDecmial(), PERCENTAGE_CONTEXT).toFloat() } - private class Regular(val mag: BigInteger, marker: Nothing?) : Decimal() { + private class Regular(override val mag: BigInteger, marker: Nothing?) : Decimal() { constructor(value: BigInteger) : this(value * PRECISION_POW_BI, null) constructor(value: BigDecimal) : this(value.setScale(PRECISION, RoundingMode.HALF_UP).unscaledValue(), null) constructor(value: Float) : this(BigDecimal.valueOf(value.toDouble())) @@ -703,6 +705,9 @@ sealed class Decimal : Number(), Comparable { } private object PositiveInfinity : Decimal() { + override val mag: BigInteger + get() = throw UnsupportedOperationException() + private fun readResolve(): Any = PositiveInfinity override val isInfinite: Boolean @@ -952,6 +957,9 @@ sealed class Decimal : Number(), Comparable { } private object NegativeInfinity : Decimal() { + override val mag: BigInteger + get() = throw UnsupportedOperationException() + private fun readResolve(): Any = NegativeInfinity override val isInfinite: Boolean @@ -1195,6 +1203,9 @@ sealed class Decimal : Number(), Comparable { } private object Zero : Decimal() { + override val mag: BigInteger + get() = BigInteger.ZERO + private fun readResolve(): Any = Zero override val isInfinite: Boolean From a3ed8869009118ac10e9f697ce8f2cb295aa0ad7 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 26 Mar 2025 22:11:37 +0700 Subject: [PATCH 132/154] Fix wrong matter recycler receive values --- .../otm/block/entity/matter/MatterRecyclerBlockEntity.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt index ce4f69727..f87ee9707 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterRecyclerBlockEntity.kt @@ -24,6 +24,7 @@ import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.container.MatteryContainer import ru.dbotthepony.mc.otm.container.HandlerFilter import ru.dbotthepony.mc.otm.core.math.Decimal +import ru.dbotthepony.mc.otm.core.nextDecimal import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.graph.matter.MatterGraph import ru.dbotthepony.mc.otm.item.matter.MatterDustItem @@ -137,7 +138,7 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) else if (matter.receiveMatter(toReceive, true) != toReceive) return status.noMatter() - matter.receiveMatter(toReceive * 0.4 + level!!.otmRandom.nextDouble() * 0.6, false) + matter.receiveMatter(toReceive * level!!.otmRandom.nextDecimal(BASE_RECEIVE, Decimal.ONE), false) job.totalMatter -= toReceive } @@ -151,4 +152,8 @@ class MatterRecyclerBlockEntity(blockPos: BlockPos, blockState: BlockState) matter.extractMatter(received, false) } } + + companion object { + private val BASE_RECEIVE = Decimal("0.4") + } } From 140bdab59c5c909f9cb0497e308600b04d5216ec Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 26 Mar 2025 22:21:02 +0700 Subject: [PATCH 133/154] Fix swapped out condition checks in nextDecimal --- src/main/kotlin/ru/dbotthepony/mc/otm/core/RandomUtils.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/RandomUtils.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/RandomUtils.kt index 38dd8b17e..cf7da7c9a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/RandomUtils.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/RandomUtils.kt @@ -161,9 +161,9 @@ class RandomByteSource(private val source: RandomSource) { */ fun RandomSource.nextDecimal(bound: Decimal, round: Boolean = false): Decimal { if (round) - require(bound > Decimal.ZERO) { "Bound must be positive, $bound given" } - else require(bound >= Decimal.ONE) { "Bound must be 1 or bigger, $bound given" } + else + require(bound > Decimal.ZERO) { "Bound must be positive, $bound given" } require(bound.isFinite) { "Bound must be finite" } From 750f94152586f868a59e02c87dcb6d2accf228a7 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 26 Mar 2025 22:38:02 +0700 Subject: [PATCH 134/154] Optimize matter capacitor bank --- .../matter/MatterCapacitorBankBlockEntity.kt | 69 +++++++++---------- 1 file changed, 33 insertions(+), 36 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt index 60f2383a9..96f2b418d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt @@ -39,10 +39,9 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) var summ = Decimal.ZERO for (stack in container) - if (!stack.isEmpty) - stack.getCapability(MatteryCapability.MATTER_ITEM)?.let { - summ += it.storedMatter - } + stack.getCapability(MatteryCapability.MATTER_ITEM)?.let { + summ += it.storedMatter + } return summ } @@ -50,19 +49,31 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) throw UnsupportedOperationException() } - override val maxStoredMatter: Decimal - get() { + override val maxStoredMatter: Decimal get() { var summ = Decimal.ZERO for (stack in container) - if (!stack.isEmpty) - stack.getCapability(MatteryCapability.MATTER_ITEM)?.let { - summ += it.maxStoredMatter - } + stack.getCapability(MatteryCapability.MATTER_ITEM)?.let { + summ += it.maxStoredMatter + } return summ } + override fun tick() { + super.tick() + var stored = Decimal.ZERO + var maxStored = Decimal.ZERO + + for (stack in container) { + val cap = stack.getCapability(MatteryCapability.MATTER_ITEM) ?: continue + stored += cap.storedMatter + maxStored += cap.maxStoredMatter + } + + gaugeLevel = stored.percentage(maxStored) + } + override fun receiveMatter(howMuch: Decimal, simulate: Boolean): Decimal { if (!howMuch.isPositive) return Decimal.ZERO @@ -72,23 +83,16 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) var summ = Decimal.ZERO for (stack in container) { - if (!stack.isEmpty) { - stack.getCapability(MatteryCapability.MATTER_ITEM)?.let { - val diff = it.receiveMatterChecked(howMuch, simulate) - summ += diff - howMuch -= diff - } + val it = stack.getCapability(MatteryCapability.MATTER_ITEM) ?: continue + val diff = it.receiveMatterChecked(howMuch, simulate) + summ += diff + howMuch -= diff - if (howMuch.isZero) { - break - } + if (howMuch.isZero) { + break } } - if (summ.isPositive && !simulate) { - gaugeLevel = storedMatter.percentage(maxStoredMatter) - } - return summ } @@ -101,23 +105,16 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) var summ = Decimal.ZERO for (stack in container) { - if (!stack.isEmpty) { - stack.getCapability(MatteryCapability.MATTER_ITEM)?.let { - val diff = it.extractMatterChecked(howMuch, simulate) - summ += diff - howMuch -= diff - } + val it = stack.getCapability(MatteryCapability.MATTER_ITEM) ?: continue + val diff = it.extractMatterChecked(howMuch, simulate) + summ += diff + howMuch -= diff - if (howMuch.isZero) { - break - } + if (howMuch.isZero) { + break } } - if (summ.isPositive && !simulate) { - gaugeLevel = storedMatter.percentage(maxStoredMatter) - } - return summ } From 5281a5aeee5229ab9be1459a43a1e5420ddade09 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 26 Mar 2025 22:38:18 +0700 Subject: [PATCH 135/154] Remove jvm overloads from matter capacitor bank menu --- .../dbotthepony/mc/otm/menu/matter/MatterCapacitorBankMenu.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterCapacitorBankMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterCapacitorBankMenu.kt index e820a9f62..1d76d930d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterCapacitorBankMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/matter/MatterCapacitorBankMenu.kt @@ -12,7 +12,7 @@ import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.registry.game.MMenus -class MatterCapacitorBankMenu @JvmOverloads constructor( +class MatterCapacitorBankMenu( p_38852_: Int, inventory: Inventory, tile: MatterCapacitorBankBlockEntity? = null From a26840f6705a0419206da372216c2447a49ce784 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 26 Mar 2025 22:38:27 +0700 Subject: [PATCH 136/154] sumOfDecimal --- .../ru/dbotthepony/mc/otm/core/collect/Iterables.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/Iterables.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/Iterables.kt index 4c1a23635..3b73cab8a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/Iterables.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/collect/Iterables.kt @@ -4,6 +4,7 @@ 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.IntSortedSet +import ru.dbotthepony.mc.otm.core.math.Decimal fun IntRange.asIterable(): IntIterable { return IntIterable { @@ -52,3 +53,15 @@ fun IntSortedSet.ktIterator(fromElement: Int): kotlin.collections.IntIterator { } } } + +inline fun Iterable.sumOfDecimal(selector: (T) -> Decimal): Decimal { + var result = Decimal.ZERO + forEach { result += selector(it) } + return result +} + +inline fun Iterator.sumOfDecimal(selector: (T) -> Decimal): Decimal { + var result = Decimal.ZERO + forEach { result += selector(it) } + return result +} From 39a996f79f663c07de4b2830995d9abf55bcde4d Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 26 Mar 2025 22:40:44 +0700 Subject: [PATCH 137/154] Fix matter capacitor bank not marking chunks as dirty --- .../block/entity/matter/MatterCapacitorBankBlockEntity.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt index 96f2b418d..1e437404a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt @@ -93,6 +93,10 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) } } + if (!simulate && !summ.isZero) { + markDirtyFast() + } + return summ } @@ -115,6 +119,10 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) } } + if (!simulate && !summ.isZero) { + markDirtyFast() + } + return summ } From 4d51ed5210ef9b739f97bcb0cba9b6071c2821c7 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 26 Mar 2025 22:46:12 +0700 Subject: [PATCH 138/154] Optimize battery bank --- .../entity/tech/BatteryBankBlockEntity.kt | 66 +++++++++++++------ 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/BatteryBankBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/BatteryBankBlockEntity.kt index d50def635..882eea52d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/BatteryBankBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/BatteryBankBlockEntity.kt @@ -1,5 +1,6 @@ package ru.dbotthepony.mc.otm.block.entity.tech +import it.unimi.dsi.fastutil.ints.IntArrayList import net.minecraft.core.BlockPos import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player @@ -12,6 +13,7 @@ import ru.dbotthepony.kommons.util.setValue import ru.dbotthepony.kommons.util.value import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.capability.FlowDirection +import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.energy import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage @@ -19,10 +21,12 @@ import ru.dbotthepony.mc.otm.capability.energyStoredMattery import ru.dbotthepony.mc.otm.capability.matteryEnergy import ru.dbotthepony.mc.otm.capability.maxEnergyStoredMattery import ru.dbotthepony.mc.otm.capability.transcieveEnergy +import ru.dbotthepony.mc.otm.container.slotRange import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.immutableList +import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.core.shuffle @@ -34,6 +38,8 @@ class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte var gaugeLevel by syncher.float() private set + private var containerSlotIndices = IntArray(0) + private inner class Slot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) { override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { return super.canAutomationPlaceItem(itemStack) && itemStack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { it.canExtract() && it.extractEnergy(Int.MAX_VALUE, true) > 0 } == true @@ -47,15 +53,30 @@ class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte super.notifyChanged(old) batteryStatus[slot].value = item.getCapability(Capabilities.EnergyStorage.ITEM) != null - gaugeLevel = batteryLevel.percentage(maxBatteryLevel) + updateGaugeLevel() } override val maxStackSize: Int get() = 1 } + private fun containerUpdated() { + markDirtyFast() + + val newSlots = IntArrayList() + + for (i in 0 until container.containerSize) { + val stack = container[i] + + if (stack.isNotEmpty && stack.energy != null) + newSlots.add(i) + } + + containerSlotIndices = newSlots.toIntArray() + } + // 6 на 2 - val container = SlottedContainer.simple(CAPACITY, ::Slot, ::markDirtyFast).also(::addDroppableContainer) + val container = SlottedContainer.simple(CAPACITY, ::Slot, ::containerUpdated).also(::addDroppableContainer) val batteryStatus = immutableList(CAPACITY) { syncher.boolean(false) } val itemConfig = ConfigurableItemHandler(inputOutput = container) @@ -64,10 +85,26 @@ class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte savetables.stateful(::container, INVENTORY_KEY) } - private val containerSlotIndices = IntArray(CAPACITY) { it } + private fun updateGaugeLevel() { + var stored = Decimal.ZERO + var maxStored = Decimal.ZERO + + for (stack in container) { + val cap = stack.energy ?: continue + stored += cap.energyStoredMattery + maxStored += cap.maxEnergyStoredMattery + } + + gaugeLevel = stored.percentage(maxStored) + } + + override fun tick() { + super.tick() + updateGaugeLevel() + } private fun distributeEnergy(isReceiving: Boolean, howMuch: Decimal, simulate: Boolean): Decimal { - if (!howMuch.isPositive) + if (!howMuch.isPositive || containerSlotIndices.isEmpty()) return Decimal.ZERO containerSlotIndices.shuffle(level!!.otmRandom) @@ -94,7 +131,6 @@ class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte if (!simulate && !summ.isZero) { markDirtyFast() - gaugeLevel = batteryLevel.percentage(maxBatteryLevel) } return summ @@ -118,13 +154,9 @@ class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte get() { var result = Decimal.ZERO - for (i in 0 until container.containerSize) { - val stack = container.getItem(i) - - if (!stack.isEmpty) { - stack.energy?.let { - result += it.energyStoredMattery - } + for (stack in container) { + stack.energy?.let { + result += it.energyStoredMattery } } @@ -138,13 +170,9 @@ class BatteryBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : Matte get() { var result = Decimal.ZERO - for (i in 0 until container.containerSize) { - val stack = container.getItem(i) - - if (!stack.isEmpty) { - stack.energy?.let { - result += it.maxEnergyStoredMattery - } + for (stack in container) { + stack.energy?.let { + result += it.maxEnergyStoredMattery } } From 10421570be767536f21827e5dba2a05b07b58171 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 26 Mar 2025 22:51:42 +0700 Subject: [PATCH 139/154] forgor about gauge updates when container contents changes in matter capacitor bank --- .../matter/MatterCapacitorBankBlockEntity.kt | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt index 1e437404a..40d188eb6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterCapacitorBankBlockEntity.kt @@ -60,8 +60,7 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) return summ } - override fun tick() { - super.tick() + private fun updateGaugeLevel() { var stored = Decimal.ZERO var maxStored = Decimal.ZERO @@ -74,6 +73,11 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) gaugeLevel = stored.percentage(maxStored) } + override fun tick() { + super.tick() + updateGaugeLevel() + } + override fun receiveMatter(howMuch: Decimal, simulate: Boolean): Decimal { if (!howMuch.isPositive) return Decimal.ZERO @@ -134,7 +138,6 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) super.notifyChanged(old) capacitorStatus[slot].value = item.getCapability(MatteryCapability.MATTER_ITEM) != null - gaugeLevel = storedMatter.percentage(maxStoredMatter) } override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { @@ -155,7 +158,12 @@ class MatterCapacitorBankBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) get() = 1 } - val container = SlottedContainer.simple(BatteryBankBlockEntity.CAPACITY, ::Slot, ::markDirtyFast).also(::addDroppableContainer) + private fun containerUpdated() { + markDirtyFast() + updateGaugeLevel() + } + + val container = SlottedContainer.simple(BatteryBankBlockEntity.CAPACITY, ::Slot, ::containerUpdated).also(::addDroppableContainer) val itemConfig = ConfigurableItemHandler(inputOutput = container) val capacitorStatus = immutableList(BatteryBankBlockEntity.CAPACITY) { From af24f391df9e9215b9fe9c15c84e65c8d339d879 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Wed, 26 Mar 2025 23:00:18 +0700 Subject: [PATCH 140/154] Fix blocks without menu still behaving like being interacted with clientside --- .../ru/dbotthepony/mc/otm/block/MatteryBlock.kt | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/MatteryBlock.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/MatteryBlock.kt index cc5bd8684..ffe8b684a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/MatteryBlock.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/MatteryBlock.kt @@ -16,7 +16,6 @@ import net.minecraft.network.chat.Component import net.minecraft.network.chat.ComponentSerialization import net.minecraft.server.level.ServerLevel import net.minecraft.util.RandomSource -import net.minecraft.world.Containers import net.minecraft.world.InteractionResult import net.minecraft.world.MenuProvider import net.minecraft.world.entity.LivingEntity @@ -36,8 +35,6 @@ import net.minecraft.world.phys.shapes.VoxelShape import org.apache.logging.log4j.LogManager import ru.dbotthepony.mc.otm.block.entity.IRedstoneControlled import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity -import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity -import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity.Companion import ru.dbotthepony.mc.otm.block.entity.WorkerState import ru.dbotthepony.mc.otm.core.TooltipList import ru.dbotthepony.mc.otm.core.TranslatableComponent @@ -149,6 +146,9 @@ open class MatteryBlock(properties: Properties = DEFAULT_PROPERTIES) : Block(pro return getShapeForEachState(ArrayList(stateDefinition.properties), mapper) } + protected open val neverOpensAMenu: Boolean + get() = false + override fun useWithoutItem( blockState: BlockState, level: Level, @@ -156,18 +156,17 @@ open class MatteryBlock(properties: Properties = DEFAULT_PROPERTIES) : Block(pro ply: Player, blockHitResult: BlockHitResult ): InteractionResult { - if (this is EntityBlock && !level.isClientSide) { + if (!neverOpensAMenu && this is EntityBlock) { val tile = level.getBlockEntity(blockPos) if (tile is MenuProvider) { - ply.openMenu(tile) - return InteractionResult.CONSUME + if (!level.isClientSide) + ply.openMenu(tile) + + return InteractionResult.sidedSuccess(level.isClientSide) } } - if (this is EntityBlock && level.isClientSide) - return InteractionResult.SUCCESS - return super.useWithoutItem(blockState, level, blockPos, ply, blockHitResult) } From 3e593748f7f5c58056678d4bd141635c7bf8fe69 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 27 Mar 2025 07:17:28 +0700 Subject: [PATCH 141/154] Remove dummy filtered slot implementation since it is no longer required --- .../dbotthepony/mc/otm/container/IFilteredContainerSlot.kt | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt index 1a6c6f250..11bb4c44a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt @@ -25,11 +25,4 @@ interface IFilteredContainerSlot : IContainerSlot { return filter === item } } - - @Deprecated("Dummy implementation") - class Dummy(parent: IContainerSlot) : IFilteredContainerSlot, IContainerSlot by parent { - override var filter: Item? - get() = null - set(value) {} - } } From 78fad5d3cca41b99e72cca37f84c4e1ca0235100 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 29 Mar 2025 10:55:32 +0700 Subject: [PATCH 142/154] Initial implementation for improved item filters --- .../mc/otm/OverdriveThatMatters.kt | 2 + .../matter/MatterEntanglerBlockEntity.kt | 8 +- .../entity/storage/StorageBusBlockEntity.kt | 10 +- .../block/entity/storage/StorageInterfaces.kt | 14 +- .../tech/AbstractPoweredFurnaceBlockEntity.kt | 4 +- .../entity/tech/PlatePressBlockEntity.kt | 7 +- .../ru/dbotthepony/mc/otm/capability/Ext.kt | 10 +- .../screen/panels/slot/FilterSlotPanel.kt | 22 +- .../client/screen/panels/slot/SlotPanel.kt | 58 +++- .../panels/slot/UserFilteredSlotPanel.kt | 13 +- .../screen/storage/DriveViewerScreen.kt | 6 +- .../storage/StorageImporterExporterScreen.kt | 12 - .../mc/otm/container/ContainerHelpers.kt | 6 +- .../mc/otm/container/IEnhancedContainer.kt | 8 +- .../IFilteredAutomatedContainerSlot.kt | 4 +- .../otm/container/IFilteredContainerSlot.kt | 25 +- .../mc/otm/container/ItemFilter.kt | 277 +++++++++++------- .../mc/otm/container/ItemFilterSet.kt | 130 ++++++++ .../{core/util => container}/ItemStackKey.kt | 38 ++- .../slotted/FilteredContainerSlot.kt | 21 +- .../otm/container/slotted/SlottedContainer.kt | 3 +- .../otm/item/PortableCondensationDriveItem.kt | 12 +- .../dbotthepony/mc/otm/menu/QuickMoveInput.kt | 78 +++-- .../ru/dbotthepony/mc/otm/menu/Slots.kt | 70 +---- .../mc/otm/menu/input/ItemFilterInput.kt | 39 +++ .../mc/otm/menu/storage/DriveViewerMenu.kt | 23 +- .../mc/otm/menu/storage/StorageBusMenu.kt | 4 +- .../storage/StorageImporterExporterMenu.kt | 4 +- .../mc/otm/network/MatteryPlayerPackets.kt | 2 +- .../mc/otm/network/StreamCodecs.kt | 3 + .../mc/otm/player/ExopackContainer.kt | 7 +- .../mc/otm/player/MatteryPlayer.kt | 7 +- .../mc/otm/player/PlayerInventoryWrapper.kt | 7 +- .../mc/otm/registry/MBuiltInRegistries.kt | 4 + .../mc/otm/registry/MRegistries.kt | 2 + .../otm/registry/game/MDataComponentTypes.kt | 5 +- 36 files changed, 610 insertions(+), 335 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/container/ItemFilterSet.kt rename src/main/kotlin/ru/dbotthepony/mc/otm/{core/util => container}/ItemStackKey.kt (59%) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/menu/input/ItemFilterInput.kt diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt index bf56c3b7f..0d99c1660 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt @@ -52,6 +52,7 @@ import ru.dbotthepony.mc.otm.config.ItemsConfig import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.config.ServerConfig import ru.dbotthepony.mc.otm.config.ToolsConfig +import ru.dbotthepony.mc.otm.container.ItemFilter import ru.dbotthepony.mc.otm.data.FlywheelMaterials import ru.dbotthepony.mc.otm.data.world.DecimalProvider import ru.dbotthepony.mc.otm.entity.WitheredSkeletonSpawnHandler @@ -141,6 +142,7 @@ object OverdriveThatMatters { AbstractRegistryAction.register(MOD_BUS) IMatterFunction.register(MOD_BUS) + ItemFilter.register(MOD_BUS) MRegistry.initialize(MOD_BUS) MatterManager.initialize(MOD_BUS) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt index 079f70e18..dbdd0e799 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt @@ -1,11 +1,7 @@ package ru.dbotthepony.mc.otm.block.entity.matter -import com.github.benmanes.caffeine.cache.Cache -import com.github.benmanes.caffeine.cache.Caffeine -import com.github.benmanes.caffeine.cache.Scheduler import com.mojang.serialization.Codec import com.mojang.serialization.codecs.RecordCodecBuilder -import net.minecraft.Util import net.minecraft.core.BlockPos import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player @@ -39,8 +35,8 @@ import ru.dbotthepony.mc.otm.core.collect.forEach import ru.dbotthepony.mc.otm.core.collect.map import ru.dbotthepony.mc.otm.core.collect.toList import ru.dbotthepony.mc.otm.core.math.Decimal -import ru.dbotthepony.mc.otm.core.util.ItemStackKey -import ru.dbotthepony.mc.otm.core.util.asKey +import ru.dbotthepony.mc.otm.container.ItemStackKey +import ru.dbotthepony.mc.otm.container.asKey import ru.dbotthepony.mc.otm.data.codec.DecimalCodec import ru.dbotthepony.mc.otm.data.codec.minRange import ru.dbotthepony.mc.otm.graph.matter.MatterNode diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageBusBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageBusBlockEntity.kt index 9430419f0..056d2e832 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageBusBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageBusBlockEntity.kt @@ -23,7 +23,7 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.config.MachinesConfig -import ru.dbotthepony.mc.otm.container.ItemFilter +import ru.dbotthepony.mc.otm.container.ItemFilterSet import ru.dbotthepony.mc.otm.core.* import ru.dbotthepony.mc.otm.core.math.RelativeSide import ru.dbotthepony.mc.otm.core.math.isPositive @@ -123,7 +123,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter }) } - var filter = ItemFilter(MAX_FILTERS) + var filter = ItemFilterSet.EMPTY set(value) { field = value component?.scan() @@ -131,7 +131,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter } init { - savetablesConfig.codec(::filter, ItemFilter.CODEC, FILTER_KEY, Supplier { ItemFilter(MAX_FILTERS) }) + savetablesConfig.codec(::filter, ItemFilterSet.CODEC, FILTER_KEY, Supplier { ItemFilterSet.EMPTY }) } override fun setLevel(level: Level) { @@ -348,7 +348,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter } fun scan(slot: Int) { - val current = parent[slot].let { if (it.isEmpty || !filter.match(it)) null else it } + val current = parent[slot].let { if (it.isEmpty || !filter.test(it)) null else it } val last = slot2itemStack[slot] if (current == null && last != null) { @@ -374,7 +374,7 @@ class StorageBusBlockEntity(blockPos: BlockPos, blockState: BlockState) : Matter } override fun insertStack(stack: ItemStorageStack, simulate: Boolean): ItemStorageStack { - if (redstoneControl.isBlockedByRedstone || energy.batteryLevel.isZero || !filter.match(stack.toItemStack()) || !mode.input) + if (redstoneControl.isBlockedByRedstone || energy.batteryLevel.isZero || !filter.test(stack.toItemStack()) || !mode.input) return stack val required = StorageStack.ITEMS.energyPerInsert(stack) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageInterfaces.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageInterfaces.kt index 17aa2e953..d6573d11b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageInterfaces.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/StorageInterfaces.kt @@ -23,7 +23,7 @@ import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.WorkerEnergyStorage import ru.dbotthepony.mc.otm.config.EnergyBalanceValues import ru.dbotthepony.mc.otm.config.MachinesConfig -import ru.dbotthepony.mc.otm.container.ItemFilter +import ru.dbotthepony.mc.otm.container.ItemFilterSet import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.math.RelativeSide @@ -98,7 +98,7 @@ abstract class AbstractStorageImportExport( protected val target = CapabilityCache(RelativeSide.FRONT, Capabilities.ItemHandler.BLOCK) - var filter: ItemFilter = ItemFilter(MAX_FILTERS) + var filter: ItemFilterSet = ItemFilterSet.EMPTY set(value) { if (value != field) { field = value @@ -112,7 +112,7 @@ abstract class AbstractStorageImportExport( } init { - savetablesConfig.codec(::filter, ItemFilter.CODEC, FILTER_KEY, Supplier { ItemFilter(MAX_FILTERS) }) + savetablesConfig.codec(::filter, ItemFilterSet.CODEC, FILTER_KEY, Supplier { ItemFilterSet.EMPTY }) } companion object { @@ -168,7 +168,7 @@ class StorageImporterBlockEntity( } override fun insertItem(slot: Int, stack: ItemStack, simulate: Boolean): ItemStack { - if (redstoneControl.isBlockedByRedstone || !filter.match(stack)) + if (redstoneControl.isBlockedByRedstone || !filter.test(stack)) return stack return acceptItem(stack, simulate) @@ -183,7 +183,7 @@ class StorageImporterBlockEntity( } override fun isItemValid(slot: Int, stack: ItemStack): Boolean { - return filter.match(stack) + return filter.test(stack) } override fun tick() { @@ -205,7 +205,7 @@ class StorageImporterBlockEntity( val extracted = target.extractItem(lastSlot, MAX_MOVE_PER_OPERATION, true) - if (extracted.isEmpty || !filter.match(extracted)) { + if (extracted.isEmpty || !filter.test(extracted)) { lastSlot++ } else { val leftover = acceptItem(extracted, true) @@ -244,7 +244,7 @@ class StorageExporterBlockEntity(blockPos: BlockPos, blockState: BlockState) : } override fun onStackAdded(stack: ItemStorageStack, id: UUID, provider: IStorageProvider) { - if (filter.match(stack.toItemStack())) { + if (filter.test(stack.toItemStack())) { relevantTuples.add(id) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt index 8afae2f5c..1145eec92 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt @@ -36,8 +36,8 @@ import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.SimpleCache import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.otmRandom -import ru.dbotthepony.mc.otm.core.util.ItemStackKey -import ru.dbotthepony.mc.otm.core.util.asKey +import ru.dbotthepony.mc.otm.container.ItemStackKey +import ru.dbotthepony.mc.otm.container.asKey import ru.dbotthepony.mc.otm.menu.tech.PoweredFurnaceMenu import ru.dbotthepony.mc.otm.recipe.MatteryCookingRecipe import ru.dbotthepony.mc.otm.recipe.MicrowaveRecipe diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt index 16ec5cf96..a415dfc26 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt @@ -23,12 +23,9 @@ import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer import ru.dbotthepony.mc.otm.core.SimpleCache -import ru.dbotthepony.mc.otm.core.collect.any -import ru.dbotthepony.mc.otm.core.collect.filter -import ru.dbotthepony.mc.otm.core.collect.maybe import ru.dbotthepony.mc.otm.core.otmRandom -import ru.dbotthepony.mc.otm.core.util.ItemStackKey -import ru.dbotthepony.mc.otm.core.util.asKey +import ru.dbotthepony.mc.otm.container.ItemStackKey +import ru.dbotthepony.mc.otm.container.asKey import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import ru.dbotthepony.mc.otm.registry.game.MRecipes diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/Ext.kt index 489398d4e..644e715c1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/Ext.kt @@ -149,10 +149,10 @@ fun Player.items(includeCosmetics: Boolean = true): Iterator { val matteryPlayer = matteryPlayer val iterators = ArrayList>() - iterators.add(matteryPlayer.wrappedInventory.slotIterator().filter { !it.isForbiddenForAutomation }.map { it.item }) + iterators.add(matteryPlayer.wrappedInventory.slotIterator().filter { !it.filter.denyAll }.map { it.item }) if (matteryPlayer.hasExopack) { - iterators.add(matteryPlayer.exopackContainer.slotIterator().filter { !it.isForbiddenForAutomation }.map { it.item }) + iterators.add(matteryPlayer.exopackContainer.slotIterator().filter { !it.filter.denyAll }.map { it.item }) iterators.add(matteryPlayer.exopackEnergy.parent.iterator()) iterators.add(matteryPlayer.exopackChargeSlots.iterator()) } @@ -185,10 +185,8 @@ fun Player.awareItemsStream(includeCosmetics: Boolean = false): Stream>() streams.add(inventory.awareStream()) - matteryPlayer?.let { - if (it.hasExopack) { - streams.add(it.exopackContainer.awareStream()) - } + if (matteryPlayer.hasExopack) { + streams.add(matteryPlayer.exopackContainer.awareStream()) } if (isCuriosLoaded) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/FilterSlotPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/FilterSlotPanel.kt index b3ebe2cab..698ce1a91 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/FilterSlotPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/FilterSlotPanel.kt @@ -4,22 +4,36 @@ import net.minecraft.world.item.ItemStack import ru.dbotthepony.kommons.util.Delegate import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel +import ru.dbotthepony.mc.otm.container.ItemFilter -open class FilterSlotPanel> @JvmOverloads constructor( +open class FilterSlotPanel>( screen: S, parent: EditablePanel<*>?, - val slot: Delegate, + val slot: Delegate, x: Float = 0f, y: Float = 0f, width: Float = SIZE, height: Float = SIZE ) : AbstractSlotPanel(screen, parent, x, y, width, height) { + private var lastFilteredItemDisplayUpdate = System.nanoTime() + private var filteredItemDisplayIndex = 0 + override val itemStack: ItemStack get() { - return slot.get() + val items = slot.get().displayItems + + if (items.isEmpty()) + return ItemStack.EMPTY + + if (System.nanoTime() - lastFilteredItemDisplayUpdate >= 1_000_000_000L || filteredItemDisplayIndex !in items.indices) { + lastFilteredItemDisplayUpdate = System.nanoTime() + filteredItemDisplayIndex = random.nextInt(items.size) + } + + return items.asList()[filteredItemDisplayIndex].asItemStack() } override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean { - slot.accept(screen.menu.carried) + slot.accept(ItemFilter.item(screen.menu.carried)) return true } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/SlotPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/SlotPanel.kt index 1deb00732..3ebc0be4a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/SlotPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/SlotPanel.kt @@ -20,9 +20,12 @@ import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.compat.itemborders.isItemBordersLoaded import ru.dbotthepony.mc.otm.compat.itemborders.renderSlotBorder import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot +import ru.dbotthepony.mc.otm.container.ItemFilter +import ru.dbotthepony.mc.otm.container.ItemStackKey import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent +import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot import javax.annotation.Nonnull import kotlin.math.roundToInt @@ -63,6 +66,24 @@ open class SlotPanel, out T : Slot>( protected open fun renderBackgroundBeforeFilter(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) {} + private var lastFilteredItemDisplayUpdate = System.nanoTime() + private var filteredItemDisplayIndex = 0 + + private fun selectRandomItemFromFilter(filter: ItemFilter): ItemStack { + val items = filter.displayItems + + if (items.isEmpty()) { + return ItemStack.EMPTY + } else { + if (System.nanoTime() - lastFilteredItemDisplayUpdate >= 1_000_000_000L || filteredItemDisplayIndex !in items.indices) { + lastFilteredItemDisplayUpdate = System.nanoTime() + filteredItemDisplayIndex = random.nextInt(items.size) + } + + return items.asList()[filteredItemDisplayIndex].asItemStack() + } + } + override fun renderSlotBackground(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float) { super.renderSlotBackground(graphics, mouseX, mouseY, partialTick) @@ -71,16 +92,16 @@ open class SlotPanel, out T : Slot>( if (containerSlot is IFilteredContainerSlot) { renderBackgroundBeforeFilter(graphics, mouseX, mouseY, partialTick) - if (containerSlot.filter !== null) { - if (containerSlot.filter !== Items.AIR) { - val itemStack = ItemStack(containerSlot.filter!!, 1) + if (containerSlot.filter.denyAll) { + graphics.renderRect(0f, 0f, width, height, color = SLOT_BLOCK_COLOR) + } else if (!containerSlot.filter.allowAll) { + val itemStack = selectRandomItemFromFilter(containerSlot.filter) + if (itemStack.isNotEmpty) { screen.renderItemStack(graphics, itemStack, null) clearDepth(graphics) graphics.renderRect(0f, 0f, width, height, color = SLOT_FILTER_COLOR) - } else { - graphics.renderRect(0f, 0f, width, height, color = SLOT_BLOCK_COLOR) } } } @@ -154,26 +175,37 @@ open class SlotPanel, out T : Slot>( } } - override fun innerRenderTooltips(@Nonnull graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float): Boolean { + override fun innerRenderTooltips(graphics: MGUIGraphics, mouseX: Float, mouseY: Float, partialTick: Float): Boolean { val slot = slot.container.containerSlotOrNull(slot.containerSlot) as? IFilteredContainerSlot - if (isHovered && slot?.filter != null && slot.filter !== Items.AIR && itemStack.isEmpty) { - val itemstack = ItemStack(slot.filter!!, 1) + if (isHovered && slot?.filter != null && slot.filter.hasRules && itemStack.isEmpty) { + val itemstack = selectRandomItemFromFilter(slot.filter) - graphics.renderComponentTooltip( - IClientItemExtensions.of(itemstack).getFont(itemstack, IClientItemExtensions.FontContext.TOOLTIP) ?: font, - getItemStackTooltip(itemstack).toMutableList().also { + val text: List + + if (itemstack.isEmpty) { + text = listOf( + TranslatableComponent("otm.gui.slot_filter.filtered").withStyle(ChatFormatting.GRAY), + TranslatableComponent("otm.gui.slot_filter.hint").withStyle(ChatFormatting.GRAY) + ) + } else { + text = getItemStackTooltip(itemstack).toMutableList().also { it.add(0, TranslatableComponent("otm.gui.slot_filter.filtered").withStyle(ChatFormatting.GRAY)) it.add(1, TranslatableComponent("otm.gui.slot_filter.hint").withStyle(ChatFormatting.GRAY)) it.add(2, TextComponent("")) - }, + } + } + + graphics.renderComponentTooltip( + IClientItemExtensions.of(itemstack).getFont(itemstack, IClientItemExtensions.FontContext.TOOLTIP) ?: font, + text, mouseX.toInt(), mouseY.toInt(), itemstack ) return true - } else if (isHovered && slot?.filter === Items.AIR && itemStack.isEmpty) { + } else if (isHovered && slot?.filter?.denyAll == true && itemStack.isEmpty) { graphics.renderComponentTooltip( font, ArrayList().also { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/UserFilteredSlotPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/UserFilteredSlotPanel.kt index 2d6a269a7..93edb8608 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/UserFilteredSlotPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/slot/UserFilteredSlotPanel.kt @@ -7,6 +7,7 @@ import ru.dbotthepony.mc.otm.client.playGuiClickSound import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot +import ru.dbotthepony.mc.otm.container.ItemFilter import ru.dbotthepony.mc.otm.container.util.containerSlot import ru.dbotthepony.mc.otm.menu.UserFilteredMenuSlot @@ -20,20 +21,18 @@ open class UserFilteredSlotPanel, out T : UserFilteredM height: Float = SIZE, ) : SlotPanel(screen, parent, slot, x, y, width, height) { override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean { - if (slot.filterInput == null) - return super.mouseClickedInner(x, y, button) - + val filterInput = slot.filterInput ?: return super.mouseClickedInner(x, y, button) val containerSlot = slot.containerSlot() as IFilteredContainerSlot if (button == InputConstants.MOUSE_BUTTON_LEFT && minecraft.window.isCtrlDown) { - if (containerSlot.filter === null) { + if (containerSlot.filter.allowAll) { if (screen.menu.carried.isEmpty) { - slot.filterInput!!.accept(slot.item.item) + filterInput.accept(ItemFilter.item(slot.item.item)) } else { - slot.filterInput!!.accept(screen.menu.carried.item) + filterInput.accept(ItemFilter.item(screen.menu.carried.item)) } } else { - slot.filterInput!!.accept(null) + filterInput.accept(ItemFilter.EMPTY) } playGuiClickSound() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/storage/DriveViewerScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/storage/DriveViewerScreen.kt index 96c9022ee..5a6a5ffa9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/storage/DriveViewerScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/storage/DriveViewerScreen.kt @@ -66,14 +66,12 @@ class DriveViewerScreen(menu: DriveViewerMenu, inventory: Inventory, title: Comp settings.add(filterGrid) for (i in 0 until PortableCondensationDriveItem.MAX_FILTERS) { - FilterSlotPanel(this, filterGrid, menu.driveFilterSlots[i], 0f, 0f) + FilterSlotPanel(this, filterGrid, menu.driveFilter.slots[i], 0f, 0f) } settings.add(EditablePanel(this, frame, width = 90f).also { it.dock = Dock.LEFT - BooleanButtonPanel.Checkbox(this, it, menu.isWhitelist, TranslatableComponent("otm.gui.filter.is_whitelist")).also { it.dockTop = 20f; it.dock = Dock.TOP } - BooleanButtonPanel.Checkbox(this, it, menu.matchTag, TranslatableComponent("otm.gui.filter.match_tag")).also { it.dockTop = 4f; it.dock = Dock.TOP } - BooleanButtonPanel.Checkbox(this, it, menu.matchComponents, TranslatableComponent("otm.gui.filter.match_nbt")).also { it.dockTop = 4f; it.dock = Dock.TOP } + BooleanButtonPanel.Checkbox(this, it, menu.driveFilter.isWhitelist, TranslatableComponent("otm.gui.filter.is_whitelist")).also { it.dockTop = 20f; it.dock = Dock.TOP } }) frame.CustomTab(view, activeIcon = ItemStackIcon(ItemStack(MItems.PORTABLE_CONDENSATION_DRIVE))) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/storage/StorageImporterExporterScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/storage/StorageImporterExporterScreen.kt index a85e84860..4b1669648 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/storage/StorageImporterExporterScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/storage/StorageImporterExporterScreen.kt @@ -34,18 +34,6 @@ class StorageImporterExporterScreen(menu: StorageImporterExporterMenu, inventory it.childrenOrder = -1 } - BooleanButtonPanel.Checkbox(this, right, menu.filter.matchComponents, TranslatableComponent("otm.gui.filter.match_nbt")).also { - it.dock = Dock.BOTTOM - it.dockTop = 2f - it.childrenOrder = -2 - } - - BooleanButtonPanel.Checkbox(this, right, menu.filter.matchTag, TranslatableComponent("otm.gui.filter.match_tag")).also { - it.dock = Dock.BOTTOM - it.dockTop = 2f - it.childrenOrder = -3 - } - makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig) return frame 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 cb61feae0..6cee3f401 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerHelpers.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ContainerHelpers.kt @@ -241,9 +241,9 @@ fun Container.sortWithIndices(sortedSlots: IntCollection) { if (slot is IFilteredContainerSlot) { condition = slot.isNotEmpty && - !slot.isForbiddenForAutomation && + !slot.filter.denyAll && slot.item.count <= slot.maxStackSize(slot.item) && - (!slot.hasFilter || slot.filter != slot.item.item || slot.maxStackSize(slot.item) > 1) + (slot.filter.allowAll || !slot.filter.test(slot.item) || slot.maxStackSize(slot.item) > 1) } else { condition = slot.isNotEmpty && slot.item.count <= slot.maxStackSize(slot.item) } @@ -268,7 +268,7 @@ fun Container.computeSortedIndices(comparator: Comparator = ItemStack val slots = slotIterator() .withIndex() - .filter { (_, it) -> (it !is IFilteredContainerSlot || !it.isForbiddenForAutomation) && it.maxStackSize(it.item) >= it.item.count } + .filter { (_, it) -> (it !is IFilteredContainerSlot || !it.filter.denyAll) && it.maxStackSize(it.item) >= it.item.count } .toList() if (slots.isEmpty()) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt index af2b978fe..c201a4bb8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IEnhancedContainer.kt @@ -282,9 +282,9 @@ interface IEnhancedContainer : Container, RecipeInput, I val condition: Boolean if (slot is IFilteredContainerSlot) { - condition = (ignoreFilters || !slot.isForbiddenForAutomation) && + condition = (ignoreFilters || !slot.filter.denyAll) && ItemStack.isSameItemSameComponents(slot.item, stack) && - (ignoreFilters || !filterPass && !slot.hasFilter || filterPass && slot.hasFilter && slot.testSlotFilter(stack)) + (ignoreFilters || !filterPass && slot.filter.allowAll || filterPass && !slot.filter.allowAll && slot.filter.test(stack)) } else { condition = (ignoreFilters || !filterPass) && ItemStack.isSameItemSameComponents(slot.item, stack) } @@ -318,8 +318,8 @@ interface IEnhancedContainer : Container, RecipeInput, I val condition: Boolean if (slot is IFilteredContainerSlot) { - condition = (ignoreFilters || !slot.isForbiddenForAutomation) && - (ignoreFilters || !filterPass && !slot.hasFilter || filterPass && slot.hasFilter && slot.testSlotFilter(stack)) + condition = (ignoreFilters || !slot.filter.denyAll) && + (ignoreFilters || !filterPass && slot.filter.allowAll || filterPass && !slot.filter.allowAll && slot.filter.test(stack)) } else { condition = ignoreFilters || !filterPass } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredAutomatedContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredAutomatedContainerSlot.kt index a94f6ba05..4ee9144a0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredAutomatedContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredAutomatedContainerSlot.kt @@ -5,10 +5,10 @@ import net.minecraft.world.item.Items interface IFilteredAutomatedContainerSlot : IFilteredContainerSlot, IAutomatedContainerSlot { override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { - return super.canAutomationPlaceItem(itemStack) && testSlotFilter(itemStack) + return super.canAutomationPlaceItem(itemStack) && filter.test(itemStack) } override fun canAutomationTakeItem(desired: Int): Boolean { - return super.canAutomationTakeItem(desired) && (filter == null || filter !== Items.AIR) + return super.canAutomationTakeItem(desired) && !filter.denyAll } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt index 11bb4c44a..6562192b0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/IFilteredContainerSlot.kt @@ -1,28 +1,5 @@ package ru.dbotthepony.mc.otm.container -import net.minecraft.world.item.Item -import net.minecraft.world.item.ItemStack -import net.minecraft.world.item.Items - interface IFilteredContainerSlot : IContainerSlot { - var filter: Item? - - val isForbiddenForAutomation: Boolean get() { - return filter === Items.AIR - } - - val hasFilter: Boolean - get() = filter != null - - fun testSlotFilter(itemStack: ItemStack): Boolean { - return testSlotFilter(itemStack.item) - } - - fun testSlotFilter(item: Item): Boolean { - if (filter == null) { - return true - } else { - return filter === item - } - } + var filter: ItemFilter } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ItemFilter.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ItemFilter.kt index 4f0f53114..762b65a94 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ItemFilter.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ItemFilter.kt @@ -1,124 +1,205 @@ package ru.dbotthepony.mc.otm.container +import com.google.common.collect.ImmutableSet +import com.mojang.datafixers.util.Either import com.mojang.serialization.Codec -import com.mojang.serialization.codecs.RecordCodecBuilder -import it.unimi.dsi.fastutil.objects.ObjectArrayList +import com.mojang.serialization.DataResult +import com.mojang.serialization.MapCodec +import net.minecraft.core.component.DataComponentPatch +import net.minecraft.core.registries.BuiltInRegistries +import net.minecraft.core.registries.Registries +import net.minecraft.resources.ResourceLocation import net.minecraft.tags.TagKey -import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import net.neoforged.bus.api.IEventBus +import ru.dbotthepony.mc.otm.core.isNotEmpty +import ru.dbotthepony.mc.otm.registry.MBuiltInRegistries +import ru.dbotthepony.mc.otm.registry.MDeferredRegister +import ru.dbotthepony.mc.otm.registry.MRegistries +import java.util.function.Predicate +import kotlin.jvm.optionals.getOrElse -class ItemFilter private constructor(private val filter: Array, val isWhitelist: Boolean, val matchTag: Boolean, val matchComponents: Boolean) { - constructor(size: Int, isWhitelist: Boolean = false, matchTag: Boolean = false, matchComponents: Boolean = false) : this(Array(size) { ItemStack.EMPTY }, isWhitelist, matchTag, matchComponents) - constructor(list: List, isWhitelist: Boolean = false, matchTag: Boolean = false, matchComponents: Boolean = false) : this(list.toTypedArray(), isWhitelist, matchTag, matchComponents) - - override fun equals(other: Any?): Boolean { - return this === other || other is ItemFilter && - this.filter.contentEquals(other.filter) && - this.isWhitelist == other.isWhitelist && - this.matchTag == other.matchTag && - this.matchComponents == other.matchComponents +interface ItemFilter : Predicate { + interface Type { + val codec: MapCodec } - override fun hashCode(): Int { - return filter.contentHashCode() + val type: Type<*> + + /** + * Whenever [test] will return `true` no matter the argument, + * effectively telling that this filter is "allow all" / "no filter specified" + * + * Can be treated as (but is not equal to) "isEmpty" + */ + val allowAll: Boolean + get() = false + + /** + * Whenever [test] will return `false` no matter the argument, + * effectively telling that this filter is "deny all" / "forbidden for automation" + */ + val denyAll: Boolean + get() = false + + /** + * Whenever this filter has meaningful rules behind it, e.g. [test] will return either `true` or `false`, + * depending on value passed. + * + * In other words, returns whenever [denyAll] and [allowAll] are both `false`. + */ + val hasRules: Boolean + get() = !denyAll && !allowAll + + val depth: Int + get() = 1 + + val displayItems: ImmutableSet + get() = ImmutableSet.of() + + private data class Item(val item: net.minecraft.world.item.Item) : ItemFilter { + override val type: Type<*> + get() = Companion + + override val denyAll: Boolean + get() = item === Items.AIR + + override fun test(t: ItemStack): Boolean { + return t.isNotEmpty && t.item === item + } + + override val displayItems: ImmutableSet + get() = ImmutableSet.of(ItemStackKey(item)) + + companion object : Type { + override val codec: MapCodec by lazy { + BuiltInRegistries.ITEM.byNameCodec().xmap(::Item, Item::item).fieldOf("item") + } + } } - val size: Int - get() = filter.size + private data class Tag(val tag: TagKey) : ItemFilter { + override val type: Type<*> + get() = Companion - fun set(index: Int, value: ItemStack): ItemFilter { - if (ItemStack.isSameItemSameComponents(filter[index], value) || !value.isEmpty && filter.any { ItemStack.isSameItemSameComponents(it, value) }) - return this + override fun test(t: ItemStack): Boolean { + return t.`is`(tag) + } - return copy(filter.copyOf().also { it[index] = value }) + // TODO: can not be "lazy" cached because this will break with /reload command + override val displayItems: ImmutableSet get() { + return BuiltInRegistries.ITEM + .getTag(tag) + .map { it.stream().map { ItemStackKey(it.value()) }.collect(ImmutableSet.toImmutableSet()) } + .orElseGet { ImmutableSet.of() } + } + + companion object : Type { + override val codec: MapCodec by lazy { + TagKey.codec(Registries.ITEM).xmap(::Tag, Tag::tag).fieldOf("tag") + } + } } - operator fun get(index: Int): ItemStack { - return filter[index] - } + private object DenyAll : ItemFilter, Type { + override val type: Type<*> + get() = this - private fun copy( - filter: Array = this.filter, - isWhitelist: Boolean = this.isWhitelist, - matchTag: Boolean = this.matchTag, - matchComponents: Boolean = this.matchComponents, - ) = ItemFilter(filter, isWhitelist, matchTag, matchComponents) + override val codec: MapCodec = MapCodec.unit(this) - fun isWhitelist(flag: Boolean): ItemFilter { - if (flag == isWhitelist) - return this - else - return copy(isWhitelist = flag) - } + override val denyAll: Boolean + get() = true - fun matchTag(flag: Boolean): ItemFilter { - if (flag == matchTag) - return this - else - return copy(matchTag = flag) - } - - fun matchComponents(flag: Boolean): ItemFilter { - if (flag == matchComponents) - return this - else - return copy(matchComponents = flag) - } - - fun match(value: ItemStack): Boolean { - if (value.isEmpty) { + override fun test(t: ItemStack): Boolean { return false } - - if (filter.isEmpty()) { - return !isWhitelist - } - - for (item in filter) { - var matches = item.`is`(value.item) - - if (matches && matchTag) { - matches = false - - val thisTags = item.tags - val stackTags = HashSet>() - - for (tag in value.tags) { - stackTags.add(tag) - } - - for (tag1 in thisTags) { - if (stackTags.contains(tag1)) { - matches = true - break - } - } - } - - if (matches && matchComponents) { - matches = item.components == value.components - } - - if (matches) { - return isWhitelist - } - } - - return !isWhitelist } - companion object { - val EMPTY = ItemFilter(0) + companion object : ItemFilter, Type { + const val MAX_DEPTH = 16 + + private fun roll(input: ItemFilter): Either { + if (input is Item) { + return Either.left(input) + } else if (input is ItemStackKey && input.components == DataComponentPatch.EMPTY) { + return Either.left(Item(input.item)) + } else { + return Either.right(input) + } + } val CODEC: Codec by lazy { - RecordCodecBuilder.create { - it.group( - Codec.list(ItemStack.OPTIONAL_CODEC, 0, 40).fieldOf("filter").forGetter { ObjectArrayList.wrap(it.filter) }, - Codec.BOOL.optionalFieldOf("isWhitelist", false).forGetter { it.isWhitelist }, - Codec.BOOL.optionalFieldOf("matchTag", false).forGetter { it.matchTag }, - Codec.BOOL.optionalFieldOf("matchComponents", false).forGetter { it.matchComponents }, - ).apply(it, ::ItemFilter) - } + val codecA = BuiltInRegistries.ITEM + .byNameCodec() + .xmap(::Item, Item::item) + + val codecB = MBuiltInRegistries.ITEM_FILTER + .byNameCodec() + .dispatch(ItemFilter::type, { it.codec }) + + Codec.either(codecA, codecB) + .xmap({ it.right().getOrElse { it.left().get() } }, ::roll) + .validate { + if (it.depth <= MAX_DEPTH) { + return@validate DataResult.success(it) + } else { + return@validate DataResult.error { "Too deep item filter, max depth of $MAX_DEPTH is allowed (depth: ${it.depth})" } + } + } + } + + val EMPTY: ItemFilter + get() = this + + val DENY_ALL: ItemFilter + get() = DenyAll + + private val registrar = MDeferredRegister(MRegistries.ITEM_FILTER) + + init { + registrar.register("item") { Item.Companion } + registrar.register("item_stack") { ItemStackKey.Companion } + registrar.register("tag") { Tag.Companion } + registrar.register("set") { ItemFilterSet.Companion } + registrar.register("empty") { this } + registrar.register("deny_all") { DenyAll } + } + + internal fun register(bus: IEventBus) { + registrar.register(bus) + } + + override val type: Type<*> + get() = this + + override fun test(t: ItemStack): Boolean { + return true + } + + override val codec: MapCodec = MapCodec.unit(this) + + override val allowAll: Boolean + get() = true + + @JvmStatic + fun item(item: net.minecraft.world.item.Item): ItemFilter { + return Item(item) + } + + @JvmStatic + fun item(item: ItemStack): ItemFilter { + return Item(item.item) + } + + @JvmStatic + fun itemAndComponents(item: ItemStack): ItemFilter { + return ItemStackKey(item) + } + + @JvmStatic + fun tag(tag: TagKey): ItemFilter { + return Tag(tag) } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ItemFilterSet.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ItemFilterSet.kt new file mode 100644 index 000000000..8319020b8 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ItemFilterSet.kt @@ -0,0 +1,130 @@ +package ru.dbotthepony.mc.otm.container + +import com.google.common.collect.ImmutableSet +import com.mojang.serialization.Codec +import com.mojang.serialization.MapCodec +import com.mojang.serialization.codecs.RecordCodecBuilder +import it.unimi.dsi.fastutil.objects.ObjectArrayList +import net.minecraft.world.item.ItemStack + +data class ItemFilterSet(val filter: ImmutableSet, val isWhitelist: Boolean = false) : ItemFilter { + constructor(list: Collection, isWhitelist: Boolean = false) : this(ImmutableSet.copyOf(list), isWhitelist) + + val size: Int + get() = filter.size + + override val allowAll: Boolean by lazy(LazyThreadSafetyMode.PUBLICATION) { + filter.isEmpty() && !isWhitelist || filter.isNotEmpty() && isWhitelist && filter.any { it.allowAll } + } + + override val denyAll: Boolean by lazy(LazyThreadSafetyMode.PUBLICATION) { + filter.isEmpty() && isWhitelist || filter.isNotEmpty() && !isWhitelist && filter.any { it.denyAll } + } + + fun replace(index: Int, value: ItemFilter): ItemFilterSet { + if (index !in filter.indices) + throw IndexOutOfBoundsException("No such filter at index $index") + else if (value in filter) + return this + + val values = ObjectArrayList(filter) + values[index] = value + return copy(filter = ImmutableSet.copyOf(values)) + } + + fun addOrReplace(index: Int, value: ItemFilter): ItemFilterSet { + if (index !in filter.indices) + return add(value) + else + return replace(index, value) + } + + fun add(value: ItemFilter): ItemFilterSet { + if (value in filter) + return this + + val values = ObjectArrayList(filter) + values.add(value) + return copy(filter = ImmutableSet.copyOf(values)) + } + + fun removeAt(index: Int): ItemFilterSet { + if (index !in filter.indices) + throw IndexOutOfBoundsException("No such filter at index $index") + + if (filter.size == 1) + return copy(filter = ImmutableSet.of()) + + val values = ObjectArrayList(filter) + values.removeAt(index) + return copy(filter = ImmutableSet.copyOf(values)) + } + + fun indexOf(value: ItemFilter): Int { + return filter.asList().indexOf(value) + } + + operator fun get(index: Int): ItemFilter { + return filter.asList()[index] + } + + fun clear(): ItemFilterSet { + if (filter.isEmpty()) + return this + + return copy(filter = ImmutableSet.of()) + } + + fun isWhitelist(flag: Boolean): ItemFilterSet { + if (flag == isWhitelist) + return this + else + return copy(isWhitelist = flag) + } + + override fun test(value: ItemStack): Boolean { + return if (denyAll || value.isEmpty) + false + else if (allowAll) + true + else if (filter.any { it.test(value) }) + isWhitelist + else + !isWhitelist + } + + override val type: ItemFilter.Type<*> + get() = Companion + + override val depth: Int by lazy { + if (filter.isNotEmpty()) + return@lazy 1 + filter.maxOf { it.depth } + + return@lazy 1 + } + + // TODO: can not be "lazy" cached because that will break with /reload command + override val displayItems: ImmutableSet get() { + val sub = filter.map { it.displayItems } + val results = ArrayList(sub.sumOf { it.size }) + sub.forEach { results.addAll(it) } + return ImmutableSet.copyOf(results) + } + + companion object : ItemFilter.Type { + override val codec: MapCodec by lazy { + RecordCodecBuilder.mapCodec { + it.group( + Codec.list(ItemFilter.CODEC, 0, 40).fieldOf("filter").forGetter { ObjectArrayList(it.filter) }, + Codec.BOOL.optionalFieldOf("isWhitelist", false).forGetter { it.isWhitelist }, + ).apply(it, ::ItemFilterSet) + } + } + + val EMPTY = ItemFilterSet(ImmutableSet.of()) + + val CODEC: Codec by lazy { + codec.codec() + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/ItemStackKey.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ItemStackKey.kt similarity index 59% rename from src/main/kotlin/ru/dbotthepony/mc/otm/core/util/ItemStackKey.kt rename to src/main/kotlin/ru/dbotthepony/mc/otm/container/ItemStackKey.kt index 0145c1988..9fc344f59 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/ItemStackKey.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ItemStackKey.kt @@ -1,15 +1,18 @@ -package ru.dbotthepony.mc.otm.core.util +package ru.dbotthepony.mc.otm.container +import com.google.common.collect.ImmutableSet +import com.mojang.serialization.Codec +import com.mojang.serialization.MapCodec +import com.mojang.serialization.codecs.RecordCodecBuilder import it.unimi.dsi.fastutil.HashCommon -import net.minecraft.core.component.DataComponentMap import net.minecraft.core.component.DataComponentPatch -import net.minecraft.core.component.PatchedDataComponentMap import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items import ru.dbotthepony.mc.otm.core.getHolder -class ItemStackKey(val item: Item, val components: DataComponentPatch) { +class ItemStackKey(val item: Item, val components: DataComponentPatch) : ItemFilter { // make copy of original itemstack because there is no copy() method on DataComponentMap, which is returned by ItemStack#getComponents constructor(itemStack: ItemStack) : this(itemStack.item, itemStack.copy().componentsPatch) constructor(item: Item) : this(item, DataComponentPatch.EMPTY) @@ -37,6 +40,33 @@ class ItemStackKey(val item: Item, val components: DataComponentPatch) { override fun toString(): String { return "ItemStackKey[$item, $components]" } + + override fun test(t: ItemStack): Boolean { + return t.item === item && t.componentsPatch == components + } + + override val type: ItemFilter.Type<*> + get() = Companion + + override val displayItems: ImmutableSet = ImmutableSet.of(this) + + companion object : ItemFilter.Type { + override val codec: MapCodec + get() = MAP_CODEC + + val MAP_CODEC: MapCodec by lazy { + RecordCodecBuilder.mapCodec { + it.group( + BuiltInRegistries.ITEM.byNameCodec().fieldOf("item").forGetter(ItemStackKey::item), + DataComponentPatch.CODEC.fieldOf("components").forGetter(ItemStackKey::components) + ).apply(it, ::ItemStackKey) + } + } + + val CODEC: Codec by lazy { + MAP_CODEC.codec() + } + } } fun ItemStack.asKey(): ItemStackKey { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt index 909534c01..d78c871bf 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt @@ -3,10 +3,13 @@ package ru.dbotthepony.mc.otm.container.slotted import net.minecraft.core.HolderLookup import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.nbt.CompoundTag +import net.minecraft.nbt.NbtOps import net.minecraft.resources.ResourceLocation import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack +import org.apache.logging.log4j.LogManager import ru.dbotthepony.mc.otm.container.IFilteredAutomatedContainerSlot +import ru.dbotthepony.mc.otm.container.ItemFilter import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.registryName import java.util.Collections @@ -15,7 +18,7 @@ open class FilteredContainerSlot( container: SlottedContainer, slot: Int ) : ContainerSlot(container, slot), IFilteredAutomatedContainerSlot { - override var filter: Item? = null + override var filter: ItemFilter = ItemFilter.EMPTY set(value) { if (field !== value) { field = value @@ -25,21 +28,25 @@ open class FilteredContainerSlot( override fun clear() { super.clear() - filter = null + filter = ItemFilter.EMPTY } override fun serializeNBT(provider: HolderLookup.Provider): CompoundTag { return super.serializeNBT(provider).also { - if (filter != null) - it["filter"] = filter!!.registryName!!.toString() + it["filter"] = ItemFilter.CODEC.encodeStart(provider.createSerializationContext(NbtOps.INSTANCE), filter) + .getOrThrow { RuntimeException("Failed to serialize item filter: $it") } } } override fun deserializeNBT(provider: HolderLookup.Provider, nbt: CompoundTag) { super.deserializeNBT(provider, nbt) + filter = ItemFilter.EMPTY + if ("filter" in nbt) { - filter = BuiltInRegistries.ITEM.get(ResourceLocation.parse(nbt.getString("filter"))) + ItemFilter.CODEC.decode(provider.createSerializationContext(NbtOps.INSTANCE), nbt) + .ifError { LOGGER.error("Unable to deserialize item filter: ${it.message()}") } + .resultOrPartial().map { it.first }.ifPresent { filter = it } } } @@ -87,4 +94,8 @@ open class FilteredContainerSlot( return Instance(container, index) } } + + companion object { + private val LOGGER = LogManager.getLogger() + } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt index 31a8b5795..50fe19366 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/SlottedContainer.kt @@ -22,6 +22,7 @@ import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.IAutomatedContainer import ru.dbotthepony.mc.otm.container.IAutomatedContainerSlot import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot +import ru.dbotthepony.mc.otm.container.ItemFilter import ru.dbotthepony.mc.otm.container.balance import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.nbt.set @@ -293,7 +294,7 @@ class SlottedContainer( val getSlot = slots[slot] if (getSlot is IFilteredContainerSlot) { - getSlot.filter = filter + getSlot.filter = ItemFilter.item(filter) } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/PortableCondensationDriveItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/PortableCondensationDriveItem.kt index c23e65dee..26250d8a3 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/PortableCondensationDriveItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/PortableCondensationDriveItem.kt @@ -13,7 +13,7 @@ import net.neoforged.neoforge.event.entity.player.ItemEntityPickupEvent import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.drive.DrivePool import ru.dbotthepony.mc.otm.capability.drive.ItemMatteryDrive -import ru.dbotthepony.mc.otm.container.ItemFilter +import ru.dbotthepony.mc.otm.container.ItemFilterSet import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.isServerThread import ru.dbotthepony.mc.otm.registry.CapabilitiesRegisterListener @@ -55,18 +55,18 @@ class PortableCondensationDriveItem(capacity: Int) : Item(Properties().stacksTo( }, this) } - fun getFilterSettings(item: ItemStack): ItemFilter { + fun getFilterSettings(item: ItemStack): ItemFilterSet { return item.getOrDefault(MDataComponentTypes.ITEM_FILTER, EMPTY_FILTER) } - fun setFilterSettings(item: ItemStack, filter: ItemFilter) { + fun setFilterSettings(item: ItemStack, filter: ItemFilterSet) { item.set(MDataComponentTypes.ITEM_FILTER, filter) } @Suppress("unused") companion object { const val MAX_FILTERS = 4 * 3 - private val EMPTY_FILTER = ItemFilter(MAX_FILTERS) + private val EMPTY_FILTER = ItemFilterSet.EMPTY internal fun onPickupEvent(event: ItemEntityPickupEvent.Pre) { if (event.itemEntity.owner != null && event.itemEntity.owner != event.player && event.itemEntity.age < 200 || event.itemEntity.item.isEmpty) { @@ -83,9 +83,9 @@ class PortableCondensationDriveItem(capacity: Int) : Item(Properties().stacksTo( var doBreak = false stack.getCapability(MatteryCapability.CONDENSATION_DRIVE)?.let { - val filter = stack[MDataComponentTypes.ITEM_FILTER] ?: ItemFilter.EMPTY + val filter = stack[MDataComponentTypes.ITEM_FILTER] ?: ItemFilterSet.EMPTY - if (filter.match(event.itemEntity.item)) { + if (filter.test(event.itemEntity.item)) { val copy = event.itemEntity.item.copy() val remaining = (it as ItemMatteryDrive).insertStack(event.itemEntity.item, false) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt index 7deac409c..3d49f5cd8 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/QuickMoveInput.kt @@ -11,9 +11,9 @@ import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.isNotEmpty -import ru.dbotthepony.mc.otm.core.util.ItemStackKey -import ru.dbotthepony.mc.otm.core.util.asKey -import ru.dbotthepony.mc.otm.core.util.asKeyOrNull +import ru.dbotthepony.mc.otm.container.ItemStackKey +import ru.dbotthepony.mc.otm.container.asKey +import ru.dbotthepony.mc.otm.container.asKeyOrNull class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, val to: Collection, val mode: Mode, val dontTouchFilteredSlots: Boolean = true) { /** @@ -36,8 +36,8 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, val slotA = a.containerSlotOrNull() val slotB = b.containerSlotOrNull() - val hasFilterA = slotA is IFilteredContainerSlot && slotA.hasFilter - val hasFilterB = slotB is IFilteredContainerSlot && slotB.hasFilter + val hasFilterA = slotA is IFilteredContainerSlot && slotA.filter.hasRules + val hasFilterB = slotB is IFilteredContainerSlot && slotB.filter.hasRules return hasFilterB.compareTo(hasFilterA) } @@ -51,19 +51,22 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, override fun move(from: Collection, to: Collection, player: Player, dontTouchFilteredSlots: Boolean) { if (from.isEmpty() || to.isEmpty()) return val (_, itemsFrom) = computeSlotLists(from, dontTouchFilteredSlots) - val (_, itemsTo) = computeSlotLists(to, false) + val (_, itemsTo, filteredTo) = computeSlotLists(to, false) - val intersect = if (itemsFrom.size < itemsTo.size) itemsFrom.keys.filter { it in itemsTo.keys } else itemsTo.keys.filter { it in itemsFrom.keys } + val intersect: Collection + + if (filteredTo.isNotEmpty()) + intersect = itemsFrom.keys + else if (itemsFrom.size < itemsTo.size) + intersect = itemsFrom.keys.filter { it in itemsTo.keys } + else + intersect = itemsTo.keys.filter { it in itemsFrom.keys } for (key in intersect) { - val slotsTo = itemsTo[key]!! + val slotsTo = ArrayList(itemsTo[key] ?: listOf()) + slotsTo.addAll(0, filteredTo) val slotsFrom = itemsFrom[key]!! - if (!dontTouchFilteredSlots) { - // touch filtered slots last - slotsFrom.sortWith(HasFilterComparator.reversed()) - } - slotsFrom.forEach { moveItemStackTo(player, it, slotsTo) } } } @@ -76,18 +79,23 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, override fun move(from: Collection, to: Collection, player: Player, dontTouchFilteredSlots: Boolean) { if (from.isEmpty() || to.isEmpty()) return val (_, itemsFrom) = computeSlotLists(from, dontTouchFilteredSlots) - val (emptyTo, itemsTo) = computeSlotLists(to, false) + val (emptyTo, itemsTo, filteredTo) = computeSlotLists(to, false) - val intersect = if (itemsFrom.size < itemsTo.size) itemsFrom.keys.filter { it in itemsTo.keys } else itemsTo.keys.filter { it in itemsFrom.keys } + val intersect: Collection + + if (filteredTo.isNotEmpty()) + intersect = itemsFrom.keys + else if (itemsFrom.size < itemsTo.size) + intersect = itemsFrom.keys.filter { it in itemsTo.keys } + else + intersect = itemsTo.keys.filter { it in itemsFrom.keys } for (key in intersect) { - val slotsTo = prioritySortSlots(itemsTo[key]!!, key.asItemStack()) - val slotsFrom = itemsFrom[key]!! + val slotsTo = ArrayList(itemsTo[key] ?: listOf()).also { it.addAll(0, filteredTo) } + if (slotsTo.isEmpty()) continue + prioritySortSlotsInPlace(slotsTo, key.asItemStack()) - if (!dontTouchFilteredSlots) { - // touch filtered slots last - slotsFrom.sortWith(HasFilterComparator.reversed()) - } + val slotsFrom = itemsFrom[key]!! slotsFrom.removeIf { moveItemStackTo(player, it, slotsTo, sort = false); it.item.isEmpty } var moveAny = false @@ -108,7 +116,7 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, from.forEach { val slot = it.containerSlotOrNull() - if (!dontTouchFilteredSlots || slot !is IFilteredContainerSlot || !slot.hasFilter) + if (!dontTouchFilteredSlots || slot !is IFilteredContainerSlot || !slot.filter.hasRules) moveItemStackTo(player, it, toSorted, sort = false) } } @@ -135,31 +143,42 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, mode.move(from, to, menu.player, dontTouchFilteredSlots) } + private data class SlotLists( + val empty: MutableList, + val withItems: MutableMap>, + val withFilters: MutableList, + ) + companion object { fun create(menu: MatteryMenu, from: Collection, to: Collection, dontTouchFilteredSlots: Boolean = true): Map { return Mode.entries.associateWith { QuickMoveInput(menu, from, to, it, dontTouchFilteredSlots) } } - private fun computeSlotLists(slots: Collection, skipFilteredSlots: Boolean): Pair, MutableMap>> { + private fun computeSlotLists(slots: Collection, skipFilteredSlots: Boolean): SlotLists { val emptySlots = ArrayList() + val filteredSlots = ArrayList() val filledSlots = HashMap>() for (slot in slots) { val underlyingSlot = slot.containerSlotOrNull() - if (underlyingSlot is IFilteredContainerSlot && (underlyingSlot.filter == Items.AIR || underlyingSlot.filter != null && skipFilteredSlots)) + if (underlyingSlot is IFilteredContainerSlot && (underlyingSlot.filter.denyAll || !underlyingSlot.filter.allowAll && skipFilteredSlots)) continue - val key = slot.item.asKeyOrNull() ?: (underlyingSlot as? IFilteredContainerSlot)?.filter?.asKey() + val key = slot.item.asKeyOrNull() if (key == null) { - emptySlots.add(slot) + if (underlyingSlot is IFilteredContainerSlot && underlyingSlot.filter.hasRules) { + filteredSlots.add(slot) + } else { + emptySlots.add(slot) + } } else { filledSlots.computeIfAbsent(key) { ArrayList() }.add(slot) } } - return emptySlots to filledSlots + return SlotLists(emptySlots, filledSlots, filteredSlots) } fun moveItemStackTo( @@ -195,7 +214,10 @@ class QuickMoveInput(private val menu: MatteryMenu, val from: Collection, fun > prioritySortSlotsInPlace(slots: T, filterItem: ItemStack? = null): T { slots.removeIf { val slot = it.containerSlotOrNull() - it.isOverCapacity || filterItem != null && !it.mayPlace(filterItem) || slot is IFilteredContainerSlot && slot.isForbiddenForAutomation + + it.isOverCapacity || + filterItem != null && !it.mayPlace(filterItem) || + slot is IFilteredContainerSlot && (slot.filter.denyAll || filterItem != null && !slot.filter.test(filterItem)) } slots.sortWith(itemFilterSlotComparator) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt index 2ad6091ee..64f4bc51e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/Slots.kt @@ -7,7 +7,6 @@ import net.minecraft.world.entity.player.Player import net.minecraft.world.inventory.Slot import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack -import net.neoforged.neoforge.capabilities.Capabilities import ru.dbotthepony.kommons.util.Delegate import ru.dbotthepony.kommons.util.getValue import ru.dbotthepony.kommons.util.value @@ -17,11 +16,11 @@ import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.UpgradeType import ru.dbotthepony.mc.otm.capability.energy import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage -import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.IEnhancedContainer import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot import ru.dbotthepony.mc.otm.container.ItemFilter +import ru.dbotthepony.mc.otm.container.ItemFilterSet import ru.dbotthepony.mc.otm.container.UpgradeContainer import ru.dbotthepony.mc.otm.container.util.containerSlotOrNull import ru.dbotthepony.mc.otm.core.collect.ConditionalEnumSet @@ -30,9 +29,9 @@ import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.InstantBooleanInput +import ru.dbotthepony.mc.otm.menu.input.ItemFilterInput import ru.dbotthepony.mc.otm.network.StreamCodecs import ru.dbotthepony.mc.otm.player.IPlayerInventorySlot -import ru.dbotthepony.mc.otm.runOnClient import java.util.* import java.util.function.BooleanSupplier import java.util.function.DoubleSupplier @@ -61,7 +60,7 @@ open class MatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int val slot = containerSlotOrNull() if (slot is IFilteredContainerSlot && slot !is IPlayerInventorySlot) { - menu.mSynchronizer.add(Delegate.Of(slot::filter), StreamCodecs.ITEM_TYPE_NULLABLE) + menu.mSynchronizer.add(Delegate.Of(slot::filter), StreamCodecs.ITEM_FILTER) } } @@ -113,7 +112,7 @@ open class MatteryMenuSlot(container: Container, index: Int, x: Int = 0, y: Int } open class UserFilteredMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = 0) : MatteryMenuSlot(container, index, x, y) { - var filterInput: MatteryMenu.PlayerInput? = null + var filterInput: MatteryMenu.PlayerInput? = null private set override fun setupNetworkControls(menu: MatteryMenu) { @@ -121,7 +120,7 @@ open class UserFilteredMenuSlot(container: Container, index: Int, x: Int = 0, y: val slot = containerSlotOrNull() if (slot is IFilteredContainerSlot) { - filterInput = menu.PlayerInput(StreamCodecs.ITEM_TYPE_NULLABLE, handler = { slot.filter = it }) + filterInput = menu.PlayerInput(StreamCodecs.ITEM_FILTER, handler = { slot.filter = it }) } } } @@ -184,63 +183,16 @@ open class DriveMenuSlot(container: Container, index: Int, x: Int = 0, y: Int = } } -fun MatteryMenu.addFilterSlots(slots: Delegate): List> { - val result = ArrayList>(slots.value.size) - - for (i in 0 until slots.value.size) { - result.add(Delegate.Of( - mSynchronizer.computedItem { slots.value[i] }, - itemStackInput { slots.value = slots.value.set(i, it) } - )) - } - - return result +fun MatteryMenu.addFilterSlots(amount: Int, slots: Delegate?): ItemFilterInput { + return ItemFilterInput(this, amount, slots) } -fun MatteryMenu.addFilterSlots(amount: Int): List> { - val result = ArrayList>(amount) - - for (i in 0 until amount) { - result.add(Delegate.Of( - mSynchronizer.computedItem { ItemStack.EMPTY }, - itemStackInput { throw UnsupportedOperationException() } - )) - } - - return result +fun MatteryMenu.addFilterSlots(amount: Int): ItemFilterInput { + return addFilterSlots(amount, Delegate.Box(ItemFilterSet.EMPTY)) } -fun MatteryMenu.addFilterSlots(slots: Delegate?, amount: Int): List> { - if (slots != null && amount != slots.value.size) - throw IllegalStateException("Provided ItemFiler has different amount of slots than expected: ${slots.value.size} != $amount") - - if (slots == null) - return addFilterSlots(amount) - else - return addFilterSlots(slots) -} - -fun MatteryMenu.addFilterSlots(slots: KMutableProperty0?, amount: Int): List> { - return addFilterSlots(if (slots == null) null else Delegate.Of(slots), amount) -} - -data class FilterControls(val slots: List>, val isWhitelist: BooleanInputWithFeedback, val matchComponents: BooleanInputWithFeedback, val matchTag: BooleanInputWithFeedback) - -fun MatteryMenu.addFilterControls(slots: Delegate?, amount: Int): FilterControls { - if (slots == null) { - return FilterControls(addFilterSlots(amount), BooleanInputWithFeedback(this), BooleanInputWithFeedback(this), BooleanInputWithFeedback(this)) - } else { - return FilterControls( - addFilterSlots(slots, amount), - BooleanInputWithFeedback.dispatch(this, slots, ItemFilter::isWhitelist, ItemFilter::isWhitelist), - BooleanInputWithFeedback.dispatch(this, slots, ItemFilter::matchComponents, ItemFilter::matchComponents), - BooleanInputWithFeedback.dispatch(this, slots, ItemFilter::matchTag, ItemFilter::matchTag), - ) - } -} - -fun MatteryMenu.addFilterControls(slots: KMutableProperty0?, amount: Int): FilterControls { - return addFilterControls(slots?.let { Delegate.Of(it) }, amount) +fun MatteryMenu.addFilterSlots(amount: Int, slots: KMutableProperty0?): ItemFilterInput { + return addFilterSlots(amount, if (slots == null) null else Delegate.Of(slots)) } val Slot.isOverCapacity: Boolean get() { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/input/ItemFilterInput.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/input/ItemFilterInput.kt new file mode 100644 index 000000000..43c96518c --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/input/ItemFilterInput.kt @@ -0,0 +1,39 @@ +package ru.dbotthepony.mc.otm.menu.input + +import net.minecraft.world.entity.player.Player +import ru.dbotthepony.kommons.util.Delegate +import ru.dbotthepony.mc.otm.container.ItemFilter +import ru.dbotthepony.mc.otm.container.ItemFilterSet +import ru.dbotthepony.mc.otm.core.immutableList +import ru.dbotthepony.mc.otm.menu.MatteryMenu +import ru.dbotthepony.mc.otm.network.StreamCodecs +import java.util.function.Predicate + +class ItemFilterInput(menu: MatteryMenu, maxSlots: Int, var filter: Delegate?, var allowRecursive: Boolean = false) { + val synchers = immutableList(maxSlots) { i -> + menu.mSynchronizer.computed({ filter?.get()?.get(i) ?: ItemFilter.EMPTY }, StreamCodecs.ITEM_FILTER) + } + + val inputs = immutableList(maxSlots) { i -> + menu.PlayerInput(StreamCodecs.ITEM_FILTER, handler = { + if (allowRecursive || it.depth <= 1) + filter?.get()?.addOrReplace(i, it) + }) + } + + val slots = immutableList(maxSlots) { i -> + Delegate.Of(synchers[i], inputs[i]) + } + + val isWhitelist = BooleanInputWithFeedback.dispatch( + menu, + Delegate.Of({ filter?.get() ?: ItemFilterSet.EMPTY }, { filter?.accept(it) }), + { it.isWhitelist }, + { it, v -> it.isWhitelist(v) } + ) + + fun filter(predicate: Predicate) { + inputs.forEach { it.filter(predicate) } + isWhitelist.input.filter(predicate) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveViewerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveViewerMenu.kt index 1f0a190c0..1e10b89dc 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveViewerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/DriveViewerMenu.kt @@ -1,6 +1,5 @@ package ru.dbotthepony.mc.otm.menu.storage -import net.minecraft.world.SimpleContainer import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player import net.minecraft.world.item.ItemStack @@ -14,6 +13,7 @@ import ru.dbotthepony.mc.otm.capability.drive.IMatteryDrive import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.ItemFilter +import ru.dbotthepony.mc.otm.container.ItemFilterSet import ru.dbotthepony.mc.otm.core.immutableList import ru.dbotthepony.mc.otm.core.util.ItemStorageStackSorter import ru.dbotthepony.mc.otm.item.PortableCondensationDriveItem @@ -24,7 +24,9 @@ import ru.dbotthepony.mc.otm.menu.data.NetworkedItemView import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback +import ru.dbotthepony.mc.otm.menu.input.ItemFilterInput import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget +import ru.dbotthepony.mc.otm.network.StreamCodecs import ru.dbotthepony.mc.otm.registry.game.MMenus import ru.dbotthepony.mc.otm.storage.ItemStorageStack import ru.dbotthepony.mc.otm.storage.StorageStack @@ -75,26 +77,21 @@ class DriveViewerMenu( var drivePresent by mSynchronizer.boolean() - private fun getFilter(): ItemFilter? { + private fun getFilter(): ItemFilterSet { val stack = (tile as? DriveViewerBlockEntity)?.container?.getItem(0) - return (stack?.item as? PortableCondensationDriveItem)?.getFilterSettings(stack) + return (stack?.item as? PortableCondensationDriveItem)?.getFilterSettings(stack) ?: ItemFilterSet.EMPTY } - private fun setFilter(value: ItemFilter) { + private fun setFilter(value: ItemFilterSet) { val stack = (tile as? DriveViewerBlockEntity)?.container?.getItem(0) (stack?.item as? PortableCondensationDriveItem)?.setFilterSettings(stack, value) } - val driveFilterSlots = immutableList(PortableCondensationDriveItem.MAX_FILTERS) { i -> - Delegate.Of( - mSynchronizer.computedItem { getFilter()?.get(i) ?: ItemStack.EMPTY }, - itemStackInput { getFilter()?.set(i, it) }.filter { drivePresent } - ) - } + val driveFilter = ItemFilterInput(this, PortableCondensationDriveItem.MAX_FILTERS, Delegate.Of(::getFilter, ::setFilter)) - val isWhitelist = BooleanInputWithFeedback.dispatch(this, Delegate.Of({ getFilter() }, { setFilter(it!!) }), { it?.isWhitelist ?: false }, { it, v -> it?.isWhitelist(v) }).also { it.filter { drivePresent } } - val matchTag = BooleanInputWithFeedback.dispatch(this, Delegate.Of({ getFilter() }, { setFilter(it!!) }), { it?.matchTag ?: false }, { it, v -> it?.matchTag(v) }).also { it.filter { drivePresent } } - val matchComponents = BooleanInputWithFeedback.dispatch(this, Delegate.Of({ getFilter() }, { setFilter(it!!) }), { it?.matchComponents ?: false }, { it, v -> it?.matchComponents(v) }).also { it.filter { drivePresent } } + init { + driveFilter.filter { drivePresent } + } override fun broadcastChanges() { super.broadcastChanges() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/StorageBusMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/StorageBusMenu.kt index 27f750294..b091300c7 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/StorageBusMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/StorageBusMenu.kt @@ -4,7 +4,7 @@ import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.block.entity.storage.StorageBusBlockEntity import ru.dbotthepony.mc.otm.capability.FlowDirection import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu -import ru.dbotthepony.mc.otm.menu.addFilterControls +import ru.dbotthepony.mc.otm.menu.addFilterSlots import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.IntInputWithFeedback @@ -16,7 +16,7 @@ class StorageBusMenu( inventory: Inventory, tile: StorageBusBlockEntity? = null ) : MatteryPoweredMenu(MMenus.STORAGE_BUS, containerId, inventory, tile) { - val filter = addFilterControls(tile?.let { it::filter }, StorageBusBlockEntity.MAX_FILTERS) + val filter = addFilterSlots(StorageBusBlockEntity.MAX_FILTERS, tile?.let { it::filter }) val insertPriority = IntInputWithFeedback(this, tile?.let { it::insertPriority }) val extractPriority = IntInputWithFeedback(this, tile?.let { it::extractPriority }) val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/StorageImporterExporterMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/StorageImporterExporterMenu.kt index 3f5d89d62..1337d6d83 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/StorageImporterExporterMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/storage/StorageImporterExporterMenu.kt @@ -3,7 +3,7 @@ package ru.dbotthepony.mc.otm.menu.storage import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.block.entity.storage.AbstractStorageImportExport import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu -import ru.dbotthepony.mc.otm.menu.addFilterControls +import ru.dbotthepony.mc.otm.menu.addFilterSlots import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.registry.game.MMenus @@ -11,7 +11,7 @@ import ru.dbotthepony.mc.otm.registry.game.MMenus class StorageImporterExporterMenu( containerId: Int, inventory: Inventory, tile: AbstractStorageImportExport? = null ) : MatteryPoweredMenu(MMenus.STORAGE_IMPORTER_EXPORTER, containerId, inventory, tile) { - val filter = addFilterControls(tile?.let { it::filter }, AbstractStorageImportExport.MAX_FILTERS) + val filter = addFilterSlots(AbstractStorageImportExport.MAX_FILTERS, tile?.let { it::filter }) val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget) val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt index bf17ce3bb..2c796bf21 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryPlayerPackets.kt @@ -484,7 +484,7 @@ class QuickStackPacket( slots.forEach { val slot = it.containerSlotOrNull() - if (it.hasItem() || slot is IFilteredContainerSlot && slot.hasFilter) + if (it.hasItem() || slot is IFilteredContainerSlot && !slot.filter.allowAll) prioritySlots.add(it) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt index 8fffdd713..7479ced2e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt @@ -9,6 +9,7 @@ import net.minecraft.resources.ResourceLocation import net.minecraft.world.level.block.Block import net.minecraft.world.level.block.state.BlockState import ru.dbotthepony.kommons.math.RGBAColor +import ru.dbotthepony.mc.otm.container.ItemFilter import ru.dbotthepony.mc.otm.core.util.readDecimal import ru.dbotthepony.mc.otm.core.util.writeDecimal import ru.dbotthepony.mc.otm.core.readBlockType @@ -43,6 +44,8 @@ object StreamCodecs { val ITEM_TYPE_NULLABLE = ITEM_TYPE.nullable() val DECIMAL = StreamCodec.of(FriendlyByteBuf::writeDecimal, FriendlyByteBuf::readDecimal).wrap() + val ITEM_FILTER = ByteBufCodecs.fromCodecWithRegistries(ItemFilter.CODEC).wrap() + fun composite( c0: StreamCodec, g0: (T) -> T0, c1: StreamCodec, g1: (T) -> T1, diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt index f7c86e5b2..f2477935a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt @@ -4,6 +4,7 @@ import net.minecraft.world.item.Item import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.IContainerSlot import ru.dbotthepony.mc.otm.container.IEnhancedContainer +import ru.dbotthepony.mc.otm.container.ItemFilter class ExopackContainer(size: Int, val player: MatteryPlayer) : EnhancedContainer(size) { private inner class Slot(slot: Int) : IContainerSlot.Simple(slot, this@ExopackContainer), IPlayerInventorySlot { @@ -11,9 +12,9 @@ class ExopackContainer(size: Int, val player: MatteryPlayer) : EnhancedContainer get() = (PlayerInventoryWrapper.SLOTS + slot) in player.slotsChargeFlag set(value) { if (value) player.slotsChargeFlag.add(PlayerInventoryWrapper.SLOTS + slot) else player.slotsChargeFlag.remove(PlayerInventoryWrapper.SLOTS + slot) } - override var filter: Item? - get() = player.slotFilters[PlayerInventoryWrapper.SLOTS + slot] - set(value) { if (value == null) player.slotFilters.remove(PlayerInventoryWrapper.SLOTS + slot) else player.slotFilters[PlayerInventoryWrapper.SLOTS + slot] = value } + override var filter: ItemFilter + get() = player.slotFilters[PlayerInventoryWrapper.SLOTS + slot] ?: ItemFilter.EMPTY + set(value) { if (value.allowAll) player.slotFilters.remove(PlayerInventoryWrapper.SLOTS + slot) else player.slotFilters[PlayerInventoryWrapper.SLOTS + slot] = value } } override fun containerSlot(slot: Int): IPlayerInventorySlot { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt index 9e2868e7f..7f488e078 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/MatteryPlayer.kt @@ -83,6 +83,7 @@ import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.IContainerSlot import ru.dbotthepony.mc.otm.container.IEnhancedContainer import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot +import ru.dbotthepony.mc.otm.container.ItemFilter import ru.dbotthepony.mc.otm.container.get import ru.dbotthepony.mc.otm.container.slotted.ContainerSlot import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer @@ -254,7 +255,7 @@ class MatteryPlayer(val ply: Player) { val slotFilters = syncher.map( backing = ListenableMap(Int2ObjectOpenHashMap()), keyCodec = StreamCodecs.VAR_INT, - valueCodec = StreamCodecs.ITEM_TYPE + valueCodec = StreamCodecs.ITEM_FILTER ).delegate private fun slotChargeToDefault() { @@ -1299,11 +1300,11 @@ class MatteryPlayer(val ply: Player) { @Suppress("unused") companion object { - private val filtersCodec: Codec>> = Codec.list( + private val filtersCodec: Codec>> = Codec.list( RecordCodecBuilder.create { it.group( Codec.INT.minRange(0).fieldOf("slot").forGetter { it.first }, - BuiltInRegistries.ITEM.byNameCodec().fieldOf("filter").forGetter { it.second } + ItemFilter.CODEC.fieldOf("filter").forGetter { it.second } ).apply(it, ::Pair) } ) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/PlayerInventoryWrapper.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/PlayerInventoryWrapper.kt index 35b15d786..4371b50e5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/player/PlayerInventoryWrapper.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/PlayerInventoryWrapper.kt @@ -5,6 +5,7 @@ import net.minecraft.world.entity.player.Player import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.container.ISlottedContainer +import ru.dbotthepony.mc.otm.container.ItemFilter import ru.dbotthepony.mc.otm.container.get import ru.dbotthepony.mc.otm.container.set @@ -17,9 +18,9 @@ class PlayerInventoryWrapper(val player: MatteryPlayer) : ISlottedContainer>("android_research_result") val ANDROID_FEATURE = k>("android_feature") val STACK_TYPE = k>("stack_type") + val ITEM_FILTER = k>("item_filter") } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MDataComponentTypes.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MDataComponentTypes.kt index fbf77afc9..92fbcbfcc 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MDataComponentTypes.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MDataComponentTypes.kt @@ -4,7 +4,6 @@ import com.google.common.collect.ImmutableList import com.mojang.serialization.Codec import net.minecraft.core.UUIDUtil import net.minecraft.core.component.DataComponentType -import net.minecraft.core.component.DataComponents import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.nbt.CompoundTag import net.minecraft.network.RegistryFriendlyByteBuf @@ -15,7 +14,7 @@ import net.neoforged.bus.api.IEventBus import net.neoforged.neoforge.fluids.SimpleFluidContent import ru.dbotthepony.mc.otm.capability.FlowDirection import ru.dbotthepony.mc.otm.capability.matter.PatternState -import ru.dbotthepony.mc.otm.container.ItemFilter +import ru.dbotthepony.mc.otm.container.ItemFilterSet import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.data.codec.DecimalCodec import ru.dbotthepony.mc.otm.item.tool.RedstoneInteractorItem @@ -80,7 +79,7 @@ object MDataComponentTypes { DataComponentType.builder>().persistent(Codec.list(PatternState.CODEC).xmap({ ImmutableList.copyOf(it) }, { it })).build() } - val ITEM_FILTER: DataComponentType by registry.register("item_filter") { DataComponentType.builder().persistent(ItemFilter.CODEC).build() } + val ITEM_FILTER: DataComponentType by registry.register("item_filter") { DataComponentType.builder().persistent(ItemFilterSet.CODEC).build() } val TICK_TIMER: DataComponentType by registry.register("tick_timer") { DataComponentType.builder().persistent(RedstoneInteractorItem.TickTimer.CODEC).build() } val EXPERIENCE: DataComponentType by registry.register("experience") { DataComponentType.builder().persistent(Codec.LONG).networkSynchronized(StreamCodecs.LONG).build() } From 8454db6785365f95d4031da22f88b608315c3bcf Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 29 Mar 2025 12:07:32 +0700 Subject: [PATCH 143/154] Some fixes for item filters --- .../ru/dbotthepony/mc/otm/container/ItemFilterSet.kt | 8 +++----- .../dbotthepony/mc/otm/menu/input/ItemFilterInput.kt | 10 ++++++++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ItemFilterSet.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ItemFilterSet.kt index 8319020b8..18c43bafe 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/ItemFilterSet.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/ItemFilterSet.kt @@ -22,9 +22,7 @@ data class ItemFilterSet(val filter: ImmutableSet, val isWhitelist: } fun replace(index: Int, value: ItemFilter): ItemFilterSet { - if (index !in filter.indices) - throw IndexOutOfBoundsException("No such filter at index $index") - else if (value in filter) + if (index !in filter.indices || value in filter) return this val values = ObjectArrayList(filter) @@ -50,7 +48,7 @@ data class ItemFilterSet(val filter: ImmutableSet, val isWhitelist: fun removeAt(index: Int): ItemFilterSet { if (index !in filter.indices) - throw IndexOutOfBoundsException("No such filter at index $index") + return this if (filter.size == 1) return copy(filter = ImmutableSet.of()) @@ -65,7 +63,7 @@ data class ItemFilterSet(val filter: ImmutableSet, val isWhitelist: } operator fun get(index: Int): ItemFilter { - return filter.asList()[index] + return filter.asList().getOrElse(index) { ItemFilter.EMPTY } } fun clear(): ItemFilterSet { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/input/ItemFilterInput.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/input/ItemFilterInput.kt index 43c96518c..e944af6a6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/input/ItemFilterInput.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/input/ItemFilterInput.kt @@ -16,8 +16,14 @@ class ItemFilterInput(menu: MatteryMenu, maxSlots: Int, var filter: Delegate menu.PlayerInput(StreamCodecs.ITEM_FILTER, handler = { - if (allowRecursive || it.depth <= 1) - filter?.get()?.addOrReplace(i, it) + if (allowRecursive || it.depth <= 1) { + val filter = filter ?: return@PlayerInput + + if (it.hasRules) + filter.accept(filter.get().addOrReplace(i, it)) + else + filter.accept(filter.get().removeAt(i)) + } }) } From f5e21f5582b87a0342a2f4a80004811c4a001612 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 29 Mar 2025 12:41:55 +0700 Subject: [PATCH 144/154] Fix filter deserialization --- .../mc/otm/container/slotted/FilteredContainerSlot.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt index d78c871bf..4e2d50f3d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt @@ -44,7 +44,7 @@ open class FilteredContainerSlot( filter = ItemFilter.EMPTY if ("filter" in nbt) { - ItemFilter.CODEC.decode(provider.createSerializationContext(NbtOps.INSTANCE), nbt) + ItemFilter.CODEC.decode(provider.createSerializationContext(NbtOps.INSTANCE), nbt["filter"]) .ifError { LOGGER.error("Unable to deserialize item filter: ${it.message()}") } .resultOrPartial().map { it.first }.ifPresent { filter = it } } From 571c7bc3390153ad6f01c85d5caab3a9841aa9ae Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 29 Mar 2025 13:33:07 +0700 Subject: [PATCH 145/154] Passing Int.MAX_VALUE to simple container slot factory will make its slots ignore max stack size completely --- .../dbotthepony/mc/otm/container/slotted/ContainerSlot.kt | 8 ++++++++ .../mc/otm/container/slotted/FilteredContainerSlot.kt | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt index 7d4821597..178ee81f5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/ContainerSlot.kt @@ -133,6 +133,13 @@ open class ContainerSlot( override val maxStackSize: Int get() = this@Simple.maxStackSize + override fun maxStackSize(item: ItemStack): Int { + if (maxStackSize == Int.MAX_VALUE) + return Int.MAX_VALUE + + return super.maxStackSize(item) + } + override fun notifyChanged(old: ItemStack) { super.notifyChanged(old) listener(item, old) @@ -160,6 +167,7 @@ open class ContainerSlot( } } + companion object { private val LOGGER = LogManager.getLogger() } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt index 4e2d50f3d..11a59da02 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/FilteredContainerSlot.kt @@ -68,6 +68,13 @@ open class FilteredContainerSlot( override val maxStackSize: Int get() = this@Simple.maxStackSize + override fun maxStackSize(item: ItemStack): Int { + if (maxStackSize == Int.MAX_VALUE) + return Int.MAX_VALUE + + return super.maxStackSize(item) + } + override fun notifyChanged(old: ItemStack) { super.notifyChanged(old) listener(item, old) From 4db52b83c4d567ed3fea86cbe8099d30ccd77414 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 29 Mar 2025 13:34:43 +0700 Subject: [PATCH 146/154] Since /reload reloads everything, we can cache isIncomplete --- .../ru/dbotthepony/mc/otm/recipe/MatterEntanglerRecipe.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/MatterEntanglerRecipe.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/MatterEntanglerRecipe.kt index b5999ed44..bbb540040 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/MatterEntanglerRecipe.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/MatterEntanglerRecipe.kt @@ -89,8 +89,12 @@ open class MatterEntanglerRecipe( return ingredients.ingredients() } + private val isIncomplete by lazy(LazyThreadSafetyMode.PUBLICATION) { + result.isEmpty || ingredients.isIncomplete + } + override fun isIncomplete(): Boolean { - return result.isEmpty || ingredients.isIncomplete + return isIncomplete } override fun isSpecial(): Boolean { From c93fa7bb7a63c7f1083e35b84b7773817bf0d409 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 29 Mar 2025 13:37:14 +0700 Subject: [PATCH 147/154] Weaken type argument in AutomationFilters --- .../otm/container/slotted/AutomationFilter.kt | 11 ++-- .../container/slotted/AutomationFilters.kt | 51 ++++++++++--------- 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilter.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilter.kt index c7cf2bf35..43f09142f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilter.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilter.kt @@ -1,24 +1,25 @@ package ru.dbotthepony.mc.otm.container.slotted import net.minecraft.world.item.ItemStack +import ru.dbotthepony.mc.otm.container.IContainerSlot -fun interface AutomationPlaceItem { +fun interface AutomationPlaceItem { fun canAutomationPlaceItem(self: S, itemStack: ItemStack): Boolean } -fun interface AutomationTakeItem { +fun interface AutomationTakeItem { fun canAutomationTakeItem(self: S, desired: Int): Boolean } -fun interface AutomationModifyPlaceCount { +fun interface AutomationModifyPlaceCount { fun modifyAutomationPlaceCount(self: S, itemStack: ItemStack): Int } -fun interface AutomationModifyExtractionCount { +fun interface AutomationModifyExtractionCount { fun modifyAutomationExtractionCount(self: S, desired: Int): Int } -interface AutomationFilter : AutomationPlaceItem, AutomationTakeItem, AutomationModifyPlaceCount, AutomationModifyExtractionCount { +interface AutomationFilter : AutomationPlaceItem, AutomationTakeItem, AutomationModifyPlaceCount, AutomationModifyExtractionCount { override fun modifyAutomationPlaceCount(self: S, itemStack: ItemStack): Int { return itemStack.count } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt index 702cd4a54..39ea51c3c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt @@ -4,118 +4,119 @@ import net.minecraft.world.item.ItemStack import net.neoforged.neoforge.capabilities.Capabilities import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.fluid.stream +import ru.dbotthepony.mc.otm.container.IContainerSlot import ru.dbotthepony.mc.otm.core.isNotEmpty import ru.dbotthepony.mc.otm.core.math.Decimal -enum class AutomationFilters : AutomationFilter { +enum class AutomationFilters : AutomationFilter { ONLY_OUT { - override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + override fun canAutomationPlaceItem(self: IContainerSlot, itemStack: ItemStack): Boolean { return true } - override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + override fun canAutomationTakeItem(self: IContainerSlot, desired: Int): Boolean { return false } }, ONLY_IN { - override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + override fun canAutomationPlaceItem(self: IContainerSlot, itemStack: ItemStack): Boolean { return false } - override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + override fun canAutomationTakeItem(self: IContainerSlot, desired: Int): Boolean { return true } }, ALLOW { - override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + override fun canAutomationPlaceItem(self: IContainerSlot, itemStack: ItemStack): Boolean { return true } - override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + override fun canAutomationTakeItem(self: IContainerSlot, desired: Int): Boolean { return true } }, DENY { - override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + override fun canAutomationPlaceItem(self: IContainerSlot, itemStack: ItemStack): Boolean { return false } - override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + override fun canAutomationTakeItem(self: IContainerSlot, desired: Int): Boolean { return false } }, FLUID_CONTAINERS { - override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + override fun canAutomationPlaceItem(self: IContainerSlot, itemStack: ItemStack): Boolean { return itemStack.getCapability(Capabilities.FluidHandler.ITEM)?.let { it.tanks > 0 } ?: false } - override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + override fun canAutomationTakeItem(self: IContainerSlot, desired: Int): Boolean { return true } }, DRAINABLE_FLUID_CONTAINERS { - override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + override fun canAutomationPlaceItem(self: IContainerSlot, itemStack: ItemStack): Boolean { return itemStack.getCapability(Capabilities.FluidHandler.ITEM)?.let { it.stream().anyMatch { it.isNotEmpty } } ?: false } - override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + override fun canAutomationTakeItem(self: IContainerSlot, desired: Int): Boolean { return !canAutomationPlaceItem(self, self.item) } }, DISCHARGABLE { - override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + override fun canAutomationPlaceItem(self: IContainerSlot, itemStack: ItemStack): Boolean { return itemStack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { it.canExtract() && it.extractEnergy(Int.MAX_VALUE, true) > 0 } ?: false } - override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + override fun canAutomationTakeItem(self: IContainerSlot, desired: Int): Boolean { return self.item.getCapability(Capabilities.EnergyStorage.ITEM)?.let { !it.canExtract() || it.extractEnergy(Int.MAX_VALUE, true) <= 0 } ?: true } }, CHARGEABLE { - override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + override fun canAutomationPlaceItem(self: IContainerSlot, itemStack: ItemStack): Boolean { return itemStack.getCapability(Capabilities.EnergyStorage.ITEM)?.let { it.canReceive() && it.receiveEnergy(Int.MAX_VALUE, true) > 0 } ?: false } - override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + override fun canAutomationTakeItem(self: IContainerSlot, desired: Int): Boolean { return self.item.getCapability(Capabilities.EnergyStorage.ITEM)?.let { !it.canReceive() || it.receiveEnergy(Int.MAX_VALUE, true) <= 0 } ?: true } }, CHEMICAL_FUEL { - override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + override fun canAutomationPlaceItem(self: IContainerSlot, itemStack: ItemStack): Boolean { return itemStack.getBurnTime(null) > 0 } - override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + override fun canAutomationTakeItem(self: IContainerSlot, desired: Int): Boolean { return self.item.getBurnTime(null) <= 0 } }, IS_PATTERN { - override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + override fun canAutomationPlaceItem(self: IContainerSlot, itemStack: ItemStack): Boolean { return itemStack.getCapability(MatteryCapability.PATTERN_ITEM) != null } - override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + override fun canAutomationTakeItem(self: IContainerSlot, desired: Int): Boolean { return true } }, MATTER_PROVIDERS { - override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + override fun canAutomationPlaceItem(self: IContainerSlot, itemStack: ItemStack): Boolean { return itemStack.getCapability(MatteryCapability.MATTER_ITEM) ?.let { it.matterFlow.output && it.extractMatterChecked(Decimal.POSITIVE_INFINITY, true) > Decimal.ZERO } ?: false } - override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + override fun canAutomationTakeItem(self: IContainerSlot, desired: Int): Boolean { return self.item.getCapability(MatteryCapability.MATTER_ITEM) ?.let { !it.matterFlow.output || it.extractMatterChecked(Decimal.POSITIVE_INFINITY, true) <= Decimal.ZERO } ?: true @@ -123,13 +124,13 @@ enum class AutomationFilters : AutomationFilter { }, MATTER_CONSUMERS { - override fun canAutomationPlaceItem(self: ContainerSlot, itemStack: ItemStack): Boolean { + override fun canAutomationPlaceItem(self: IContainerSlot, itemStack: ItemStack): Boolean { return itemStack.getCapability(MatteryCapability.MATTER_ITEM) ?.let { it.matterFlow.input && it.receiveMatterChecked(Decimal.POSITIVE_INFINITY, true) > Decimal.ZERO } ?: false } - override fun canAutomationTakeItem(self: ContainerSlot, desired: Int): Boolean { + override fun canAutomationTakeItem(self: IContainerSlot, desired: Int): Boolean { return self.item.getCapability(MatteryCapability.MATTER_ITEM) ?.let { !it.matterFlow.input || it.receiveMatterChecked(Decimal.POSITIVE_INFINITY, true) <= Decimal.ZERO } ?: true From 2d1c9184f49c773a2beea6f3e0ec1ee4db465022 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 29 Mar 2025 13:37:27 +0700 Subject: [PATCH 148/154] Fix platform declaration clash --- .../ru/dbotthepony/mc/otm/recipe/MatterEntanglerRecipe.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/MatterEntanglerRecipe.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/MatterEntanglerRecipe.kt index bbb540040..64e322653 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/MatterEntanglerRecipe.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/recipe/MatterEntanglerRecipe.kt @@ -89,12 +89,12 @@ open class MatterEntanglerRecipe( return ingredients.ingredients() } - private val isIncomplete by lazy(LazyThreadSafetyMode.PUBLICATION) { + private val _isIncomplete by lazy(LazyThreadSafetyMode.PUBLICATION) { result.isEmpty || ingredients.isIncomplete } override fun isIncomplete(): Boolean { - return isIncomplete + return _isIncomplete } override fun isSpecial(): Boolean { From 072d2187f83e00eecf042573c79ca1b580c08f38 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 29 Mar 2025 13:39:56 +0700 Subject: [PATCH 149/154] Specify default cache size to 16384 entries, and bump cache size for matter entangler --- .../mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt | 2 +- .../block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt | 2 +- .../mc/otm/block/entity/tech/PlatePressBlockEntity.kt | 2 +- src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt | 4 ++++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt index dbdd0e799..5dfb606a1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt @@ -92,7 +92,7 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M } private inner class InputSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) { - val insertCache = SimpleCache(1024L, Duration.ofMinutes(1)) + val insertCache = SimpleCache(Duration.ofMinutes(1)) override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { if (!super.canAutomationPlaceItem(itemStack)) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt index 1145eec92..6ef977b1a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt @@ -202,7 +202,7 @@ sealed class AbstractPoweredFurnaceBlockEntity

(16384L, Duration.ofMinutes(1)) + private val acceptableItems = SimpleCache(Duration.ofMinutes(1)) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt index a415dfc26..59d6d166a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt @@ -127,6 +127,6 @@ class PlatePressBlockEntity( } companion object { - private val cache = SimpleCache(16384L, Duration.ofMinutes(1L)) + private val cache = SimpleCache(Duration.ofMinutes(1L)) } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt index d839a4269..c099f54d9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt @@ -610,3 +610,7 @@ fun SimpleCache(size: Long, freshness: Duration): Cache { .expireAfterWrite(freshness) .build() } + +fun SimpleCache(freshness: Duration): Cache { + return SimpleCache(16384L, freshness) +} From c98a1573aa2aa7ad710fe18a1eb40f7f48d4e7e7 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 29 Mar 2025 13:47:39 +0700 Subject: [PATCH 150/154] ooprs!!1 --- .../mc/otm/container/slotted/AutomationFilters.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt index 39ea51c3c..b6d5e95a4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/slotted/AutomationFilters.kt @@ -11,21 +11,21 @@ import ru.dbotthepony.mc.otm.core.math.Decimal enum class AutomationFilters : AutomationFilter { ONLY_OUT { override fun canAutomationPlaceItem(self: IContainerSlot, itemStack: ItemStack): Boolean { - return true + return false } override fun canAutomationTakeItem(self: IContainerSlot, desired: Int): Boolean { - return false + return true } }, ONLY_IN { override fun canAutomationPlaceItem(self: IContainerSlot, itemStack: ItemStack): Boolean { - return false + return true } override fun canAutomationTakeItem(self: IContainerSlot, desired: Int): Boolean { - return true + return false } }, From 640aeabb0760f2295ec7ac8984bf3db6d4297822 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 29 Mar 2025 14:06:38 +0700 Subject: [PATCH 151/154] Invalidate recipe caches on resources reload --- .../kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt | 5 +++++ .../mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt | 2 ++ .../block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt | 5 +++++ .../mc/otm/block/entity/tech/PlatePressBlockEntity.kt | 5 +++++ 4 files changed, 17 insertions(+) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt index 0d99c1660..572532f27 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/OverdriveThatMatters.kt @@ -14,6 +14,8 @@ import ru.dbotthepony.mc.otm.player.android.AndroidResearchResults import ru.dbotthepony.mc.otm.player.android.feature.EnderTeleporterFeature import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity import ru.dbotthepony.mc.otm.block.entity.decorative.DevChestBlockEntity +import ru.dbotthepony.mc.otm.block.entity.tech.AbstractPoweredFurnaceBlockEntity +import ru.dbotthepony.mc.otm.block.entity.tech.PlatePressBlockEntity import ru.dbotthepony.mc.otm.player.MatteryPlayer import ru.dbotthepony.mc.otm.capability.drive.DrivePool import ru.dbotthepony.mc.otm.client.AndroidAbilityKeyMapping @@ -244,6 +246,9 @@ object OverdriveThatMatters { FORGE_BUS.addListener(EventPriority.NORMAL, MStructureTags::registerVillagerTrades) + FORGE_BUS.addListener(EventPriority.LOWEST, PlatePressBlockEntity::onReload) + FORGE_BUS.addListener(EventPriority.LOWEST, AbstractPoweredFurnaceBlockEntity.Companion::onReload) + if (isCuriosLoaded) { FORGE_BUS.addListener(EventPriority.NORMAL, ::onCuriosSlotModifiersUpdated) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt index 5dfb606a1..e0e4857ef 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/matter/MatterEntanglerBlockEntity.kt @@ -92,6 +92,8 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M } private inner class InputSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) { + // may get stalled on /reload command for up to a minute + // shouldn't cause major issues through, since /reload is not something you frequently be executing val insertCache = SimpleCache(Duration.ofMinutes(1)) override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt index 6ef977b1a..e92851a9f 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AbstractPoweredFurnaceBlockEntity.kt @@ -16,6 +16,7 @@ import net.minecraft.world.item.crafting.SmokingRecipe import net.minecraft.world.level.block.entity.BlockEntityType import net.minecraft.world.level.block.state.BlockState import net.neoforged.neoforge.capabilities.Capabilities +import net.neoforged.neoforge.event.AddReloadListenerEvent import ru.dbotthepony.kommons.util.getValue import ru.dbotthepony.kommons.util.setValue import ru.dbotthepony.mc.otm.block.entity.ExperienceStorage @@ -203,6 +204,10 @@ sealed class AbstractPoweredFurnaceBlockEntity

(Duration.ofMinutes(1)) + + internal fun onReload(event: AddReloadListenerEvent) { + acceptableItems.invalidateAll() + } } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt index 59d6d166a..3f1c9ca45 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/PlatePressBlockEntity.kt @@ -9,6 +9,7 @@ import net.minecraft.world.item.ItemStack import net.minecraft.world.item.crafting.SingleRecipeInput import net.minecraft.world.level.block.state.BlockState import net.neoforged.neoforge.capabilities.Capabilities +import net.neoforged.neoforge.event.AddReloadListenerEvent import ru.dbotthepony.mc.otm.block.entity.ExperienceStorage import ru.dbotthepony.mc.otm.block.entity.JobContainer import ru.dbotthepony.mc.otm.block.entity.JobStatus @@ -128,5 +129,9 @@ class PlatePressBlockEntity( companion object { private val cache = SimpleCache(Duration.ofMinutes(1L)) + + internal fun onReload(event: AddReloadListenerEvent) { + cache.invalidateAll() + } } } From f82c7977fa506865bf4287b44fdb109fde5ca976 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 29 Mar 2025 14:11:17 +0700 Subject: [PATCH 152/154] Fix being unable to drain sub 1-xp point liquid xp --- .../mc/otm/block/entity/ExperienceStorage.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/ExperienceStorage.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/ExperienceStorage.kt index 43d03cd67..3a0af5351 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/ExperienceStorage.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/ExperienceStorage.kt @@ -117,6 +117,10 @@ class ExperienceStorage(val maxExperience: DoubleSupplier = DoubleSupplier { Dou experience = (nbt?.asDouble ?: 0.0).coerceAtLeast(0.0) } + private val liquidXPMilliBuckets: Int get() { + return (experience * XP_TO_LIQUID_RATIO).toInt() + } + override fun getTanks(): Int { return 1 } @@ -125,7 +129,7 @@ class ExperienceStorage(val maxExperience: DoubleSupplier = DoubleSupplier { Dou if (tank != 0) return FluidStack.EMPTY - return FluidStack(MFluids.LIQUID_XP, (experience * XP_TO_LIQUID_RATIO).toInt()) + return FluidStack(MFluids.LIQUID_XP, liquidXPMilliBuckets) } override fun getTankCapacity(tank: Int): Int { @@ -148,13 +152,13 @@ class ExperienceStorage(val maxExperience: DoubleSupplier = DoubleSupplier { Dou } override fun drain(maxDrain: Int, action: IFluidHandler.FluidAction): FluidStack { - val actualDrain = maxDrain.coerceAtMost((experience * XP_TO_LIQUID_RATIO).toInt()).let { it / XP_TO_LIQUID_RATIO * XP_TO_LIQUID_RATIO } + val actualDrain = maxDrain.coerceAtMost(liquidXPMilliBuckets) if (actualDrain <= 0) return FluidStack.EMPTY if (action.execute()) - experience -= actualDrain / XP_TO_LIQUID_RATIO + experience -= actualDrain.toDouble() / XP_TO_LIQUID_RATIO return FluidStack(MFluids.LIQUID_XP, actualDrain) } From f57ccafcfad2d5cdef7f5b9e8811afb7d7a421ae Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 29 Mar 2025 17:06:01 +0700 Subject: [PATCH 153/154] Fix player not getting advancements for items picked up into exopack inventory --- .../ru/dbotthepony/mc/otm/player/ExopackContainer.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt index f2477935a..945f76272 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/player/ExopackContainer.kt @@ -1,10 +1,13 @@ package ru.dbotthepony.mc.otm.player +import net.minecraft.server.level.ServerPlayer import net.minecraft.world.item.Item +import net.minecraft.world.item.ItemStack import ru.dbotthepony.mc.otm.container.EnhancedContainer import ru.dbotthepony.mc.otm.container.IContainerSlot import ru.dbotthepony.mc.otm.container.IEnhancedContainer import ru.dbotthepony.mc.otm.container.ItemFilter +import ru.dbotthepony.mc.otm.triggers.MatteryInventoryChangeTrigger class ExopackContainer(size: Int, val player: MatteryPlayer) : EnhancedContainer(size) { private inner class Slot(slot: Int) : IContainerSlot.Simple(slot, this@ExopackContainer), IPlayerInventorySlot { @@ -17,6 +20,13 @@ class ExopackContainer(size: Int, val player: MatteryPlayer) : EnhancedContainer set(value) { if (value.allowAll) player.slotFilters.remove(PlayerInventoryWrapper.SLOTS + slot) else player.slotFilters[PlayerInventoryWrapper.SLOTS + slot] = value } } + override fun notifySlotChanged(slot: Int, old: ItemStack) { + super.notifySlotChanged(slot, old) + + if (player.ply is ServerPlayer) + MatteryInventoryChangeTrigger.trigger(player.ply, this, this[slot]) + } + override fun containerSlot(slot: Int): IPlayerInventorySlot { return Slot(slot) } From 3e5f47c9a304ee405fe558b294c6d46776d3c74c Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 29 Mar 2025 17:12:49 +0700 Subject: [PATCH 154/154] Fix matter reconstructor being a downgrade regarding energy values compared to replicator --- .../kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt index 115f0fb4f..3eb517494 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/config/MachinesConfig.kt @@ -110,8 +110,8 @@ object MachinesConfig : AbstractConfig("machines") { private val MATTER_RECONSTRUCTOR = workerValues( MNames.MATTER_RECONSTRUCTOR, - energyStorage = Decimal(100_000), - energyThroughput = Decimal(1000), + energyStorage = Decimal(200_000), + energyThroughput = Decimal(4_000), energyConsumption = Decimal(400), matterCapacity = Decimal(200), workTimeMultiplier = null,