Update storage system to use hashmap for partitioning

This commit is contained in:
DBotThePony 2022-04-26 15:16:25 +07:00
parent a7d11dae3f
commit 6819866c48
4 changed files with 41 additions and 41 deletions

View File

@ -1,8 +1,6 @@
package ru.dbotthepony.mc.otm.block.entity package ru.dbotthepony.mc.otm.block.entity
import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap
import it.unimi.dsi.fastutil.longs.Long2ObjectAVLTreeMap
import it.unimi.dsi.fastutil.longs.Long2ObjectFunction
import it.unimi.dsi.fastutil.objects.Object2ObjectAVLTreeMap import it.unimi.dsi.fastutil.objects.Object2ObjectAVLTreeMap
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Direction import net.minecraft.core.Direction
@ -72,7 +70,7 @@ private class ItemHandlerComponent(private val parent: IItemHandler) : IStorageC
private var scanned = arrayOfNulls<ItemStack>(0) private var scanned = arrayOfNulls<ItemStack>(0)
private var scannedMap = arrayOfNulls<TrackedTuple>(0) private var scannedMap = arrayOfNulls<TrackedTuple>(0)
private val partitioned = Long2ObjectAVLTreeMap<ArrayList<TrackedTuple>>() private val tuples = HashMap<ItemStackWrapper, TrackedTuple>()
private val index = Object2ObjectAVLTreeMap<UUID, TrackedTuple>() private val index = Object2ObjectAVLTreeMap<UUID, TrackedTuple>()
private fun removeTracked(slot: Int) { private fun removeTracked(slot: Int) {
@ -96,15 +94,8 @@ private class ItemHandlerComponent(private val parent: IItemHandler) : IStorageC
index.remove(scannedMap.id) index.remove(scannedMap.id)
val listing = partitioned[scannedMap.stack.longHashCode] ?: throw IllegalStateException("Item listing is not present for ${scannedMap.stack}") val key = scannedMap.stack.key()
tuples.remove(key) ?: throw IllegalStateException("Item tuple is not present for slot $slot at ${scannedMap.stack}")
if (listing.remove(scannedMap)) {
if (listing.isEmpty()) {
partitioned.remove(scannedMap.stack.longHashCode)
}
} else {
throw IllegalStateException("Item listing for ${scannedMap.stack} did not contain $scannedMap")
}
} }
} }
@ -124,24 +115,16 @@ private class ItemHandlerComponent(private val parent: IItemHandler) : IStorageC
private fun addTracked(slot: Int, stack: ItemStack) { private fun addTracked(slot: Int, stack: ItemStack) {
check(scannedMap[slot] == null) { "Already tracking slot $slot" } check(scannedMap[slot] == null) { "Already tracking slot $slot" }
val listing = partitioned.computeIfAbsent(ItemStackWrapper.longHashCode(stack.item), Long2ObjectFunction { ArrayList() }) val storageStack = ItemStackWrapper(stack)
var tuple: TrackedTuple? = null val key = storageStack.key()
var tuple: TrackedTuple? = tuples[key]
for (storedTuple in listing) {
if (storedTuple.stack.sameItem(stack)) {
tuple = storedTuple
break
}
}
val added = tuple == null val added = tuple == null
var oldCount = ImpreciseFraction.ZERO var oldCount = ImpreciseFraction.ZERO
if (added) { if (added) {
val storageStack = ItemStackWrapper(stack)
tuple = TrackedTuple(storageStack, UUID.randomUUID()) tuple = TrackedTuple(storageStack, UUID.randomUUID())
index[tuple.id] = tuple index[tuple.id] = tuple
listing.add(tuple) tuples[key] = tuple
} else { } else {
oldCount = tuple!!.stack.count oldCount = tuple!!.stack.count
tuple.stack.count += stack.count tuple.stack.count += stack.count

View File

@ -20,9 +20,9 @@ interface IItemMatteryDrive : IMatteryDrive<ItemStackWrapper> {
/** /**
* @param stack * @param stack
* @return all items that match this itemstack * @return [ItemStack] that match specified [stack] (item type, nbt tag)
*/ */
fun findItems(stack: ItemStack): Collection<IStorageTuple<ItemStackWrapper>> fun findItems(stack: ItemStack): IStorageTuple<ItemStackWrapper>?
} }
interface IItemViewListener { interface IItemViewListener {

View File

@ -12,7 +12,9 @@ import ru.dbotthepony.mc.otm.set
import ru.dbotthepony.mc.otm.storage.IStorageTuple import ru.dbotthepony.mc.otm.storage.IStorageTuple
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper import ru.dbotthepony.mc.otm.storage.ItemStackWrapper
import ru.dbotthepony.mc.otm.storage.StorageStackType import ru.dbotthepony.mc.otm.storage.StorageStackType
import ru.dbotthepony.mc.otm.storage.key
import java.util.* import java.util.*
import kotlin.collections.ArrayList
class ItemMatteryDrive : AbstractMatteryDrive<ItemStackWrapper>, IItemMatteryDrive { class ItemMatteryDrive : AbstractMatteryDrive<ItemStackWrapper>, IItemMatteryDrive {
constructor(capacity: ImpreciseFraction, max_different_stacks: Int) : super(capacity, maxDifferentStacks = max_different_stacks) constructor(capacity: ImpreciseFraction, max_different_stacks: Int) : super(capacity, maxDifferentStacks = max_different_stacks)
@ -56,22 +58,19 @@ class ItemMatteryDrive : AbstractMatteryDrive<ItemStackWrapper>, IItemMatteryDri
} }
override fun findItems(item: Item): List<IStorageTuple<ItemStackWrapper>> { override fun findItems(item: Item): List<IStorageTuple<ItemStackWrapper>> {
val list = tuples[ItemStackWrapper.longHashCode(item)] val list = ArrayList<IStorageTuple<ItemStackWrapper>>()
return if (list != null) java.util.List.copyOf(list) else emptyList()
}
override fun findItems(stack: ItemStack): List<IStorageTuple<ItemStackWrapper>> { for ((key, value) in tuples.entries) {
val list = tuples[ItemStackWrapper.longHashCode(stack.item)] ?: return emptyList() if (key.item.item === item) {
list.add(value)
val buildList = ArrayList<IStorageTuple<ItemStackWrapper>>()
for (_stack in list) {
if (_stack.stack.sameItem(stack)) {
buildList.add(_stack)
} }
} }
return buildList return list
}
override fun findItems(stack: ItemStack): IStorageTuple<ItemStackWrapper>? {
return tuples[ItemStackWrapper(stack).key()]
} }
companion object { companion object {

View File

@ -4,6 +4,7 @@ import net.minecraft.world.item.Item
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraftforge.registries.ForgeRegistries import net.minecraftforge.registries.ForgeRegistries
import net.minecraftforge.registries.ForgeRegistry import net.minecraftforge.registries.ForgeRegistry
import org.jetbrains.annotations.ApiStatus
import ru.dbotthepony.mc.otm.core.ImpreciseFraction import ru.dbotthepony.mc.otm.core.ImpreciseFraction
/** /**
@ -15,6 +16,7 @@ class ItemStackWrapper : IStorageStack {
* *
* In most cases you want to use [stack] instead. * In most cases you want to use [stack] instead.
*/ */
@ApiStatus.Internal
val item: ItemStack val item: ItemStack
val registryName get() = item.item.registryName!! val registryName get() = item.item.registryName!!
private val hash: Int private val hash: Int
@ -22,10 +24,24 @@ class ItemStackWrapper : IStorageStack {
override var count: ImpreciseFraction override var count: ImpreciseFraction
set(value) { field = value.floor() } set(value) { field = value.floor() }
constructor(item: ItemStack) { /**
this.item = item.copy() * [copy] as false is used internally for fast index construction, do not specify
* it unless you know what you are doing!
*/
@JvmOverloads
constructor(item: ItemStack, copy: Boolean = true) {
if (copy) {
this.item = item.copy()
} else {
this.item = item
}
this.count = ImpreciseFraction(item.count) this.count = ImpreciseFraction(item.count)
this.item.count = 1
if (copy) {
this.item.count = 1
}
this.hash = item.tag.hashCode() xor item.item.hashCode() this.hash = item.tag.hashCode() xor item.item.hashCode()
} }
@ -40,6 +56,8 @@ class ItemStackWrapper : IStorageStack {
return ItemStackWrapper(this) return ItemStackWrapper(this)
} }
fun sameItem(other: ItemStack) = ItemStack.isSameItemSameTags(item, other)
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (other === this) if (other === this)
return true return true