From cbbde37b737afdf300133991ac3315ed0867b154 Mon Sep 17 00:00:00 2001 From: solidDoWant Date: Tue, 20 Jan 2026 07:37:18 +0000 Subject: [PATCH 1/9] try mixin approach Signed-off-by: solidDoWant --- .../integration/jei/JeiPlugin.java | 68 ++++++------------- .../jei/RecipeTransferHandler.java | 30 ++++++-- .../mixins/jei/RecipeRegistryMixin.java | 67 ++++++++++++++++++ .../resources/mixins.gregtechenergistics.json | 3 +- 4 files changed, 115 insertions(+), 53 deletions(-) create mode 100644 src/main/java/com/soliddowant/gregtechenergistics/mixins/jei/RecipeRegistryMixin.java diff --git a/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/JeiPlugin.java b/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/JeiPlugin.java index 8002dac..42d5d45 100644 --- a/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/JeiPlugin.java +++ b/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/JeiPlugin.java @@ -1,63 +1,35 @@ package com.soliddowant.gregtechenergistics.integration.jei; -import appeng.container.implementations.ContainerPatternTerm; -import com.google.common.collect.HashBasedTable; -import com.google.common.collect.ImmutableTable; import com.soliddowant.gregtechenergistics.gui.ExtendedPatternContainer; -import mezz.jei.collect.Table; + import mezz.jei.api.IModPlugin; import mezz.jei.api.IModRegistry; import mezz.jei.api.JEIPlugin; -import mezz.jei.api.recipe.transfer.IRecipeTransferHandler; -import mezz.jei.api.recipe.transfer.IRecipeTransferRegistry; import mezz.jei.config.Constants; -import mezz.jei.recipes.RecipeTransferRegistry; -import net.minecraftforge.fml.relauncher.ReflectionHelper; -@SuppressWarnings({"unused", "rawtypes"}) +/** + * JEI Plugin for GregTech Energistics. + * + * Registers the Extended Pattern Terminal handler directly. + * + * Note: The native AE2 Pattern Terminal (ContainerPatternTerm) handler is replaced + * at runtime via Mixin (see RecipeRegistryMixin) to support fluid encoding. + */ +@SuppressWarnings({ "unused", "rawtypes" }) @JEIPlugin public class JeiPlugin implements IModPlugin { - @Override - public void register(IModRegistry registry) - { - IRecipeTransferRegistry transferRegistry = registry.getRecipeTransferRegistry(); - - // If true, some change to JEI broke this integration - if(!(transferRegistry instanceof RecipeTransferRegistry)) - return; - - RecipeTransferRegistry castedTransferRegistry = (RecipeTransferRegistry) transferRegistry; - - // Collect non-ContainerPatternTerm transfer handlers and flag if AE2 has been found - // JEE checks if AE2 has been found, but that's not needed as the JVM would throw an exception on the import - // of ContainerPatternTerm if AE2 was not present - Table, String, IRecipeTransferHandler> collectedRegistry = - collectNonPatternTerminals(castedTransferRegistry.getRecipeTransferHandlers()); - collectedRegistry.put(ContainerPatternTerm.class, Constants.UNIVERSAL_RECIPE_TRANSFER_UID, - new RecipeTransferHandler()); - collectedRegistry.put(ExtendedPatternContainer.class, Constants.UNIVERSAL_RECIPE_TRANSFER_UID, - new ExtendedRecipeTransferHandler()); - ReflectionHelper.setPrivateValue(RecipeTransferRegistry.class, - (RecipeTransferRegistry) registry.getRecipeTransferRegistry(), collectedRegistry, - "recipeTransferHandlers", null); - } - - protected static Table, T, U> collectNonPatternTerminals(ImmutableTable transferHandlers) { - Table, T, U> newRegistry = Table.hashBasedTable(); - for (final ImmutableTable.Cell currentCell : transferHandlers.cellSet()) { - Class rowKey = currentCell.getRowKey(); - if(rowKey == null) - continue; - - if (currentCell.getRowKey().equals(ContainerPatternTerm.class)) { - continue; - } + @Override + public void register(IModRegistry registry) { + System.out.println("[GTE-JEI] Registering Extended Pattern Terminal handler"); - //noinspection ConstantConditions - newRegistry.put(currentCell.getRowKey(), currentCell.getColumnKey(), currentCell.getValue()); - } + // Register our Extended Pattern Terminal handler + // This uses the public API and works fine since there's no conflict + registry.getRecipeTransferRegistry().addRecipeTransferHandler( + new ExtendedRecipeTransferHandler(), + Constants.UNIVERSAL_RECIPE_TRANSFER_UID); - return newRegistry; + System.out.println("[GTE-JEI] Registration complete"); + System.out.println("[GTE-JEI] Native Pattern Terminal handler will be replaced via Mixin"); } } diff --git a/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/RecipeTransferHandler.java b/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/RecipeTransferHandler.java index 1f24d9b..672a3df 100644 --- a/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/RecipeTransferHandler.java +++ b/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/RecipeTransferHandler.java @@ -1,6 +1,5 @@ package com.soliddowant.gregtechenergistics.integration.jei; -import java.util.Map.Entry; import java.util.function.Function; import javax.annotation.Nonnull; @@ -40,9 +39,11 @@ public Class getContainerClass() { public IRecipeTransferError transferRecipe(@Nonnull ContainerPatternTerm container, @Nonnull IRecipeLayout recipeLayout, @Nonnull EntityPlayer player, boolean maxTransfer, boolean doTransfer) { + System.out.println("[GTE-JEI] Transferring recipe to pattern terminal..."); if (doTransfer) performTransfer(container, recipeLayout, player, maxTransfer); + System.out.println("[GTE-JEI] Recipe transfer complete."); return null; } @@ -55,11 +56,21 @@ protected void performTransfer(ContainerPatternTerm container, IRecipeLayout rec FluidStack[] inputFluids = new FluidStack[9]; FluidStack[] outputFluids = new FluidStack[3]; + IGuiIngredientGroup fluidGroup = recipeLayout.getFluidStacks(); + System.out.println("[GTE-JEI] Fluid group: " + (fluidGroup == null ? "NULL" : "present")); + if (fluidGroup != null) { + System.out.println("[GTE-JEI] Fluid ingredients: " + fluidGroup.getGuiIngredients().size()); + } else { + System.out.println("[GTE-JEI] No fluid ingredients present."); + } + // Crafting recipes: preserve slot indices (with JEI's 1-based offset) // Processing recipes: fill sequentially (ignore slot indices) performTransferWithSlots(recipeLayout.getItemStacks(), inputItems, outputItems, isCraftingRecipe, this::getFirstItemStack); - performTransferWithSlots(recipeLayout.getFluidStacks(), inputFluids, outputFluids, isCraftingRecipe, + // For fluids, always use processing mode (sequential fill) to avoid slot + // conflicts + performTransferWithSlots(recipeLayout.getFluidStacks(), inputFluids, outputFluids, false, this::getFirstFluidStack); NetworkHandler.ServerHandlerChannel.sendToServer( @@ -73,6 +84,9 @@ protected void performTransfer(ContainerPatternTerm container, IRecipeLayout rec protected void performTransferWithSlots(IGuiIngredientGroup ingredientGroup, T[] inputs, T[] outputs, boolean preserveSlots, Function, T> getFirstStack) { + if (ingredientGroup == null || ingredientGroup.getGuiIngredients() == null) + return; + if (preserveSlots) { // Crafting mode: preserve exact slot positions (with JEI 1-based offset // correction) @@ -195,8 +209,13 @@ public static void transferToTerminal(JEIPacket message, Container con) { if (!(con instanceof ContainerPatternTerm)) return; + // If there are fluids, always use processing mode to avoid slot conflicts in + // crafting mode + boolean hasInputFluids = message.inputFluids != null && message.inputFluids.length > 0; + boolean preserveSlots = message.isCraftingRecipe && !hasInputFluids; + ItemStack[] inputStacks = mergeStacks(message.inputItems, message.inputFluids, inputAreaSize, - message.isCraftingRecipe); + preserveSlots); for (int i = 0; i < inputStacks.length && i < inputAreaSize; i++) { ItemStack stack = inputStacks[i]; @@ -206,8 +225,11 @@ public static void transferToTerminal(JEIPacket message, Container con) { if (message.isCraftingRecipe) con.onCraftMatrixChanged(new WrapperInvItemHandler(craftMatrix)); else { + boolean hasOutputFluids = message.outputFluids != null && message.outputFluids.length > 0; + boolean preserveOutputSlots = message.isCraftingRecipe && !hasOutputFluids; + ItemStack[] outputStacks = mergeStacks(message.outputItems, message.outputFluids, outputAreaSize, - message.isCraftingRecipe); + preserveOutputSlots); for (int i = 0; i < outputStacks.length && i < outputAreaSize; i++) { ItemStack stack = outputStacks[i]; diff --git a/src/main/java/com/soliddowant/gregtechenergistics/mixins/jei/RecipeRegistryMixin.java b/src/main/java/com/soliddowant/gregtechenergistics/mixins/jei/RecipeRegistryMixin.java new file mode 100644 index 0000000..4d574c4 --- /dev/null +++ b/src/main/java/com/soliddowant/gregtechenergistics/mixins/jei/RecipeRegistryMixin.java @@ -0,0 +1,67 @@ +package com.soliddowant.gregtechenergistics.mixins.jei; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import com.soliddowant.gregtechenergistics.integration.jei.RecipeTransferHandler; + +import appeng.container.implementations.ContainerPatternTerm; +import mezz.jei.api.recipe.IRecipeCategory; +import mezz.jei.api.recipe.transfer.IRecipeTransferHandler; +import mezz.jei.recipes.RecipeRegistry; +import net.minecraft.inventory.Container; + +/** + * Mixin to override JEI's recipe transfer handler lookup for ContainerPatternTerm. + * + * This is necessary because RecipeRegistry creates an immutable snapshot of handlers + * during construction, so runtime modifications via reflection don't work. AE2's native + * JEI handler doesn't support fluid encoding, so we need to replace it with our own. + */ +@Mixin(value = RecipeRegistry.class, remap = false) +public class RecipeRegistryMixin { + + private static RecipeTransferHandler GT_ENERGISTICS_HANDLER = null; + + @Inject( + method = "getRecipeTransferHandler", + at = @At("RETURN"), + cancellable = true, + remap = false + ) + private void injectPatternTermHandler( + Container container, + IRecipeCategory recipeCategory, + CallbackInfoReturnable cir) { + + // Only intercept for ContainerPatternTerm + if (!(container instanceof ContainerPatternTerm)) { + return; + } + + IRecipeTransferHandler originalHandler = cir.getReturnValue(); + + // If there's no handler or it's already ours, do nothing + if (originalHandler == null) { + return; + } + + if (originalHandler instanceof RecipeTransferHandler) { + return; + } + + // Replace AE2's handler with ours (lazy initialization) + if (GT_ENERGISTICS_HANDLER == null) { + GT_ENERGISTICS_HANDLER = new RecipeTransferHandler(); + System.out.println("[GTE-JEI-Mixin] Created GregTech Energistics recipe transfer handler for ContainerPatternTerm"); + } + + System.out.println("[GTE-JEI-Mixin] Replacing " + originalHandler.getClass().getName() + + " with " + GT_ENERGISTICS_HANDLER.getClass().getName() + + " for recipe category: " + recipeCategory.getUid()); + + cir.setReturnValue(GT_ENERGISTICS_HANDLER); + } +} diff --git a/src/main/resources/mixins.gregtechenergistics.json b/src/main/resources/mixins.gregtechenergistics.json index 43cbfc8..b5f1577 100644 --- a/src/main/resources/mixins.gregtechenergistics.json +++ b/src/main/resources/mixins.gregtechenergistics.json @@ -10,7 +10,8 @@ "client": [ "GuiCraftingStatusMixin", "ItemEncodedPatternMixin", - "RenderItemOverlayMixin" + "RenderItemOverlayMixin", + "jei.RecipeRegistryMixin" ], "server": [] } \ No newline at end of file From c63fdebff9f9baeded0711c8dbc47019ad7352a1 Mon Sep 17 00:00:00 2001 From: solidDoWant Date: Tue, 20 Jan 2026 07:44:56 +0000 Subject: [PATCH 2/9] remove d ebug code Signed-off-by: solidDoWant --- .../integration/jei/JeiPlugin.java | 5 ----- .../integration/jei/RecipeTransferHandler.java | 13 +------------ .../mixins/jei/RecipeRegistryMixin.java | 5 ----- 3 files changed, 1 insertion(+), 22 deletions(-) diff --git a/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/JeiPlugin.java b/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/JeiPlugin.java index 42d5d45..6e463a6 100644 --- a/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/JeiPlugin.java +++ b/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/JeiPlugin.java @@ -21,15 +21,10 @@ public class JeiPlugin implements IModPlugin { @Override public void register(IModRegistry registry) { - System.out.println("[GTE-JEI] Registering Extended Pattern Terminal handler"); - // Register our Extended Pattern Terminal handler // This uses the public API and works fine since there's no conflict registry.getRecipeTransferRegistry().addRecipeTransferHandler( new ExtendedRecipeTransferHandler(), Constants.UNIVERSAL_RECIPE_TRANSFER_UID); - - System.out.println("[GTE-JEI] Registration complete"); - System.out.println("[GTE-JEI] Native Pattern Terminal handler will be replaced via Mixin"); } } diff --git a/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/RecipeTransferHandler.java b/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/RecipeTransferHandler.java index 672a3df..67e1bcd 100644 --- a/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/RecipeTransferHandler.java +++ b/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/RecipeTransferHandler.java @@ -39,11 +39,9 @@ public Class getContainerClass() { public IRecipeTransferError transferRecipe(@Nonnull ContainerPatternTerm container, @Nonnull IRecipeLayout recipeLayout, @Nonnull EntityPlayer player, boolean maxTransfer, boolean doTransfer) { - System.out.println("[GTE-JEI] Transferring recipe to pattern terminal..."); if (doTransfer) performTransfer(container, recipeLayout, player, maxTransfer); - System.out.println("[GTE-JEI] Recipe transfer complete."); return null; } @@ -56,20 +54,11 @@ protected void performTransfer(ContainerPatternTerm container, IRecipeLayout rec FluidStack[] inputFluids = new FluidStack[9]; FluidStack[] outputFluids = new FluidStack[3]; - IGuiIngredientGroup fluidGroup = recipeLayout.getFluidStacks(); - System.out.println("[GTE-JEI] Fluid group: " + (fluidGroup == null ? "NULL" : "present")); - if (fluidGroup != null) { - System.out.println("[GTE-JEI] Fluid ingredients: " + fluidGroup.getGuiIngredients().size()); - } else { - System.out.println("[GTE-JEI] No fluid ingredients present."); - } - // Crafting recipes: preserve slot indices (with JEI's 1-based offset) // Processing recipes: fill sequentially (ignore slot indices) performTransferWithSlots(recipeLayout.getItemStacks(), inputItems, outputItems, isCraftingRecipe, this::getFirstItemStack); - // For fluids, always use processing mode (sequential fill) to avoid slot - // conflicts + // For fluids, always use processing mode (sequential fill) to avoid slot conflicts performTransferWithSlots(recipeLayout.getFluidStacks(), inputFluids, outputFluids, false, this::getFirstFluidStack); diff --git a/src/main/java/com/soliddowant/gregtechenergistics/mixins/jei/RecipeRegistryMixin.java b/src/main/java/com/soliddowant/gregtechenergistics/mixins/jei/RecipeRegistryMixin.java index 4d574c4..71b0d42 100644 --- a/src/main/java/com/soliddowant/gregtechenergistics/mixins/jei/RecipeRegistryMixin.java +++ b/src/main/java/com/soliddowant/gregtechenergistics/mixins/jei/RecipeRegistryMixin.java @@ -55,13 +55,8 @@ private void injectPatternTermHandler( // Replace AE2's handler with ours (lazy initialization) if (GT_ENERGISTICS_HANDLER == null) { GT_ENERGISTICS_HANDLER = new RecipeTransferHandler(); - System.out.println("[GTE-JEI-Mixin] Created GregTech Energistics recipe transfer handler for ContainerPatternTerm"); } - System.out.println("[GTE-JEI-Mixin] Replacing " + originalHandler.getClass().getName() + - " with " + GT_ENERGISTICS_HANDLER.getClass().getName() + - " for recipe category: " + recipeCategory.getUid()); - cir.setReturnValue(GT_ENERGISTICS_HANDLER); } } From 0debb227794325e9bf8794e6f23443e5bea3268f Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 02:10:58 -0600 Subject: [PATCH 3/9] Fix hasInputFluids check to prevent shaped recipe compression (#14) * Initial plan * Fix hasInputFluids and hasOutputFluids calculation Co-authored-by: solidDoWant <16456946+solidDoWant@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: solidDoWant <16456946+solidDoWant@users.noreply.github.com> --- .../integration/jei/RecipeTransferHandler.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/RecipeTransferHandler.java b/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/RecipeTransferHandler.java index 67e1bcd..86aece6 100644 --- a/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/RecipeTransferHandler.java +++ b/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/RecipeTransferHandler.java @@ -176,6 +176,18 @@ protected static ItemStack createFluidEncoder(FluidStack fluid) { return fluidEncoder; } + protected static boolean hasAnyFluids(@Nullable FluidStack[] fluids) { + if (fluids == null) + return false; + + for (FluidStack fluid : fluids) { + if (fluid != null && fluid.amount > 0) + return true; + } + + return false; + } + public static void transferToTerminal(JEIPacket message, Container con) { // Get information about the crafting terminal, and do some checks if (!(con instanceof IContainerCraftingPacket)) @@ -200,7 +212,7 @@ public static void transferToTerminal(JEIPacket message, Container con) { // If there are fluids, always use processing mode to avoid slot conflicts in // crafting mode - boolean hasInputFluids = message.inputFluids != null && message.inputFluids.length > 0; + boolean hasInputFluids = hasAnyFluids(message.inputFluids); boolean preserveSlots = message.isCraftingRecipe && !hasInputFluids; ItemStack[] inputStacks = mergeStacks(message.inputItems, message.inputFluids, inputAreaSize, @@ -214,7 +226,7 @@ public static void transferToTerminal(JEIPacket message, Container con) { if (message.isCraftingRecipe) con.onCraftMatrixChanged(new WrapperInvItemHandler(craftMatrix)); else { - boolean hasOutputFluids = message.outputFluids != null && message.outputFluids.length > 0; + boolean hasOutputFluids = hasAnyFluids(message.outputFluids); boolean preserveOutputSlots = message.isCraftingRecipe && !hasOutputFluids; ItemStack[] outputStacks = mergeStacks(message.outputItems, message.outputFluids, outputAreaSize, From ab8bbcbe5c8c49413684450c39ec6a715b94d65a Mon Sep 17 00:00:00 2001 From: solidDoWant Date: Tue, 20 Jan 2026 08:15:08 +0000 Subject: [PATCH 4/9] rm dead code Signed-off-by: solidDoWant --- .../integration/jei/RecipeTransferHandler.java | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/RecipeTransferHandler.java b/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/RecipeTransferHandler.java index 86aece6..f810ef3 100644 --- a/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/RecipeTransferHandler.java +++ b/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/RecipeTransferHandler.java @@ -58,7 +58,8 @@ protected void performTransfer(ContainerPatternTerm container, IRecipeLayout rec // Processing recipes: fill sequentially (ignore slot indices) performTransferWithSlots(recipeLayout.getItemStacks(), inputItems, outputItems, isCraftingRecipe, this::getFirstItemStack); - // For fluids, always use processing mode (sequential fill) to avoid slot conflicts + // For fluids, always use processing mode (sequential fill) to avoid slot + // conflicts performTransferWithSlots(recipeLayout.getFluidStacks(), inputFluids, outputFluids, false, this::getFirstFluidStack); @@ -179,12 +180,12 @@ protected static ItemStack createFluidEncoder(FluidStack fluid) { protected static boolean hasAnyFluids(@Nullable FluidStack[] fluids) { if (fluids == null) return false; - + for (FluidStack fluid : fluids) { if (fluid != null && fluid.amount > 0) return true; } - + return false; } @@ -226,11 +227,7 @@ public static void transferToTerminal(JEIPacket message, Container con) { if (message.isCraftingRecipe) con.onCraftMatrixChanged(new WrapperInvItemHandler(craftMatrix)); else { - boolean hasOutputFluids = hasAnyFluids(message.outputFluids); - boolean preserveOutputSlots = message.isCraftingRecipe && !hasOutputFluids; - - ItemStack[] outputStacks = mergeStacks(message.outputItems, message.outputFluids, outputAreaSize, - preserveOutputSlots); + ItemStack[] outputStacks = mergeStacks(message.outputItems, message.outputFluids, outputAreaSize, false); for (int i = 0; i < outputStacks.length && i < outputAreaSize; i++) { ItemStack stack = outputStacks[i]; From 476d22fa104cdf26d9474bfac1136f581388be58 Mon Sep 17 00:00:00 2001 From: solidDoWant Date: Tue, 20 Jan 2026 08:16:14 +0000 Subject: [PATCH 5/9] rm old import, warning Signed-off-by: solidDoWant --- .../gregtechenergistics/integration/jei/JeiPlugin.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/JeiPlugin.java b/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/JeiPlugin.java index 6e463a6..b768c90 100644 --- a/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/JeiPlugin.java +++ b/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/JeiPlugin.java @@ -1,7 +1,5 @@ package com.soliddowant.gregtechenergistics.integration.jei; -import com.soliddowant.gregtechenergistics.gui.ExtendedPatternContainer; - import mezz.jei.api.IModPlugin; import mezz.jei.api.IModRegistry; import mezz.jei.api.JEIPlugin; @@ -12,10 +10,11 @@ * * Registers the Extended Pattern Terminal handler directly. * - * Note: The native AE2 Pattern Terminal (ContainerPatternTerm) handler is replaced + * Note: The native AE2 Pattern Terminal (ContainerPatternTerm) handler is + * replaced * at runtime via Mixin (see RecipeRegistryMixin) to support fluid encoding. */ -@SuppressWarnings({ "unused", "rawtypes" }) +@SuppressWarnings({ "unused" }) @JEIPlugin public class JeiPlugin implements IModPlugin { From 3dc75f4d169ac32ff95589c1f3883c98ac844613 Mon Sep 17 00:00:00 2001 From: solidDoWant Date: Tue, 20 Jan 2026 08:26:49 +0000 Subject: [PATCH 6/9] address PR comments Signed-off-by: solidDoWant --- .../integration/jei/JeiPlugin.java | 4 ++-- .../mixins/jei/RecipeRegistryMixin.java | 23 ++++++++++--------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/JeiPlugin.java b/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/JeiPlugin.java index b768c90..30705b4 100644 --- a/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/JeiPlugin.java +++ b/src/main/java/com/soliddowant/gregtechenergistics/integration/jei/JeiPlugin.java @@ -11,8 +11,8 @@ * Registers the Extended Pattern Terminal handler directly. * * Note: The native AE2 Pattern Terminal (ContainerPatternTerm) handler is - * replaced - * at runtime via Mixin (see RecipeRegistryMixin) to support fluid encoding. + * replaced at runtime via Mixin (see RecipeRegistryMixin) to support fluid + * encoding. */ @SuppressWarnings({ "unused" }) @JEIPlugin diff --git a/src/main/java/com/soliddowant/gregtechenergistics/mixins/jei/RecipeRegistryMixin.java b/src/main/java/com/soliddowant/gregtechenergistics/mixins/jei/RecipeRegistryMixin.java index 71b0d42..8280d38 100644 --- a/src/main/java/com/soliddowant/gregtechenergistics/mixins/jei/RecipeRegistryMixin.java +++ b/src/main/java/com/soliddowant/gregtechenergistics/mixins/jei/RecipeRegistryMixin.java @@ -1,6 +1,7 @@ package com.soliddowant.gregtechenergistics.mixins.jei; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; @@ -14,23 +15,23 @@ import net.minecraft.inventory.Container; /** - * Mixin to override JEI's recipe transfer handler lookup for ContainerPatternTerm. + * Mixin to override JEI's recipe transfer handler lookup for + * ContainerPatternTerm. * - * This is necessary because RecipeRegistry creates an immutable snapshot of handlers - * during construction, so runtime modifications via reflection don't work. AE2's native - * JEI handler doesn't support fluid encoding, so we need to replace it with our own. + * This is necessary because RecipeRegistry creates an immutable snapshot of + * handlers + * during construction, so runtime modifications via reflection don't work. + * AE2's native + * JEI handler doesn't support fluid encoding, so we need to replace it with our + * own. */ @Mixin(value = RecipeRegistry.class, remap = false) -public class RecipeRegistryMixin { +public abstract class RecipeRegistryMixin { + @Unique private static RecipeTransferHandler GT_ENERGISTICS_HANDLER = null; - @Inject( - method = "getRecipeTransferHandler", - at = @At("RETURN"), - cancellable = true, - remap = false - ) + @Inject(method = "getRecipeTransferHandler", at = @At("RETURN"), cancellable = true, remap = false) private void injectPatternTermHandler( Container container, IRecipeCategory recipeCategory, From d1d492f33f5ed376616d074ce930c9dba7cc7560 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Tue, 20 Jan 2026 02:33:40 -0600 Subject: [PATCH 7/9] Gate JEI mixin behind mod presence check to prevent crashes without JEI (#15) * Initial plan * Add IMixinConfigPlugin to gate JEI mixin behind mod presence check Co-authored-by: solidDoWant <16456946+solidDoWant@users.noreply.github.com> * Use startsWith for more precise JEI mixin package detection Co-authored-by: solidDoWant <16456946+solidDoWant@users.noreply.github.com> * Make JEI package detection more robust using mixinPackage parameter Co-authored-by: solidDoWant <16456946+solidDoWant@users.noreply.github.com> * Extract JEI constants and fix formatting Co-authored-by: solidDoWant <16456946+solidDoWant@users.noreply.github.com> * Add documentation for JEI package convention Co-authored-by: solidDoWant <16456946+solidDoWant@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: solidDoWant <16456946+solidDoWant@users.noreply.github.com> --- .../GregTechEnergisticsMixinPlugin.java | 71 +++++++++++++++++++ .../resources/mixins.gregtechenergistics.json | 1 + 2 files changed, 72 insertions(+) create mode 100644 src/main/java/com/soliddowant/gregtechenergistics/mixins/GregTechEnergisticsMixinPlugin.java diff --git a/src/main/java/com/soliddowant/gregtechenergistics/mixins/GregTechEnergisticsMixinPlugin.java b/src/main/java/com/soliddowant/gregtechenergistics/mixins/GregTechEnergisticsMixinPlugin.java new file mode 100644 index 0000000..a3e5ddb --- /dev/null +++ b/src/main/java/com/soliddowant/gregtechenergistics/mixins/GregTechEnergisticsMixinPlugin.java @@ -0,0 +1,71 @@ +package com.soliddowant.gregtechenergistics.mixins; + +import java.util.List; +import java.util.Set; + +import org.spongepowered.asm.lib.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import net.minecraftforge.fml.common.Loader; + +/** + * Mixin config plugin that conditionally loads mixins based on mod presence. + * This prevents crashes when optional dependencies like JEI are not installed. + * + *

This plugin assumes that JEI-specific mixins are placed in a ".jei" subpackage + * under the main mixin package. For example, if the mixin package is + * "com.soliddowant.gregtechenergistics.mixins", then JEI mixins should be in + * "com.soliddowant.gregtechenergistics.mixins.jei".

+ */ +public class GregTechEnergisticsMixinPlugin implements IMixinConfigPlugin { + + private static final String JEI_PACKAGE_SUFFIX = ".jei."; + private static final String JEI_MOD_ID = "jei"; + + private String mixinPackage; + + @Override + public void onLoad(String mixinPackage) { + this.mixinPackage = mixinPackage; + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + // Only gate JEI-related mixins behind JEI presence check + // Check if the mixin is in the jei subpackage + String jeiMixinPackage = mixinPackage + JEI_PACKAGE_SUFFIX; + if (mixinClassName.startsWith(jeiMixinPackage)) { + return Loader.isModLoaded(JEI_MOD_ID); + } + + // Apply all other mixins unconditionally + return true; + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + // No special target handling needed + } + + @Override + public List getMixins() { + // Return null to let the config file handle mixin listing + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + // No pre-apply processing needed + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + // No post-apply processing needed + } +} \ No newline at end of file diff --git a/src/main/resources/mixins.gregtechenergistics.json b/src/main/resources/mixins.gregtechenergistics.json index b5f1577..8fd452e 100644 --- a/src/main/resources/mixins.gregtechenergistics.json +++ b/src/main/resources/mixins.gregtechenergistics.json @@ -4,6 +4,7 @@ "target": "@env(DEFAULT)", "minVersion": "0.8", "compatibilityLevel": "JAVA_8", + "plugin": "com.soliddowant.gregtechenergistics.mixins.GregTechEnergisticsMixinPlugin", "mixins": [ "MetaTileEntityHolderMixin" ], From b548fc0b8287d4e295a4460fc09c19be89e48a25 Mon Sep 17 00:00:00 2001 From: solidDoWant Date: Tue, 20 Jan 2026 08:36:33 +0000 Subject: [PATCH 8/9] fix import Signed-off-by: solidDoWant --- .../mixins/GregTechEnergisticsMixinPlugin.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/soliddowant/gregtechenergistics/mixins/GregTechEnergisticsMixinPlugin.java b/src/main/java/com/soliddowant/gregtechenergistics/mixins/GregTechEnergisticsMixinPlugin.java index a3e5ddb..8b76fb9 100644 --- a/src/main/java/com/soliddowant/gregtechenergistics/mixins/GregTechEnergisticsMixinPlugin.java +++ b/src/main/java/com/soliddowant/gregtechenergistics/mixins/GregTechEnergisticsMixinPlugin.java @@ -3,7 +3,7 @@ import java.util.List; import java.util.Set; -import org.spongepowered.asm.lib.tree.ClassNode; +import org.objectweb.asm.tree.ClassNode; import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; import org.spongepowered.asm.mixin.extensibility.IMixinInfo; @@ -13,10 +13,13 @@ * Mixin config plugin that conditionally loads mixins based on mod presence. * This prevents crashes when optional dependencies like JEI are not installed. * - *

This plugin assumes that JEI-specific mixins are placed in a ".jei" subpackage + *

+ * This plugin assumes that JEI-specific mixins are placed in a ".jei" + * subpackage * under the main mixin package. For example, if the mixin package is * "com.soliddowant.gregtechenergistics.mixins", then JEI mixins should be in - * "com.soliddowant.gregtechenergistics.mixins.jei".

+ * "com.soliddowant.gregtechenergistics.mixins.jei". + *

*/ public class GregTechEnergisticsMixinPlugin implements IMixinConfigPlugin { @@ -43,7 +46,7 @@ public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { if (mixinClassName.startsWith(jeiMixinPackage)) { return Loader.isModLoaded(JEI_MOD_ID); } - + // Apply all other mixins unconditionally return true; } From ff002603c48162af1e926a43594836dfbe676aad Mon Sep 17 00:00:00 2001 From: solidDoWant Date: Tue, 20 Jan 2026 08:49:44 +0000 Subject: [PATCH 9/9] Statically init GT_ENERGISTICS_HANDLER Signed-off-by: solidDoWant --- .../mixins/jei/RecipeRegistryMixin.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/soliddowant/gregtechenergistics/mixins/jei/RecipeRegistryMixin.java b/src/main/java/com/soliddowant/gregtechenergistics/mixins/jei/RecipeRegistryMixin.java index 8280d38..f94493e 100644 --- a/src/main/java/com/soliddowant/gregtechenergistics/mixins/jei/RecipeRegistryMixin.java +++ b/src/main/java/com/soliddowant/gregtechenergistics/mixins/jei/RecipeRegistryMixin.java @@ -29,7 +29,7 @@ public abstract class RecipeRegistryMixin { @Unique - private static RecipeTransferHandler GT_ENERGISTICS_HANDLER = null; + private static final RecipeTransferHandler GT_ENERGISTICS_HANDLER = new RecipeTransferHandler(); @Inject(method = "getRecipeTransferHandler", at = @At("RETURN"), cancellable = true, remap = false) private void injectPatternTermHandler( @@ -53,11 +53,7 @@ private void injectPatternTermHandler( return; } - // Replace AE2's handler with ours (lazy initialization) - if (GT_ENERGISTICS_HANDLER == null) { - GT_ENERGISTICS_HANDLER = new RecipeTransferHandler(); - } - + // Replace AE2's handler with this mod's handler cir.setReturnValue(GT_ENERGISTICS_HANDLER); } }