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 7aba49fdf..a934783c5 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 @@ -27,9 +27,12 @@ import dev.latvian.mods.kubejs.util.ConsoleJS; import dev.latvian.mods.kubejs.util.JsonIO; import dev.latvian.mods.kubejs.util.UtilsJS; +import dev.latvian.mods.rhino.WrappedException; import dev.latvian.mods.rhino.mod.util.JsonUtils; import dev.latvian.mods.rhino.util.HideFromJS; +import net.minecraft.ReportedException; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.Bootstrap; import net.minecraft.util.GsonHelper; import net.minecraft.world.item.crafting.Recipe; import net.minecraft.world.item.crafting.RecipeManager; @@ -38,17 +41,9 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; -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.ConcurrentLinkedQueue; +import java.lang.reflect.InvocationTargetException; +import java.util.*; +import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.function.Function; @@ -62,6 +57,30 @@ public class RecipesEventJS extends EventJS { public static final Map MODIFY_RESULT_CALLBACKS = new HashMap<>(); + // hacky workaround for parallel streams, which are executed on the common fork/join pool by default + // and forge / event bus REALLY does not like that (plus it's generally just safer to use our own pool) + private static final ForkJoinPool PARALLEL_THREAD_POOL = new ForkJoinPool(Math.max(1, Runtime.getRuntime().availableProcessors() - 1), + forkJoinPool -> { + final ForkJoinWorkerThread thread = new ForkJoinWorkerThread(forkJoinPool) { + }; + thread.setContextClassLoader(RecipesEventJS.class.getClassLoader()); // better safe than sorry + thread.setName(String.format("KubeJS Recipe Event Worker %d", thread.getPoolIndex())); + return thread; + }, + (thread, ex) -> { + while ((ex instanceof CompletionException | ex instanceof InvocationTargetException | ex instanceof WrappedException) && ex.getCause() != null) { + ex = ex.getCause(); + } + + if (ex instanceof ReportedException crashed) { + // crash the same way Minecraft would + Bootstrap.realStdoutPrintln(crashed.getReport().getFriendlyReport()); + System.exit(-1); + } + + throw new RecipeExceptionJS("Caught exception in thread " + thread + " while performing async operation!", ex); + }, true); + public static Map customIngredientMap = null; public static RecipesEventJS instance; @@ -259,7 +278,7 @@ public void post(RecipeManager recipeManager, Map var recipesByName = new HashMap>(originalRecipes.size() + addedRecipes.size()); try { - recipesByName.putAll(UtilsJS.runInParallel(() -> originalRecipes.values().parallelStream() + recipesByName.putAll(runInParallel(() -> originalRecipes.values().parallelStream() .map(recipe -> { try { return recipe.createRecipe(); @@ -276,7 +295,7 @@ public void post(RecipeManager recipeManager, Map } try { - recipesByName.putAll(UtilsJS.runInParallel(() -> addedRecipes.parallelStream() + recipesByName.putAll(runInParallel(() -> addedRecipes.parallelStream() .map(recipe -> { try { return recipe.createRecipe(); @@ -408,11 +427,11 @@ private Stream recipeStreamAsync(RecipeFilter filter) { } private void forEachRecipeAsync(RecipeFilter filter, Consumer consumer) { - UtilsJS.runInParallel(() -> recipeStreamAsync(filter).forEach(consumer)); + runInParallel(() -> recipeStreamAsync(filter).forEach(consumer)); } private T reduceRecipesAsync(RecipeFilter filter, Function, T> function) { - return UtilsJS.runInParallel(() -> function.apply(recipeStreamAsync(filter))); + return runInParallel(() -> function.apply(recipeStreamAsync(filter))); } public void forEachRecipe(RecipeFilter filter, Consumer consumer) { @@ -568,4 +587,12 @@ public void setItemErrors(boolean b) { public void stage(RecipeFilter filter, String stage) { forEachRecipeAsync(filter, r -> r.stage(stage)); } + + public static void runInParallel(final Runnable runnable) { + PARALLEL_THREAD_POOL.invoke(ForkJoinTask.adapt(runnable)); + } + + public static T runInParallel(final Callable callable) { + return PARALLEL_THREAD_POOL.invoke(ForkJoinTask.adapt(callable)); + } } \ No newline at end of file diff --git a/common/src/main/java/dev/latvian/mods/kubejs/util/UtilsJS.java b/common/src/main/java/dev/latvian/mods/kubejs/util/UtilsJS.java index 3953cfd66..96ccceb19 100644 --- a/common/src/main/java/dev/latvian/mods/kubejs/util/UtilsJS.java +++ b/common/src/main/java/dev/latvian/mods/kubejs/util/UtilsJS.java @@ -16,13 +16,15 @@ import dev.latvian.mods.kubejs.platform.MiscPlatformHelper; import dev.latvian.mods.kubejs.registry.KubeJSRegistries; import dev.latvian.mods.kubejs.script.ScriptType; -import dev.latvian.mods.rhino.*; +import dev.latvian.mods.rhino.BaseFunction; +import dev.latvian.mods.rhino.Context; +import dev.latvian.mods.rhino.NativeJavaObject; +import dev.latvian.mods.rhino.Wrapper; import dev.latvian.mods.rhino.mod.util.Copyable; import dev.latvian.mods.rhino.mod.util.NBTUtils; import dev.latvian.mods.rhino.mod.util.color.Color; import dev.latvian.mods.rhino.mod.util.color.SimpleColorWithAlpha; import dev.latvian.mods.rhino.regexp.NativeRegExp; -import net.minecraft.ReportedException; import net.minecraft.ResourceLocationException; import net.minecraft.advancements.critereon.MinMaxBounds; import net.minecraft.commands.arguments.selector.EntitySelector; @@ -31,7 +33,6 @@ import net.minecraft.nbt.*; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.Bootstrap; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.valueproviders.*; @@ -62,8 +63,6 @@ import java.time.Duration; import java.time.temporal.TemporalAmount; import java.util.*; -import java.util.concurrent.Callable; -import java.util.concurrent.*; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; @@ -86,30 +85,6 @@ public class UtilsJS { private static final Map ENTITY_SELECTOR_CACHE = new HashMap<>(); private static final EntitySelector ALL_ENTITIES_SELECTOR = new EntitySelector(EntitySelector.INFINITE, true, false, e -> true, MinMaxBounds.Doubles.ANY, Function.identity(), null, EntitySelectorParser.ORDER_ARBITRARY, false, null, null, null, true); - // hacky workaround for parallel streams, which are executed on the common fork/join pool by default - // and forge / event bus REALLY does not like that (plus it's generally just safer to use our own pool) - private static final ForkJoinPool POOL = new ForkJoinPool(Math.max(1, Runtime.getRuntime().availableProcessors() - 1), - forkJoinPool -> { - final ForkJoinWorkerThread thread = new ForkJoinWorkerThread(forkJoinPool) { - }; - thread.setContextClassLoader(KubeJS.class.getClassLoader()); // better safe than sorry - thread.setName(String.format("KubeJS Parallel Worker %d", thread.getPoolIndex())); - return thread; - }, - (thread, ex) -> { - while ((ex instanceof CompletionException | ex instanceof InvocationTargetException | ex instanceof WrappedException) && ex.getCause() != null) { - ex = ex.getCause(); - } - - if (ex instanceof ReportedException crashed) { - // crash the same way Minecraft would - Bootstrap.realStdoutPrintln(crashed.getReport().getFriendlyReport()); - System.exit(-1); - } - - KubeJS.LOGGER.error(String.format("Caught exception in thread %s while performing async operation!", thread), ex); - }, true); - public interface TryIO { void run() throws IOException; } @@ -885,12 +860,4 @@ public static void writeColor(FriendlyByteBuf buf, Color color) { public static Color readColor(FriendlyByteBuf buf) { return new SimpleColorWithAlpha(buf.readInt()); } - - public static void runInParallel(final Runnable runnable) { - POOL.invoke(ForkJoinTask.adapt(runnable)); - } - - public static T runInParallel(final Callable callable) { - return POOL.invoke(ForkJoinTask.adapt(callable)); - } } \ No newline at end of file