Skip to content

Commit

Permalink
Rethrow exceptions as RecipeExceptionJS during async operations
Browse files Browse the repository at this point in the history
  • Loading branch information
MaxNeedsSnacks committed Jul 17, 2023
1 parent 1cfe448 commit e22b57f
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -62,6 +57,30 @@ public class RecipesEventJS extends EventJS {

public static final Map<UUID, ModifyRecipeResultCallback> 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<UUID, IngredientWithCustomPredicate> customIngredientMap = null;

public static RecipesEventJS instance;
Expand Down Expand Up @@ -259,7 +278,7 @@ public void post(RecipeManager recipeManager, Map<ResourceLocation, JsonObject>
var recipesByName = new HashMap<ResourceLocation, Recipe<?>>(originalRecipes.size() + addedRecipes.size());

try {
recipesByName.putAll(UtilsJS.runInParallel(() -> originalRecipes.values().parallelStream()
recipesByName.putAll(runInParallel(() -> originalRecipes.values().parallelStream()
.map(recipe -> {
try {
return recipe.createRecipe();
Expand All @@ -276,7 +295,7 @@ public void post(RecipeManager recipeManager, Map<ResourceLocation, JsonObject>
}

try {
recipesByName.putAll(UtilsJS.runInParallel(() -> addedRecipes.parallelStream()
recipesByName.putAll(runInParallel(() -> addedRecipes.parallelStream()
.map(recipe -> {
try {
return recipe.createRecipe();
Expand Down Expand Up @@ -408,11 +427,11 @@ private Stream<RecipeJS> recipeStreamAsync(RecipeFilter filter) {
}

private void forEachRecipeAsync(RecipeFilter filter, Consumer<RecipeJS> consumer) {
UtilsJS.runInParallel(() -> recipeStreamAsync(filter).forEach(consumer));
runInParallel(() -> recipeStreamAsync(filter).forEach(consumer));
}

private <T> T reduceRecipesAsync(RecipeFilter filter, Function<Stream<RecipeJS>, T> function) {
return UtilsJS.runInParallel(() -> function.apply(recipeStreamAsync(filter)));
return runInParallel(() -> function.apply(recipeStreamAsync(filter)));
}

public void forEachRecipe(RecipeFilter filter, Consumer<RecipeJS> consumer) {
Expand Down Expand Up @@ -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> T runInParallel(final Callable<T> callable) {
return PARALLEL_THREAD_POOL.invoke(ForkJoinTask.adapt(callable));
}
}
41 changes: 4 additions & 37 deletions common/src/main/java/dev/latvian/mods/kubejs/util/UtilsJS.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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.*;
Expand Down Expand Up @@ -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;
Expand All @@ -86,30 +85,6 @@ public class UtilsJS {
private static final Map<String, EntitySelector> 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;
}
Expand Down Expand Up @@ -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> T runInParallel(final Callable<T> callable) {
return POOL.invoke(ForkJoinTask.adapt(callable));
}
}

0 comments on commit e22b57f

Please sign in to comment.