Finely optimize MatteryContainer iterator() and isEmpty(), add Cache<T> to container
This commit is contained in:
parent
0878bd9a7e
commit
8653dd343f
@ -1,59 +1,42 @@
|
||||
package ru.dbotthepony.mc.otm.container
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectIterators
|
||||
import net.minecraft.world.Container
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import ru.dbotthepony.mc.otm.core.collect.ContainerItemStackEntry
|
||||
import ru.dbotthepony.mc.otm.core.collect.AwareItemStack
|
||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||
|
||||
class ContainerIterator(private val container: Container, initialPosition: Int = 0) : ObjectIterators.AbstractIndexBasedListIterator<ItemStack>(0, initialPosition), MutableListIterator<ItemStack> {
|
||||
init {
|
||||
require(initialPosition in 0 .. container.containerSize) { "Invalid initial position: $initialPosition" }
|
||||
class ContainerIterator(private val container: Container) : MutableIterator<ItemStack> {
|
||||
private var index = 0
|
||||
private var lastIndex = -1
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
while (index < container.containerSize) {
|
||||
if (container[index].isNotEmpty) {
|
||||
return true
|
||||
}
|
||||
|
||||
index++
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
override fun add(location: Int, k: ItemStack) {
|
||||
throw UnsupportedOperationException()
|
||||
override fun next(): ItemStack {
|
||||
if (!hasNext()) {
|
||||
throw NoSuchElementException()
|
||||
}
|
||||
|
||||
lastIndex = index
|
||||
return container[index++]
|
||||
}
|
||||
|
||||
override fun set(location: Int, k: ItemStack) {
|
||||
container[location] = k
|
||||
}
|
||||
override fun remove() {
|
||||
if (lastIndex == -1) {
|
||||
throw NoSuchElementException()
|
||||
}
|
||||
|
||||
override fun remove(location: Int) {
|
||||
pos++
|
||||
container[location] = ItemStack.EMPTY
|
||||
}
|
||||
|
||||
override fun get(location: Int): ItemStack {
|
||||
return container[location]
|
||||
}
|
||||
|
||||
override fun getMaxPos(): Int {
|
||||
return container.containerSize
|
||||
container[lastIndex] = ItemStack.EMPTY
|
||||
lastIndex = -1
|
||||
}
|
||||
}
|
||||
|
||||
class AwareContainerIterator(private val container: Container, initialPosition: Int = 0) : ObjectIterators.AbstractIndexBasedIterator<AwareItemStack>(0, initialPosition), Iterator<AwareItemStack> {
|
||||
init {
|
||||
require(initialPosition in 0 .. container.containerSize) { "Invalid initial position: $initialPosition" }
|
||||
}
|
||||
|
||||
override fun remove(location: Int) {
|
||||
pos++
|
||||
container[location] = ItemStack.EMPTY
|
||||
}
|
||||
|
||||
override fun get(location: Int): AwareItemStack {
|
||||
return ContainerItemStackEntry(location, container)
|
||||
}
|
||||
|
||||
override fun getMaxPos(): Int {
|
||||
return container.containerSize
|
||||
}
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun Container.iterator(initialPosition: Int = 0) = ContainerIterator(this, initialPosition)
|
||||
|
||||
@JvmOverloads
|
||||
fun Container.awareIterator(initialPosition: Int = 0) = AwareContainerIterator(this, initialPosition)
|
||||
fun Container.iterator() = ContainerIterator(this)
|
||||
|
@ -2,6 +2,9 @@ package ru.dbotthepony.mc.otm.container
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
|
||||
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.objects.ObjectIterators
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.ListTag
|
||||
@ -14,6 +17,8 @@ import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.Items
|
||||
import net.minecraftforge.common.util.INBTSerializable
|
||||
import net.minecraftforge.registries.ForgeRegistries
|
||||
import ru.dbotthepony.mc.otm.core.addSorted
|
||||
import ru.dbotthepony.mc.otm.core.isNotEmpty
|
||||
import ru.dbotthepony.mc.otm.core.nbt.map
|
||||
import ru.dbotthepony.mc.otm.core.nbt.set
|
||||
import ru.dbotthepony.mc.otm.core.registryName
|
||||
@ -23,6 +28,8 @@ import ru.dbotthepony.mc.otm.network.synchronizer.FieldSynchronizer
|
||||
import ru.dbotthepony.mc.otm.network.synchronizer.IField
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.*
|
||||
import java.util.function.Supplier
|
||||
import kotlin.NoSuchElementException
|
||||
|
||||
@Suppress("UNUSED")
|
||||
open class MatteryContainer(protected val watcher: Runnable, private val size: Int) : Container, Iterable<ItemStack>, INBTSerializable<Tag?> {
|
||||
@ -32,11 +39,40 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
||||
require(size >= 0) { "Invalid container size $size" }
|
||||
}
|
||||
|
||||
protected val slots: Array<ItemStack> = Array(size) { ItemStack.EMPTY }
|
||||
private val slots = Array(size) { ItemStack.EMPTY }
|
||||
private val nonEmptyFlags = BitSet()
|
||||
private val nonEmptyIndices = IntArrayList()
|
||||
private val trackedSlots: Array<ItemStack> = Array(size) { ItemStack.EMPTY }
|
||||
private val filters: Array<Item?> = arrayOfNulls(size)
|
||||
private var filterSynchronizer: WeakReference<IField<MutableMap<Int, Item>>>? = null
|
||||
|
||||
var changeset = 0
|
||||
private set
|
||||
|
||||
inner class Cache<T>(private val supplier: (MatteryContainer) -> T) : Supplier<T> {
|
||||
private var thisChangeset = -1
|
||||
private var value: T? = null
|
||||
private var isDisabled = false
|
||||
|
||||
fun disable() {
|
||||
isDisabled = true
|
||||
}
|
||||
|
||||
fun enable() {
|
||||
isDisabled = false
|
||||
}
|
||||
|
||||
override fun get(): T {
|
||||
if (thisChangeset == changeset && !isDisabled) {
|
||||
return value as T
|
||||
}
|
||||
|
||||
value = supplier.invoke(this@MatteryContainer)
|
||||
thisChangeset = changeset
|
||||
return value as T
|
||||
}
|
||||
}
|
||||
|
||||
fun clearSlotFilters() {
|
||||
Arrays.fill(filters, null)
|
||||
filterSynchronizer?.get()?.value?.clear()
|
||||
@ -159,6 +195,9 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
||||
override fun deserializeNBT(tag: Tag?) {
|
||||
Arrays.fill(slots, ItemStack.EMPTY)
|
||||
Arrays.fill(filters, null)
|
||||
nonEmptyFlags.clear()
|
||||
nonEmptyIndices.clear()
|
||||
|
||||
filterSynchronizer?.get()?.value?.clear()
|
||||
|
||||
when (tag) {
|
||||
@ -244,6 +283,7 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
||||
val old = slotStack.copy()
|
||||
slotStack.count = newCount
|
||||
trackedSlots[slot] = slotStack.copy()
|
||||
changeset++
|
||||
setChanged(slot, slotStack, old)
|
||||
|
||||
if (popTime != null) {
|
||||
@ -269,7 +309,11 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
||||
if (!simulate) {
|
||||
val copyToPut = copy.copy()
|
||||
copyToPut.count = diff
|
||||
this[slot] = copyToPut
|
||||
slots[slot] = copyToPut
|
||||
trackedSlots[slot] = copyToPut.copy()
|
||||
updateEmptyFlag(slot)
|
||||
changeset++
|
||||
setChanged(slot, copyToPut, ItemStack.EMPTY)
|
||||
|
||||
if (popTime != null) {
|
||||
copyToPut.popTime = popTime
|
||||
@ -327,11 +371,14 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
||||
}
|
||||
|
||||
override fun isEmpty(): Boolean {
|
||||
return slots.all { it.isEmpty }
|
||||
return nonEmptyIndices.isEmpty
|
||||
}
|
||||
|
||||
operator fun get(slot: Int) = getItem(slot)
|
||||
operator fun set(slot: Int, stack: ItemStack) = setItem(slot, stack)
|
||||
@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)
|
||||
|
||||
operator fun contains(other: ItemStack): Boolean {
|
||||
for (i in 0 until size) {
|
||||
@ -346,10 +393,19 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
||||
final override fun getItem(slot: Int): ItemStack {
|
||||
val item = slots[slot]
|
||||
|
||||
if (item.isEmpty)
|
||||
if (item.isEmpty) {
|
||||
if (nonEmptyFlags[slot]) {
|
||||
setChanged(slot)
|
||||
}
|
||||
|
||||
return ItemStack.EMPTY
|
||||
else
|
||||
} else {
|
||||
if (!nonEmptyFlags[slot]) {
|
||||
setChanged(slot)
|
||||
}
|
||||
|
||||
return item
|
||||
}
|
||||
}
|
||||
|
||||
final override fun removeItem(slot: Int, amount: Int): ItemStack {
|
||||
@ -359,6 +415,8 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
||||
val old = slots[slot].copy()
|
||||
val split = slots[slot].split(amount)
|
||||
trackedSlots[slot] = slots[slot].copy()
|
||||
changeset++
|
||||
updateEmptyFlag(slot)
|
||||
setChanged(slot, if (slots[slot].isEmpty) ItemStack.EMPTY else slots[slot], old)
|
||||
|
||||
return split
|
||||
@ -368,6 +426,12 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
||||
val old = slots[slot]
|
||||
slots[slot] = ItemStack.EMPTY
|
||||
trackedSlots[slot] = ItemStack.EMPTY
|
||||
|
||||
if (old.isNotEmpty) {
|
||||
updateEmptyFlag(slot)
|
||||
changeset++
|
||||
}
|
||||
|
||||
return old
|
||||
}
|
||||
|
||||
@ -376,8 +440,11 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
||||
return
|
||||
|
||||
val old = slots[slot]
|
||||
slots[slot] = stack
|
||||
slots[slot] = if (stack.isEmpty) ItemStack.EMPTY else stack
|
||||
trackedSlots[slot] = if (stack.isEmpty) ItemStack.EMPTY else stack.copy()
|
||||
|
||||
updateEmptyFlag(slot)
|
||||
changeset++
|
||||
setChanged(slot, stack, old)
|
||||
}
|
||||
|
||||
@ -389,17 +456,38 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
||||
|
||||
fun setChanged(slot: Int) {
|
||||
if (!slots[slot].equals(trackedSlots[slot], false)) {
|
||||
setChanged(slot, slots[slot], trackedSlots[slot])
|
||||
trackedSlots[slot] = slots[slot].copy()
|
||||
updateEmptyFlag(slot)
|
||||
changeset++
|
||||
setChanged(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
|
||||
nonEmptyIndices.removeInt(slot)
|
||||
}
|
||||
} else {
|
||||
if (!nonEmptyFlags[slot]) {
|
||||
nonEmptyFlags[slot] = true
|
||||
nonEmptyIndices.addSorted(slot, IntComparators.NATURAL_COMPARATOR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun stillValid(player: Player): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
final override fun clearContent() {
|
||||
nonEmptyFlags.clear()
|
||||
nonEmptyIndices.clear()
|
||||
|
||||
Arrays.fill(trackedSlots, ItemStack.EMPTY)
|
||||
|
||||
for (slot in 0 until size) {
|
||||
if (!slots[slot].isEmpty) {
|
||||
val old = slots[slot]
|
||||
@ -407,11 +495,37 @@ open class MatteryContainer(protected val watcher: Runnable, private val size: I
|
||||
setChanged(slot, ItemStack.EMPTY, old)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Arrays.fill(trackedSlots, ItemStack.EMPTY)
|
||||
private inner class Iterator : MutableIterator<ItemStack> {
|
||||
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)
|
||||
}
|
||||
|
||||
override fun remove() {
|
||||
if (lastIndex == -1) {
|
||||
throw NoSuchElementException()
|
||||
}
|
||||
|
||||
parent.remove()
|
||||
setItem(lastIndex, ItemStack.EMPTY)
|
||||
lastIndex = -1
|
||||
}
|
||||
}
|
||||
|
||||
final override fun iterator(): MutableIterator<ItemStack> {
|
||||
return ContainerIterator(this)
|
||||
if (isEmpty) {
|
||||
return ObjectIterators.EMPTY_ITERATOR as MutableIterator<ItemStack>
|
||||
}
|
||||
|
||||
return Iterator()
|
||||
}
|
||||
}
|
||||
|
@ -376,6 +376,7 @@ fun <E> List<E>.searchInsertionIndex(element: E, comparator: Comparator<E>, from
|
||||
return fromIndex
|
||||
}
|
||||
|
||||
// линейный поиск если границы маленькие
|
||||
if (toIndex - fromIndex <= 10) {
|
||||
for (i in fromIndex + 1 until toIndex) {
|
||||
val compare = comparator.compare(element, this[i])
|
||||
@ -387,6 +388,7 @@ fun <E> List<E>.searchInsertionIndex(element: E, comparator: Comparator<E>, from
|
||||
|
||||
return size
|
||||
} else {
|
||||
// двоичный поиск
|
||||
var lower = fromIndex
|
||||
var upper = toIndex - 1
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user