Some helper functions, split "Filtered" into own subclass with own "Simple" factory
This commit is contained in:
parent
ab1446b682
commit
9f6b9ad85b
@ -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
|
if (slots.isEmpty() || checkForEmpty && !slots.any { getItem(it).isNotEmpty }) return
|
||||||
|
|
||||||
val empty = IntArrayList()
|
val empty = IntArrayList()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package ru.dbotthepony.mc.otm.container
|
package ru.dbotthepony.mc.otm.container
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntCollection
|
||||||
import it.unimi.dsi.fastutil.ints.IntSet
|
import it.unimi.dsi.fastutil.ints.IntSet
|
||||||
import net.minecraft.world.Container
|
import net.minecraft.world.Container
|
||||||
import net.minecraft.world.entity.player.Player
|
import net.minecraft.world.entity.player.Player
|
||||||
@ -32,10 +33,10 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable<ItemStack> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun nonEmptySlotIterator(): Iterator<IContainerSlot> {
|
fun nonEmptySlotIterator(): Iterator<IContainerSlot> {
|
||||||
return (0 until containerSize).iterator().map { containerSlot(it) }.filter { it.isNotEmpty }
|
return slotIterator().filter { it.isNotEmpty }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun slotIterator(allowedSlots: IntSet, predicate: Predicate<ItemStack>): IntIterator {
|
private fun slotIterator(allowedSlots: IntCollection, predicate: Predicate<ItemStack>): IntIterator {
|
||||||
return object : IntIterator() {
|
return object : IntIterator() {
|
||||||
private val parent = allowedSlots.intIterator()
|
private val parent = allowedSlots.intIterator()
|
||||||
private var foundNext = false
|
private var foundNext = false
|
||||||
@ -76,15 +77,15 @@ interface IEnhancedContainer : IContainer, RecipeInput, Iterable<ItemStack> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun emptySlotIterator(allowedSlots: IntSet = slotRange): IntIterator {
|
fun emptySlotIterator(allowedSlots: IntCollection = slotRange): IntIterator {
|
||||||
return slotIterator(allowedSlots) { it.isEmpty }
|
return slotIterator(allowedSlots) { it.isEmpty }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun nonEmptySlotIterator(allowedSlots: IntSet = slotRange): IntIterator {
|
fun nonEmptySlotIterator(allowedSlots: IntCollection = slotRange): IntIterator {
|
||||||
return slotIterator(allowedSlots) { it.isNotEmpty }
|
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 }
|
return slotIterator(allowedSlots) { it.isNotEmpty && it.item === item }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package ru.dbotthepony.mc.otm.container
|
package ru.dbotthepony.mc.otm.container
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntCollection
|
||||||
import it.unimi.dsi.fastutil.ints.IntSet
|
import it.unimi.dsi.fastutil.ints.IntSet
|
||||||
import net.minecraft.world.Container
|
import net.minecraft.world.Container
|
||||||
import net.minecraft.world.item.ItemStack
|
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
|
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 {
|
interface ISlottedContainer : IEnhancedContainer {
|
||||||
override fun slotIterator(): Iterator<IContainerSlot> {
|
|
||||||
return (0 until containerSize).iterator().map { containerSlot(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun nonEmptySlotIterator(): Iterator<IContainerSlot> {
|
|
||||||
return (0 until containerSize).iterator().map { containerSlot(it) }.filter { it.isNotEmpty }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setChanged(slot: Int) {
|
override fun setChanged(slot: Int) {
|
||||||
containerSlot(slot).setChanged()
|
containerSlot(slot).setChanged()
|
||||||
}
|
}
|
||||||
@ -44,7 +37,7 @@ interface ISlottedContainer : IEnhancedContainer {
|
|||||||
containerSlot(slot).item = itemStack
|
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())
|
if (stack.isEmpty || slots.isEmpty())
|
||||||
return stack
|
return stack
|
||||||
|
|
||||||
@ -129,7 +122,7 @@ interface ISlottedContainer : IEnhancedContainer {
|
|||||||
val hasFilterableSlots: Boolean
|
val hasFilterableSlots: Boolean
|
||||||
get() = slotIterator().any { it is IFilteredContainerSlot }
|
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())
|
if (stack.isEmpty || slots.isEmpty())
|
||||||
return stack
|
return stack
|
||||||
|
|
||||||
@ -148,7 +141,7 @@ interface ISlottedContainer : IEnhancedContainer {
|
|||||||
*
|
*
|
||||||
* @return Whenever [stack] was modified
|
* @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)
|
if (stack.isEmpty)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
@ -157,7 +150,7 @@ interface ISlottedContainer : IEnhancedContainer {
|
|||||||
return result.count != stack.count
|
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)
|
if (!addItem(stack, true, slots, popTime = popTime, onlyIntoExisting = onlyIntoExisting, ignoreFilters = ignoreFilters).isEmpty)
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
@ -109,11 +109,15 @@ open class ContainerSlot(
|
|||||||
notifyChanged(ItemStack.EMPTY)
|
notifyChanged(ItemStack.EMPTY)
|
||||||
}
|
}
|
||||||
|
|
||||||
open class Simple(
|
class Simple(
|
||||||
protected val listener: (new: ItemStack, old: ItemStack) -> Unit,
|
private val listener: (new: ItemStack, old: ItemStack) -> Unit = { _, _ -> },
|
||||||
protected val maxStackSize: Int = Item.DEFAULT_MAX_STACK_SIZE,
|
private val maxStackSize: Int = Item.DEFAULT_MAX_STACK_SIZE,
|
||||||
) : SlottedContainer.SlotProvider {
|
private val canAutomationPlaceItem: AutomationPlaceItem<ContainerSlot> = AutomationPlaceItem { _, _ -> true },
|
||||||
protected open inner class Instance(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) {
|
private val canAutomationTakeItem: AutomationTakeItem<ContainerSlot> = AutomationTakeItem { _, _ -> true },
|
||||||
|
private val modifyAutomationPlaceCount: AutomationModifyPlaceCount<ContainerSlot> = AutomationModifyPlaceCount { _, item -> item.count },
|
||||||
|
private val modifyAutomationExtractionCount: AutomationModifyExtractionCount<ContainerSlot> = AutomationModifyExtractionCount { _, desired -> desired },
|
||||||
|
) : SlottedContainer.SlotProvider<ContainerSlot> {
|
||||||
|
private open inner class Instance(container: SlottedContainer, slot: Int) : ContainerSlot(container, slot) {
|
||||||
override val maxStackSize: Int
|
override val maxStackSize: Int
|
||||||
get() = this@Simple.maxStackSize
|
get() = this@Simple.maxStackSize
|
||||||
|
|
||||||
@ -121,45 +125,21 @@ open class ContainerSlot(
|
|||||||
super.notifyChanged(old)
|
super.notifyChanged(old)
|
||||||
listener(item, old)
|
listener(item, old)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun create(container: SlottedContainer, index: Int): ContainerSlot {
|
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||||
return Instance(container, index)
|
return super.canAutomationPlaceItem(itemStack) && canAutomationPlaceItem.canAutomationPlaceItem(this, itemStack)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 serializeNBT(provider: HolderLookup.Provider): CompoundTag {
|
override fun canAutomationTakeItem(desired: Int): Boolean {
|
||||||
return super.serializeNBT(provider).also {
|
return super.canAutomationTakeItem(desired) && canAutomationTakeItem.canAutomationTakeItem(this, desired)
|
||||||
if (filter != null)
|
|
||||||
it["filter"] = filter!!.registryName!!.toString()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deserializeNBT(provider: HolderLookup.Provider, nbt: CompoundTag) {
|
override fun modifyAutomationPlaceCount(itemStack: ItemStack): Int {
|
||||||
super.deserializeNBT(provider, nbt)
|
return modifyAutomationPlaceCount.modifyAutomationPlaceCount(this, itemStack)
|
||||||
|
}
|
||||||
|
|
||||||
if ("filter" in nbt) {
|
override fun modifyAutomationExtractionCount(desired: Int): Int {
|
||||||
filter = BuiltInRegistries.ITEM.get(ResourceLocation.parse(nbt.getString("filter")))
|
return modifyAutomationExtractionCount.modifyAutomationExtractionCount(this, desired)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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<FilteredContainerSlot> = AutomationPlaceItem { _, _ -> true },
|
||||||
|
private val canAutomationTakeItem: AutomationTakeItem<FilteredContainerSlot> = AutomationTakeItem { _, _ -> true },
|
||||||
|
private val modifyAutomationPlaceCount: AutomationModifyPlaceCount<FilteredContainerSlot> = AutomationModifyPlaceCount { _, item -> item.count },
|
||||||
|
private val modifyAutomationExtractionCount: AutomationModifyExtractionCount<FilteredContainerSlot> = AutomationModifyExtractionCount { _, desired -> desired },
|
||||||
|
) : SlottedContainer.SlotProvider<FilteredContainerSlot> {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package ru.dbotthepony.mc.otm.container.slotted
|
||||||
|
|
||||||
|
import net.minecraft.world.item.ItemStack
|
||||||
|
|
||||||
|
fun interface AutomationPlaceItem<S : ContainerSlot> {
|
||||||
|
fun canAutomationPlaceItem(self: S, itemStack: ItemStack): Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface AutomationTakeItem<S : ContainerSlot> {
|
||||||
|
fun canAutomationTakeItem(self: S, desired: Int): Boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface AutomationModifyPlaceCount<S : ContainerSlot> {
|
||||||
|
fun modifyAutomationPlaceCount(self: S, itemStack: ItemStack): Int
|
||||||
|
}
|
||||||
|
|
||||||
|
fun interface AutomationModifyExtractionCount<S : ContainerSlot> {
|
||||||
|
fun modifyAutomationExtractionCount(self: S, desired: Int): Int
|
||||||
|
}
|
@ -2,6 +2,11 @@ package ru.dbotthepony.mc.otm.container.slotted
|
|||||||
|
|
||||||
import com.mojang.serialization.Codec
|
import com.mojang.serialization.Codec
|
||||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
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.HolderLookup
|
||||||
import net.minecraft.core.registries.BuiltInRegistries
|
import net.minecraft.core.registries.BuiltInRegistries
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.CompoundTag
|
||||||
@ -14,24 +19,106 @@ import net.minecraft.world.item.Item
|
|||||||
import net.minecraft.world.item.ItemStack
|
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.kommons.util.Either
|
||||||
import ru.dbotthepony.mc.otm.container.IAutomatedContainer
|
import ru.dbotthepony.mc.otm.container.IAutomatedContainer
|
||||||
import ru.dbotthepony.mc.otm.container.IAutomatedContainerSlot
|
import ru.dbotthepony.mc.otm.container.IAutomatedContainerSlot
|
||||||
import ru.dbotthepony.mc.otm.container.IFilteredContainerSlot
|
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.isNotEmpty
|
||||||
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
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
class SlottedContainer(
|
class SlottedContainer(
|
||||||
slots: Collection<SlotProvider>,
|
slots: Collection<MarkedSlotProvider<*>>,
|
||||||
private val stillValid: Predicate<Player>,
|
private val stillValid: Predicate<Player>,
|
||||||
private val globalChangeListeners: Array<Runnable>
|
private val globalChangeListeners: Array<Runnable>
|
||||||
) : IAutomatedContainer, INBTSerializable<Tag> {
|
) : IAutomatedContainer, INBTSerializable<Tag> {
|
||||||
|
interface ISlotGroup<T : ContainerSlot> : List<T> {
|
||||||
|
/**
|
||||||
|
* @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<T : ContainerSlot> : ISlotGroup<T>, AbstractList<T>() {
|
||||||
|
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<T : ContainerSlot>(val clazz: KClass<T>) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "SlottedContainer.SingleTag[${System.identityHashCode(this).toString(16)}@${clazz.qualifiedName}]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MultiTag<T : ContainerSlot>(val clazz: KClass<T>) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "SlottedContainer.MultiTag[${System.identityHashCode(this).toString(16)}@${clazz.qualifiedName}]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val sets = HashMap<MultiTag<*>, SlotGroup<*>>()
|
||||||
|
private val singular = HashMap<SingleTag<*>, ContainerSlot>()
|
||||||
private val slots: Array<ContainerSlot>
|
private val slots: Array<ContainerSlot>
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val itr = slots.iterator()
|
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<ContainerSlot>() }.slots.add(index) })
|
||||||
|
slot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun <T : ContainerSlot> get(tag: MultiTag<T>): ISlotGroup<T> {
|
||||||
|
return sets[tag] as ISlotGroup<T>? ?: throw NoSuchElementException("Container does not contain $tag")
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun <T : ContainerSlot> get(tag: SingleTag<T>): T {
|
||||||
|
return singular[tag] as T? ?: throw NoSuchElementException("Container does not contain $tag")
|
||||||
}
|
}
|
||||||
|
|
||||||
override val hasFilterableSlots: Boolean = this.slots.any { it is IFilteredContainerSlot }
|
override val hasFilterableSlots: Boolean = this.slots.any { it is IFilteredContainerSlot }
|
||||||
@ -218,23 +305,44 @@ class SlottedContainer(
|
|||||||
notifyChanged()
|
notifyChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun interface SlotProvider {
|
fun interface SlotProvider<T : ContainerSlot> {
|
||||||
fun create(container: SlottedContainer, index: Int): ContainerSlot
|
fun create(container: SlottedContainer, index: Int): T
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class MarkedSlotProvider<T : ContainerSlot>(val mark: Either<SingleTag<T>, MultiTag<T>>?, val provider: SlotProvider<T>)
|
||||||
|
|
||||||
class Builder {
|
class Builder {
|
||||||
private val slots = ArrayList<SlotProvider>()
|
private val slots = ArrayList<MarkedSlotProvider<*>>()
|
||||||
private var stillValid = Predicate<Player> { true }
|
private var stillValid = Predicate<Player> { true }
|
||||||
private val globalChangeListeners = ArrayList<Runnable>()
|
private val globalChangeListeners = ArrayList<Runnable>()
|
||||||
|
private val seenSingleTags = ObjectOpenHashSet<SingleTag<*>>()
|
||||||
|
|
||||||
fun add(slot: SlotProvider): Builder {
|
fun add(slot: SlotProvider<*>): Builder {
|
||||||
slots.add(slot)
|
slots.add(MarkedSlotProvider(null, slot))
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun add(amount: Int, provider: SlotProvider): Builder {
|
fun <T : ContainerSlot> add(tag: SingleTag<T>, slot: SlotProvider<T>): Builder {
|
||||||
|
require(seenSingleTags.add(tag)) { "Duplicate slot tag: $tag" }
|
||||||
|
slots.add(MarkedSlotProvider(Either.left(tag), slot))
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : ContainerSlot> add(tag: MultiTag<T>, slot: SlotProvider<T>): Builder {
|
||||||
|
slots.add(MarkedSlotProvider(Either.right(tag), slot))
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun add(amount: Int, provider: SlotProvider<*>): Builder {
|
||||||
for (i in 0 until amount)
|
for (i in 0 until amount)
|
||||||
slots.add(provider)
|
slots.add(MarkedSlotProvider(null, provider))
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : ContainerSlot> add(amount: Int, tag: MultiTag<T>, provider: SlotProvider<T>): Builder {
|
||||||
|
for (i in 0 until amount)
|
||||||
|
slots.add(MarkedSlotProvider(Either.right(tag), provider))
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
@ -262,8 +370,37 @@ class SlottedContainer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val LOGGER = LogManager.getLogger()
|
private val LOGGER = LogManager.getLogger()
|
||||||
|
|
||||||
|
inline fun <reified T : ContainerSlot> tag(): SingleTag<T> {
|
||||||
|
return SingleTag(T::class)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : ContainerSlot> tagList(): MultiTag<T> {
|
||||||
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user