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