Compare commits
5 Commits
70c5382e9d
...
0efc520782
Author | SHA1 | Date | |
---|---|---|---|
0efc520782 | |||
8b38504a26 | |||
69d9aaab50 | |||
448041fe2e | |||
54012cf136 |
@ -22,7 +22,7 @@ mixin_version=0.8.5
|
|||||||
neogradle.subsystems.parchment.minecraftVersion=1.21.1
|
neogradle.subsystems.parchment.minecraftVersion=1.21.1
|
||||||
neogradle.subsystems.parchment.mappingsVersion=2024.11.17
|
neogradle.subsystems.parchment.mappingsVersion=2024.11.17
|
||||||
|
|
||||||
kommons_version=3.5.2
|
kommons_version=3.6.0
|
||||||
caffeine_cache_version=3.1.5
|
caffeine_cache_version=3.1.5
|
||||||
|
|
||||||
jei_version=19.16.4.171
|
jei_version=19.16.4.171
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -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.IntOpenHashSet
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet
|
||||||
import net.minecraft.core.HolderLookup.Provider
|
import net.minecraft.core.HolderLookup.Provider
|
||||||
import net.minecraft.nbt.CompoundTag
|
import net.minecraft.nbt.CompoundTag
|
||||||
@ -12,9 +13,14 @@ import net.minecraft.world.entity.player.Player
|
|||||||
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.collect.iterateClearBits
|
||||||
|
import ru.dbotthepony.kommons.collect.iterateSetBits
|
||||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.IntRange2Set
|
||||||
|
import ru.dbotthepony.mc.otm.core.collect.map
|
||||||
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 java.util.BitSet
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flexible base implementation of [IEnhancedContainer], designed to be inherited, or used as-is
|
* Flexible base implementation of [IEnhancedContainer], designed to be inherited, or used as-is
|
||||||
@ -23,7 +29,7 @@ import ru.dbotthepony.mc.otm.core.nbt.set
|
|||||||
* This is supposed to be counterpart to [SimpleContainer] of Minecraft itself, with more features
|
* This is supposed to be counterpart to [SimpleContainer] of Minecraft itself, with more features
|
||||||
* and improved performance (inside [IEnhancedContainer] defined methods).
|
* 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 items = Array(size) { ItemStack.EMPTY }
|
||||||
private val observedItems = Array(size) { ItemStack.EMPTY }
|
private val observedItems = Array(size) { ItemStack.EMPTY }
|
||||||
|
|
||||||
@ -36,9 +42,11 @@ abstract class EnhancedContainer<out S : IContainerSlot>(private val size: Int)
|
|||||||
if (items[slot].isEmpty) {
|
if (items[slot].isEmpty) {
|
||||||
items[slot] = ItemStack.EMPTY
|
items[slot] = ItemStack.EMPTY
|
||||||
observedItems[slot] = ItemStack.EMPTY
|
observedItems[slot] = ItemStack.EMPTY
|
||||||
|
bitmap[slot] = false
|
||||||
} else {
|
} else {
|
||||||
notifySlotChanged(slot, observedItems[slot])
|
notifySlotChanged(slot, observedItems[slot])
|
||||||
observedItems[slot] = items[slot].copy()
|
observedItems[slot] = items[slot].copy()
|
||||||
|
bitmap[slot] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,6 +58,7 @@ abstract class EnhancedContainer<out S : IContainerSlot>(private val size: Int)
|
|||||||
override fun clearContent() {
|
override fun clearContent() {
|
||||||
items.fill(ItemStack.EMPTY)
|
items.fill(ItemStack.EMPTY)
|
||||||
observedItems.fill(ItemStack.EMPTY)
|
observedItems.fill(ItemStack.EMPTY)
|
||||||
|
bitmap.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setChanged() {
|
override fun setChanged() {
|
||||||
@ -146,6 +155,7 @@ abstract class EnhancedContainer<out S : IContainerSlot>(private val size: Int)
|
|||||||
val copy = observedItems.copyOf()
|
val copy = observedItems.copyOf()
|
||||||
items.fill(ItemStack.EMPTY)
|
items.fill(ItemStack.EMPTY)
|
||||||
observedItems.fill(ItemStack.EMPTY)
|
observedItems.fill(ItemStack.EMPTY)
|
||||||
|
bitmap.clear()
|
||||||
|
|
||||||
val seenSlots = IntOpenHashSet()
|
val seenSlots = IntOpenHashSet()
|
||||||
val ops = provider.createSerializationContext(NbtOps.INSTANCE)
|
val ops = provider.createSerializationContext(NbtOps.INSTANCE)
|
||||||
@ -166,6 +176,7 @@ abstract class EnhancedContainer<out S : IContainerSlot>(private val size: Int)
|
|||||||
if (it.isNotEmpty) {
|
if (it.isNotEmpty) {
|
||||||
items[slot] = it
|
items[slot] = it
|
||||||
observedItems[slot] = it.copy()
|
observedItems[slot] = it.copy()
|
||||||
|
bitmap[slot] = true
|
||||||
|
|
||||||
if (it.count != copy[slot].count || !ItemStack.isSameItemSameComponents(it, copy[slot]))
|
if (it.count != copy[slot].count || !ItemStack.isSameItemSameComponents(it, copy[slot]))
|
||||||
notifySlotChanged(slot, copy[slot])
|
notifySlotChanged(slot, copy[slot])
|
||||||
|
@ -76,10 +76,22 @@ interface IEnhancedContainer<out S : IContainerSlot> : Container, RecipeInput, I
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun nonEmptySlotIterator(): Iterator<S> {
|
fun nonEmptySlotIterator(): Iterator<S> {
|
||||||
return slotIterator().filter { it.isNotEmpty }
|
return nonEmptySlotIndexIterator().map { containerSlot(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun slotIterator(allowedSlots: IntCollection, predicate: Predicate<ItemStack>): IntIterator {
|
fun emptySlotIterator(): Iterator<S> {
|
||||||
|
return emptySlotIndexIterator().map { containerSlot(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nonEmptySlotIterator(allowedSlots: IntCollection): Iterator<S> {
|
||||||
|
return nonEmptySlotIndexIterator(allowedSlots).map { containerSlot(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun emptySlotIterator(allowedSlots: IntCollection): Iterator<S> {
|
||||||
|
return emptySlotIndexIterator(allowedSlots).map { containerSlot(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun slotIndexWalker(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
|
||||||
@ -120,6 +132,14 @@ interface IEnhancedContainer<out S : IContainerSlot> : Container, RecipeInput, I
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun emptySlotIndexIterator(allowedSlots: IntCollection): IntIterator {
|
||||||
|
return slotIndexWalker(allowedSlots) { it.isEmpty }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun nonEmptySlotIndexIterator(allowedSlots: IntCollection): IntIterator {
|
||||||
|
return slotIndexWalker(allowedSlots) { it.isNotEmpty }
|
||||||
|
}
|
||||||
|
|
||||||
fun emptySlotIndexIterator(): IntIterator {
|
fun emptySlotIndexIterator(): IntIterator {
|
||||||
return emptySlotIndexIterator(slotRange)
|
return emptySlotIndexIterator(slotRange)
|
||||||
}
|
}
|
||||||
@ -128,20 +148,30 @@ interface IEnhancedContainer<out S : IContainerSlot> : Container, RecipeInput, I
|
|||||||
return nonEmptySlotIndexIterator(slotRange)
|
return nonEmptySlotIndexIterator(slotRange)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun emptySlotIndexIterator(allowedSlots: IntCollection): IntIterator {
|
fun slotIndexWithItemIterator(item: Item): IntIterator {
|
||||||
return slotIterator(allowedSlots) { it.isEmpty }
|
return slotIndexWithItemIterator(item, slotRange)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun nonEmptySlotIndexIterator(allowedSlots: IntCollection): IntIterator {
|
fun slotIndexWithItemIterator(item: Item, allowedSlots: IntCollection): IntIterator {
|
||||||
return slotIterator(allowedSlots) { it.isNotEmpty }
|
val parent = nonEmptySlotIndexIterator(allowedSlots).filter { this[it].isNotEmpty && this[it].item === item }
|
||||||
|
|
||||||
|
return object : IntIterator() {
|
||||||
|
override fun nextInt(): Int {
|
||||||
|
return parent.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasNext(): Boolean {
|
||||||
|
return parent.hasNext()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun slotWithItemIterator(item: Item): IntIterator {
|
fun slotWithItemIterator(item: Item): Iterator<S> {
|
||||||
return slotWithItemIterator(item, slotRange)
|
return slotWithItemIterator(item, slotRange)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun slotWithItemIterator(item: Item, allowedSlots: IntCollection): IntIterator {
|
fun slotWithItemIterator(item: Item, allowedSlots: IntCollection): Iterator<S> {
|
||||||
return slotIterator(allowedSlots) { it.isNotEmpty && it.item === item }
|
return slotIndexWithItemIterator(item, allowedSlots).map { containerSlot(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun nextEmptySlot(startIndex: Int): Int {
|
fun nextEmptySlot(startIndex: Int): Int {
|
||||||
@ -189,17 +219,11 @@ interface IEnhancedContainer<out S : IContainerSlot> : Container, RecipeInput, I
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun isEmpty(): Boolean {
|
override fun isEmpty(): Boolean {
|
||||||
return super.isEmpty()
|
return nextNonEmptySlot(0) != -1
|
||||||
}
|
}
|
||||||
|
|
||||||
val hasEmptySlots: Boolean get() {
|
val hasEmptySlots: Boolean get() {
|
||||||
for (i in 0 until containerSize) {
|
return nextEmptySlot(0) != -1
|
||||||
if (this[i].isEmpty) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun size(): Int {
|
override fun size(): Int {
|
||||||
@ -209,11 +233,8 @@ interface IEnhancedContainer<out S : IContainerSlot> : Container, RecipeInput, I
|
|||||||
override fun countItem(item: Item): Int {
|
override fun countItem(item: Item): Int {
|
||||||
var count = 0
|
var count = 0
|
||||||
|
|
||||||
for (stack in this) {
|
for (slot in slotWithItemIterator(item))
|
||||||
if (stack.item === item) {
|
count += slot.item.count
|
||||||
count += stack.count
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
@ -257,9 +278,7 @@ interface IEnhancedContainer<out S : IContainerSlot> : Container, RecipeInput, I
|
|||||||
return stack
|
return stack
|
||||||
|
|
||||||
// двигаем в одинаковые слоты
|
// двигаем в одинаковые слоты
|
||||||
for (i in slotWithItemIterator(stack.item, slots)) {
|
for (slot in slotWithItemIterator(stack.item, slots)) {
|
||||||
val slot = containerSlot(i)
|
|
||||||
|
|
||||||
val condition: Boolean
|
val condition: Boolean
|
||||||
|
|
||||||
if (slot is IFilteredContainerSlot) {
|
if (slot is IFilteredContainerSlot) {
|
||||||
@ -295,9 +314,7 @@ interface IEnhancedContainer<out S : IContainerSlot> : Container, RecipeInput, I
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!onlyIntoExisting) {
|
if (!onlyIntoExisting) {
|
||||||
for (i in emptySlotIndexIterator(slots)) {
|
for (slot in emptySlotIterator(slots)) {
|
||||||
val slot = containerSlot(i)
|
|
||||||
|
|
||||||
val condition: Boolean
|
val condition: Boolean
|
||||||
|
|
||||||
if (slot is IFilteredContainerSlot) {
|
if (slot is IFilteredContainerSlot) {
|
||||||
|
@ -56,12 +56,12 @@ open class ContainerSlot(
|
|||||||
notifyChanged(observedItem)
|
notifyChanged(observedItem)
|
||||||
observedItem = ItemStack.EMPTY
|
observedItem = ItemStack.EMPTY
|
||||||
_item = ItemStack.EMPTY
|
_item = ItemStack.EMPTY
|
||||||
container.notifyChanged()
|
container.notifyChanged(slot)
|
||||||
return true
|
return true
|
||||||
} else if (observedItem.count != item.count || !ItemStack.isSameItemSameComponents(item, observedItem)) {
|
} else if (observedItem.count != item.count || !ItemStack.isSameItemSameComponents(item, observedItem)) {
|
||||||
notifyChanged(observedItem)
|
notifyChanged(observedItem)
|
||||||
observedItem = item.copy()
|
observedItem = item.copy()
|
||||||
container.notifyChanged()
|
container.notifyChanged(slot)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ 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.kommons.util.Either
|
||||||
|
import ru.dbotthepony.mc.otm.container.BitmapTrackingContainer
|
||||||
import ru.dbotthepony.mc.otm.container.EnhancedContainer
|
import ru.dbotthepony.mc.otm.container.EnhancedContainer
|
||||||
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
|
||||||
@ -25,6 +26,7 @@ import ru.dbotthepony.mc.otm.container.balance
|
|||||||
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.BitSet
|
||||||
import java.util.function.Predicate
|
import java.util.function.Predicate
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
@ -40,7 +42,7 @@ class SlottedContainer(
|
|||||||
slots: Collection<MarkedSlotProvider<*>>,
|
slots: Collection<MarkedSlotProvider<*>>,
|
||||||
private val stillValid: Predicate<Player>,
|
private val stillValid: Predicate<Player>,
|
||||||
private val globalChangeListeners: Array<Runnable>
|
private val globalChangeListeners: Array<Runnable>
|
||||||
) : IAutomatedContainer<ContainerSlot>, INBTSerializable<Tag> {
|
) : BitmapTrackingContainer<ContainerSlot>(), IAutomatedContainer<ContainerSlot>, INBTSerializable<Tag> {
|
||||||
interface ISlotGroup<T : ContainerSlot> : List<T> {
|
interface ISlotGroup<T : ContainerSlot> : List<T> {
|
||||||
/**
|
/**
|
||||||
* @see IAutomatedContainer.addItem
|
* @see IAutomatedContainer.addItem
|
||||||
@ -130,6 +132,7 @@ class SlottedContainer(
|
|||||||
private var suppressListeners = false
|
private var suppressListeners = false
|
||||||
|
|
||||||
override fun clearContent() {
|
override fun clearContent() {
|
||||||
|
bitmap.clear()
|
||||||
suppressListeners = true
|
suppressListeners = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -149,6 +152,11 @@ class SlottedContainer(
|
|||||||
globalChangeListeners.forEach { it.run() }
|
globalChangeListeners.forEach { it.run() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun notifyChanged(slot: Int) {
|
||||||
|
notifyChanged()
|
||||||
|
bitmap[slot] = slots[slot].isNotEmpty
|
||||||
|
}
|
||||||
|
|
||||||
// called by outside code (vanilla and other unaware mods)
|
// called by outside code (vanilla and other unaware mods)
|
||||||
override fun setChanged() {
|
override fun setChanged() {
|
||||||
suppressListeners = true
|
suppressListeners = true
|
||||||
@ -253,6 +261,7 @@ class SlottedContainer(
|
|||||||
override fun deserializeNBT(provider: HolderLookup.Provider, nbt: Tag) {
|
override fun deserializeNBT(provider: HolderLookup.Provider, nbt: Tag) {
|
||||||
lostItems.clear()
|
lostItems.clear()
|
||||||
slots.forEach { it.clear() }
|
slots.forEach { it.clear() }
|
||||||
|
bitmap.clear()
|
||||||
|
|
||||||
if (nbt is CompoundTag) {
|
if (nbt is CompoundTag) {
|
||||||
// legacy container
|
// legacy container
|
||||||
|
Loading…
Reference in New Issue
Block a user