Cache recipes in Matter Entangler
This commit is contained in:
parent
45a32dce3c
commit
83d11d531d
@ -1,13 +1,18 @@
|
||||
package ru.dbotthepony.mc.otm.block.entity.matter
|
||||
|
||||
import com.github.benmanes.caffeine.cache.Cache
|
||||
import com.github.benmanes.caffeine.cache.Caffeine
|
||||
import com.github.benmanes.caffeine.cache.Scheduler
|
||||
import com.mojang.serialization.Codec
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder
|
||||
import net.minecraft.Util
|
||||
import net.minecraft.core.BlockPos
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.entity.player.Player
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.crafting.CraftingInput
|
||||
import net.minecraft.world.item.crafting.RecipeManager
|
||||
import net.minecraft.world.level.Level
|
||||
import net.minecraft.world.level.block.state.BlockState
|
||||
import net.neoforged.neoforge.capabilities.Capabilities
|
||||
@ -28,13 +33,21 @@ import ru.dbotthepony.mc.otm.container.IEnhancedCraftingContainer
|
||||
import ru.dbotthepony.mc.otm.container.slotted.AutomationFilters
|
||||
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
|
||||
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer
|
||||
import ru.dbotthepony.mc.otm.core.collect.filter
|
||||
import ru.dbotthepony.mc.otm.core.collect.forEach
|
||||
import ru.dbotthepony.mc.otm.core.collect.map
|
||||
import ru.dbotthepony.mc.otm.core.collect.toList
|
||||
import ru.dbotthepony.mc.otm.core.math.Decimal
|
||||
import ru.dbotthepony.mc.otm.core.util.ItemStackKey
|
||||
import ru.dbotthepony.mc.otm.core.util.asKey
|
||||
import ru.dbotthepony.mc.otm.data.codec.DecimalCodec
|
||||
import ru.dbotthepony.mc.otm.data.codec.minRange
|
||||
import ru.dbotthepony.mc.otm.graph.matter.MatterNode
|
||||
import ru.dbotthepony.mc.otm.menu.matter.MatterEntanglerMenu
|
||||
import ru.dbotthepony.mc.otm.recipe.IMatterEntanglerRecipe
|
||||
import ru.dbotthepony.mc.otm.registry.game.MBlockEntities
|
||||
import ru.dbotthepony.mc.otm.registry.game.MRecipes
|
||||
import java.time.Duration
|
||||
|
||||
class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryWorkerBlockEntity<MatterEntanglerBlockEntity.Job>(MBlockEntities.MATTER_ENTANGLER, blockPos, blockState, Job.CODEC) {
|
||||
class Job(itemStack: ItemStack, val matter: Decimal, ticks: Double, experience: Float) : ItemJob(itemStack, ticks, MachinesConfig.MATTER_ENTANGLER.energyConsumption, experience = experience) {
|
||||
@ -60,20 +73,47 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M
|
||||
val experience = ExperienceStorage(MachinesConfig.MATTER_ENTANGLER::maxExperienceStored).also(::addNeighbourListener)
|
||||
val energyConfig = ConfigurableEnergy(energy)
|
||||
|
||||
private var recipeCache: Collection<IMatterEntanglerRecipe> = listOf()
|
||||
private var seenRecipeManager: RecipeManager? = null
|
||||
|
||||
private fun getRecipes(): Collection<IMatterEntanglerRecipe> {
|
||||
val level = level!!
|
||||
val manager = level.recipeManager
|
||||
|
||||
if (seenRecipeManager !== manager) {
|
||||
seenRecipeManager = manager
|
||||
val input = inputs.asPositionedCraftInput()
|
||||
|
||||
recipeCache = manager.byType(MRecipes.MATTER_ENTANGLER)
|
||||
.iterator()
|
||||
.map { it.value }
|
||||
.filter { it.preemptivelyMatches(input, level, 3, 3) }
|
||||
.toList()
|
||||
}
|
||||
|
||||
return recipeCache
|
||||
}
|
||||
|
||||
private inner class InputSlot(container: SlottedContainer, slot: Int) : FilteredContainerSlot(container, slot) {
|
||||
val insertCache: Cache<ItemStackKey, Boolean> = Caffeine.newBuilder()
|
||||
.maximumSize(1024L)
|
||||
.expireAfterWrite(Duration.ofMinutes(1L))
|
||||
.scheduler(Scheduler.systemScheduler())
|
||||
.executor(Util.backgroundExecutor())
|
||||
.build()
|
||||
|
||||
override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
|
||||
if (!super.canAutomationPlaceItem(itemStack))
|
||||
return false
|
||||
|
||||
val level = level ?: return false
|
||||
val list = container.toList()
|
||||
list[slot] = itemStack
|
||||
val shadow = CraftingInput.ofPositioned(3, 3, list)
|
||||
|
||||
return level
|
||||
.recipeManager
|
||||
.byType(MRecipes.MATTER_ENTANGLER)
|
||||
.any { it.value.preemptivelyMatches(shadow, level, 3, 3) }
|
||||
return insertCache.get(itemStack.asKey()) {
|
||||
val list = container.toList()
|
||||
list[slot] = itemStack
|
||||
val shadow = CraftingInput.ofPositioned(3, 3, list)
|
||||
getRecipes().any { it.preemptivelyMatches(shadow, level, 3, 3) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun canAutomationTakeItem(desired: Int): Boolean {
|
||||
@ -84,7 +124,14 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M
|
||||
get() = 1
|
||||
}
|
||||
|
||||
val inputs = IEnhancedCraftingContainer.Wrapper(SlottedContainer.simple(3 * 3, ::InputSlot, ::setChanged), 3, 3)
|
||||
private fun inputsChanged() {
|
||||
inputs.slotIterator().forEach { (it as InputSlot).insertCache.invalidateAll() }
|
||||
seenRecipeManager = null
|
||||
recipeCache = listOf()
|
||||
setChanged()
|
||||
}
|
||||
|
||||
val inputs = IEnhancedCraftingContainer.Wrapper(SlottedContainer.simple(3 * 3, ::InputSlot, ::inputsChanged), 3, 3)
|
||||
val output = SlottedContainer.simple(1, AutomationFilters.ONLY_OUT.unlimitedSimpleProvider, ::markDirtyFast)
|
||||
|
||||
val itemConfig = ConfigurableItemHandler(
|
||||
|
@ -0,0 +1,35 @@
|
||||
package ru.dbotthepony.mc.otm.core.util
|
||||
|
||||
import it.unimi.dsi.fastutil.HashCommon
|
||||
import net.minecraft.core.component.DataComponentMap
|
||||
import net.minecraft.world.item.Item
|
||||
import net.minecraft.world.item.ItemStack
|
||||
|
||||
class ItemStackKey(val item: Item, val components: DataComponentMap) {
|
||||
// make copy of original itemstack because there is no copy() method on DataComponentMap, which is returned by ItemStack#getComponents
|
||||
constructor(itemStack: ItemStack) : this(itemStack.item, itemStack.copy().components)
|
||||
|
||||
private var hashComputed = false
|
||||
private var hash = 0
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return this === other || other is ItemStackKey && other.item === item && other.components == components
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
if (!hashComputed) {
|
||||
hash = HashCommon.murmurHash3(item.hashCode().toLong().shl(32) or components.hashCode().toLong()).toInt()
|
||||
hashComputed = true
|
||||
}
|
||||
|
||||
return hash
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "ItemStackKey[$item, $components]"
|
||||
}
|
||||
}
|
||||
|
||||
fun ItemStack.asKey(): ItemStackKey {
|
||||
return ItemStackKey(this)
|
||||
}
|
Loading…
Reference in New Issue
Block a user