Implement faster lookup methods for Slotted Container as well
This commit is contained in:
parent
8b38504a26
commit
0efc520782
@ -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<out S : IContainerSlot> : IEnhancedContainer<S> {
|
||||
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<ItemStack> {
|
||||
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)
|
||||
}
|
||||
}
|
@ -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<out S : IContainerSlot>(private val size: Int) : IEnhancedContainer<S>, INBTSerializable<CompoundTag> {
|
||||
abstract class EnhancedContainer<out S : IContainerSlot>(private val size: Int) : BitmapTrackingContainer<S>(), INBTSerializable<CompoundTag> {
|
||||
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<ItemStack> {
|
||||
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) {}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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<MarkedSlotProvider<*>>,
|
||||
private val stillValid: Predicate<Player>,
|
||||
private val globalChangeListeners: Array<Runnable>
|
||||
) : IAutomatedContainer<ContainerSlot>, INBTSerializable<Tag> {
|
||||
) : BitmapTrackingContainer<ContainerSlot>(), IAutomatedContainer<ContainerSlot>, INBTSerializable<Tag> {
|
||||
interface ISlotGroup<T : ContainerSlot> : List<T> {
|
||||
/**
|
||||
* @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
|
||||
|
Loading…
Reference in New Issue
Block a user