diff --git a/src/main/java/com/gregtechceu/gtceu/api/recipe/lookup/RecipeManagerHandler.java b/src/main/java/com/gregtechceu/gtceu/api/recipe/lookup/RecipeManagerHandler.java
new file mode 100644
index 00000000000..f5e5bd08c5d
--- /dev/null
+++ b/src/main/java/com/gregtechceu/gtceu/api/recipe/lookup/RecipeManagerHandler.java
@@ -0,0 +1,66 @@
+package com.gregtechceu.gtceu.api.recipe.lookup;
+
+import com.gregtechceu.gtceu.api.recipe.GTRecipe;
+import com.gregtechceu.gtceu.api.recipe.GTRecipeType;
+
+import net.minecraft.world.item.crafting.RecipeHolder;
+import net.minecraft.world.item.crafting.RecipeType;
+
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Internal class handling adding recipes to GT's lookup system.
+ *
+ * Intended for use by {@link com.gregtechceu.gtceu.core.mixins.RecipeManagerLateMixin} and
+ * {@link com.gregtechceu.gtceu.integration.kjs.GregTechKubeJSPlugin}
+ */
+@ApiStatus.Internal
+public final class RecipeManagerHandler {
+
+ /**
+ * Adds proxy recipes to an {@link GTRecipeType}'s {@link RecipeAdditionHandler} and adds them to a list.
+ *
+ * @param recipes the recipes stored by their ID
+ * @param gtRecipeType the recipe type to add the recipes to, which owns the proxy recipes
+ * @param proxyRecipes the list of proxy recipes to populate
+ */
+ public static void addProxyRecipesToLookup(@NotNull Collection> recipes,
+ @NotNull GTRecipeType gtRecipeType, @NotNull RecipeType> proxyType,
+ @NotNull List> proxyRecipes) {
+ var lookup = gtRecipeType.getAdditionHandler();
+ proxyRecipes.clear();
+ recipes.forEach((recipe) -> {
+ if (recipe.value().getType() != proxyType) {
+ // do not add recipes of incompatible type
+ return;
+ }
+ RecipeHolder gtRecipe = gtRecipeType.toGTRecipe(recipe);
+ proxyRecipes.add(gtRecipe);
+ lookup.addStaging(gtRecipe.value());
+ });
+ }
+
+ /**
+ * Adds recipes to an {@link GTRecipeType}'s {@link RecipeAdditionHandler}
+ *
+ * @param recipes the recipes stored by their ID
+ * @param gtRecipeType the recipe type to add recipes to
+ */
+ public static void addRecipesToLookup(@NotNull Collection> recipes,
+ @NotNull GTRecipeType gtRecipeType) {
+ var lookup = gtRecipeType.getAdditionHandler();
+ for (RecipeHolder> r : recipes) {
+ if (r.value().getType() != gtRecipeType) {
+ // do not add recipes of incompatible type
+ continue;
+ }
+ if (r.value() instanceof GTRecipe recipe) {
+ lookup.addStaging(recipe);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/RecipeManagerLateMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/RecipeManagerLateMixin.java
index 563c9523382..28770123d8f 100644
--- a/src/main/java/com/gregtechceu/gtceu/core/mixins/RecipeManagerLateMixin.java
+++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/RecipeManagerLateMixin.java
@@ -2,7 +2,8 @@
import com.gregtechceu.gtceu.api.recipe.GTRecipe;
import com.gregtechceu.gtceu.api.recipe.GTRecipeType;
-import com.gregtechceu.gtceu.api.recipe.lookup.StagingRecipeDB;
+import com.gregtechceu.gtceu.api.recipe.lookup.MapIngredientPool;
+import com.gregtechceu.gtceu.api.recipe.lookup.RecipeManagerHandler;
import com.gregtechceu.gtceu.data.recipe.builder.GTRecipeBuilder;
import net.minecraft.advancements.Advancement;
@@ -19,22 +20,19 @@
import net.minecraft.world.item.crafting.RecipeType;
import net.neoforged.neoforge.common.conditions.ICondition;
-import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import com.google.gson.JsonElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
-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.CallbackInfo;
-import java.util.HashMap;
-import java.util.List;
+import java.util.Collection;
+import java.util.LinkedHashMap;
import java.util.Map;
-import java.util.stream.Stream;
@Mixin(value = RecipeManager.class, priority = 1500)
public abstract class RecipeManagerLateMixin {
@@ -45,11 +43,16 @@ public abstract class RecipeManagerLateMixin {
@Shadow
private Map> byName;
+ @Shadow
+ public abstract void replaceRecipes(Iterable> recipes);
+
@Inject(method = "apply(Ljava/util/Map;Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/util/profiling/ProfilerFiller;)V",
at = @At(value = "TAIL"))
private void gtceu$cloneVanillaRecipes(Map map, ResourceManager resourceManager,
ProfilerFiller profiler, CallbackInfo ci) {
- var recipesByName = new HashMap<>(byName);
+ // use a linked hash map to keep the immutable map's order
+ Map> recipesByName = new LinkedHashMap<>(byName);
+ // regenerate child recipes
byName.values().forEach(holder -> {
if (holder.value() instanceof GTRecipe gtRecipe) {
new GTRecipeBuilder(gtRecipe, gtRecipe.recipeType)
@@ -73,55 +76,24 @@ public void accept(@NotNull ResourceLocation id, @NotNull Recipe> recipe,
});
}
});
- gtceu$replaceRecipes(recipesByName);
+ replaceRecipes(recipesByName.values());
for (RecipeType> recipeType : BuiltInRegistries.RECIPE_TYPE) {
- if (recipeType instanceof GTRecipeType gtRecipeType) {
- var stagingDB = new StagingRecipeDB();
-
- var proxyRecipes = gtRecipeType.getProxyRecipes();
- for (Map.Entry, List>> entry : proxyRecipes.entrySet()) {
- var type = entry.getKey();
- var recipes = entry.getValue();
- recipes.clear();
- if (this.byType.containsKey(type)) {
- for (var recipe : this.byType.get(type)) {
- recipes.add(gtRecipeType.toGTRecipe(recipe));
- }
- }
- }
-
- if (this.byType.containsKey(gtRecipeType)) {
- Stream.concat(
- this.byType.get(gtRecipeType).stream(),
- proxyRecipes.entrySet().stream().flatMap(entry -> entry.getValue().stream()))
- .filter(holder -> holder != null && holder.value() instanceof GTRecipe)
- .forEach(holder -> {
- GTRecipe recipe = (GTRecipe) holder.value();
- recipe.setId(holder.id());
- stagingDB.add(recipe);
- });
- } else if (!proxyRecipes.isEmpty()) {
- proxyRecipes.values().stream()
- .flatMap(List::stream)
- .forEach(gtRecipe -> stagingDB.add(gtRecipe.value()));
- }
-
- stagingDB.populateDB(gtRecipeType.db());
+ if (!(recipeType instanceof GTRecipeType gtRecipeType)) {
+ continue;
}
+ gtRecipeType.beginStagingRecipes();
+ gtRecipeType.getProxyRecipes().forEach((type, list) -> {
+ Collection> recipes = this.byType.get(type);
+ if (recipes.isEmpty()) {
+ return;
+ }
+ RecipeManagerHandler.addProxyRecipesToLookup(recipes, gtRecipeType, type, list);
+ });
+ Collection> recipesByID = this.byType.get(gtRecipeType);
+ RecipeManagerHandler.addRecipesToLookup(recipesByID, gtRecipeType);
+ gtRecipeType.getAdditionHandler().completeStaging();
}
- }
-
- @Unique
- public void gtceu$replaceRecipes(Map> map) {
- byName = map;
-
- var recipesByType = ImmutableMultimap., RecipeHolder>>builder();
-
- for (var entry : map.entrySet()) {
- recipesByType.put(entry.getValue().value().getType(), entry.getValue());
- }
-
- byType = recipesByType.build();
+ MapIngredientPool.clear();
}
}