diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt index 3a6a0d860..5d9f7e8b7 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/storage/ItemMonitorBlockEntity.kt @@ -240,7 +240,7 @@ class ItemMonitorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : val item = craftingGrid[i] if (!item.isEmpty) { - poweredView[ItemStackWrapper(item).key()].let(craftingGridTuples[i]::addAll) + poweredView[ItemStackWrapper(item).key()]?.let(craftingGridTuples[i]::add) } } } @@ -248,7 +248,6 @@ class ItemMonitorBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : } private val craftingGridTuples = Array(3 * 3) { HashSet() } - private val craftingGridTuplesFuzzy = Array(3 * 3) { HashSet() } private val craftingMenu = object : AbstractContainerMenu(null, Int.MIN_VALUE) { override fun stillValid(p_38874_: Player): Boolean { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/storage/API.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/API.kt index 8b6558614..44380ac09 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/storage/API.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/storage/API.kt @@ -101,6 +101,9 @@ interface IStorageEventConsumer : IStorage { fun removeStack(stack: T, id: UUID) } +/** + * Storage acceptor, accepts (insert only) stacks provided via [insertStack] method. + */ interface IStorageAcceptor : IStorage { /** * Inserts an item into system. @@ -109,14 +112,40 @@ interface IStorageAcceptor : IStorage { fun insertStack(stack: T, simulate: Boolean): T } +/** + * Storage provider, provides (extract only) stacks to whoever needs them (the "warehouse"). + * + * [get] methods work as in bidirectional map. + * + * It is **required** for storage having **exactly one or none** of mappings of one stack [T] + * to one [UUID] (exactly one *UUID -> stack* and exactly one *stack -> UUID*). + * + * What this means is that [get] with [T] as an argument shall never experience a situation where + * two stacks match provided key. + * + * Technical decision of using [UUID]s for primary key for locating stacks is performance. + * This allows us to avoid burden of constantly constructing keys out of stacks (e.g. [net.minecraft.world.item.ItemStack]s) + * which may or may not produce performance hit; [UUID]s are lightweight, semantically not bound to anything and are + * very good for distributed ID generation (so nothing in game has to be bound to one sequential number generator). + */ interface IStorageProvider : IStorageEventProducer { /** + * Attempts to retrieve stored stack by its [id]. + * + * Returns stored stack as-is. If no stack with [id] exists, then + * "empty stack" is returned. + * * @param id identifier of stack * @return stored object (not a copy). Do not edit it. */ operator fun get(id: UUID): T /** + * Attempts to map given [key] to [UUID] inside this storage provider. + * + * Implementation requirement: There should **never** be a situation where one [key] + * matches two or more stacks. **Exactly one or none**. + * * @param key stack we want to find UUID of * @return UUID of stack if present */ @@ -169,6 +198,9 @@ fun IStorageProvider.addListenerAuto(listener: IStorageEv return false } +/** + * Storage component, which basically implement Input and Output + */ interface IStorageComponent : IStorageProvider, IStorageAcceptor fun IStorageEventConsumer.changeStack(tuple: IStorageTuple, oldCount: BigInteger) {