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