Further split ISlottedContainer into IAutomatedContainer

This commit is contained in:
DBotThePony 2025-02-27 23:40:29 +07:00
parent 124a1b3db6
commit 6747d5f471
Signed by: DBot
GPG Key ID: DCC23B5715498507
8 changed files with 98 additions and 99 deletions

View File

@ -5,6 +5,7 @@ import com.google.common.collect.ImmutableMap
import com.google.common.collect.ImmutableSet import com.google.common.collect.ImmutableSet
import it.unimi.dsi.fastutil.ints.IntAVLTreeSet import it.unimi.dsi.fastutil.ints.IntAVLTreeSet
import it.unimi.dsi.fastutil.ints.IntArrayList import it.unimi.dsi.fastutil.ints.IntArrayList
import it.unimi.dsi.fastutil.ints.IntOpenHashSet
import it.unimi.dsi.fastutil.ints.IntSet import it.unimi.dsi.fastutil.ints.IntSet
import it.unimi.dsi.fastutil.objects.Object2ObjectFunction import it.unimi.dsi.fastutil.objects.Object2ObjectFunction
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap 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 ru.dbotthepony.mc.otm.core.stream
import java.util.stream.Stream import java.util.stream.Stream
class CombinedContainer(containers: Stream<Pair<Container, Iterable<Int>>>) : IMatteryContainer { class CombinedContainer(containers: Stream<Pair<IEnhancedContainer, Iterable<Int>>>) : ISlottedContainer {
constructor(vararg containers: Container) : this(containers.stream().map { it to (0 until it.containerSize) }) constructor(vararg containers: IEnhancedContainer) : this(containers.stream().map { it to (0 until it.containerSize) })
constructor(containers: Collection<Container>) : this(containers.stream().map { it to (0 until it.containerSize) }) constructor(containers: Collection<IEnhancedContainer>) : this(containers.stream().map { it to (0 until it.containerSize) })
private inner class Slot(override val slot: Int, val outer: IContainerSlot) : IContainerSlot by outer { private val slots: ImmutableList<IContainerSlot>
override val container: Container
get() = this@CombinedContainer
}
private val slots: ImmutableList<Slot>
private val slotsMap: ImmutableMap<Container, List<IContainerSlot>> private val slotsMap: ImmutableMap<Container, List<IContainerSlot>>
private val containers: ImmutableSet<Container> private val containers: ImmutableSet<Container>
private val fullCoverage: ImmutableList<Container> private val fullCoverage: ImmutableList<Container>
private val notFullCoverage: ImmutableMap<Container, List<IContainerSlot>> private val notFullCoverage: ImmutableMap<Container, List<IContainerSlot>>
init { init {
val list = ImmutableList.Builder<Slot>() val list = ImmutableList.Builder<IContainerSlot>()
var i = 0
val validationMap = Reference2ObjectOpenHashMap<Container, IntSet>() val validationMap = Reference2ObjectOpenHashMap<Container, IntSet>()
val slotsMap = Reference2ObjectOpenHashMap<Container, ArrayList<IContainerSlot>>() val slotsMap = Reference2ObjectOpenHashMap<Container, ArrayList<IContainerSlot>>()
var i = 0
for ((container, slots) in containers) { 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() }) val slotList = slotsMap.computeIfAbsent(container, Object2ObjectFunction { ArrayList() })
for (slot in slots) { for (slot in slots) {
if (validator.add(slot)) { if (validator.add(slot)) {
val slotObj = container.containerSlot(slot) val slotObj = container.containerSlot(slot)
list.add(Slot(i++, slotObj)) list.add(slotObj)
slotList.add(slotObj) slotList.add(slotObj)
} else { } else {
throw IllegalArgumentException("Duplicate mapping for $container at $i for slot $slot") throw IllegalArgumentException("Duplicate mapping for $container at $i for slot $slot")
} }
i++
} }
} }
@ -85,20 +83,7 @@ class CombinedContainer(containers: Stream<Pair<Container, Iterable<Int>>>) : IM
for (slots in notFullCoverage.values) { for (slots in notFullCoverage.values) {
for (slot in slots) { for (slot in slots) {
slot.item = ItemStack.EMPTY slot.remove()
}
}
}
override fun clearSlotFilters() {
for (container in fullCoverage) {
if (container is IMatteryContainer)
container.clearSlotFilters()
}
for (slots in notFullCoverage.values) {
for (slot in slots) {
slot.setFilter()
} }
} }
} }
@ -127,16 +112,6 @@ class CombinedContainer(containers: Stream<Pair<Container, Iterable<Int>>>) : IM
return slots.getOrNull(slot)?.item ?: ItemStack.EMPTY 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) { override fun setItem(slot: Int, itemStack: ItemStack) {
slots.getOrNull(slot)?.item = itemStack slots.getOrNull(slot)?.item = itemStack
} }
@ -155,20 +130,17 @@ class CombinedContainer(containers: Stream<Pair<Container, Iterable<Int>>>) : IM
return true return true
} }
override fun iterator(nonEmpty: Boolean): Iterator<ItemStack> { override fun iterator(): Iterator<ItemStack> {
if (notFullCoverage.isEmpty()) if (notFullCoverage.isEmpty())
return fullCoverage.iterator().flatMap { it.iterator(nonEmpty) } return fullCoverage.iterator().flatMap { it.iterator() }
return concatIterators( return concatIterators(
fullCoverage.iterator().flatMap { it.iterator(nonEmpty) }, fullCoverage.iterator().flatMap { it.iterator() },
notFullCoverage.values.iterator().flatMap { it.iterator() }.map { it.item }.let { if (nonEmpty) it.filter { it.isNotEmpty } else it } notFullCoverage.values.iterator().flatMap { it.iterator() }.map { it.item }.filter { it.isNotEmpty }
) )
} }
override fun slotIterator(nonEmpty: Boolean): Iterator<IContainerSlot> { override fun slotIterator(): Iterator<IContainerSlot> {
if (nonEmpty)
return slots.iterator().filter { it.isNotEmpty }
return slots.iterator() return slots.iterator()
} }
@ -176,42 +148,54 @@ class CombinedContainer(containers: Stream<Pair<Container, Iterable<Int>>>) : IM
return slots[slot] return slots[slot]
} }
override fun getSlotFilter(slot: Int): Item? {
return slots[slot].getFilter()
}
override fun setChanged(slot: Int) { override fun setChanged(slot: Int) {
slots[slot].setChanged() slots[slot].setChanged()
} }
override fun setSlotFilter(slot: Int, filter: Item?): Boolean {
return slots[slot].setFilter(filter)
}
class Builder { class Builder {
private val values = ArrayList<Pair<Container, Iterable<Int>>>() private val values = ArrayList<Pair<IEnhancedContainer, Iterable<Int>>>()
fun add(container: Container): Builder { fun add(container: Container): Builder {
return add(IEnhancedContainer.wrap(container))
}
fun add(container: Container, slots: Iterator<Int>): 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<Int>): Builder {
return add(IEnhancedContainer.wrap(container), slots)
}
fun add(container: IEnhancedContainer): Builder {
values.add(container to container.slotRange) values.add(container to container.slotRange)
return this return this
} }
fun add(container: Container, slots: Iterator<Int>): Builder { fun add(container: IEnhancedContainer, slots: Iterator<Int>): Builder {
values.add(container to IntArrayList(slots)) values.add(container to IntArrayList(slots))
return this return this
} }
fun add(container: Container, slot: Int): Builder { fun add(container: IEnhancedContainer, slot: Int): Builder {
values.add(container to intArrayOf(slot).asIterable()) values.add(container to intArrayOf(slot).asIterable())
return this 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)) values.add(container to (from .. to))
return this return this
} }
fun add(container: Container, slots: Iterable<Int>): Builder { fun add(container: IEnhancedContainer, slots: Iterable<Int>): Builder {
values.add(container to slots) values.add(container to slots)
return this return this
} }

View File

@ -17,7 +17,7 @@ import ru.dbotthepony.mc.otm.data.getOrNull
open class ContainerSlot( open class ContainerSlot(
protected val container: SlottedContainer, protected val container: SlottedContainer,
protected val slot: Int protected val slot: Int
) : ISlottedContainerSlot, INBTSerializable<CompoundTag> { ) : IAutomatedContainerSlot, INBTSerializable<CompoundTag> {
private var _item: ItemStack = ItemStack.EMPTY private var _item: ItemStack = ItemStack.EMPTY
final override var item: ItemStack final override var item: ItemStack
@ -130,7 +130,7 @@ open class ContainerSlot(
listener: (new: ItemStack, old: ItemStack) -> Unit, listener: (new: ItemStack, old: ItemStack) -> Unit,
maxStackSize: Int = Item.DEFAULT_MAX_STACK_SIZE, maxStackSize: Int = Item.DEFAULT_MAX_STACK_SIZE,
) : Simple(listener, maxStackSize) { ) : 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 override var filter: Item? = null
set(value) { set(value) {
if (field !== value) { if (field !== value) {

View File

@ -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)
}
}

View File

@ -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 * 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 { fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
return true return true
} }

View File

@ -24,6 +24,9 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable<ItemStack> {
return IContainerSlot.Simple(slot, this) return IContainerSlot.Simple(slot, this)
} }
/**
* Returns iterator over **all** slots this container has
*/
fun slotIterator(): Iterator<IContainerSlot> { fun slotIterator(): Iterator<IContainerSlot> {
return (0 until containerSize).iterator().map { containerSlot(it) } return (0 until containerSize).iterator().map { containerSlot(it) }
} }
@ -122,6 +125,9 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable<ItemStack> {
return maxStackSize return maxStackSize
} }
/**
* Returns iterator over **non-empty** [ItemStack]s inside this container
*/
override fun iterator(): Iterator<ItemStack> { override fun iterator(): Iterator<ItemStack> {
return (0 until containerSize).iterator().map { this[it] }.filter { it.isNotEmpty } return (0 until containerSize).iterator().map { this[it] }.filter { it.isNotEmpty }
} }

View File

@ -2,7 +2,7 @@ package ru.dbotthepony.mc.otm.container
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
interface IFilteredSlottedContainerSlot : IFilteredContainerSlot, ISlottedContainerSlot { interface IFilteredAutomatedContainerSlot : IFilteredContainerSlot, IAutomatedContainerSlot {
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean { override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
return super.canAutomationPlaceItem(itemStack) && testSlotFilter(itemStack) return super.canAutomationPlaceItem(itemStack) && testSlotFilter(itemStack)
} }

View File

@ -9,17 +9,14 @@ import ru.dbotthepony.mc.otm.core.collect.filter
import ru.dbotthepony.mc.otm.core.collect.map import ru.dbotthepony.mc.otm.core.collect.map
/** /**
* Container which revolve around embedding slot objects rather than providing direct item access, * Container which revolve around embedding slot objects rather than providing direct item access
* and subsequently fully implement [IItemHandler]
*/ */
interface ISlottedContainer : IEnhancedContainer, IItemHandler { interface ISlottedContainer : IEnhancedContainer {
override fun containerSlot(slot: Int): ISlottedContainerSlot override fun slotIterator(): Iterator<IContainerSlot> {
override fun slotIterator(): Iterator<ISlottedContainerSlot> {
return (0 until containerSize).iterator().map { containerSlot(it) } return (0 until containerSize).iterator().map { containerSlot(it) }
} }
override fun nonEmptySlotIterator(): Iterator<ISlottedContainerSlot> { override fun nonEmptySlotIterator(): Iterator<IContainerSlot> {
return (0 until containerSize).iterator().map { containerSlot(it) }.filter { it.isNotEmpty } return (0 until containerSize).iterator().map { containerSlot(it) }.filter { it.isNotEmpty }
} }
@ -47,33 +44,6 @@ interface ISlottedContainer : IEnhancedContainer, IItemHandler {
containerSlot(slot).item = 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 { private fun addItem(stack: ItemStack, simulate: Boolean, filterPass: Boolean, slots: IntSet, onlyIntoExisting: Boolean, popTime: Int?, ignoreFilters: Boolean): ItemStack {
if (stack.isEmpty || slots.isEmpty()) if (stack.isEmpty || slots.isEmpty())
return stack return stack

View File

@ -15,7 +15,6 @@ import net.minecraft.world.item.ItemStack
import net.neoforged.neoforge.common.util.INBTSerializable import net.neoforged.neoforge.common.util.INBTSerializable
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.core.isNotEmpty 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.core.nbt.set
import ru.dbotthepony.mc.otm.data.codec.minRange import ru.dbotthepony.mc.otm.data.codec.minRange
import java.util.function.Predicate import java.util.function.Predicate
@ -24,7 +23,7 @@ class SlottedContainer(
slots: Collection<SlotProvider>, slots: Collection<SlotProvider>,
private val stillValid: Predicate<Player>, private val stillValid: Predicate<Player>,
private val globalChangeListeners: Array<Runnable> private val globalChangeListeners: Array<Runnable>
) : ISlottedContainer, INBTSerializable<Tag> { ) : IAutomatedContainer, INBTSerializable<Tag> {
private val slots: Array<ContainerSlot> private val slots: Array<ContainerSlot>
init { init {
@ -46,7 +45,7 @@ class SlottedContainer(
} }
} }
override fun containerSlot(slot: Int): ISlottedContainerSlot { override fun containerSlot(slot: Int): IAutomatedContainerSlot {
return slots[slot] return slots[slot]
} }