diff --git a/common/src/main/java/dev/latvian/mods/kubejs/recipe/RecipeJS.java b/common/src/main/java/dev/latvian/mods/kubejs/recipe/RecipeJS.java index 2670962ed..e25e9b011 100644 --- a/common/src/main/java/dev/latvian/mods/kubejs/recipe/RecipeJS.java +++ b/common/src/main/java/dev/latvian/mods/kubejs/recipe/RecipeJS.java @@ -5,6 +5,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.mojang.util.UUIDTypeAdapter; +import dev.latvian.mods.kubejs.DevProperties; import dev.latvian.mods.kubejs.core.RecipeKJS; import dev.latvian.mods.kubejs.fluid.FluidStackJS; import dev.latvian.mods.kubejs.fluid.InputFluid; @@ -426,8 +427,16 @@ public String getUniqueId() { return UtilsJS.getUniqueId(json); } - public void remove() { - removed = true; + public final void remove() { + if (!removed) { + removed = true; + + if (DevProperties.get().logRemovedRecipes) { + ConsoleJS.SERVER.info("- " + this + ": " + getFromToString()); + } else if (ConsoleJS.SERVER.shouldPrintDebug()) { + ConsoleJS.SERVER.debug("- " + this + ": " + getFromToString()); + } + } } public RecipeJS stage(String s) { diff --git a/common/src/main/java/dev/latvian/mods/kubejs/recipe/RecipesEventJS.java b/common/src/main/java/dev/latvian/mods/kubejs/recipe/RecipesEventJS.java index 5f1d4fc90..d4cce5889 100644 --- a/common/src/main/java/dev/latvian/mods/kubejs/recipe/RecipesEventJS.java +++ b/common/src/main/java/dev/latvian/mods/kubejs/recipe/RecipesEventJS.java @@ -8,6 +8,7 @@ import dev.latvian.mods.kubejs.CommonProperties; import dev.latvian.mods.kubejs.DevProperties; import dev.latvian.mods.kubejs.bindings.event.ServerEvents; +import dev.latvian.mods.kubejs.core.RecipeKJS; import dev.latvian.mods.kubejs.event.EventJS; import dev.latvian.mods.kubejs.item.ingredient.IngredientWithCustomPredicate; import dev.latvian.mods.kubejs.item.ingredient.TagContext; @@ -43,8 +44,22 @@ import org.jetbrains.annotations.Nullable; import java.lang.reflect.InvocationTargetException; -import java.util.*; -import java.util.concurrent.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.ForkJoinTask; +import java.util.concurrent.ForkJoinWorkerThread; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.function.Function; @@ -55,6 +70,7 @@ public class RecipesEventJS extends EventJS { public static final Pattern SKIP_ERROR = Pattern.compile("at.*dev\\.latvian\\.mods\\.kubejs\\.recipe\\.RecipesEventJS\\.post"); + private static final Predicate RECIPE_NOT_REMOVED = r -> r != null && !r.removed; public static final Map MODIFY_RESULT_CALLBACKS = new HashMap<>(); @@ -88,7 +104,6 @@ public class RecipesEventJS extends EventJS { public final Map originalRecipes; public final Collection addedRecipes; - public final AtomicInteger removedCount; public final AtomicInteger failedCount; private final Map recipeFunctions; @@ -102,6 +117,7 @@ public class RecipesEventJS extends EventJS { public final RecipeTypeFunction smithing; final RecipeSerializer stageSerializer; + private final JsonObject dataExport; public RecipesEventJS() { ConsoleJS.SERVER.info("Scanning recipes..."); @@ -109,7 +125,6 @@ public RecipesEventJS() { addedRecipes = new ConcurrentLinkedQueue<>(); recipeFunctions = new HashMap<>(); - removedCount = new AtomicInteger(0); failedCount = new AtomicInteger(0); var allNamespaces = RecipeNamespace.getAll(); @@ -162,6 +177,7 @@ public RecipesEventJS() { recipeFunctions.put("smithing", smithing); stageSerializer = KubeJSRegistries.recipeSerializers().get(new ResourceLocation("recipestages:stage")); + dataExport = DataExport.dataExport; } @HideFromJS @@ -201,7 +217,7 @@ public void post(RecipeManager recipeManager, Map continue; } - if (DataExport.dataExport != null) { + if (dataExport != null) { allRecipeMap.add(recipeId.toString(), JsonUtils.copy(json)); } } catch (Exception ex) { @@ -260,9 +276,12 @@ public void post(RecipeManager recipeManager, Map ServerEvents.RECIPES.post(ScriptType.SERVER, this); int modifiedCount = 0; + var removedRecipes = new ConcurrentLinkedQueue(); for (var r : originalRecipes.values()) { - if (r.hasChanged()) { + if (r.removed) { + removedRecipes.add(r); + } else if (r.hasChanged()) { modifiedCount++; } } @@ -276,7 +295,7 @@ public void post(RecipeManager recipeManager, Map try { recipesByName.putAll(runInParallel(() -> originalRecipes.values().parallelStream() - .filter(r -> !r.removed) + .filter(RECIPE_NOT_REMOVED) .map(recipe -> { try { return recipe.createRecipe(); @@ -316,14 +335,14 @@ public void post(RecipeManager recipeManager, Map ConsoleJS.SERVER.error("Error creating script recipes", ex, SKIP_ERROR); } - if (DataExport.dataExport != null) { - originalRecipes.values().stream().filter(r -> r.removed).forEach(r -> { + if (dataExport != null) { + for (var r : removedRecipes) { if (allRecipeMap.get(r.getId()) instanceof JsonObject json) { json.addProperty("removed", true); } - }); + } - DataExport.dataExport.add("recipes", allRecipeMap); + dataExport.add("recipes", allRecipeMap); } var newRecipeMap = new HashMap, Map>>(); @@ -337,7 +356,7 @@ public void post(RecipeManager recipeManager, Map RecipePlatformHelper.get().pingNewRecipes(newRecipeMap); recipeManager.byName = recipesByName; recipeManager.recipes = newRecipeMap; - ConsoleJS.SERVER.info("Added " + addedRecipes.size() + " recipes, removed " + removedCount.get() + " recipes, modified " + modifiedCount + " recipes, with " + failedCount.get() + " failed recipes in " + timer.stop()); + ConsoleJS.SERVER.info("Added " + addedRecipes.size() + " recipes, removed " + removedRecipes.size() + " recipes, modified " + modifiedCount + " recipes, with " + failedCount.get() + " failed recipes in " + timer.stop()); RecipeJS.itemErrors = false; if (DevProperties.get().debugInfo) { @@ -350,17 +369,15 @@ public void post(RecipeManager recipeManager, Map ConsoleJS.SERVER.info("======== Debug output of all modified recipes ========"); for (var r : originalRecipes.values()) { - if (r.hasChanged()) { + if (!r.removed && r.hasChanged()) { ConsoleJS.SERVER.info(r.getOrCreateId() + ": " + r.json + " FROM " + r.originalJson); } } ConsoleJS.SERVER.info("======== Debug output of all removed recipes ========"); - for (var r : originalRecipes.values()) { - if (r.removed) { - ConsoleJS.SERVER.info(r.getOrCreateId() + ": " + r.json); - } + for (var r : removedRecipes) { + ConsoleJS.SERVER.info(r.getOrCreateId() + ": " + r.json); } } } @@ -381,8 +398,15 @@ public RecipeJS addRecipe(RecipeJS r, boolean json) { return r; } - public RecipeFilter customFilter(RecipeFilter filter) { - return filter; + public RecipeFilter customFilter(Predicate filter) { + return filter::test; + } + + private record RecipeStreamFilter(RecipeFilter filter) implements Predicate { + @Override + public boolean test(RecipeJS r) { + return r != null && !r.removed && filter.test(r); + } } /** @@ -395,35 +419,27 @@ public RecipeFilter customFilter(RecipeFilter filter) { public Stream recipeStream(RecipeFilter filter) { if (filter == ConstantFilter.FALSE) { return Stream.empty(); + } else if (filter instanceof IDFilter id) { + var r = originalRecipes.get(id.id); + return r == null || r.removed ? Stream.empty() : Stream.of(r); } - var stream = Stream.empty(); - - if (filter instanceof IDFilter id) { - stream = Stream.ofNullable(originalRecipes.get(id.id)); - } else if (filter instanceof OrFilter or) { - var ids = new ArrayList(or.list.size()); - for (RecipeFilter recipeFilter : or.list) { - if (recipeFilter instanceof IDFilter id) { - ids.add(id.id); - } + exit: + if (filter instanceof OrFilter or) { + if (or.list.isEmpty()) { + return Stream.empty(); } - if (ids.size() == or.list.size()) { - stream = ids.stream().map(originalRecipes::get).filter(Objects::nonNull); - } - } else { - stream = originalRecipes.values().stream(); - if (filter != ConstantFilter.TRUE) { - stream = stream.filter(filter); + for (var recipeFilter : or.list) { + if (!(recipeFilter instanceof IDFilter)) { + break exit; + } } - } - if (removedCount.get() != 0) { - stream = stream.filter(r -> !r.removed); + return or.list.stream().map(idf -> originalRecipes.get(((IDFilter) idf).id)).filter(RECIPE_NOT_REMOVED); } - return stream; + return originalRecipes.values().stream().filter(new RecipeStreamFilter(filter)); } /** @@ -460,14 +476,14 @@ public boolean containsRecipe(RecipeFilter filter) { } public void remove(RecipeFilter filter) { - for (var r : recipeStream(filter).toList()) { - r.removed = true; + if (filter instanceof IDFilter id) { + var r = originalRecipes.get(id.id); - if (DevProperties.get().logRemovedRecipes) { - ConsoleJS.SERVER.info("- " + r + ": " + r.getFromToString()); - } else if (ConsoleJS.SERVER.shouldPrintDebug()) { - ConsoleJS.SERVER.debug("- " + r + ": " + r.getFromToString()); + if (r != null) { + r.remove(); } + } else { + forEachRecipeAsync(filter, RecipeJS::remove); } }