From 661243d99ffaf22b8774f50decdf61d9c1647c98 Mon Sep 17 00:00:00 2001 From: LatvianModder Date: Tue, 29 Oct 2024 12:19:02 +0200 Subject: [PATCH] Fixed long stack traces, added ID.reduce(id), added error printing for item component tooltip --- .../client/KubeJSGameClientEventHandler.java | 49 +++++++++++++++---- .../component/DataComponentWrapper.java | 6 +-- .../kubejs/recipe/RecipeTypeFunction.java | 2 +- .../mods/kubejs/recipe/RecipesKubeEvent.java | 4 +- .../latvian/mods/kubejs/script/ConsoleJS.java | 9 +++- .../java/dev/latvian/mods/kubejs/util/ID.java | 4 ++ .../mods/kubejs/util/StackTraceCollector.java | 9 ++-- 7 files changed, 64 insertions(+), 19 deletions(-) diff --git a/src/main/java/dev/latvian/mods/kubejs/client/KubeJSGameClientEventHandler.java b/src/main/java/dev/latvian/mods/kubejs/client/KubeJSGameClientEventHandler.java index 3a9a43ccb..078b1092e 100644 --- a/src/main/java/dev/latvian/mods/kubejs/client/KubeJSGameClientEventHandler.java +++ b/src/main/java/dev/latvian/mods/kubejs/client/KubeJSGameClientEventHandler.java @@ -13,6 +13,8 @@ import dev.latvian.mods.kubejs.text.action.DynamicTextAction; import dev.latvian.mods.kubejs.text.tooltip.ItemTooltipData; import dev.latvian.mods.kubejs.text.tooltip.TooltipRequirements; +import dev.latvian.mods.kubejs.util.ID; +import dev.latvian.mods.kubejs.util.StackTraceCollector; import dev.latvian.mods.kubejs.util.Tristate; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.ImageButton; @@ -47,10 +49,16 @@ import net.neoforged.neoforge.event.entity.player.ItemTooltipEvent; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.List; +import java.util.regex.Pattern; @EventBusSubscriber(modid = KubeJS.MOD_ID, value = Dist.CLIENT) public class KubeJSGameClientEventHandler { + public static final Pattern COMPONENT_ERROR = ConsoleJS.methodPattern(KubeJSGameClientEventHandler.class, "onItemTooltip"); + private static List lastComponentError = List.of(); + @SubscribeEvent public static void debugInfo(CustomizeGuiOverlayEvent.DebugText event) { var mc = Minecraft.getInstance(); @@ -65,19 +73,23 @@ public static void debugInfo(CustomizeGuiOverlayEvent.DebugText event) { } } - private static void appendComponentValue(DynamicOps ops, MutableComponent line, DataComponentType type, T value) { + private static List appendComponentValue(DynamicOps ops, MutableComponent line, DataComponentType type, T value) { if (value == null) { line.append(Component.literal("null").kjs$red()); - return; + return List.of(); } else if (value instanceof Component c) { - line.append(Component.empty().kjs$green().append(c)); + line.append(Component.empty().kjs$gold().append(c)); } try { var tag = type.codecOrThrow().encodeStart(ops, value).getOrThrow(); line.append(NbtUtils.toPrettyComponent(tag)); - } catch (Exception ex) { - line.append(Component.literal(String.valueOf(value)).kjs$green()); + return List.of(); + } catch (Throwable ex) { + line.append(Component.literal(String.valueOf(value)).kjs$red()); + var lines = new ArrayList(); + ex.printStackTrace(new StackTraceCollector(lines, COMPONENT_ERROR, ConsoleJS.ERROR_REDUCE)); + return lines; } } @@ -161,6 +173,7 @@ public static void onItemTooltip(ItemTooltipEvent event) { if (mc.level != null && advanced && ClientProperties.get().showComponents && dynamicEvent.alt) { var components = BuiltInRegistries.DATA_COMPONENT_TYPE; var ops = mc.level.registryAccess().createSerializationContext(NbtOps.INSTANCE); + var errors = new ArrayList(0); for (var entry : stack.getComponentsPatch().entrySet()) { var id = components.getKey(entry.getKey()); @@ -173,11 +186,17 @@ public static void onItemTooltip(ItemTooltipEvent event) { line.append(Component.literal("!")); } - line.append(Component.literal(id.getNamespace().equals("minecraft") ? id.getPath() : id.toString()).kjs$yellow()); + line.append(Component.literal(ID.reduce(id)).kjs$yellow()); if (entry.getValue().isPresent()) { line.append(Component.literal("=")); - appendComponentValue(ops, line, (DataComponentType) entry.getKey(), entry.getValue().get()); + var errors0 = appendComponentValue(ops, line, (DataComponentType) entry.getKey(), entry.getValue().get()); + + if (!errors0.isEmpty()) { + lines.add(Component.literal(ID.reduce(id) + " errored, see log").kjs$darkRed()); + errors.add("Failed to encode value of " + id + ": " + entry.getValue().get()); + errors.addAll(errors0); + } } lines.add(line); @@ -191,13 +210,25 @@ public static void onItemTooltip(ItemTooltipEvent event) { if (id != null && stack.getComponentsPatch().get(type.type()) == null) { var line = Component.empty(); line.append(TextIcons.icon(Component.literal("P."))); - line.append(Component.literal(id.getNamespace().equals("minecraft") ? id.getPath() : id.toString()).kjs$gray()); + line.append(Component.literal(ID.reduce(id)).kjs$gray()); line.append(Component.literal("=")); - appendComponentValue(ops, line, (DataComponentType) type.type(), type.value()); + var errors0 = appendComponentValue(ops, line, (DataComponentType) type.type(), type.value()); + + if (!errors0.isEmpty()) { + lines.add(Component.literal(ID.reduce(id) + " errored, see log").kjs$darkRed()); + errors.add("Failed to encode value of " + id + ": " + type.value()); + errors.addAll(errors0); + } + lines.add(line); } } } + + if (!errors.isEmpty() && !lastComponentError.equals(errors)) { + lastComponentError = errors; + errors.forEach(ConsoleJS.CLIENT::error); + } } else if (advanced && ClientProperties.get().showTagNames && dynamicEvent.shift) { var tempTagNames = new LinkedHashMap(); TagInstance.Type.ITEM.append(tempTagNames, stack.getItem().builtInRegistryHolder().tags()); diff --git a/src/main/java/dev/latvian/mods/kubejs/component/DataComponentWrapper.java b/src/main/java/dev/latvian/mods/kubejs/component/DataComponentWrapper.java index 5f7f56bad..99f6d4a46 100644 --- a/src/main/java/dev/latvian/mods/kubejs/component/DataComponentWrapper.java +++ b/src/main/java/dev/latvian/mods/kubejs/component/DataComponentWrapper.java @@ -315,7 +315,7 @@ static StringBuilder mapToString(StringBuilder builder, DynamicOps ops, Dat } var value = codec == Codec.BOOL ? comp.value() : codec.encodeStart(ops, Cast.to(comp.value())).getOrThrow(); - builder.append(id.getNamespace().equals("minecraft") ? id.getPath() : id.toString()).append('=').append(value); + builder.append(ID.reduce(id)).append('=').append(value); } builder.append(']'); @@ -343,9 +343,9 @@ static StringBuilder patchToString(StringBuilder builder, DynamicOps ops, D if (comp.getValue().isPresent()) { var value = codec == Codec.BOOL ? comp.getValue().get() : codec.encodeStart(ops, Cast.to(comp.getValue().get())).result().get(); - builder.append(id.getNamespace().equals("minecraft") ? id.getPath() : id.toString()).append('=').append(value); + builder.append(ID.reduce(id)).append('=').append(value); } else { - builder.append('!').append(id.getNamespace().equals("minecraft") ? id.getPath() : id.toString()); + builder.append('!').append(ID.reduce(id)); } } diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/RecipeTypeFunction.java b/src/main/java/dev/latvian/mods/kubejs/recipe/RecipeTypeFunction.java index e35a749fd..d8177334e 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/RecipeTypeFunction.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/RecipeTypeFunction.java @@ -20,7 +20,7 @@ import java.util.stream.Collectors; public class RecipeTypeFunction extends BaseFunction implements WrappedJS { - public static final Pattern SKIP_ERROR = Pattern.compile("dev\\.latvian\\.mods\\.kubejs\\.recipe\\.RecipeTypeFunction\\.call"); + public static final Pattern SKIP_ERROR = ConsoleJS.methodPattern(RecipeTypeFunction.class, "call"); public final RecipesKubeEvent event; public final ResourceLocation id; diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/RecipesKubeEvent.java b/src/main/java/dev/latvian/mods/kubejs/recipe/RecipesKubeEvent.java index da31f7fc5..3b1c638b3 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/RecipesKubeEvent.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/RecipesKubeEvent.java @@ -69,8 +69,8 @@ import java.util.stream.Stream; public class RecipesKubeEvent implements KubeEvent { - public static final Pattern POST_SKIP_ERROR = Pattern.compile("dev\\.latvian\\.mods\\.kubejs\\.recipe\\.RecipesKubeEvent\\.post"); - public static final Pattern CREATE_RECIPE_SKIP_ERROR = Pattern.compile("dev\\.latvian\\.mods\\.kubejs\\.recipe\\.RecipesKubeEvent\\.createRecipe"); + public static final Pattern POST_SKIP_ERROR = ConsoleJS.methodPattern(RecipesKubeEvent.class, "post"); + public static final Pattern CREATE_RECIPE_SKIP_ERROR = ConsoleJS.methodPattern(RecipesKubeEvent.class, "createRecipe"); private static final Predicate RECIPE_NOT_REMOVED = r -> r != null && !r.removed; private static final Predicate RECIPE_IS_SYNTHETIC = r -> !r.newRecipe; diff --git a/src/main/java/dev/latvian/mods/kubejs/script/ConsoleJS.java b/src/main/java/dev/latvian/mods/kubejs/script/ConsoleJS.java index 2cabdaa71..5e8dcbddf 100644 --- a/src/main/java/dev/latvian/mods/kubejs/script/ConsoleJS.java +++ b/src/main/java/dev/latvian/mods/kubejs/script/ConsoleJS.java @@ -21,6 +21,7 @@ import dev.latvian.mods.rhino.EcmaError; import dev.latvian.mods.rhino.RhinoException; import dev.latvian.mods.rhino.WrappedException; +import dev.latvian.mods.rhino.util.HideFromJS; import net.minecraft.network.chat.Component; import net.neoforged.fml.loading.FMLLoader; import org.jetbrains.annotations.Nullable; @@ -58,7 +59,9 @@ public static ConsoleJS getCurrent(@Nullable Context cx) { } private static final Pattern GARBAGE_PATTERN = Pattern.compile("(?:TRANSFORMER|LAYER PLUGIN)/\\w+@[^/]+/"); - private static final Function ERROR_REDUCE = s -> { + + @HideFromJS + public static final Function ERROR_REDUCE = s -> { if (s.startsWith("java.util.concurrent.ForkJoin") || s.startsWith("jdk.internal.")) { return ""; } @@ -66,6 +69,10 @@ public static ConsoleJS getCurrent(@Nullable Context cx) { return GARBAGE_PATTERN.matcher(s).replaceAll("").replace("dev.latvian.mods.", "…"); }; + public static Pattern methodPattern(Class c, String method) { + return Pattern.compile(c.getName().replace(".", "\\.") + "\\." + method); + } + public final ScriptType scriptType; public final transient Collection errors; public final transient Collection warnings; diff --git a/src/main/java/dev/latvian/mods/kubejs/util/ID.java b/src/main/java/dev/latvian/mods/kubejs/util/ID.java index 889475322..04d975718 100644 --- a/src/main/java/dev/latvian/mods/kubejs/util/ID.java +++ b/src/main/java/dev/latvian/mods/kubejs/util/ID.java @@ -109,4 +109,8 @@ static boolean isKey(Object from) { static String url(ResourceLocation id) { return URLEncoder.encode(id.getNamespace(), StandardCharsets.UTF_8) + "/" + URLEncoder.encode(id.getPath(), StandardCharsets.UTF_8); } + + static String reduce(ResourceLocation id) { + return id.getNamespace().equals("minecraft") ? id.getPath() : id.toString(); + } } diff --git a/src/main/java/dev/latvian/mods/kubejs/util/StackTraceCollector.java b/src/main/java/dev/latvian/mods/kubejs/util/StackTraceCollector.java index 665e89fd0..aa4ecb583 100644 --- a/src/main/java/dev/latvian/mods/kubejs/util/StackTraceCollector.java +++ b/src/main/java/dev/latvian/mods/kubejs/util/StackTraceCollector.java @@ -68,15 +68,18 @@ public void println(@Nullable String x) { x = x.substring(10); } + if (exitPattern != null && exitPattern.matcher(x).find()) { + exit = true; + return; + } + x = reduce.apply(x); if (x == null || x.isEmpty()) { return; } - if (exitPattern != null && exitPattern.matcher(x).find()) { - exit = true; - } else if (isAt) { + if (isAt) { stackTrace.add(" at " + x); } else { stackTrace.add(x);