Cache recipes in Matter Entangler

This commit is contained in:
DBotThePony 2025-03-05 15:23:27 +07:00
parent 45a32dce3c
commit 83d11d531d
Signed by: DBot
GPG Key ID: DCC23B5715498507
2 changed files with 90 additions and 8 deletions

View File

@ -1,13 +1,18 @@
package ru.dbotthepony.mc.otm.block.entity.matter 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.Codec
import com.mojang.serialization.codecs.RecordCodecBuilder import com.mojang.serialization.codecs.RecordCodecBuilder
import net.minecraft.Util
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.entity.player.Player import net.minecraft.world.entity.player.Player
import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.inventory.AbstractContainerMenu
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.crafting.CraftingInput 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.Level
import net.minecraft.world.level.block.state.BlockState import net.minecraft.world.level.block.state.BlockState
import net.neoforged.neoforge.capabilities.Capabilities 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.AutomationFilters
import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot import ru.dbotthepony.mc.otm.container.slotted.FilteredContainerSlot
import ru.dbotthepony.mc.otm.container.slotted.SlottedContainer 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.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.DecimalCodec
import ru.dbotthepony.mc.otm.data.codec.minRange import ru.dbotthepony.mc.otm.data.codec.minRange
import ru.dbotthepony.mc.otm.graph.matter.MatterNode import ru.dbotthepony.mc.otm.graph.matter.MatterNode
import ru.dbotthepony.mc.otm.menu.matter.MatterEntanglerMenu 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.MBlockEntities
import ru.dbotthepony.mc.otm.registry.game.MRecipes 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 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) { 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 experience = ExperienceStorage(MachinesConfig.MATTER_ENTANGLER::maxExperienceStored).also(::addNeighbourListener)
val energyConfig = ConfigurableEnergy(energy) 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) { 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 { override fun canAutomationPlaceItem(itemStack: ItemStack): Boolean {
if (!super.canAutomationPlaceItem(itemStack)) if (!super.canAutomationPlaceItem(itemStack))
return false return false
val level = level ?: return false val level = level ?: return false
val list = container.toList()
list[slot] = itemStack
val shadow = CraftingInput.ofPositioned(3, 3, list)
return level return insertCache.get(itemStack.asKey()) {
.recipeManager val list = container.toList()
.byType(MRecipes.MATTER_ENTANGLER) list[slot] = itemStack
.any { it.value.preemptivelyMatches(shadow, level, 3, 3) } val shadow = CraftingInput.ofPositioned(3, 3, list)
getRecipes().any { it.preemptivelyMatches(shadow, level, 3, 3) }
}
} }
override fun canAutomationTakeItem(desired: Int): Boolean { override fun canAutomationTakeItem(desired: Int): Boolean {
@ -84,7 +124,14 @@ class MatterEntanglerBlockEntity(blockPos: BlockPos, blockState: BlockState) : M
get() = 1 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 output = SlottedContainer.simple(1, AutomationFilters.ONLY_OUT.unlimitedSimpleProvider, ::markDirtyFast)
val itemConfig = ConfigurableItemHandler( val itemConfig = ConfigurableItemHandler(

View File

@ -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)
}