Repository: GregTechCEu/GregTech-Modern
Pull request #3031: Refactor ItemMaterialData and fix addon recipes load order
Author: login: nutant233
Labels: name: type: refactor
description: Suggestion to refactor a section of code
name: type: bugfix
description: General bug fixes
Created: 2025-04-02T10:41:29Z | Merged: 2025-04-23T18:45:19Z

## What
Fixed an issue where some items could not obtain MaterialEntry.
Fixed KJS empty script recycling recipes failing to load.

## Implementation Details
Replaced all ItemLike with Item to maintain consistent usage of Item instead of other class.

## Outcome
![f8b14e00-5345-4a57-a4a3-07a779c27704](https://github.com/user-attachments/assets/7ddfc38a-aead-4aac-86d2-5981620aaf55)
![749704a5-1c94-469e-86e0-bb37665ff745](https://github.com/user-attachments/assets/fd87b75b-3b98-4ae4-b907-d3191c6abca4)


## Additional Information
Load addons recipes before recycling recipes.
Changed some private modifiers to protected in GTRecipeBuilder to allow easier extension by addons.

## Potential Compatibility Issues
no breaking changes


Diff:
diff --git a/src/main/java/com/gregtechceu/gtceu/api/data/chemical/ChemicalHelper.java b/src/main/java/com/gregtechceu/gtceu/api/data/chemical/ChemicalHelper.java
index 9268ad0511c..65e1a217436 100644
--- a/src/main/java/com/gregtechceu/gtceu/api/data/chemical/ChemicalHelper.java
+++ b/src/main/java/com/gregtechceu/gtceu/api/data/chemical/ChemicalHelper.java
@@ -85,7 +85,7 @@ public static MaterialStack getMaterialStack(ItemLike itemLike) {
             Material entryMaterial = entry.material();
             return new MaterialStack(entryMaterial, entry.tagPrefix().getMaterialAmount(entryMaterial));
         }
-        ItemMaterialInfo info = ITEM_MATERIAL_INFO.get(itemLike);
+        ItemMaterialInfo info = ITEM_MATERIAL_INFO.get(itemLike.asItem());
         if (info == null) return MaterialStack.EMPTY;
         if (info.getMaterial().isEmpty()) {
             GTCEu.LOGGER.error("ItemMaterialInfo for {} is empty!", itemLike);
@@ -226,7 +226,7 @@ public static MaterialEntry getMaterialEntry(TagKey<Item> tag) {
     public static List<ItemLike> getItems(MaterialEntry materialEntry) {
         if (materialEntry.material().isNull()) return new ArrayList<>();
         return MATERIAL_ENTRY_ITEM_MAP.computeIfAbsent(materialEntry, entry -> {
-            var items = new ArrayList<Supplier<? extends ItemLike>>();
+            var items = new ArrayList<Supplier<? extends Item>>();
             for (TagKey<Item> tag : getTags(entry.tagPrefix(), entry.material())) {
                 for (Holder<Item> itemHolder : BuiltInRegistries.ITEM.getTagOrEmpty(tag)) {
                     items.add(itemHolder::value);
@@ -234,7 +234,7 @@ public static List<ItemLike> getItems(MaterialEntry materialEntry) {
             }
             TagPrefix prefix = entry.tagPrefix();
             if (items.isEmpty() && prefix.hasItemTable() && prefix.doGenerateItem(entry.material())) {
-                return List.of(prefix.getItemFromTable(entry.material()));
+                return List.of(() -> prefix.getItemFromTable(entry.material()).get().asItem());
             }
             return items;
         }).stream().map(Supplier::get).collect(Collectors.toList());
@@ -308,7 +308,7 @@ public static TagKey<Item>[] getTags(TagPrefix orePrefix, @NotNull Material mate
     public static List<Pair<ItemStack, ItemMaterialInfo>> getAllItemInfos() {
         List<Pair<ItemStack, ItemMaterialInfo>> f = new ArrayList<>();
         for (var entry : ITEM_MATERIAL_INFO.entrySet()) {
-            f.add(Pair.of(new ItemStack(entry.getKey().asItem()), entry.getValue()));
+            f.add(Pair.of(new ItemStack(entry.getKey()), entry.getValue()));
         }
         return f;
     }
diff --git a/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/ItemMaterialData.java b/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/ItemMaterialData.java
index 776d2bd47ff..5c0332daef5 100644
--- a/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/ItemMaterialData.java
+++ b/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/ItemMaterialData.java
@@ -15,7 +15,6 @@
 import net.minecraft.core.registries.Registries;
 import net.minecraft.data.recipes.FinishedRecipe;
 import net.minecraft.tags.TagKey;
-import net.minecraft.world.item.BlockItem;
 import net.minecraft.world.item.Item;
 import net.minecraft.world.item.ItemStack;
 import net.minecraft.world.level.ItemLike;
@@ -26,7 +25,6 @@
 
 import com.mojang.datafixers.util.Pair;
 import com.tterrag.registrate.util.entry.BlockEntry;
-import com.tterrag.registrate.util.entry.ItemEntry;
 import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
 import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap;
 import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
@@ -41,16 +39,16 @@
 public class ItemMaterialData {
 
     /** Used for custom material data for items that do not fall into the normal "prefix, material" pair */
-    public static final Map<ItemLike, ItemMaterialInfo> ITEM_MATERIAL_INFO = new Object2ObjectOpenHashMap<>();
+    public static final Map<Item, ItemMaterialInfo> ITEM_MATERIAL_INFO = new Object2ObjectOpenHashMap<>();
     /** Mapping of an item to a "prefix, material" pair */
-    public static final List<Pair<Supplier<? extends ItemLike>, MaterialEntry>> ITEM_MATERIAL_ENTRY = new ArrayList<>();
-    public static final Map<ItemLike, MaterialEntry> ITEM_MATERIAL_ENTRY_COLLECTED = new Object2ObjectOpenHashMap<>();
+    public static final List<Pair<Supplier<? extends Item>, MaterialEntry>> ITEM_MATERIAL_ENTRY = new ArrayList<>();
+    public static final Map<Item, MaterialEntry> ITEM_MATERIAL_ENTRY_COLLECTED = new Object2ObjectOpenHashMap<>();
     /** Mapping of a tag to a "prefix, material" pair */
     public static final Map<TagKey<Item>, MaterialEntry> TAG_MATERIAL_ENTRY = new Object2ObjectLinkedOpenHashMap<>();
     /** Mapping of a fluid to a material */
     public static final Map<Fluid, Material> FLUID_MATERIAL = new Object2ObjectOpenHashMap<>();
     /** Mapping of all items that represent a "prefix, material" pair */
-    public static final Map<MaterialEntry, List<Supplier<? extends ItemLike>>> MATERIAL_ENTRY_ITEM_MAP = new Object2ObjectOpenHashMap<>();
+    public static final Map<MaterialEntry, List<Supplier<? extends Item>>> MATERIAL_ENTRY_ITEM_MAP = new Object2ObjectOpenHashMap<>();
     public static final Map<MaterialEntry, List<Supplier<? extends Block>>> MATERIAL_ENTRY_BLOCK_MAP = new Object2ObjectOpenHashMap<>();
     /** Mapping of stone type blockState to "prefix, material" */
     public static final Map<Supplier<BlockState>, TagPrefix> ORES_INVERSE = new Object2ReferenceOpenHashMap<>();
@@ -59,45 +57,15 @@ public class ItemMaterialData {
             ItemStackHashStrategy.comparingAllButCount());
 
     public static void registerMaterialInfo(ItemLike item, ItemMaterialInfo materialInfo) {
-        if (item instanceof Block block) {
-            ITEM_MATERIAL_INFO.put(block, materialInfo);
-        } else if (item instanceof BlockItem blockItem) {
-            ITEM_MATERIAL_INFO.put(blockItem.getBlock(), materialInfo);
-        } else if (item instanceof ItemEntry<?> entry) {
-            ITEM_MATERIAL_INFO.put(entry.asItem(), materialInfo);
-        } else {
-            ITEM_MATERIAL_INFO.put(item, materialInfo);
-        }
+        ITEM_MATERIAL_INFO.put(item.asItem(), materialInfo);
     }
 
     public static ItemMaterialInfo getMaterialInfo(ItemLike item) {
-        if (item instanceof Block block) {
-            return ITEM_MATERIAL_INFO.get(block);
-        } else if (item instanceof BlockItem blockItem) {
-            var info = ITEM_MATERIAL_INFO.get(blockItem.getBlock());
-            if (info != null) return info;
-            return ITEM_MATERIAL_INFO.get(item);
-        } else if (item instanceof ItemEntry<?> entry) {
-            return ITEM_MATERIAL_INFO.get(entry.asItem());
-        }
-        return ITEM_MATERIAL_INFO.get(item);
+        return ITEM_MATERIAL_INFO.get(item.asItem());
     }
 
     public static void clearMaterialInfo(ItemLike item) {
-        if (item instanceof Block block) {
-            ITEM_MATERIAL_INFO.remove(block);
-        } else if (item instanceof BlockItem blockItem) {
-            var info = ITEM_MATERIAL_INFO.get(blockItem.getBlock());
-            if (info != null) {
-                ITEM_MATERIAL_INFO.remove(blockItem.getBlock());
-            } else {
-                ITEM_MATERIAL_INFO.remove(item);
-            }
-        } else if (item instanceof ItemEntry<?> entry) {
-            ITEM_MATERIAL_INFO.remove(entry.asItem());
-        } else {
-            ITEM_MATERIAL_INFO.remove(item);
-        }
+        ITEM_MATERIAL_INFO.remove(item.asItem());
     }
 
     /**
@@ -109,7 +77,7 @@ public static void clearMaterialInfo(ItemLike item) {
     public static void registerMaterialEntry(@NotNull Supplier<? extends ItemLike> supplier,
                                              @NotNull MaterialEntry materialEntry) {
         registerItemEntry(supplier, materialEntry);
-        ITEM_MATERIAL_ENTRY.add(Pair.of(supplier, materialEntry));
+        ITEM_MATERIAL_ENTRY.add(Pair.of(() -> supplier.get().asItem(), materialEntry));
         if (supplier instanceof RegistryObject<? extends ItemLike> registryObject) {
             registerRegistryObjectEntry(registryObject, materialEntry);
         } else if (supplier instanceof BlockEntry<?> entry) {
@@ -151,7 +119,7 @@ public static void registerMaterialEntry(@NotNull ItemLike item,
     private static void registerItemEntry(@NotNull Supplier<? extends ItemLike> supplier,
                                           @NotNull MaterialEntry materialEntry) {
         MATERIAL_ENTRY_ITEM_MAP.computeIfAbsent(materialEntry, k -> new ArrayList<>())
-                .add(supplier);
+                .add(() -> supplier.get().asItem());
         if (TagPrefix.ORES.containsKey(materialEntry.tagPrefix()) &&
                 !ORES_INVERSE.containsValue(materialEntry.tagPrefix())) {
             ORES_INVERSE.put(TagPrefix.ORES.get(materialEntry.tagPrefix()).stoneType(), materialEntry.tagPrefix());
diff --git a/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/stack/ItemMaterialInfo.java b/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/stack/ItemMaterialInfo.java
index 7ab1fe007a1..806a2a1768f 100644
--- a/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/stack/ItemMaterialInfo.java
+++ b/src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/stack/ItemMaterialInfo.java
@@ -1,5 +1,6 @@
 package com.gregtechceu.gtceu.api.data.chemical.material.stack;
 
+import com.gregtechceu.gtceu.api.GTValues;
 import com.gregtechceu.gtceu.api.data.chemical.material.Material;
 
 import it.unimi.dsi.fastutil.objects.Reference2LongMap;
@@ -15,6 +16,7 @@ public class ItemMaterialInfo {
 
     private final List<MaterialStack> sortedMaterials = new ArrayList<>();
     private int sortedHash = 0;
+    private String toStringValue;
 
     public ItemMaterialInfo(MaterialStack... materialStacks) {
         var materials = new Reference2LongOpenHashMap<Material>();
@@ -58,12 +60,23 @@ public void addMaterialStacks(List<MaterialStack> stacks) {
         setSortedMaterials(materials);
     }
 
-    private void setSortedMaterials(Reference2LongMap<Material> materials) {
+    private void setSortedMaterials(Reference2LongMap<Material> matStacks) {
         sortedMaterials.clear();
-        materials.reference2LongEntrySet().stream()
-                .sorted(Comparator.comparingLong(Reference2LongMap.Entry::getLongValue))
-                .forEach(entry -> sortedMaterials.add(new MaterialStack(entry.getKey(), entry.getLongValue())));
+
+        for (var entry : matStacks.reference2LongEntrySet()) {
+            sortedMaterials.add(new MaterialStack(entry.getKey(), entry.getLongValue()));
+        }
+        sortedMaterials.sort(Comparator.comparingLong(MaterialStack::amount));
+
         sortedHash = sortedMaterials.hashCode();
+
+        StringBuilder ret = new StringBuilder("[ ");
+        for (var matStack : sortedMaterials) {
+            ret.append(matStack.amount() / (float) GTValues.M).append("x ")
+                    .append(matStack.material().getResourceLocation()).append(" ");
+        }
+        ret.append("]");
+        toStringValue = ret.toString();
     }
 
     @Override
@@ -82,6 +95,6 @@ public int hashCode() {
 
     @Override
     public String toString() {
-        return sortedMaterials.isEmpty() ? "" : sortedMaterials.get(0).material().toCamelCaseString();
+        return toStringValue;
     }
 }
diff --git a/src/main/java/com/gregtechceu/gtceu/common/CommonProxy.java b/src/main/java/com/gregtechceu/gtceu/common/CommonProxy.java
index 69951aa11e7..a10284b2a04 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/CommonProxy.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/CommonProxy.java
@@ -6,7 +6,6 @@
 import com.gregtechceu.gtceu.api.addon.AddonFinder;
 import com.gregtechceu.gtceu.api.addon.IGTAddon;
 import com.gregtechceu.gtceu.api.capability.forge.GTCapability;
-import com.gregtechceu.gtceu.api.data.chemical.material.ItemMaterialData;
 import com.gregtechceu.gtceu.api.data.chemical.material.event.MaterialEvent;
 import com.gregtechceu.gtceu.api.data.chemical.material.event.MaterialRegistryEvent;
 import com.gregtechceu.gtceu.api.data.chemical.material.event.PostMaterialEvent;
@@ -271,7 +270,6 @@ public void registerPackFinders(AddPackFindersEvent event) {
             GTDynamicDataPack.clearServer();
 
             long startTime = System.currentTimeMillis();
-            ItemMaterialData.reinitializeMaterialData();
             GTCraftingComponents.init();
             GTRecipes.recipeRemoval();
             GTRecipes.recipeAddition(GTDynamicDataPack::addRecipe);
diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipes.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipes.java
index def70696fb5..1fe4c3fcd74 100644
--- a/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipes.java
+++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTRecipes.java
@@ -17,6 +17,8 @@
 import net.minecraft.resources.ResourceLocation;
 import net.minecraft.world.level.block.ComposterBlock;
 
+import dev.latvian.mods.kubejs.bindings.event.ServerEvents;
+import dev.latvian.mods.kubejs.recipe.RecipesEventJS;
 import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
 
 import java.util.Set;
@@ -45,6 +47,7 @@ public static void recipeAddition(Consumer<FinishedRecipe> originalConsumer) {
         ComposterRecipes.addComposterRecipes(ComposterBlock.COMPOSTABLES::put);
 
         // Decomposition info loading
+        ItemMaterialData.reinitializeMaterialData();
         MaterialInfoLoader.init();
 
         // com.gregtechceu.gtceu.data.recipe.generated.*
@@ -92,12 +95,13 @@ public static void recipeAddition(Consumer<FinishedRecipe> originalConsumer) {
         // Config-dependent recipes
         RecipeAddition.init(consumer);
 
+        AddonFinder.getAddons().forEach(addon -> addon.addRecipes(consumer));
+
         // Must run recycling recipes very last
-        if (!GTCEu.Mods.isKubeJSLoaded()) {
+        if (!(GTCEu.Mods.isKubeJSLoaded() && KJSCallWrapper.recipeEventHasListeners())) {
             RecyclingRecipes.init(consumer);
             ItemMaterialData.resolveItemMaterialInfos(consumer);
         }
-        AddonFinder.getAddons().forEach(addon -> addon.addRecipes(consumer));
     }
 
     /*
@@ -111,4 +115,11 @@ public static void recipeRemoval() {
         RecipeRemoval.init(RECIPE_FILTERS::add);
         AddonFinder.getAddons().forEach(addon -> addon.removeRecipes(RECIPE_FILTERS::add));
     }
+
+    private static class KJSCallWrapper {
+
+        private static boolean recipeEventHasListeners() {
+            return ServerEvents.RECIPES.hasListeners() && RecipesEventJS.instance != null;
+        }
+    }
 }
diff --git a/src/main/java/com/gregtechceu/gtceu/data/recipe/VanillaRecipeHelper.java b/src/main/java/com/gregtechceu/gtceu/data/recipe/VanillaRecipeHelper.java
index 9965d888630..b688edb7627 100644
--- a/src/main/java/com/gregtechceu/gtceu/data/recipe/VanillaRecipeHelper.java
+++ b/src/main/java/com/gregtechceu/gtceu/data/recipe/VanillaRecipeHelper.java
@@ -601,7 +601,7 @@ public static ItemMaterialInfo getRecyclingIngredients(int outputCount, @NotNull
             if (info != null) {
                 for (MaterialStack ms : info.getMaterials()) {
                     if (!(ms.material() instanceof MarkerMaterial)) {
-                        addMaterialStack(materialStacksExploded, inputCountMap, ms, lastChar);
+                        addMaterialStack(materialStacksExploded, outputCount, inputCountMap, ms, lastChar);
                     }
                 }
                 continue;
@@ -610,14 +610,14 @@ public static ItemMaterialInfo getRecyclingIngredients(int outputCount, @NotNull
             // Then try to get a single Material (UnificationEntry needs this, for example)
             MaterialStack materialStack = ChemicalHelper.getMaterialStack(itemLike);
             if (!materialStack.isEmpty() && !(materialStack.material() instanceof MarkerMaterial)) {
-                addMaterialStack(materialStacksExploded, inputCountMap, materialStack, lastChar);
+                addMaterialStack(materialStacksExploded, outputCount, inputCountMap, materialStack, lastChar);
             }
 
             // Gather any secondary materials if this item has an OrePrefix
             TagPrefix prefix = ChemicalHelper.getPrefix(itemLike);
             if (!prefix.isEmpty() && !prefix.secondaryMaterials().isEmpty()) {
                 for (MaterialStack ms : prefix.secondaryMaterials()) {
-                    addMaterialStack(materialStacksExploded, inputCountMap, ms, lastChar);
+                    addMaterialStack(materialStacksExploded, outputCount, inputCountMap, ms, lastChar);
                 }
             }
         }
@@ -626,8 +626,8 @@ public static ItemMaterialInfo getRecyclingIngredients(int outputCount, @NotNull
     }
 
     private static void addMaterialStack(@NotNull Reference2LongOpenHashMap<Material> materialStacksExploded,
-                                         @NotNull Char2IntFunction inputCountMap, @NotNull MaterialStack ms, char c) {
-        long amount = materialStacksExploded.getOrDefault(ms.material(), 0L);
-        materialStacksExploded.put(ms.material(), (ms.amount() * inputCountMap.get(c)) + amount);
+                                         int outputStackCount, @NotNull Char2IntFunction inputCountMap,
+                                         @NotNull MaterialStack ms, char c) {
+        materialStacksExploded.merge(ms.material(), (ms.amount() * inputCountMap.get(c) / outputStackCount), Long::sum);
     }
 }
diff --git a/src/main/java/com/gregtechceu/gtceu/data/recipe/builder/GTRecipeBuilder.java b/src/main/java/com/gregtechceu/gtceu/data/recipe/builder/GTRecipeBuilder.java
index 28432863c21..96aa5861c1d 100644
--- a/src/main/java/com/gregtechceu/gtceu/data/recipe/builder/GTRecipeBuilder.java
+++ b/src/main/java/com/gregtechceu/gtceu/data/recipe/builder/GTRecipeBuilder.java
@@ -1404,7 +1404,7 @@ public void save(Consumer<FinishedRecipe> consumer) {
         consumer.accept(build());
     }
 
-    public void addOutputMaterialInfo() {
+    private void addOutputMaterialInfo() {
         var itemOutputs = output.getOrDefault(ItemRecipeCapability.CAP, new ArrayList<>());
         var itemInputs = input.getOrDefault(ItemRecipeCapability.CAP, new ArrayList<>());
         if (itemOutputs.size() == 1 && (!itemInputs.isEmpty() || !tempFluidStacks.isEmpty())) {


Reviews:
user: login: screret
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T14:50:41Z
user: login: nutant233
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T15:31:41Z
user: login: nutant233
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T15:33:50Z
user: login: nutant233
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T15:35:41Z
user: login: nutant233
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T15:38:33Z
user: login: nutant233
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T15:51:03Z
user: login: screret
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T16:19:04Z
user: login: screret
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T12:18:13Z
user: login: nutant233
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T12:25:37Z
user: login: nutant233
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-11T12:48:00Z
user: login: screret
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T10:19:30Z
user: login: screret
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T10:40:34Z
user: login: screret
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T10:43:47Z
user: login: screret
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T10:44:10Z
user: login: screret
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T17:41:58Z
user: login: screret
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T18:03:38Z

Review comments:
diff_hunk: @@ -57,66 +55,37 @@ public class ItemMaterialData {
             ItemStackHashStrategy.comparingAllButCount());
 
     public static void registerMaterialInfo(ItemLike item, ItemMaterialInfo materialInfo) {
-        if (item instanceof Block block) {
-            ITEM_MATERIAL_INFO.put(block, materialInfo);
-        } else if (item instanceof BlockItem blockItem) {
-            ITEM_MATERIAL_INFO.put(blockItem.getBlock(), materialInfo);
-        } else if (item instanceof ItemEntry<?> entry) {
-            ITEM_MATERIAL_INFO.put(entry.asItem(), materialInfo);
-        } else {
-            ITEM_MATERIAL_INFO.put(item, materialInfo);
-        }
path: src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/ItemMaterialData.java
user: login: screret
body: as per my last review (which you made disappear) you shouldn't remove these cases as IIRC they're not only used in recipes. worldgen also uses this.
created_at: 2025-04-09T14:47:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,66 +55,37 @@ public class ItemMaterialData {
             ItemStackHashStrategy.comparingAllButCount());
 
     public static void registerMaterialInfo(ItemLike item, ItemMaterialInfo materialInfo) {
-        if (item instanceof Block block) {
-            ITEM_MATERIAL_INFO.put(block, materialInfo);
-        } else if (item instanceof BlockItem blockItem) {
-            ITEM_MATERIAL_INFO.put(blockItem.getBlock(), materialInfo);
-        } else if (item instanceof ItemEntry<?> entry) {
-            ITEM_MATERIAL_INFO.put(entry.asItem(), materialInfo);
-        } else {
-            ITEM_MATERIAL_INFO.put(item, materialInfo);
-        }
+        ITEM_MATERIAL_INFO.put(item.asItem(), materialInfo);
     }
 
     public static ItemMaterialInfo getMaterialInfo(ItemLike item) {
-        if (item instanceof Block block) {
-            return ITEM_MATERIAL_INFO.get(block);
-        } else if (item instanceof BlockItem blockItem) {
-            var info = ITEM_MATERIAL_INFO.get(blockItem.getBlock());
-            if (info != null) return info;
-            return ITEM_MATERIAL_INFO.get(item);
-        } else if (item instanceof ItemEntry<?> entry) {
-            return ITEM_MATERIAL_INFO.get(entry.asItem());
-        }
-        return ITEM_MATERIAL_INFO.get(item);
path: src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/ItemMaterialData.java
user: login: screret
body: don't delete this either.
created_at: 2025-04-09T14:47:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,66 +55,37 @@ public class ItemMaterialData {
             ItemStackHashStrategy.comparingAllButCount());
 
     public static void registerMaterialInfo(ItemLike item, ItemMaterialInfo materialInfo) {
-        if (item instanceof Block block) {
-            ITEM_MATERIAL_INFO.put(block, materialInfo);
-        } else if (item instanceof BlockItem blockItem) {
-            ITEM_MATERIAL_INFO.put(blockItem.getBlock(), materialInfo);
-        } else if (item instanceof ItemEntry<?> entry) {
-            ITEM_MATERIAL_INFO.put(entry.asItem(), materialInfo);
-        } else {
-            ITEM_MATERIAL_INFO.put(item, materialInfo);
-        }
+        ITEM_MATERIAL_INFO.put(item.asItem(), materialInfo);
     }
 
     public static ItemMaterialInfo getMaterialInfo(ItemLike item) {
-        if (item instanceof Block block) {
-            return ITEM_MATERIAL_INFO.get(block);
-        } else if (item instanceof BlockItem blockItem) {
-            var info = ITEM_MATERIAL_INFO.get(blockItem.getBlock());
-            if (info != null) return info;
-            return ITEM_MATERIAL_INFO.get(item);
-        } else if (item instanceof ItemEntry<?> entry) {
-            return ITEM_MATERIAL_INFO.get(entry.asItem());
-        }
-        return ITEM_MATERIAL_INFO.get(item);
+        return ITEM_MATERIAL_INFO.get(item.asItem());
     }
 
     public static void clearMaterialInfo(ItemLike item) {
-        if (item instanceof Block block) {
-            ITEM_MATERIAL_INFO.remove(block);
-        } else if (item instanceof BlockItem blockItem) {
-            var info = ITEM_MATERIAL_INFO.get(blockItem.getBlock());
-            if (info != null) {
-                ITEM_MATERIAL_INFO.remove(blockItem.getBlock());
-            } else {
-                ITEM_MATERIAL_INFO.remove(item);
-            }
-        } else if (item instanceof ItemEntry<?> entry) {
-            ITEM_MATERIAL_INFO.remove(entry.asItem());
-        } else {
-            ITEM_MATERIAL_INFO.remove(item);
-        }
path: src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/ItemMaterialData.java
user: login: screret
body: even here, the checks are fine to keep as they don't break anything.
also, removing this *is* a breaking change.
created_at: 2025-04-09T14:48:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,66 +55,37 @@ public class ItemMaterialData {
             ItemStackHashStrategy.comparingAllButCount());
 
     public static void registerMaterialInfo(ItemLike item, ItemMaterialInfo materialInfo) {
-        if (item instanceof Block block) {
-            ITEM_MATERIAL_INFO.put(block, materialInfo);
-        } else if (item instanceof BlockItem blockItem) {
-            ITEM_MATERIAL_INFO.put(blockItem.getBlock(), materialInfo);
-        } else if (item instanceof ItemEntry<?> entry) {
-            ITEM_MATERIAL_INFO.put(entry.asItem(), materialInfo);
-        } else {
-            ITEM_MATERIAL_INFO.put(item, materialInfo);
-        }
+        ITEM_MATERIAL_INFO.put(item.asItem(), materialInfo);
     }
 
     public static ItemMaterialInfo getMaterialInfo(ItemLike item) {
-        if (item instanceof Block block) {
-            return ITEM_MATERIAL_INFO.get(block);
-        } else if (item instanceof BlockItem blockItem) {
-            var info = ITEM_MATERIAL_INFO.get(blockItem.getBlock());
-            if (info != null) return info;
-            return ITEM_MATERIAL_INFO.get(item);
-        } else if (item instanceof ItemEntry<?> entry) {
-            return ITEM_MATERIAL_INFO.get(entry.asItem());
-        }
-        return ITEM_MATERIAL_INFO.get(item);
+        return ITEM_MATERIAL_INFO.get(item.asItem());
     }
 
     public static void clearMaterialInfo(ItemLike item) {
-        if (item instanceof Block block) {
-            ITEM_MATERIAL_INFO.remove(block);
-        } else if (item instanceof BlockItem blockItem) {
-            var info = ITEM_MATERIAL_INFO.get(blockItem.getBlock());
-            if (info != null) {
-                ITEM_MATERIAL_INFO.remove(blockItem.getBlock());
-            } else {
-                ITEM_MATERIAL_INFO.remove(item);
-            }
-        } else if (item instanceof ItemEntry<?> entry) {
-            ITEM_MATERIAL_INFO.remove(entry.asItem());
-        } else {
-            ITEM_MATERIAL_INFO.remove(item);
-        }
+        ITEM_MATERIAL_INFO.remove(item.asItem());
     }
 
     @SafeVarargs
     public static void registerMaterialInfoItems(MaterialEntry materialEntry,
                                                  Supplier<? extends ItemLike>... items) {
         var entryList = MATERIAL_ENTRY_ITEM_MAP.computeIfAbsent(materialEntry, entry -> new ArrayList<>());
-        for (Supplier<? extends ItemLike> item : items) {
+        for (Supplier<? extends ItemLike> itemLike : items) {
path: src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/ItemMaterialData.java
user: login: screret
body: why?
created_at: 2025-04-09T14:49:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1444,7 +1444,7 @@ public void addOutputMaterialInfo() {
         }
     }
 
-    private void removeExistingMaterialInfo() {
+    protected void removeExistingMaterialInfo() {
path: src/main/java/com/gregtechceu/gtceu/data/recipe/builder/GTRecipeBuilder.java
user: login: screret
body: you kind of didn't answer my question here? why do you need to change it? what is this "more convenient" you speak of?
created_at: 2025-04-09T14:50:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,66 +55,37 @@ public class ItemMaterialData {
             ItemStackHashStrategy.comparingAllButCount());
 
     public static void registerMaterialInfo(ItemLike item, ItemMaterialInfo materialInfo) {
-        if (item instanceof Block block) {
-            ITEM_MATERIAL_INFO.put(block, materialInfo);
-        } else if (item instanceof BlockItem blockItem) {
-            ITEM_MATERIAL_INFO.put(blockItem.getBlock(), materialInfo);
-        } else if (item instanceof ItemEntry<?> entry) {
-            ITEM_MATERIAL_INFO.put(entry.asItem(), materialInfo);
-        } else {
-            ITEM_MATERIAL_INFO.put(item, materialInfo);
-        }
path: src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/ItemMaterialData.java
user: login: nutant233
body: ![image](https://github.com/user-attachments/assets/dab05d11-d014-41bf-869c-491b9b8eedb5)
Based on my understanding, the original intention was to include Blocks in ITEM_MATERIAL_INFO so that getMaterialStack() could handle block inputs. However, the current implementation automatically converts blocks to their item forms within getMaterialStack(). Therefore, I believe using exclusively item-based storage won't cause issues.
created_at: 2025-04-09T15:31:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,66 +55,37 @@ public class ItemMaterialData {
             ItemStackHashStrategy.comparingAllButCount());
 
     public static void registerMaterialInfo(ItemLike item, ItemMaterialInfo materialInfo) {
-        if (item instanceof Block block) {
-            ITEM_MATERIAL_INFO.put(block, materialInfo);
-        } else if (item instanceof BlockItem blockItem) {
-            ITEM_MATERIAL_INFO.put(blockItem.getBlock(), materialInfo);
-        } else if (item instanceof ItemEntry<?> entry) {
-            ITEM_MATERIAL_INFO.put(entry.asItem(), materialInfo);
-        } else {
-            ITEM_MATERIAL_INFO.put(item, materialInfo);
-        }
+        ITEM_MATERIAL_INFO.put(item.asItem(), materialInfo);
     }
 
     public static ItemMaterialInfo getMaterialInfo(ItemLike item) {
-        if (item instanceof Block block) {
-            return ITEM_MATERIAL_INFO.get(block);
-        } else if (item instanceof BlockItem blockItem) {
-            var info = ITEM_MATERIAL_INFO.get(blockItem.getBlock());
-            if (info != null) return info;
-            return ITEM_MATERIAL_INFO.get(item);
-        } else if (item instanceof ItemEntry<?> entry) {
-            return ITEM_MATERIAL_INFO.get(entry.asItem());
-        }
-        return ITEM_MATERIAL_INFO.get(item);
+        return ITEM_MATERIAL_INFO.get(item.asItem());
     }
 
     public static void clearMaterialInfo(ItemLike item) {
-        if (item instanceof Block block) {
-            ITEM_MATERIAL_INFO.remove(block);
-        } else if (item instanceof BlockItem blockItem) {
-            var info = ITEM_MATERIAL_INFO.get(blockItem.getBlock());
-            if (info != null) {
-                ITEM_MATERIAL_INFO.remove(blockItem.getBlock());
-            } else {
-                ITEM_MATERIAL_INFO.remove(item);
-            }
-        } else if (item instanceof ItemEntry<?> entry) {
-            ITEM_MATERIAL_INFO.remove(entry.asItem());
-        } else {
-            ITEM_MATERIAL_INFO.remove(item);
-        }
+        ITEM_MATERIAL_INFO.remove(item.asItem());
     }
 
     @SafeVarargs
     public static void registerMaterialInfoItems(MaterialEntry materialEntry,
                                                  Supplier<? extends ItemLike>... items) {
         var entryList = MATERIAL_ENTRY_ITEM_MAP.computeIfAbsent(materialEntry, entry -> new ArrayList<>());
-        for (Supplier<? extends ItemLike> item : items) {
+        for (Supplier<? extends ItemLike> itemLike : items) {
path: src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/ItemMaterialData.java
user: login: nutant233
body: ![image](https://github.com/user-attachments/assets/5da689dc-2b73-430b-82fa-db0ebf245a44)
To differentiate from the subsequent Supplier<? extends Item> item
created_at: 2025-04-09T15:33:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1444,7 +1444,7 @@ public void addOutputMaterialInfo() {
         }
     }
 
-    private void removeExistingMaterialInfo() {
+    protected void removeExistingMaterialInfo() {
path: src/main/java/com/gregtechceu/gtceu/data/recipe/builder/GTRecipeBuilder.java
user: login: nutant233
body: I've adapted this for my mod convenience, but happy to use mixins instead if you want to preserve the current implementation.
created_at: 2025-04-09T15:35:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,66 +55,37 @@ public class ItemMaterialData {
             ItemStackHashStrategy.comparingAllButCount());
 
     public static void registerMaterialInfo(ItemLike item, ItemMaterialInfo materialInfo) {
-        if (item instanceof Block block) {
-            ITEM_MATERIAL_INFO.put(block, materialInfo);
-        } else if (item instanceof BlockItem blockItem) {
-            ITEM_MATERIAL_INFO.put(blockItem.getBlock(), materialInfo);
-        } else if (item instanceof ItemEntry<?> entry) {
-            ITEM_MATERIAL_INFO.put(entry.asItem(), materialInfo);
-        } else {
-            ITEM_MATERIAL_INFO.put(item, materialInfo);
-        }
path: src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/ItemMaterialData.java
user: login: nutant233
body: Tested across my modpack environment without failures.
created_at: 2025-04-09T15:38:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1444,7 +1444,7 @@ public void addOutputMaterialInfo() {
         }
     }
 
-    private void removeExistingMaterialInfo() {
+    protected void removeExistingMaterialInfo() {
path: src/main/java/com/gregtechceu/gtceu/data/recipe/builder/GTRecipeBuilder.java
user: login: nutant233
body: I've rewritten GTRecipeBuilder to better meet development requirements and achieve faster loading. The source code is available here: https://github.com/GregTech-Odyssey/GTOCore/blob/main/src/main/java/com/gto/gtocore/api/recipe/GTORecipeBuilder.java
created_at: 2025-04-09T15:51:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,66 +55,37 @@ public class ItemMaterialData {
             ItemStackHashStrategy.comparingAllButCount());
 
     public static void registerMaterialInfo(ItemLike item, ItemMaterialInfo materialInfo) {
-        if (item instanceof Block block) {
-            ITEM_MATERIAL_INFO.put(block, materialInfo);
-        } else if (item instanceof BlockItem blockItem) {
-            ITEM_MATERIAL_INFO.put(blockItem.getBlock(), materialInfo);
-        } else if (item instanceof ItemEntry<?> entry) {
-            ITEM_MATERIAL_INFO.put(entry.asItem(), materialInfo);
-        } else {
-            ITEM_MATERIAL_INFO.put(item, materialInfo);
-        }
+        ITEM_MATERIAL_INFO.put(item.asItem(), materialInfo);
     }
 
     public static ItemMaterialInfo getMaterialInfo(ItemLike item) {
-        if (item instanceof Block block) {
-            return ITEM_MATERIAL_INFO.get(block);
-        } else if (item instanceof BlockItem blockItem) {
-            var info = ITEM_MATERIAL_INFO.get(blockItem.getBlock());
-            if (info != null) return info;
-            return ITEM_MATERIAL_INFO.get(item);
-        } else if (item instanceof ItemEntry<?> entry) {
-            return ITEM_MATERIAL_INFO.get(entry.asItem());
-        }
-        return ITEM_MATERIAL_INFO.get(item);
+        return ITEM_MATERIAL_INFO.get(item.asItem());
     }
 
     public static void clearMaterialInfo(ItemLike item) {
-        if (item instanceof Block block) {
-            ITEM_MATERIAL_INFO.remove(block);
-        } else if (item instanceof BlockItem blockItem) {
-            var info = ITEM_MATERIAL_INFO.get(blockItem.getBlock());
-            if (info != null) {
-                ITEM_MATERIAL_INFO.remove(blockItem.getBlock());
-            } else {
-                ITEM_MATERIAL_INFO.remove(item);
-            }
-        } else if (item instanceof ItemEntry<?> entry) {
-            ITEM_MATERIAL_INFO.remove(entry.asItem());
-        } else {
-            ITEM_MATERIAL_INFO.remove(item);
-        }
+        ITEM_MATERIAL_INFO.remove(item.asItem());
     }
 
     @SafeVarargs
     public static void registerMaterialInfoItems(MaterialEntry materialEntry,
                                                  Supplier<? extends ItemLike>... items) {
         var entryList = MATERIAL_ENTRY_ITEM_MAP.computeIfAbsent(materialEntry, entry -> new ArrayList<>());
-        for (Supplier<? extends ItemLike> item : items) {
+        for (Supplier<? extends ItemLike> itemLike : items) {
path: src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/ItemMaterialData.java
user: login: screret
body: I don't see how this improves the function at all...
for me, it just makes it even less readable?
created_at: 2025-04-09T16:01:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1444,7 +1444,7 @@ public void addOutputMaterialInfo() {
         }
     }
 
-    private void removeExistingMaterialInfo() {
+    protected void removeExistingMaterialInfo() {
path: src/main/java/com/gregtechceu/gtceu/data/recipe/builder/GTRecipeBuilder.java
user: login: screret
body: no, sorry, I (and I presume the other developers are with me on this) don't want to support whatever that is.
created_at: 2025-04-09T16:02:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1444,7 +1444,7 @@ public void addOutputMaterialInfo() {
         }
     }
 
-    private void removeExistingMaterialInfo() {
+    protected void removeExistingMaterialInfo() {
path: src/main/java/com/gregtechceu/gtceu/data/recipe/builder/GTRecipeBuilder.java
user: login: screret
body: Ok, so I've looked into how you changed the world loading process to have faster loading.
you. practically removed datapacks? and mostly killed reloading by loading from a cache?
no, definitely not going to support that. 
created_at: 2025-04-09T16:18:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,66 +55,37 @@ public class ItemMaterialData {
             ItemStackHashStrategy.comparingAllButCount());
 
     public static void registerMaterialInfo(ItemLike item, ItemMaterialInfo materialInfo) {
-        if (item instanceof Block block) {
-            ITEM_MATERIAL_INFO.put(block, materialInfo);
-        } else if (item instanceof BlockItem blockItem) {
-            ITEM_MATERIAL_INFO.put(blockItem.getBlock(), materialInfo);
-        } else if (item instanceof ItemEntry<?> entry) {
-            ITEM_MATERIAL_INFO.put(entry.asItem(), materialInfo);
-        } else {
-            ITEM_MATERIAL_INFO.put(item, materialInfo);
-        }
path: src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/ItemMaterialData.java
user: login: screret
body: Well your "modpack environment" is apparently mangled beyond recognition so I don't think that's really a good testing environment for GTM changes
created_at: 2025-04-11T12:18:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,66 +55,37 @@ public class ItemMaterialData {
             ItemStackHashStrategy.comparingAllButCount());
 
     public static void registerMaterialInfo(ItemLike item, ItemMaterialInfo materialInfo) {
-        if (item instanceof Block block) {
-            ITEM_MATERIAL_INFO.put(block, materialInfo);
-        } else if (item instanceof BlockItem blockItem) {
-            ITEM_MATERIAL_INFO.put(blockItem.getBlock(), materialInfo);
-        } else if (item instanceof ItemEntry<?> entry) {
-            ITEM_MATERIAL_INFO.put(entry.asItem(), materialInfo);
-        } else {
-            ITEM_MATERIAL_INFO.put(item, materialInfo);
-        }
path: src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/ItemMaterialData.java
user: login: nutant233
body: I will conduct testing later using a standalone GTM.
created_at: 2025-04-11T12:25:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -57,66 +55,37 @@ public class ItemMaterialData {
             ItemStackHashStrategy.comparingAllButCount());
 
     public static void registerMaterialInfo(ItemLike item, ItemMaterialInfo materialInfo) {
-        if (item instanceof Block block) {
-            ITEM_MATERIAL_INFO.put(block, materialInfo);
-        } else if (item instanceof BlockItem blockItem) {
-            ITEM_MATERIAL_INFO.put(blockItem.getBlock(), materialInfo);
-        } else if (item instanceof ItemEntry<?> entry) {
-            ITEM_MATERIAL_INFO.put(entry.asItem(), materialInfo);
-        } else {
-            ITEM_MATERIAL_INFO.put(item, materialInfo);
-        }
path: src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/ItemMaterialData.java
user: login: nutant233
body: No issues have been detected in operation.
![image](https://github.com/user-attachments/assets/885456a3-a1d1-4e38-a3f5-cbd2e0bd6b76)

created_at: 2025-04-11T12:48:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -15,6 +16,7 @@ public class ItemMaterialInfo {
 
     private final List<MaterialStack> sortedMaterials = new ArrayList<>();
     private int sortedHash = 0;
+    private String str;
path: src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/stack/ItemMaterialInfo.java
user: login: screret
body: I think this should be named something like `toStringValue` instead
created_at: 2025-04-21T10:17:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -111,4 +115,11 @@ public static void recipeRemoval() {
         RecipeRemoval.init(RECIPE_FILTERS::add);
         AddonFinder.getAddons().forEach(addon -> addon.removeRecipes(RECIPE_FILTERS::add));
     }
+
+    private static class KJSCallWrapper {
+
+        private static boolean hasRecipesListeners() {
path: src/main/java/com/gregtechceu/gtceu/common/data/GTRecipes.java
user: login: screret
body: name this `recipeEventHasListeners` tyvm
created_at: 2025-04-21T10:18:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -64,6 +66,14 @@ private void setSortedMaterials(Reference2LongMap<Material> materials) {
                 .sorted(Comparator.comparingLong(Reference2LongMap.Entry::getLongValue))
                 .forEach(entry -> sortedMaterials.add(new MaterialStack(entry.getKey(), entry.getLongValue())));
         sortedHash = sortedMaterials.hashCode();
+
+        StringBuilder ret = new StringBuilder("{ ");
+        for (var matStack : sortedMaterials) {
+            ret.append(matStack.material().toCamelCaseString()).append(":")
+                    .append(matStack.amount() / (float) GTValues.M).append(" ");
path: src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/stack/ItemMaterialInfo.java
user: login: screret
body: tbh this could be formatted as `Nx material_id` instead of `materialId:N`
created_at: 2025-04-21T10:43:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -64,6 +66,14 @@ private void setSortedMaterials(Reference2LongMap<Material> materials) {
                 .sorted(Comparator.comparingLong(Reference2LongMap.Entry::getLongValue))
                 .forEach(entry -> sortedMaterials.add(new MaterialStack(entry.getKey(), entry.getLongValue())));
         sortedHash = sortedMaterials.hashCode();
+
+        StringBuilder ret = new StringBuilder("{ ");
+        for (var matStack : sortedMaterials) {
+            ret.append(matStack.material().toCamelCaseString()).append(":")
+                    .append(matStack.amount() / (float) GTValues.M).append(" ");
path: src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/stack/ItemMaterialInfo.java
user: login: screret
body: to match how we parse `MaterialStackWrapper`s
created_at: 2025-04-21T10:44:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -60,17 +60,20 @@ public void addMaterialStacks(List<MaterialStack> stacks) {
         setSortedMaterials(materials);
     }
 
-    private void setSortedMaterials(Reference2LongMap<Material> materials) {
+    private void setSortedMaterials(Reference2LongMap<Material> matStacks) {
         sortedMaterials.clear();
-        materials.reference2LongEntrySet().stream()
-                .sorted(Comparator.comparingLong(Reference2LongMap.Entry::getLongValue))
-                .forEach(entry -> sortedMaterials.add(new MaterialStack(entry.getKey(), entry.getLongValue())));
+
+        for (var entry : matStacks.reference2LongEntrySet()) {
+            sortedMaterials.add(new MaterialStack(entry.getKey(), entry.getLongValue()));
+        }
+        sortedMaterials.sort(Comparator.comparingLong(MaterialStack::amount));
+
         sortedHash = sortedMaterials.hashCode();
 
         StringBuilder ret = new StringBuilder("{ ");
         for (var matStack : sortedMaterials) {
-            ret.append(matStack.material().toCamelCaseString()).append(":")
-                    .append(matStack.amount() / (float) GTValues.M).append(" ");
+            ret.append(matStack.amount() / (float) GTValues.M).append("x ")
+                    .append(matStack.material().toCamelCaseString()).append(" ");
path: src/main/java/com/gregtechceu/gtceu/api/data/chemical/material/stack/ItemMaterialInfo.java
user: login: screret
body: wrong toString :tr:
created_at: 2025-04-23T17:41:57Z
author_association: CONTRIBUTOR

PR comments:
user: login: screret
created_at: 2025-04-09T14:09:58Z
body: why do you keep closing and remaking this?
author_association: CONTRIBUTOR
user: login: nutant233
created_at: 2025-04-09T14:26:26Z
body: > why do you keep closing and remaking this?
Previous PR modified main branch - must switch branches for updates.

author_association: CONTRIBUTOR
user: login: screret
created_at: 2025-04-09T14:30:21Z
body: well this one *doesn't*, though?
author_association: CONTRIBUTOR
user: login: nutant233
created_at: 2025-04-09T14:39:15Z
body: This conflicts with #3057, should we prioritize merging this PR or #3057 first?
author_association: CONTRIBUTOR
user: login: screret
created_at: 2025-04-11T12:29:33Z
body: ...or you could just move that one line that loads addon recipes slightly higher up. I'm trying to tell you that we don't want any of these other changes, and frankly, this back-and-forth is getting quite tiring.
author_association: CONTRIBUTOR
user: login: nutant233
created_at: 2025-04-11T12:42:16Z
body: > ...or you could just move that one line that loads addon recipes slightly higher up. I'm trying to tell you that we don't want any of these other changes, and frankly, this back-and-forth is getting quite tiring.

Placing these at the bottom is logically sound, as it allows other plugins to directly override recipe IDs without requiring explicit removal-and-add steps.

Regarding these modifications: the previous implementation doesn't work properly - for example, blocks and ignored/replaced materials (like EnderIO items in my modpack) all fail to retrieve material data.
This is the simplest fix I could find.
author_association: CONTRIBUTOR
user: login: screret
created_at: 2025-04-12T18:35:04Z
body: ok nvm the use I recalled the ItemLikes having has disappeared at some point whilst I wasn't looking
continue on
author_association: CONTRIBUTOR