diff --git a/src/main/java/dev/latvian/mods/kubejs/core/mixin/IngredientTagValueMixin.java b/src/main/java/dev/latvian/mods/kubejs/core/mixin/IngredientTagValueMixin.java index d4c984319..edfefe500 100644 --- a/src/main/java/dev/latvian/mods/kubejs/core/mixin/IngredientTagValueMixin.java +++ b/src/main/java/dev/latvian/mods/kubejs/core/mixin/IngredientTagValueMixin.java @@ -1,6 +1,6 @@ package dev.latvian.mods.kubejs.core.mixin; -import dev.latvian.mods.kubejs.recipe.RecipeExceptionJS; +import dev.latvian.mods.kubejs.error.EmptyTagException; import dev.latvian.mods.kubejs.recipe.RecipesKubeEvent; import net.minecraft.tags.TagKey; import net.minecraft.world.item.Item; @@ -29,7 +29,7 @@ public abstract class IngredientTagValueMixin { var values = lookup.values(tag); if (values.isEmpty()) { - throw new RecipeExceptionJS("Empty tag: " + tag.location()); + throw new EmptyTagException(tag); } else { info.setReturnValue(values.stream().map(ItemStack::new).toList()); } diff --git a/src/main/java/dev/latvian/mods/kubejs/error/EmptyTagException.java b/src/main/java/dev/latvian/mods/kubejs/error/EmptyTagException.java new file mode 100644 index 000000000..2bd20b9a7 --- /dev/null +++ b/src/main/java/dev/latvian/mods/kubejs/error/EmptyTagException.java @@ -0,0 +1,12 @@ +package dev.latvian.mods.kubejs.error; + +import net.minecraft.tags.TagKey; + +public class EmptyTagException extends KubeRuntimeException { + public final TagKey tagKey; + + public EmptyTagException(TagKey tagKey) { + super("Empty tag: " + tagKey.location()); + this.tagKey = tagKey; + } +} diff --git a/src/main/java/dev/latvian/mods/kubejs/error/EmptyTagTargetException.java b/src/main/java/dev/latvian/mods/kubejs/error/EmptyTagTargetException.java new file mode 100644 index 000000000..38d87b4ce --- /dev/null +++ b/src/main/java/dev/latvian/mods/kubejs/error/EmptyTagTargetException.java @@ -0,0 +1,7 @@ +package dev.latvian.mods.kubejs.error; + +public class EmptyTagTargetException extends KubeRuntimeException { + public EmptyTagTargetException(String message) { + super(message); + } +} diff --git a/src/main/java/dev/latvian/mods/kubejs/error/KubeRuntimeException.java b/src/main/java/dev/latvian/mods/kubejs/error/KubeRuntimeException.java new file mode 100644 index 000000000..4a64890b4 --- /dev/null +++ b/src/main/java/dev/latvian/mods/kubejs/error/KubeRuntimeException.java @@ -0,0 +1,37 @@ +package dev.latvian.mods.kubejs.error; + +import dev.latvian.mods.kubejs.script.SourceLine; +import dev.latvian.mods.kubejs.util.MutedError; + +public class KubeRuntimeException extends RuntimeException implements MutedError { + public SourceLine sourceLine; + + public KubeRuntimeException(String m) { + super(m); + this.sourceLine = SourceLine.UNKNOWN; + } + + public KubeRuntimeException(String m, Throwable cause) { + super(m, cause); + this.sourceLine = SourceLine.UNKNOWN; + } + + @Override + public String toString() { + var sb = new StringBuilder(); + sb.append(getMessage()); + + // append cause as well since RecipeExceptions can swallow underlying problems + if (getCause() != null) { + sb.append("\ncause: "); + sb.append(getCause()); + } + + return sb.toString(); + } + + public KubeRuntimeException source(SourceLine sourceLine) { + this.sourceLine = sourceLine; + return this; + } +} \ No newline at end of file diff --git a/src/main/java/dev/latvian/mods/kubejs/error/LegacyError.java b/src/main/java/dev/latvian/mods/kubejs/error/LegacyError.java new file mode 100644 index 000000000..1bcd15006 --- /dev/null +++ b/src/main/java/dev/latvian/mods/kubejs/error/LegacyError.java @@ -0,0 +1,12 @@ +package dev.latvian.mods.kubejs.error; + +public class LegacyError extends KubeRuntimeException { + public LegacyError(String message) { + super(message); + } + + @Override + public String toString() { + return getLocalizedMessage(); + } +} diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/component/MissingComponentException.java b/src/main/java/dev/latvian/mods/kubejs/error/MissingComponentException.java similarity index 69% rename from src/main/java/dev/latvian/mods/kubejs/recipe/component/MissingComponentException.java rename to src/main/java/dev/latvian/mods/kubejs/error/MissingComponentException.java index 96f9c72b0..9e72235dd 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/component/MissingComponentException.java +++ b/src/main/java/dev/latvian/mods/kubejs/error/MissingComponentException.java @@ -1,11 +1,10 @@ -package dev.latvian.mods.kubejs.recipe.component; +package dev.latvian.mods.kubejs.error; -import dev.latvian.mods.kubejs.recipe.RecipeExceptionJS; import dev.latvian.mods.kubejs.recipe.RecipeKey; import java.util.Collection; -public class MissingComponentException extends RecipeExceptionJS { +public class MissingComponentException extends KubeRuntimeException { public final RecipeKey key; public final Collection> valid; diff --git a/src/main/java/dev/latvian/mods/kubejs/error/UnknownRecipeTypeException.java b/src/main/java/dev/latvian/mods/kubejs/error/UnknownRecipeTypeException.java new file mode 100644 index 000000000..52cc788ed --- /dev/null +++ b/src/main/java/dev/latvian/mods/kubejs/error/UnknownRecipeTypeException.java @@ -0,0 +1,10 @@ +package dev.latvian.mods.kubejs.error; + +public class UnknownRecipeTypeException extends KubeRuntimeException { + public final String recipeType; + + public UnknownRecipeTypeException(String recipeType) { + super("Unknown recipe type: " + recipeType); + this.recipeType = recipeType; + } +} \ No newline at end of file diff --git a/src/main/java/dev/latvian/mods/kubejs/event/EventTargetType.java b/src/main/java/dev/latvian/mods/kubejs/event/EventTargetType.java index ac1b916d7..69124df6d 100644 --- a/src/main/java/dev/latvian/mods/kubejs/event/EventTargetType.java +++ b/src/main/java/dev/latvian/mods/kubejs/event/EventTargetType.java @@ -25,9 +25,9 @@ public static EventTargetType create(Class type) { return new EventTargetType<>(type); } - public static final EventTargetType STRING = create(String.class).transformer(EventTargetType::toString); - public static final EventTargetType ID = create(ResourceLocation.class).transformer(EventTargetType::toResourceLocation); - public static final EventTargetType>> REGISTRY = Cast.to(create(ResourceKey.class).transformer(EventTargetType::toRegistryKey).identity()); + public static final EventTargetType STRING = create(String.class).transformer(EventTargetType::toString).describeType(TypeInfo.STRING); + public static final EventTargetType ID = create(ResourceLocation.class).transformer(EventTargetType::toResourceLocation).describeType(TypeInfo.of(ResourceLocation.class)); + public static final EventTargetType>> REGISTRY = Cast.to(create(ResourceKey.class).transformer(EventTargetType::toRegistryKey).identity().describeType(TypeInfo.of(ResourceKey.class).withParams(TypeInfo.of(Registry.class)))); public static EventTargetType> registryKey(ResourceKey> registry, Class type) { return Cast.to(create(ResourceKey.class).identity().transformer(o -> toKey(registry, o)).describeType(TypeInfo.of(ResourceKey.class).withParams(TypeInfo.of(type)))); @@ -58,7 +58,7 @@ public static > EventTargetType fromEnum(Class type) { } else { return null; } - }); + }).describeType(typeInfo); } private static String toString(Object object) { diff --git a/src/main/java/dev/latvian/mods/kubejs/ingredient/TagIngredient.java b/src/main/java/dev/latvian/mods/kubejs/ingredient/TagIngredient.java index 416267e5e..7d58da6ab 100644 --- a/src/main/java/dev/latvian/mods/kubejs/ingredient/TagIngredient.java +++ b/src/main/java/dev/latvian/mods/kubejs/ingredient/TagIngredient.java @@ -2,8 +2,8 @@ import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import dev.latvian.mods.kubejs.error.EmptyTagException; import dev.latvian.mods.kubejs.recipe.CachedTagLookup; -import dev.latvian.mods.kubejs.recipe.RecipeExceptionJS; import dev.latvian.mods.kubejs.recipe.RecipesKubeEvent; import io.netty.buffer.ByteBuf; import net.minecraft.core.component.DataComponents; @@ -80,7 +80,7 @@ public Stream getItems() { if (set.isEmpty()) { if (RecipesKubeEvent.TEMP_ITEM_TAG_LOOKUP.getValue() != null) { - throw new RecipeExceptionJS("Empty tag: " + tagKey.location()); + throw new EmptyTagException(tagKey); } else { var error = new ItemStack(Items.BARRIER); error.set(DataComponents.CUSTOM_NAME, Component.literal("Empty Tag: " + tagKey.location())); diff --git a/src/main/java/dev/latvian/mods/kubejs/item/EmptyItemError.java b/src/main/java/dev/latvian/mods/kubejs/item/EmptyItemError.java deleted file mode 100644 index e6f0765fa..000000000 --- a/src/main/java/dev/latvian/mods/kubejs/item/EmptyItemError.java +++ /dev/null @@ -1,10 +0,0 @@ -package dev.latvian.mods.kubejs.item; - -public class EmptyItemError extends IllegalArgumentException { - public final Object from; - - public EmptyItemError(String message, Object from) { - super(message); - this.from = from; - } -} diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/ErroredKubeRecipe.java b/src/main/java/dev/latvian/mods/kubejs/recipe/ErroredKubeRecipe.java index ef112c7c5..37d5c8d54 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/ErroredKubeRecipe.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/ErroredKubeRecipe.java @@ -1,5 +1,6 @@ package dev.latvian.mods.kubejs.recipe; +import dev.latvian.mods.kubejs.error.KubeRuntimeException; import dev.latvian.mods.kubejs.recipe.component.RecipeComponentValue; import dev.latvian.mods.kubejs.recipe.match.ReplacementMatchInfo; import dev.latvian.mods.kubejs.script.ConsoleJS; @@ -22,11 +23,11 @@ public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] ar } }; - public ErroredKubeRecipe(RecipesKubeEvent event, RecipeExceptionJS rex) { + public ErroredKubeRecipe(RecipesKubeEvent event, KubeRuntimeException rex) { this(event, rex.getMessage(), rex, null); } - public ErroredKubeRecipe(RecipesKubeEvent event, String errorMessage, RecipeExceptionJS rex, @Nullable Pattern skipError) { + public ErroredKubeRecipe(RecipesKubeEvent event, String errorMessage, KubeRuntimeException rex, @Nullable Pattern skipError) { this.context = errorMessage; ConsoleJS.SERVER.error(errorMessage, rex, skipError); event.failedCount.incrementAndGet(); diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/KubeRecipe.java b/src/main/java/dev/latvian/mods/kubejs/recipe/KubeRecipe.java index 48e6d3ec0..f8c844d31 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/KubeRecipe.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/KubeRecipe.java @@ -5,7 +5,8 @@ import dev.latvian.mods.kubejs.CommonProperties; import dev.latvian.mods.kubejs.DevProperties; import dev.latvian.mods.kubejs.core.RecipeLikeKJS; -import dev.latvian.mods.kubejs.recipe.component.MissingComponentException; +import dev.latvian.mods.kubejs.error.KubeRuntimeException; +import dev.latvian.mods.kubejs.error.MissingComponentException; import dev.latvian.mods.kubejs.recipe.component.RecipeComponentBuilderMap; import dev.latvian.mods.kubejs.recipe.component.RecipeComponentValue; import dev.latvian.mods.kubejs.recipe.ingredientaction.ConsumeAction; @@ -19,6 +20,7 @@ import dev.latvian.mods.kubejs.recipe.schema.RecipeSchema; import dev.latvian.mods.kubejs.recipe.special.KubeJSCraftingRecipe; import dev.latvian.mods.kubejs.script.ConsoleJS; +import dev.latvian.mods.kubejs.script.SourceLine; import dev.latvian.mods.kubejs.util.Cast; import dev.latvian.mods.kubejs.util.SlotFilter; import dev.latvian.mods.kubejs.util.UtilsJS; @@ -46,6 +48,7 @@ public class KubeRecipe implements RecipeLikeKJS, CustomJavaToJsWrapper { public RecipeTypeFunction type; public boolean newRecipe; public boolean removed; + public SourceLine sourceLine = SourceLine.UNKNOWN; public String modifyResult = ""; private RecipeComponentBuilderMap valueMap = RecipeComponentBuilderMap.EMPTY; @@ -69,7 +72,7 @@ public void deserialize(boolean merge) { try { v.key.component.readFromJson(this, Cast.to(v), json); } catch (Exception ex) { - ConsoleJS.SERVER.error("Failed to read " + v.key + " from recipe " + this, ex, RecipesKubeEvent.POST_SKIP_ERROR); + ConsoleJS.SERVER.error("", new KubeRuntimeException("Failed to read " + v.key + " from recipe " + this, ex).source(sourceLine), RecipesKubeEvent.POST_SKIP_ERROR); } if (v.value != null) { @@ -86,7 +89,7 @@ public void serialize() { for (var v : valueMap.holders) { if (v.shouldWrite()) { if (v.value == null) { - throw new RecipeExceptionJS("Value not set for " + v.key + " in recipe " + this); + throw new KubeRuntimeException("Value not set for " + v.key + " in recipe " + this); } v.key.component.writeToJson(this, Cast.to(v), json); @@ -186,7 +189,7 @@ public void afterLoaded() { var e = v.checkEmpty(); if (!e.isEmpty()) { - throw new RecipeExceptionJS(e); + throw new KubeRuntimeException(e); } } } diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/MissingRecipeFunctionException.java b/src/main/java/dev/latvian/mods/kubejs/recipe/MissingRecipeFunctionException.java deleted file mode 100644 index 3ad5c6cc1..000000000 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/MissingRecipeFunctionException.java +++ /dev/null @@ -1,7 +0,0 @@ -package dev.latvian.mods.kubejs.recipe; - -public class MissingRecipeFunctionException extends RecipeExceptionJS { - public MissingRecipeFunctionException(String message) { - super(message); - } -} \ No newline at end of file diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/RecipeExceptionJS.java b/src/main/java/dev/latvian/mods/kubejs/recipe/RecipeExceptionJS.java deleted file mode 100644 index e003680c5..000000000 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/RecipeExceptionJS.java +++ /dev/null @@ -1,39 +0,0 @@ -package dev.latvian.mods.kubejs.recipe; - -import dev.latvian.mods.kubejs.util.MutedError; - -public class RecipeExceptionJS extends IllegalArgumentException implements MutedError { - public boolean error; - - public RecipeExceptionJS(String m) { - super(m); - error = false; - } - - public RecipeExceptionJS(String m, Throwable cause) { - super(m, cause); - error = false; - } - - @Override - public String toString() { - var sb = new StringBuilder(); - sb.append(getMessage()); - if (error) { - sb.append(" [error]"); - } - - // append cause as well since RecipeExceptions can swallow underlying problems - if (getCause() != null) { - sb.append("\ncause: "); - sb.append(getCause()); - } - - return sb.toString(); - } - - public RecipeExceptionJS error() { - error = true; - return this; - } -} \ No newline at end of file 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 892816683..11b9c7f9a 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/RecipeTypeFunction.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/RecipeTypeFunction.java @@ -1,8 +1,10 @@ package dev.latvian.mods.kubejs.recipe; import com.google.gson.JsonObject; +import dev.latvian.mods.kubejs.error.KubeRuntimeException; import dev.latvian.mods.kubejs.recipe.component.ComponentValueMap; import dev.latvian.mods.kubejs.recipe.schema.RecipeSchemaType; +import dev.latvian.mods.kubejs.script.SourceLine; import dev.latvian.mods.kubejs.util.MapJS; import dev.latvian.mods.kubejs.util.WrappedJS; import dev.latvian.mods.rhino.BaseFunction; @@ -35,12 +37,10 @@ public RecipeTypeFunction(RecipesKubeEvent event, RecipeSchemaType schemaType) { public KubeRecipe call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args0) { try { return createRecipe(cx, args0); - } catch (RecipeExceptionJS rex) { - if (rex.error) { - throw rex; - } else { - return new ErroredKubeRecipe(event, "Failed to create recipe for type '%s'".formatted(idString), rex, SKIP_ERROR); - } + } catch (KubeRuntimeException rex) { + var recipe = new ErroredKubeRecipe(event, "Failed to create recipe for type '%s'".formatted(idString), rex, SKIP_ERROR); + recipe.sourceLine = rex.sourceLine; + return recipe; } } @@ -56,13 +56,13 @@ public KubeRecipe createRecipe(Context cx, Object[] args) { if (constructor == null) { if (args.length == 1 && (args[0] instanceof Map || args[0] instanceof JsonObject)) { - var recipe = schemaType.schema.deserialize(this, null, MapJS.json(cx, args[0])); + var recipe = schemaType.schema.deserialize(SourceLine.of(cx), this, null, MapJS.json(cx, args[0])); recipe.afterLoaded(); return event.addRecipe(recipe, true); // throw new RecipeExceptionJS("Use event.custom(json) for json recipes!"); } - throw new RecipeExceptionJS("Constructor for " + id + " with " + args.length + " arguments not found!"); + throw new KubeRuntimeException("Constructor for " + id + " with " + args.length + " arguments not found!"); } /* @@ -83,10 +83,10 @@ public KubeRecipe createRecipe(Context cx, Object[] args) { var recipe = constructor.create(cx, this, schemaType, argMap); recipe.afterLoaded(); return event.addRecipe(recipe, false); - } catch (RecipeExceptionJS rex) { + } catch (KubeRuntimeException rex) { throw rex; } catch (Throwable ex) { - throw new RecipeExceptionJS("Failed to create recipe for type '" + id + "' with args " + Arrays.stream(args).map(o -> o == null ? "null" : (o + ": " + o.getClass().getSimpleName())).collect(Collectors.joining(", ", "[", "]")), ex); + throw new KubeRuntimeException("Failed to create recipe for type '" + id + "' with args " + Arrays.stream(args).map(o -> o == null ? "null" : (o + ": " + o.getClass().getSimpleName())).collect(Collectors.joining(", ", "[", "]")), ex); } } 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 2f51e016f..cfceb00f8 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/RecipesKubeEvent.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/RecipesKubeEvent.java @@ -8,6 +8,8 @@ import dev.latvian.mods.kubejs.DevProperties; import dev.latvian.mods.kubejs.bindings.event.ServerEvents; import dev.latvian.mods.kubejs.core.RecipeManagerKJS; +import dev.latvian.mods.kubejs.error.KubeRuntimeException; +import dev.latvian.mods.kubejs.error.UnknownRecipeTypeException; import dev.latvian.mods.kubejs.event.EventExceptionHandler; import dev.latvian.mods.kubejs.event.KubeEvent; import dev.latvian.mods.kubejs.plugin.KubeJSPlugins; @@ -24,6 +26,7 @@ import dev.latvian.mods.kubejs.registry.RegistryInfo; import dev.latvian.mods.kubejs.script.ConsoleJS; import dev.latvian.mods.kubejs.script.ScriptType; +import dev.latvian.mods.kubejs.script.SourceLine; import dev.latvian.mods.kubejs.server.ChangesForChat; import dev.latvian.mods.kubejs.server.DataExport; import dev.latvian.mods.kubejs.server.ServerScriptManager; @@ -73,7 +76,7 @@ public class RecipesKubeEvent implements KubeEvent { private static final Predicate RECIPE_NOT_REMOVED = r -> r != null && !r.removed; private static final EventExceptionHandler RECIPE_EXCEPTION_HANDLER = (event, handler, ex) -> { // skip the current handler on a recipe or JSON exception, but let other handlers run - if (ex instanceof RecipeExceptionJS || ex instanceof JsonParseException) { + if (ex instanceof KubeRuntimeException || ex instanceof JsonParseException) { ConsoleJS.SERVER.error("Error while processing recipe event handler: " + handler, ex); return null; } else { @@ -259,7 +262,7 @@ public void post(RecipeManagerKJS recipeManager, Map { - throw new RecipeExceptionJS("Failed to parse blockstate: " + message); + throw new KubeRuntimeException("Failed to parse blockstate: " + message); }); } } diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/component/ComponentValueMap.java b/src/main/java/dev/latvian/mods/kubejs/recipe/component/ComponentValueMap.java index 579584ede..a4668544c 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/component/ComponentValueMap.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/component/ComponentValueMap.java @@ -1,7 +1,7 @@ package dev.latvian.mods.kubejs.recipe.component; +import dev.latvian.mods.kubejs.error.KubeRuntimeException; import dev.latvian.mods.kubejs.recipe.KubeRecipe; -import dev.latvian.mods.kubejs.recipe.RecipeExceptionJS; import dev.latvian.mods.kubejs.recipe.RecipeKey; import dev.latvian.mods.rhino.Context; @@ -20,13 +20,13 @@ public T getValue(Context cx, KubeRecipe recipe, RecipeKey key) { return null; } - throw new RecipeExceptionJS("Value for '" + key + "' is missing!"); + throw new KubeRuntimeException("Value for '" + key + "' is missing!"); } try { return key.component.wrap(cx, recipe, o); } catch (Throwable ex) { - throw new RecipeExceptionJS("Unable to cast '" + key + "' value '" + o + "' to '" + key.component + "'!", ex); + throw new KubeRuntimeException("Unable to cast '" + key + "' value '" + o + "' to '" + key.component + "'!", ex); } } } diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/component/EitherRecipeComponent.java b/src/main/java/dev/latvian/mods/kubejs/recipe/component/EitherRecipeComponent.java index c01505471..672096f49 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/component/EitherRecipeComponent.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/component/EitherRecipeComponent.java @@ -2,8 +2,8 @@ import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; +import dev.latvian.mods.kubejs.error.KubeRuntimeException; import dev.latvian.mods.kubejs.recipe.KubeRecipe; -import dev.latvian.mods.kubejs.recipe.RecipeExceptionJS; import dev.latvian.mods.kubejs.recipe.match.ReplacementMatchInfo; import dev.latvian.mods.kubejs.recipe.schema.RecipeComponentFactory; import dev.latvian.mods.kubejs.script.ConsoleJS; @@ -40,9 +40,9 @@ public Either wrap(Context cx, KubeRecipe recipe, Object from) { try { return Either.right(low.wrap(cx, recipe, from)); } catch (Exception ex2) { - ConsoleJS.SERVER.error("Failed to read %s as high priority (%s)!".formatted(from, high), ex1); - ConsoleJS.SERVER.error("Failed to read %s as low priority (%s)!".formatted(from, low), ex2); - throw new RecipeExceptionJS("Failed to read %s as either %s or %s!".formatted(from, high, low)); + ConsoleJS.SERVER.warn("Failed to read %s as high priority (%s)!".formatted(from, high), ex1); + ConsoleJS.SERVER.warn("Failed to read %s as low priority (%s)!".formatted(from, low), ex2); + throw new KubeRuntimeException("Failed to read %s as either %s or %s!".formatted(from, high, low)).source(recipe.sourceLine); } } } diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/component/EnumComponent.java b/src/main/java/dev/latvian/mods/kubejs/recipe/component/EnumComponent.java index 146d62743..07d3b3c93 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/component/EnumComponent.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/component/EnumComponent.java @@ -1,7 +1,7 @@ package dev.latvian.mods.kubejs.recipe.component; import com.mojang.serialization.Codec; -import dev.latvian.mods.kubejs.recipe.RecipeExceptionJS; +import dev.latvian.mods.kubejs.error.KubeRuntimeException; import dev.latvian.mods.kubejs.recipe.schema.RecipeComponentFactory; import dev.latvian.mods.rhino.type.EnumTypeInfo; import dev.latvian.mods.rhino.type.TypeInfo; @@ -26,7 +26,7 @@ public record EnumComponent & StringRepresentable>(EnumTypeInf var typeInfo = TypeInfo.of(clazz); if (!(typeInfo instanceof EnumTypeInfo enumTypeInfo)) { - throw new RecipeExceptionJS("Class " + clazz.getTypeName() + " is not an enum!"); + throw new KubeRuntimeException("Class " + clazz.getTypeName() + " is not an enum!"); } return new EnumComponent(enumTypeInfo, Codec.STRING.xmap(s -> { @@ -38,10 +38,10 @@ public record EnumComponent & StringRepresentable>(EnumTypeInf } } - throw new RecipeExceptionJS("Enum value '" + s + "' of " + clazz.getName() + " not found"); + throw new KubeRuntimeException("Enum value '" + s + "' of " + clazz.getName() + " not found"); }, EnumTypeInfo::getName)); } catch (Exception ex) { - throw new RecipeExceptionJS("Error loading class " + cname + " for EnumComponent", ex); + throw new KubeRuntimeException("Error loading class " + cname + " for EnumComponent", ex); } }; diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/component/NestedRecipeComponent.java b/src/main/java/dev/latvian/mods/kubejs/recipe/component/NestedRecipeComponent.java index ea2283839..5f96494ac 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/component/NestedRecipeComponent.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/component/NestedRecipeComponent.java @@ -35,7 +35,7 @@ public KubeRecipe wrap(Context cx, KubeRecipe recipe, Object from) { r.newRecipe = false; return r; } else if (from instanceof JsonObject json && json.has("type")) { - var r = recipe.type.event.custom(json); + var r = recipe.type.event.custom(cx, json); r.newRecipe = false; return r; } diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/filter/RecipeFilter.java b/src/main/java/dev/latvian/mods/kubejs/recipe/filter/RecipeFilter.java index ec8a1591a..7fd9afedb 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/filter/RecipeFilter.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/filter/RecipeFilter.java @@ -1,7 +1,8 @@ package dev.latvian.mods.kubejs.recipe.filter; import dev.latvian.mods.kubejs.core.RecipeLikeKJS; -import dev.latvian.mods.kubejs.recipe.RecipeExceptionJS; +import dev.latvian.mods.kubejs.error.KubeRuntimeException; +import dev.latvian.mods.kubejs.recipe.RecipesKubeEvent; import dev.latvian.mods.kubejs.recipe.match.ReplacementMatchInfo; import dev.latvian.mods.kubejs.script.ConsoleJS; import dev.latvian.mods.kubejs.util.ID; @@ -134,13 +135,8 @@ static RecipeFilter of(Context cx, @Nullable Object o) { } return predicate.list.isEmpty() ? ConstantFilter.TRUE : predicate.list.size() == 1 ? predicate.list.getFirst() : predicate; - } catch (RecipeExceptionJS rex) { - if (rex.error) { - ConsoleJS.getCurrent(cx).error(rex.getMessage()); - } else { - ConsoleJS.getCurrent(cx).warn(rex.getMessage()); - } - + } catch (KubeRuntimeException rex) { + ConsoleJS.getCurrent(cx).warn("", rex, RecipesKubeEvent.POST_SKIP_ERROR); return ConstantFilter.FALSE; } } diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/match/FluidIngredientMatch.java b/src/main/java/dev/latvian/mods/kubejs/recipe/match/FluidIngredientMatch.java index 5480f9d23..3211c7928 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/match/FluidIngredientMatch.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/match/FluidIngredientMatch.java @@ -1,6 +1,6 @@ package dev.latvian.mods.kubejs.recipe.match; -import dev.latvian.mods.kubejs.recipe.RecipeExceptionJS; +import dev.latvian.mods.kubejs.error.KubeRuntimeException; import dev.latvian.mods.rhino.Context; import net.neoforged.neoforge.fluids.FluidStack; import net.neoforged.neoforge.fluids.crafting.FluidIngredient; @@ -24,7 +24,7 @@ public boolean matches(Context cx, FluidIngredient in, boolean exact) { } } } catch (Exception ex) { - throw new RecipeExceptionJS("Failed to test fluid ingredient " + in, ex); + throw new KubeRuntimeException("Failed to test fluid ingredient " + in, ex); } return false; diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/match/IngredientMatch.java b/src/main/java/dev/latvian/mods/kubejs/recipe/match/IngredientMatch.java index 818844373..4aff0ce79 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/match/IngredientMatch.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/match/IngredientMatch.java @@ -1,7 +1,7 @@ package dev.latvian.mods.kubejs.recipe.match; import dev.latvian.mods.kubejs.bindings.IngredientWrapper; -import dev.latvian.mods.kubejs.recipe.RecipeExceptionJS; +import dev.latvian.mods.kubejs.error.KubeRuntimeException; import dev.latvian.mods.rhino.Context; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.crafting.Ingredient; @@ -43,7 +43,7 @@ public boolean matches(Context cx, Ingredient in, boolean exact) { } } } catch (Exception ex) { - throw new RecipeExceptionJS("Failed to test ingredient " + in, ex); + throw new KubeRuntimeException("Failed to test ingredient " + in, ex); } return false; diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/schema/RecipeConstructor.java b/src/main/java/dev/latvian/mods/kubejs/recipe/schema/RecipeConstructor.java index aa3d25150..292db57ac 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/schema/RecipeConstructor.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/schema/RecipeConstructor.java @@ -5,6 +5,7 @@ import dev.latvian.mods.kubejs.recipe.RecipeKey; import dev.latvian.mods.kubejs.recipe.RecipeTypeFunction; import dev.latvian.mods.kubejs.recipe.component.ComponentValueMap; +import dev.latvian.mods.kubejs.script.SourceLine; import dev.latvian.mods.kubejs.util.Cast; import dev.latvian.mods.rhino.Context; @@ -47,6 +48,7 @@ public String toString() { public KubeRecipe create(Context cx, RecipeTypeFunction type, RecipeSchemaType schemaType, ComponentValueMap from) { var r = schemaType.schema.recipeFactory.create(); + r.sourceLine = SourceLine.of(cx); r.type = type; r.json = new JsonObject(); r.json.addProperty("type", "unknown"); diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/schema/RecipeSchema.java b/src/main/java/dev/latvian/mods/kubejs/recipe/schema/RecipeSchema.java index a6ab23c83..f269b59b2 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/schema/RecipeSchema.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/schema/RecipeSchema.java @@ -7,6 +7,7 @@ import dev.latvian.mods.kubejs.recipe.RecipeKey; import dev.latvian.mods.kubejs.recipe.RecipeTypeFunction; import dev.latvian.mods.kubejs.recipe.component.UniqueIdBuilder; +import dev.latvian.mods.kubejs.script.SourceLine; import dev.latvian.mods.kubejs.util.Cast; import dev.latvian.mods.kubejs.util.JsonUtils; import dev.latvian.mods.rhino.util.RemapForJS; @@ -222,8 +223,9 @@ public boolean isHidden() { return hidden; } - public KubeRecipe deserialize(RecipeTypeFunction type, @Nullable ResourceLocation id, JsonObject json) { + public KubeRecipe deserialize(SourceLine sourceLine, RecipeTypeFunction type, @Nullable ResourceLocation id, JsonObject json) { var r = recipeFactory.create(); + r.sourceLine = sourceLine; r.type = type; r.id = id; r.json = json; diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/schema/RecipeSchemaType.java b/src/main/java/dev/latvian/mods/kubejs/recipe/schema/RecipeSchemaType.java index 62026fd74..36a9602f7 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/schema/RecipeSchemaType.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/schema/RecipeSchemaType.java @@ -1,6 +1,6 @@ package dev.latvian.mods.kubejs.recipe.schema; -import dev.latvian.mods.kubejs.recipe.RecipeExceptionJS; +import dev.latvian.mods.kubejs.error.KubeRuntimeException; import dev.latvian.mods.kubejs.registry.RegistryInfo; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.crafting.RecipeSerializer; @@ -28,7 +28,7 @@ public RecipeSerializer getSerializer() { var s = serializer.orElse(null); if (s == null) { - throw new RecipeExceptionJS("Serializer for type " + id + " is not found!"); + throw new KubeRuntimeException("Serializer for type " + id + " is not found!"); } return s; diff --git a/src/main/java/dev/latvian/mods/kubejs/recipe/schema/minecraft/ShapedKubeRecipe.java b/src/main/java/dev/latvian/mods/kubejs/recipe/schema/minecraft/ShapedKubeRecipe.java index fc939e892..080f61771 100644 --- a/src/main/java/dev/latvian/mods/kubejs/recipe/schema/minecraft/ShapedKubeRecipe.java +++ b/src/main/java/dev/latvian/mods/kubejs/recipe/schema/minecraft/ShapedKubeRecipe.java @@ -1,8 +1,8 @@ package dev.latvian.mods.kubejs.recipe.schema.minecraft; import dev.latvian.mods.kubejs.KubeJS; +import dev.latvian.mods.kubejs.error.KubeRuntimeException; import dev.latvian.mods.kubejs.recipe.KubeRecipe; -import dev.latvian.mods.kubejs.recipe.RecipeExceptionJS; import dev.latvian.mods.kubejs.recipe.RecipeKey; import dev.latvian.mods.kubejs.recipe.RecipeTypeFunction; import dev.latvian.mods.kubejs.recipe.schema.KubeRecipeFactory; @@ -27,11 +27,11 @@ public void afterLoaded() { var key = getValue(keyKey); if (pattern.isEmpty()) { - throw new RecipeExceptionJS("Pattern is empty!"); + throw new KubeRuntimeException("Pattern is empty!"); } if (key.isEmpty()) { - throw new RecipeExceptionJS("Key map is empty!"); + throw new KubeRuntimeException("Key map is empty!"); } List airs = null; 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 be6308f8b..497093aef 100644 --- a/src/main/java/dev/latvian/mods/kubejs/script/ConsoleJS.java +++ b/src/main/java/dev/latvian/mods/kubejs/script/ConsoleJS.java @@ -2,6 +2,7 @@ import dev.latvian.mods.kubejs.DevProperties; import dev.latvian.mods.kubejs.bindings.TextIcons; +import dev.latvian.mods.kubejs.error.KubeRuntimeException; import dev.latvian.mods.kubejs.util.JSObjectType; import dev.latvian.mods.kubejs.util.LogType; import dev.latvian.mods.kubejs.util.MutedError; @@ -168,6 +169,10 @@ private ConsoleLine line(LogType type, Object object, @Nullable Throwable error) line.type = type; line.group = group; + if (error instanceof KubeRuntimeException ex) { + line.withSourceLine(ex.sourceLine); + } + if (error instanceof RhinoException ex) { if (ex.lineSource() != null) { line.withSourceLine(ex.lineSource(), ex.lineNumber()); @@ -210,9 +215,7 @@ private ConsoleLine line(LogType type, Object object, @Nullable Throwable error) var factory = contextFactory == null ? null : contextFactory.get(); if (factory != null) { - int[] lineP = {0}; - var source = Context.getSourcePositionFromStack(factory.enter(), lineP); - line.withSourceLine(source, lineP[0]); + line.withSourceLine(SourceLine.of(factory.enter())); } } diff --git a/src/main/java/dev/latvian/mods/kubejs/script/ConsoleLine.java b/src/main/java/dev/latvian/mods/kubejs/script/ConsoleLine.java index a7852b7c2..0c929d4d2 100644 --- a/src/main/java/dev/latvian/mods/kubejs/script/ConsoleLine.java +++ b/src/main/java/dev/latvian/mods/kubejs/script/ConsoleLine.java @@ -11,30 +11,6 @@ import java.util.Set; public class ConsoleLine { - public record SourceLine(String source, int line) { - public SourceLine(FriendlyByteBuf buf) { - this(buf.readUtf(), buf.readVarInt()); - } - - @Override - public String toString() { - if (source.isEmpty() && line == 0) { - return ""; - } else if (source.isEmpty()) { - return "#" + line; - } else if (line == 0) { - return source; - } else { - return source + "#" + line; - } - } - - public static void write(FriendlyByteBuf buf, SourceLine sourceLine) { - buf.writeUtf(sourceLine.source); - buf.writeVarInt(sourceLine.line); - } - } - public static final ConsoleLine[] EMPTY_ARRAY = new ConsoleLine[0]; public static final StreamCodec STREAM_CODEC = new StreamCodec<>() { @@ -46,7 +22,7 @@ public ConsoleLine decode(FriendlyByteBuf buf) { var line = new ConsoleLine(console, timestamp, message); line.type = LogType.VALUES[buf.readByte()]; line.group = ""; - line.sourceLines = buf.readList(SourceLine::new); + line.sourceLines = buf.readList(SourceLine::read); line.stackTrace = buf.readList(FriendlyByteBuf::readUtf); return line; } @@ -84,8 +60,8 @@ public String getText() { if (!sourceLines.isEmpty()) { for (var line : sourceLines) { - if (line.line != 0 && !line.source.isEmpty()) { - builder.append(line.source).append('#').append(line.line).append(':').append(' '); + if (!line.isUnknown()) { + builder.append(line.source()).append('#').append(line.line()).append(':').append(' '); break; } } @@ -115,8 +91,16 @@ public ConsoleLine withSourceLine(String source, int line) { line = 0; } + return source.isEmpty() && line == 0 ? this : withSourceLine(new SourceLine(source, line)); + } + + public ConsoleLine withSourceLine(SourceLine sourceLine) { + if (sourceLine.isUnknown()) { + return this; + } + if (sourceLines.isEmpty()) { - sourceLines = Set.of(new SourceLine(source, line)); + sourceLines = Set.of(sourceLine); return this; } else if (sourceLines.size() == 1) { var line0 = sourceLines.iterator().next(); @@ -124,7 +108,7 @@ public ConsoleLine withSourceLine(String source, int line) { sourceLines.add(line0); } - sourceLines.add(new SourceLine(source, line)); + sourceLines.add(sourceLine); return this; } diff --git a/src/main/java/dev/latvian/mods/kubejs/script/SourceLine.java b/src/main/java/dev/latvian/mods/kubejs/script/SourceLine.java new file mode 100644 index 000000000..4feac4698 --- /dev/null +++ b/src/main/java/dev/latvian/mods/kubejs/script/SourceLine.java @@ -0,0 +1,53 @@ +package dev.latvian.mods.kubejs.script; + +import dev.latvian.mods.rhino.Context; +import net.minecraft.network.FriendlyByteBuf; +import org.jetbrains.annotations.Nullable; + +public record SourceLine(String source, int line) { + public static final SourceLine UNKNOWN = new SourceLine("", 0); + + public static SourceLine of(@Nullable String source, int line) { + if ((source == null || source.isEmpty()) && line <= 0) { + return UNKNOWN; + } else { + return new SourceLine(source == null ? "" : source, Math.max(line, 0)); + } + } + + public static SourceLine read(FriendlyByteBuf buf) { + return of(buf.readUtf(), buf.readVarInt()); + } + + public static SourceLine of(@Nullable Context cx) { + if (cx == null) { + return UNKNOWN; + } + + int[] lineP = {0}; + var source = Context.getSourcePositionFromStack(cx, lineP); + return new SourceLine(source == null ? "" : source, lineP[0]); + } + + public boolean isUnknown() { + return source.isEmpty() && line <= 0; + } + + @Override + public String toString() { + if (source.isEmpty() && line <= 0) { + return ""; + } else if (source.isEmpty()) { + return "#" + line; + } else if (line <= 0) { + return source; + } else { + return source + "#" + line; + } + } + + public static void write(FriendlyByteBuf buf, SourceLine sourceLine) { + buf.writeUtf(sourceLine.source); + buf.writeVarInt(sourceLine.line); + } +} diff --git a/src/main/java/dev/latvian/mods/kubejs/server/tag/EmptyTagTargetException.java b/src/main/java/dev/latvian/mods/kubejs/server/tag/EmptyTagTargetException.java deleted file mode 100644 index f22ed3a2b..000000000 --- a/src/main/java/dev/latvian/mods/kubejs/server/tag/EmptyTagTargetException.java +++ /dev/null @@ -1,9 +0,0 @@ -package dev.latvian.mods.kubejs.server.tag; - -import java.util.NoSuchElementException; - -public class EmptyTagTargetException extends NoSuchElementException { - public EmptyTagTargetException(String message) { - super(message); - } -} diff --git a/src/main/java/dev/latvian/mods/kubejs/server/tag/TagEventFilter.java b/src/main/java/dev/latvian/mods/kubejs/server/tag/TagEventFilter.java index 782bb8cd6..841565d28 100644 --- a/src/main/java/dev/latvian/mods/kubejs/server/tag/TagEventFilter.java +++ b/src/main/java/dev/latvian/mods/kubejs/server/tag/TagEventFilter.java @@ -1,6 +1,7 @@ package dev.latvian.mods.kubejs.server.tag; import dev.latvian.mods.kubejs.DevProperties; +import dev.latvian.mods.kubejs.error.EmptyTagTargetException; import dev.latvian.mods.kubejs.script.ConsoleJS; import dev.latvian.mods.kubejs.util.RegExpKJS; import net.minecraft.resources.ResourceLocation; diff --git a/src/main/java/dev/latvian/mods/kubejs/server/tag/TagKubeEvent.java b/src/main/java/dev/latvian/mods/kubejs/server/tag/TagKubeEvent.java index 376780a64..caed40677 100644 --- a/src/main/java/dev/latvian/mods/kubejs/server/tag/TagKubeEvent.java +++ b/src/main/java/dev/latvian/mods/kubejs/server/tag/TagKubeEvent.java @@ -1,5 +1,6 @@ package dev.latvian.mods.kubejs.server.tag; +import dev.latvian.mods.kubejs.error.EmptyTagTargetException; import dev.latvian.mods.kubejs.event.EventExceptionHandler; import dev.latvian.mods.kubejs.event.KubeEvent; import dev.latvian.mods.kubejs.registry.RegistryInfo; diff --git a/src/main/java/dev/latvian/mods/kubejs/util/LegacyCodeHandler.java b/src/main/java/dev/latvian/mods/kubejs/util/LegacyCodeHandler.java index 0de7649b5..aa396d25b 100644 --- a/src/main/java/dev/latvian/mods/kubejs/util/LegacyCodeHandler.java +++ b/src/main/java/dev/latvian/mods/kubejs/util/LegacyCodeHandler.java @@ -1,22 +1,12 @@ package dev.latvian.mods.kubejs.util; +import dev.latvian.mods.kubejs.error.LegacyError; import dev.latvian.mods.rhino.BaseFunction; import dev.latvian.mods.rhino.Context; import dev.latvian.mods.rhino.Scriptable; import dev.latvian.mods.rhino.Symbol; public class LegacyCodeHandler extends BaseFunction { - public static class LegacyError extends RuntimeException implements MutedError { - public LegacyError(String message) { - super(message); - } - - @Override - public String toString() { - return getLocalizedMessage(); - } - } - public final String code; public LegacyCodeHandler(String code) {