diff --git a/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedCommon.java b/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedCommon.java index cfc5cec..79e82eb 100644 --- a/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedCommon.java +++ b/Common/src/main/java/com/almostreliable/unified/AlmostUnifiedCommon.java @@ -11,6 +11,7 @@ import com.almostreliable.unified.core.AlmostUnifiedRuntimeImpl; import com.almostreliable.unified.unification.loot.LootUnification; import com.almostreliable.unified.utils.CustomLogger; +import com.almostreliable.unified.utils.RecipeErrorHandler; import com.almostreliable.unified.utils.VanillaTagWrapper; import com.google.common.base.Preconditions; @@ -39,9 +40,18 @@ public static void onTagLoaderReload(VanillaTagWrapper itemTags, VanillaTa } public static void onRecipeManagerReload(Map recipes, HolderLookup.Provider registries) { - Preconditions.checkNotNull(RUNTIME, "AlmostUnifiedRuntime was not loaded correctly"); + Preconditions.checkNotNull(RUNTIME, "runtime was not loaded correctly"); RUNTIME.run(recipes); LootUnification.unifyLoot(RUNTIME, registries); } + + public static void onRecipeManagerError(ResourceLocation recipe) { + assert RUNTIME != null; + RecipeErrorHandler.collect(RUNTIME.getRecipeTransformerResult(), recipe); + } + + public static void onRecipeManagerEnd() { + RecipeErrorHandler.finish(); + } } diff --git a/Common/src/main/java/com/almostreliable/unified/core/AlmostUnifiedRuntimeImpl.java b/Common/src/main/java/com/almostreliable/unified/core/AlmostUnifiedRuntimeImpl.java index 821b310..cef548b 100644 --- a/Common/src/main/java/com/almostreliable/unified/core/AlmostUnifiedRuntimeImpl.java +++ b/Common/src/main/java/com/almostreliable/unified/core/AlmostUnifiedRuntimeImpl.java @@ -51,16 +51,16 @@ public final class AlmostUnifiedRuntimeImpl implements AlmostUnifiedRuntime { private final RecipeUnifierRegistry recipeUnifierRegistry; private final TagSubstitutions tagSubstitutions; private final Placeholders placeholders; - private final DebugConfig debugConfig; private final UnificationLookup compositeUnificationLookup; + private final DebugHandler debugHandler; private AlmostUnifiedRuntimeImpl(Collection unificationSettings, RecipeUnifierRegistry recipeUnifierRegistry, TagSubstitutions tagSubstitutions, Placeholders placeholders, DebugConfig debugConfig) { this.unificationSettings = unificationSettings; this.recipeUnifierRegistry = recipeUnifierRegistry; this.tagSubstitutions = tagSubstitutions; this.placeholders = placeholders; - this.debugConfig = debugConfig; this.compositeUnificationLookup = new CompositeUnificationLookup(unificationSettings); + this.debugHandler = new DebugHandler(debugConfig); } public static AlmostUnifiedRuntimeImpl create(VanillaTagWrapper itemTags, VanillaTagWrapper blockTags) { @@ -188,7 +188,7 @@ private static List createUnificationLookups(VanillaTagWrap } public void run(Map recipes) { - DebugHandler debugHandler = DebugHandler.onRunStart(recipes, compositeUnificationLookup, debugConfig); + debugHandler.onRunStart(recipes, compositeUnificationLookup); debugHandler.measure(() -> { var transformer = new RecipeTransformer(recipeUnifierRegistry, unificationSettings); @@ -230,6 +230,10 @@ public Placeholders getPlaceholders() { return placeholders; } + public RecipeTransformer.Result getRecipeTransformerResult() { + return debugHandler.getRecipeTransformerResult(); + } + private static final class CompositeUnificationLookup implements UnificationLookup { private final Iterable unificationLookups; diff --git a/Common/src/main/java/com/almostreliable/unified/mixin/runtime/RecipeManagerMixin.java b/Common/src/main/java/com/almostreliable/unified/mixin/runtime/RecipeManagerMixin.java index 0298ea0..80284ac 100644 --- a/Common/src/main/java/com/almostreliable/unified/mixin/runtime/RecipeManagerMixin.java +++ b/Common/src/main/java/com/almostreliable/unified/mixin/runtime/RecipeManagerMixin.java @@ -9,6 +9,7 @@ import com.almostreliable.unified.AlmostUnifiedCommon; import com.google.gson.JsonElement; +import com.llamalad7.mixinextras.sugar.Local; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -26,10 +27,16 @@ public class RecipeManagerMixin { @Inject(method = "apply(Ljava/util/Map;Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/util/profiling/ProfilerFiller;)V", at = @At("HEAD")) private void almostunified$onRecipeReload(Map recipes, ResourceManager resourceManager, ProfilerFiller profiler, CallbackInfo ci) { - try { - AlmostUnifiedCommon.onRecipeManagerReload(recipes, registries); - } catch (Exception e) { - AlmostUnifiedCommon.LOGGER.error(e.getMessage(), e); - } + AlmostUnifiedCommon.onRecipeManagerReload(recipes, registries); + } + + @Inject(method = "apply(Ljava/util/Map;Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/util/profiling/ProfilerFiller;)V", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;error(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V"), remap = false) + private void almostunified$onRecipeError(Map recipes, ResourceManager resourceManager, ProfilerFiller profiler, CallbackInfo ci, @Local ResourceLocation recipe) { + AlmostUnifiedCommon.onRecipeManagerError(recipe); + } + + @Inject(method = "apply(Ljava/util/Map;Lnet/minecraft/server/packs/resources/ResourceManager;Lnet/minecraft/util/profiling/ProfilerFiller;)V", at = @At("TAIL")) + private void almostunified$onRecipeReloadEnd(Map recipes, ResourceManager resourceManager, ProfilerFiller profiler, CallbackInfo ci) { + AlmostUnifiedCommon.onRecipeManagerEnd(); } } diff --git a/Common/src/main/java/com/almostreliable/unified/unification/recipe/RecipeTransformer.java b/Common/src/main/java/com/almostreliable/unified/unification/recipe/RecipeTransformer.java index d1d6ab5..a48a00e 100644 --- a/Common/src/main/java/com/almostreliable/unified/unification/recipe/RecipeTransformer.java +++ b/Common/src/main/java/com/almostreliable/unified/unification/recipe/RecipeTransformer.java @@ -204,10 +204,11 @@ public void unifyRecipe(RecipeLink recipe) { } public static class Result { + private final Multimap allRecipesByType = HashMultimap.create(); private final Multimap unifiedRecipesByType = HashMultimap.create(); - private final Multimap duplicatesByType = HashMultimap.create(); + @Nullable private Set unifiedRecipeIds; private void add(RecipeLink link) { if (allRecipesByType.containsEntry(link.getType(), link)) { @@ -218,7 +219,6 @@ private void add(RecipeLink link) { if (link.isUnified()) { unifiedRecipesByType.put(link.getType(), link); } - if (link.hasDuplicateLink()) { duplicatesByType.put(link.getType(), link.getDuplicateLink()); } @@ -228,27 +228,39 @@ private void addAll(Collection links) { links.forEach(this::add); } - public Collection getRecipes(ResourceLocation type) { + public Collection getRecipesByType(ResourceLocation type) { return Collections.unmodifiableCollection(allRecipesByType.get(type)); } - public Collection getUnifiedRecipes(ResourceLocation type) { + public Collection getUnifiedRecipes() { + if (unifiedRecipeIds == null) { + unifiedRecipeIds = unifiedRecipesByType + .values() + .stream() + .map(RecipeLink::getId) + .collect(Collectors.toSet()); + } + + return unifiedRecipeIds; + } + + public Collection getUnifiedRecipesByType(ResourceLocation type) { return Collections.unmodifiableCollection(unifiedRecipesByType.get(type)); } - public Collection getDuplicates(ResourceLocation type) { + public Collection getDuplicateRecipesByType(ResourceLocation type) { return Collections.unmodifiableCollection(duplicatesByType.get(type)); } - public int getUnifiedRecipeCount() { + public int getUnifiedRecipesCount() { return unifiedRecipesByType.size(); } - public int getDuplicatesCount() { + public int getDuplicateRecipesCount() { return duplicatesByType.size(); } - public int getDuplicateRecipesCount() { + public int getTotalDuplicateRecipesCount() { return duplicatesByType.values().stream().mapToInt(l -> l.getRecipes().size()).sum(); } diff --git a/Common/src/main/java/com/almostreliable/unified/utils/DebugHandler.java b/Common/src/main/java/com/almostreliable/unified/utils/DebugHandler.java index f4ac6cf..cd39df7 100644 --- a/Common/src/main/java/com/almostreliable/unified/utils/DebugHandler.java +++ b/Common/src/main/java/com/almostreliable/unified/utils/DebugHandler.java @@ -36,23 +36,21 @@ public final class DebugHandler { private final DebugConfig config; private final String lastRun; - private final int recipesBefore; + private int recipesBefore = -1; private long startTime; private long endTime; @Nullable private RecipeTransformer.Result transformerResult; - private DebugHandler(int recipesBefore, DebugConfig config) { + public DebugHandler(DebugConfig config) { this.config = config; this.lastRun = "# Last run: " + DATE_FORMAT.format(new Date(System.currentTimeMillis())); - this.recipesBefore = recipesBefore; } - public static DebugHandler onRunStart(Map recipes, UnificationLookup unificationLookup, DebugConfig config) { - DebugHandler handler = new DebugHandler(recipes.size(), config); - handler.dumpTags(unificationLookup); - handler.dumpRecipes(RECIPES_BEFORE, recipes); - return handler; + public void onRunStart(Map recipes, UnificationLookup unificationLookup) { + dumpTags(unificationLookup); + dumpRecipes(RECIPES_BEFORE, recipes); + recipesBefore = recipes.size(); } public void measure(Supplier transformerSupplier) { @@ -62,6 +60,7 @@ public void measure(Supplier transformerSupplier) { } public void onRunEnd(Map recipes) { + Preconditions.checkArgument(recipesBefore >= 0, "recipesBefore not set"); Preconditions.checkArgument(startTime > 0, "startTime not set"); Preconditions.checkArgument(endTime > 0, "endTime not set"); Preconditions.checkNotNull(transformerResult, "transformerResult not set"); @@ -122,12 +121,12 @@ private void dumpOverview(int recipesAfter) { .append(lastRun).append("\n") .append("# Statistics:\n") .append("- Unified Recipes: ") - .append(transformerResult.getUnifiedRecipeCount()) + .append(transformerResult.getUnifiedRecipesCount()) .append("\n") .append("- Duplicate Recipes: ") - .append(transformerResult.getDuplicatesCount()) - .append(" (Individual: ") .append(transformerResult.getDuplicateRecipesCount()) + .append(" (Individual: ") + .append(transformerResult.getTotalDuplicateRecipesCount()) .append(")\n") .append("- Recipes Before: ") .append(recipesBefore) @@ -152,11 +151,11 @@ private void dumpOverview(int recipesAfter) { .append("\n"); getSortedUnifiedRecipeTypes().forEach(type -> { - int unifiedSize = transformerResult.getUnifiedRecipes(type).size(); - int allSize = transformerResult.getRecipes(type).size(); - int duplicatesSize = transformerResult.getDuplicates(type).size(); + int unifiedSize = transformerResult.getUnifiedRecipesByType(type).size(); + int allSize = transformerResult.getRecipesByType(type).size(); + int duplicatesSize = transformerResult.getDuplicateRecipesByType(type).size(); int individualDuplicatesSize = transformerResult - .getDuplicates(type) + .getDuplicateRecipesByType(type) .stream() .mapToInt(l -> l.getRecipes().size()) .sum(); @@ -209,7 +208,7 @@ private void dumpDuplicates() { sb.append(lastRun).append("\n"); getSortedUnifiedRecipeTypes().forEach(type -> { Collection duplicates = transformerResult - .getDuplicates(type) + .getDuplicateRecipesByType(type) .stream() .sorted(Comparator.comparing(l -> l.getMaster().getId().toString())) .toList(); @@ -229,7 +228,7 @@ private String createDuplicatesDump(RecipeLink.DuplicateLink link) { .stream() .sorted(Comparator.comparing(r -> r.getId().toString())) .map(r -> "\t\t- " + r.getId() + "\n") - .collect(Collectors.joining("", String.format("\t%s\n", link.getMaster().getId().toString()), "\n")); + .collect(Collectors.joining("", String.format("\t%s\n", link.getMaster().getId()), "\n")); } private static int getMaxLength(Collection collection, ToIntFunction function) { @@ -255,8 +254,13 @@ private Stream getSortedUnifiedRecipeTypes() { private Stream getSortedUnifiedRecipes(ResourceLocation type) { Preconditions.checkNotNull(transformerResult); return transformerResult - .getUnifiedRecipes(type) + .getUnifiedRecipesByType(type) .stream() .sorted(Comparator.comparing(r -> r.getId().toString())); } + + public RecipeTransformer.Result getRecipeTransformerResult() { + Preconditions.checkNotNull(transformerResult, "transformerResult not available yet"); + return transformerResult; + } } diff --git a/Common/src/main/java/com/almostreliable/unified/utils/RecipeErrorHandler.java b/Common/src/main/java/com/almostreliable/unified/utils/RecipeErrorHandler.java new file mode 100644 index 0000000..778a7a2 --- /dev/null +++ b/Common/src/main/java/com/almostreliable/unified/utils/RecipeErrorHandler.java @@ -0,0 +1,36 @@ +package com.almostreliable.unified.utils; + +import net.minecraft.resources.ResourceLocation; + +import com.almostreliable.unified.AlmostUnifiedCommon; +import com.almostreliable.unified.unification.recipe.RecipeTransformer; + +import java.util.HashSet; +import java.util.Set; + +public final class RecipeErrorHandler { + + private static final Set RECIPES = new HashSet<>(); + + private RecipeErrorHandler() {} + + public static void collect(RecipeTransformer.Result result, ResourceLocation recipe) { + if (result.getUnifiedRecipes().contains(recipe)) { + RECIPES.add(recipe); + } + } + + public static void finish() { + if (!RECIPES.isEmpty()) { + AlmostUnifiedCommon.LOGGER.error( + "The following recipes were unified and threw exceptions when being loaded: {}", + RECIPES + ); + AlmostUnifiedCommon.LOGGER.warn( + "Try to add them to the ignore list and if the problem is gone, report it to the Almost Unified developers." + ); + } + + RECIPES.clear(); + } +}