@@ -8,6 +8,7 @@ import io.github.pylonmc.rebar.entity.packet.BlockTextureEntity
88import io.github.pylonmc.rebar.i18n.PlayerTranslationHandler
99import io.github.pylonmc.rebar.i18n.packet.PlayerPacketHandler
1010import io.github.pylonmc.rebar.nms.entity.BlockTextureEntityImpl
11+ import io.github.pylonmc.rebar.nms.recipe.AccessibleCachedCheck
1112import io.github.pylonmc.rebar.nms.recipe.HandlerRecipeBookClick
1213import io.github.pylonmc.rebar.util.position.BlockPosition
1314import io.papermc.paper.adventure.PaperAdventure
@@ -25,14 +26,16 @@ import net.minecraft.server.MinecraftServer
2526import net.minecraft.world.inventory.AbstractCraftingMenu
2627import net.minecraft.world.inventory.RecipeBookMenu.PostPlaceAction
2728import net.minecraft.world.item.Item
29+ import net.minecraft.world.item.crafting.RecipeManager
30+ import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity
2831import net.minecraft.world.level.block.state.properties.Property
2932import org.bukkit.Material
33+ import org.bukkit.NamespacedKey
3034import org.bukkit.World
3135import org.bukkit.block.Block
3236import org.bukkit.craftbukkit.CraftEquipmentSlot
3337import org.bukkit.craftbukkit.CraftWorld
3438import org.bukkit.craftbukkit.block.CraftBlock
35- import org.bukkit.craftbukkit.entity.CraftEntity
3639import org.bukkit.craftbukkit.entity.CraftLivingEntity
3740import org.bukkit.craftbukkit.entity.CraftPlayer
3841import org.bukkit.craftbukkit.inventory.CraftItemStack
@@ -45,6 +48,10 @@ import org.bukkit.entity.Player
4548import org.bukkit.inventory.EquipmentSlot
4649import org.bukkit.inventory.ItemStack
4750import org.bukkit.persistence.PersistentDataContainer
51+ import java.lang.invoke.MethodHandle
52+ import java.lang.invoke.MethodHandles
53+ import java.lang.invoke.VarHandle
54+ import java.lang.reflect.Field
4855import java.util.UUID
4956import java.util.concurrent.ConcurrentHashMap
5057import kotlin.coroutines.EmptyCoroutineContext
@@ -56,6 +63,25 @@ import net.minecraft.world.entity.EquipmentSlot as NmsEquipmentSlot
5663@Suppress(" unused" )
5764object NmsAccessorImpl : NmsAccessor {
5865
66+ // We use both the field and the handle because the handle will have significantly better performance
67+ // getting the field value but cannot be used for setting so we still need the raw field.
68+ // (even if we used a VarHandle, because the field is normally final, setting will not work)
69+ private val furnaceQuickCheckField: Field
70+ private val furnaceQuickCheckHandle: MethodHandle
71+
72+ init {
73+ try {
74+ furnaceQuickCheckField = AbstractFurnaceBlockEntity ::class .java.getDeclaredField(" quickCheck" )
75+ furnaceQuickCheckField.isAccessible = true
76+
77+ val methodHandles = MethodHandles .privateLookupIn(AbstractFurnaceBlockEntity ::class .java, MethodHandles .lookup())
78+ furnaceQuickCheckHandle = methodHandles.unreflectGetter(furnaceQuickCheckField)
79+ } catch (e: Throwable ) {
80+ Rebar .logger.severe(" Failed to access furnace quick check: ${e.message} " )
81+ throw RuntimeException (e)
82+ }
83+ }
84+
5985 private val players = ConcurrentHashMap <UUID , PlayerPacketHandler >()
6086
6187 override fun damageItem (itemStack : ItemStack , amount : Int , world : World , onBreak : (Material ) -> Unit , force : Boolean ) {
@@ -199,4 +225,22 @@ object NmsAccessorImpl : NmsAccessor {
199225 }
200226 blocks
201227 }
228+
229+ override fun setFurnaceRecipeCache (block : Block , recipe : NamespacedKey ) {
230+ val block = block as CraftBlock
231+ val blockEntity = block.level.getBlockEntity(block.position) as ? AbstractFurnaceBlockEntity ? : return
232+ try {
233+ val currentQuickCheck = furnaceQuickCheckHandle.invoke(blockEntity) as ? RecipeManager .CachedCheck <* , * > ? : return
234+ if (currentQuickCheck is AccessibleCachedCheck <* , * >) {
235+ currentQuickCheck.lastRecipe = CraftNamespacedKey .toResourceKey(Registries .RECIPE , recipe)
236+ } else {
237+ val newQuickCheck = AccessibleCachedCheck (blockEntity.recipeType)
238+ newQuickCheck.lastRecipe = CraftNamespacedKey .toResourceKey(Registries .RECIPE , recipe)
239+ furnaceQuickCheckField.set(blockEntity, newQuickCheck)
240+ }
241+ } catch (e: Throwable ) {
242+ Rebar .logger.severe(" Failed to set furnace recipe cache: ${e.message} " )
243+ e.printStackTrace()
244+ }
245+ }
202246}
0 commit comments