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 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<Pair<Container, Iterable<Int>>>) : IMatteryContainer {
constructor(vararg containers: Container) : this(containers.stream().map { it to (0 until it.containerSize) })
constructor(containers: Collection<Container>) : this(containers.stream().map { it to (0 until it.containerSize) })
class CombinedContainer(containers: Stream<Pair<IEnhancedContainer, Iterable<Int>>>) : ISlottedContainer {
constructor(vararg containers: IEnhancedContainer) : 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 {
override val container: Container
get() = this@CombinedContainer
}
private val slots: ImmutableList<Slot>
private val slots: ImmutableList<IContainerSlot>
private val slotsMap: ImmutableMap<Container, List<IContainerSlot>>
private val containers: ImmutableSet<Container>
private val fullCoverage: ImmutableList<Container>
private val notFullCoverage: ImmutableMap<Container, List<IContainerSlot>>
init {
val list = ImmutableList.Builder<Slot>()
var i = 0
val list = ImmutableList.Builder<IContainerSlot>()
val validationMap = Reference2ObjectOpenHashMap<Container, IntSet>()
val slotsMap = Reference2ObjectOpenHashMap<Container, ArrayList<IContainerSlot>>()
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<Pair<Container, Iterable<Int>>>) : 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<Pair<Container, Iterable<Int>>>) : 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<Pair<Container, Iterable<Int>>>) : IM
return true
}
override fun iterator(nonEmpty: Boolean): Iterator<ItemStack> {
override fun iterator(): Iterator<ItemStack> {
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<IContainerSlot> {
if (nonEmpty)
return slots.iterator().filter { it.isNotEmpty }
override fun slotIterator(): Iterator<IContainerSlot> {
return slots.iterator()
}
@ -176,42 +148,54 @@ class CombinedContainer(containers: Stream<Pair<Container, Iterable<Int>>>) : 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<Pair<Container, Iterable<Int>>>()
private val values = ArrayList<Pair<IEnhancedContainer, Iterable<Int>>>()
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)
return this
}
fun add(container: Container, slots: Iterator<Int>): Builder {
fun add(container: IEnhancedContainer, slots: Iterator<Int>): 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<Int>): Builder {
fun add(container: IEnhancedContainer, slots: Iterable<Int>): Builder {
values.add(container to slots)
return this
}

View File

@ -17,7 +17,7 @@ import ru.dbotthepony.mc.otm.data.getOrNull
open class ContainerSlot(
protected val container: SlottedContainer,
protected val slot: Int
) : ISlottedContainerSlot, INBTSerializable<CompoundTag> {
) : IAutomatedContainerSlot, INBTSerializable<CompoundTag> {
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) {

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
*/
interface ISlottedContainerSlot : IContainerSlot {
interface IAutomatedContainerSlot : IContainerSlot {
fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
return true
}

View File

@ -24,6 +24,9 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable<ItemStack> {
return IContainerSlot.Simple(slot, this)
}
/**
* Returns iterator over **all** slots this container has
*/
fun slotIterator(): Iterator<IContainerSlot> {
return (0 until containerSize).iterator().map { containerSlot(it) }
}
@ -122,6 +125,9 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable<ItemStack> {
return maxStackSize
}
/**
* Returns iterator over **non-empty** [ItemStack]s inside this container
*/
override fun iterator(): Iterator<ItemStack> {
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
interface IFilteredSlottedContainerSlot : IFilteredContainerSlot, ISlottedContainerSlot {
interface IFilteredAutomatedContainerSlot : IFilteredContainerSlot, IAutomatedContainerSlot {
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
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
/**
* 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<ISlottedContainerSlot> {
interface ISlottedContainer : IEnhancedContainer {
override fun slotIterator(): Iterator<IContainerSlot> {
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 }
}
@ -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

View File

@ -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<SlotProvider>,
private val stillValid: Predicate<Player>,
private val globalChangeListeners: Array<Runnable>
) : ISlottedContainer, INBTSerializable<Tag> {
) : IAutomatedContainer, INBTSerializable<Tag> {
private val slots: Array<ContainerSlot>
init {
@ -46,7 +45,7 @@ class SlottedContainer(
}
}
override fun containerSlot(slot: Int): ISlottedContainerSlot {
override fun containerSlot(slot: Int): IAutomatedContainerSlot {
return slots[slot]
}