diff --git a/src/main/java/com/extendedae_plus/integration/jei/JeiRuntimeProxy.java b/src/main/java/com/extendedae_plus/integration/jei/JeiRuntimeProxy.java index 3965a63..bc5276e 100644 --- a/src/main/java/com/extendedae_plus/integration/jei/JeiRuntimeProxy.java +++ b/src/main/java/com/extendedae_plus/integration/jei/JeiRuntimeProxy.java @@ -2,6 +2,8 @@ package com.extendedae_plus.integration.jei; import com.extendedae_plus.mixin.jei.accessor.BookmarkOverlayAccessor; import mezz.jei.api.constants.VanillaTypes; +import mezz.jei.api.forge.ForgeTypes; +import mezz.jei.api.ingredients.IIngredientType; import mezz.jei.api.ingredients.ITypedIngredient; import mezz.jei.api.runtime.IBookmarkOverlay; import mezz.jei.api.runtime.IIngredientListOverlay; @@ -10,8 +12,13 @@ import mezz.jei.gui.bookmarks.BookmarkList; import mezz.jei.gui.bookmarks.IngredientBookmark; import mezz.jei.gui.overlay.elements.IElement; import net.minecraft.world.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fml.ModList; +import org.spongepowered.asm.mixin.Pseudo; import javax.annotation.Nullable; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -19,10 +26,12 @@ import java.util.Optional; /** * 线程安全地缓存并访问 JEI Runtime。 */ +@Pseudo public final class JeiRuntimeProxy { private static volatile IJeiRuntime RUNTIME; - private JeiRuntimeProxy() {} + private JeiRuntimeProxy() { + } static void setRuntime(IJeiRuntime runtime) { RUNTIME = runtime; @@ -135,9 +144,6 @@ public final class JeiRuntimeProxy { return Collections.emptyList(); } - /** - * 将物品添加到 JEI 书签 - */ public static void addBookmark(ItemStack stack) { IJeiRuntime rt = RUNTIME; if (rt == null) return; @@ -154,6 +160,95 @@ public final class JeiRuntimeProxy { } } + public static void addBookmark(FluidStack fluidStack) { + IJeiRuntime rt = RUNTIME; + if (rt == null) return; + + IBookmarkOverlay overlay = rt.getBookmarkOverlay(); + if (overlay instanceof BookmarkOverlayAccessor accessor) { + BookmarkList list = accessor.eap$getBookmarkList(); + Optional> typedOpt = rt.getIngredientManager() + .createTypedIngredient(ForgeTypes.FLUID_STACK, fluidStack); + typedOpt.ifPresent(typed -> { + IngredientBookmark bookmark = IngredientBookmark.create(typed, rt.getIngredientManager()); + list.add(bookmark); // add 内部会自动保存到配置 + }); + } + } + + /** + * 如果存在 Mekanism/appmek,则将 Mekanism 化学堆栈添加到 JEI 书签。 + */ + public static void addBookmark(Object chemicalStack) { + if (!ModList.get().isLoaded("mekanism") && !ModList.get().isLoaded("appmek")) return; + + IJeiRuntime rt = RUNTIME; + if (rt == null) return; + + IBookmarkOverlay overlay = rt.getBookmarkOverlay(); + if (overlay instanceof BookmarkOverlayAccessor accessor) { + BookmarkList list = accessor.eap$getBookmarkList(); + try { + if (chemicalStack == null) return; + + // Determine Mekanism JEI ingredient type constant by runtime class name + String clsName = chemicalStack.getClass().getName(); + String mekanismJeiClass = "mekanism.client.jei.MekanismJEI"; + Class jeiCls = Class.forName(mekanismJeiClass); + Field typeField = getField(clsName, jeiCls); + + if (typeField == null) return; + Object typeConst = typeField.get(null); + + // Use ingredient manager reflectively to create a typed ingredient + Object ingredientManager = rt.getIngredientManager(); + Method createTypedIngredient = ingredientManager.getClass().getMethod("createTypedIngredient", IIngredientType.class, Object.class); + Object opt = createTypedIngredient.invoke(ingredientManager, typeConst, chemicalStack); + if (!(opt instanceof Optional typedOpt)) return; + if (typedOpt.isPresent()) { + Object typed = typedOpt.get(); + // Find a compatible static create(...) method on IngredientBookmark where + // the second parameter is assignable from the actual ingredientManager instance. + Method createMethod = null; + for (Method m : IngredientBookmark.class.getMethods()) { + if (!m.getName().equals("create")) continue; + Class[] params = m.getParameterTypes(); + if (params.length != 2) continue; + // first param should accept the typed ingredient + boolean firstOk = params[0].isAssignableFrom(typed.getClass()) || params[0].isAssignableFrom(ITypedIngredient.class); + boolean secondOk = params[1].isAssignableFrom(ingredientManager.getClass()); + if (firstOk && secondOk) { + createMethod = m; + break; + } + } + if (createMethod != null) { + Object bookmark = createMethod.invoke(null, typed, ingredientManager); + if (bookmark != null) { + list.add((IngredientBookmark) bookmark); + } + } + } + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + private static @Nullable Field getField(String clsName, Class jeiCls) throws NoSuchFieldException { + Field typeField = null; + if ("mekanism.api.chemical.gas.GasStack".equals(clsName)) { + typeField = jeiCls.getField("TYPE_GAS"); + } else if ("mekanism.api.chemical.infuse.InfusionStack".equals(clsName)) { + typeField = jeiCls.getField("TYPE_INFUSION"); + } else if ("mekanism.api.chemical.pigment.PigmentStack".equals(clsName)) { + typeField = jeiCls.getField("TYPE_PIGMENT"); + } else if ("mekanism.api.chemical.slurry.SlurryStack".equals(clsName)) { + typeField = jeiCls.getField("TYPE_SLURRY"); + } + return typeField; + } + /** * 从 JEI 书签移除物品 */ diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/menu/CraftConfirmMenuGoBackMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/menu/CraftConfirmMenuGoBackMixin.java index 0bbc164..c5e2d23 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/menu/CraftConfirmMenuGoBackMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/menu/CraftConfirmMenuGoBackMixin.java @@ -1,10 +1,13 @@ package com.extendedae_plus.mixin.ae2.menu; +import appeng.api.stacks.AEFluidKey; +import appeng.api.stacks.AEItemKey; import appeng.menu.me.crafting.CraftConfirmMenu; import appeng.menu.me.crafting.CraftingPlanSummary; import appeng.menu.me.crafting.CraftingPlanSummaryEntry; import com.extendedae_plus.integration.jei.JeiRuntimeProxy; import net.minecraft.client.gui.screens.Screen; +import net.minecraftforge.fml.ModList; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -44,9 +47,27 @@ public class CraftConfirmMenuGoBackMixin { // 仅在按住 shift 时为缺失的条目添加 JEI 书签 for (CraftingPlanSummaryEntry entry : entries) { if (entry.getMissingAmount() > 0) { - JeiRuntimeProxy.addBookmark(entry.getWhat().wrapForDisplayOrFilter()); + var what = entry.getWhat(); + if (what instanceof AEItemKey aeItemKey) { + JeiRuntimeProxy.addBookmark(aeItemKey.getReadOnlyStack()); + } else if (what instanceof AEFluidKey aeFluidKey) { + JeiRuntimeProxy.addBookmark(aeFluidKey.toStack(1000)); + } else if (ModList.get().isLoaded("appmek") && ModList.get().isLoaded("mekanism")) { + try { + if (what != null) { + // avoid compile-time dependency on MekanismKey by reflection + Class mekanismKeyCls = Class.forName("me.ramidzkh.mekae2.ae2.MekanismKey"); + if (mekanismKeyCls.isInstance(what)) { + java.lang.reflect.Method m = mekanismKeyCls.getMethod("getStack"); + Object stack = m.invoke(what); + JeiRuntimeProxy.addBookmark(stack); + } + } + } catch (Throwable ignored) {} + } } } - } catch (Throwable ignored) {} + } catch (Throwable ignored) { + } } } \ No newline at end of file diff --git a/src/main/resources/extendedae_plus.mixins.json b/src/main/resources/extendedae_plus.mixins.json index a69afbb..aaad6df 100644 --- a/src/main/resources/extendedae_plus.mixins.json +++ b/src/main/resources/extendedae_plus.mixins.json @@ -16,11 +16,12 @@ "ae2.accessor.PatternAccessTermScreenAccessor", "ae2.accessor.PatternAccessTermScreenSlotsRowAccessor", "ae2.client.gui.AEBaseScreenMixin", - "ae2.client.gui.PatternEncodingTermScreenMixin", "ae2.client.gui.InterfaceScreenMixin", + "ae2.client.gui.PatternEncodingTermScreenMixin", "ae2.client.gui.PatternProviderCloseMixin", "ae2.client.gui.PatternProviderScreenMixin", "ae2.client.gui.SlotGridLayoutMixin", + "ae2.menu.CraftConfirmMenuGoBackMixin", "extendedae.accessor.GuiExPatternTerminalAccessor", "extendedae.accessor.GuiExPatternTerminalSlotsRowAccessor", "extendedae.client.HighlightButtonMixin", @@ -57,7 +58,6 @@ "ae2.helpers.PatternProviderLogicAdvancedMixin", "ae2.helpers.PatternProviderLogicDoublingMixin", "ae2.menu.ContainerPatternEncodingTermMenuMixin", - "ae2.menu.CraftConfirmMenuGoBackMixin", "ae2.menu.MEStorageMenuMixin", "ae2.menu.PatternEncodingTermMenuMixin", "ae2.menu.PatternProviderMenuAdvancedMixin",