diff --git a/src/main/java/com/cleanroommc/groovyscript/api/GroovyLog.java b/src/main/java/com/cleanroommc/groovyscript/api/GroovyLog.java
index 249b7431f..e8a4c6575 100644
--- a/src/main/java/com/cleanroommc/groovyscript/api/GroovyLog.java
+++ b/src/main/java/com/cleanroommc/groovyscript/api/GroovyLog.java
@@ -231,6 +231,16 @@ default void errorMC(Object o) {
*/
void exception(Throwable throwable);
+ /**
+ * Formats and logs an exception to this log AND Minecraft's log with a message.
+ * The log will be printed without formatting to Minecraft's log.
+ * Unnecessary lines that clutter the log will get removed before logging to this log.
+ * The exception will NOT be thrown!
+ *
+ * @param throwable exception to log
+ */
+ void exception(String msg, Throwable throwable);
+
/**
* Formats a {@link String} and arguments according to the defined rules.
*
diff --git a/src/main/java/com/cleanroommc/groovyscript/sandbox/ClosureHelper.java b/src/main/java/com/cleanroommc/groovyscript/sandbox/ClosureHelper.java
index 275fd7112..74e53aebe 100644
--- a/src/main/java/com/cleanroommc/groovyscript/sandbox/ClosureHelper.java
+++ b/src/main/java/com/cleanroommc/groovyscript/sandbox/ClosureHelper.java
@@ -100,7 +100,7 @@ public static Closure> getUnderlyingClosure(Object functionalInterface) {
return (Closure>) convertedClosure.getDelegate();
}
} catch (IllegalArgumentException | IllegalAccessException e) {
- GroovyLog.get().exception(e);
+ GroovyLog.get().exception("A reflection error occurred while trying to obtain a closure from a lambda.", e);
}
return null;
}
diff --git a/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovyLogImpl.java b/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovyLogImpl.java
index 8fbb15e6e..5ff397e62 100644
--- a/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovyLogImpl.java
+++ b/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovyLogImpl.java
@@ -250,6 +250,11 @@ public void errorMC(String msg, Object... args) {
logger.error(msg, args);
}
+ @Override
+ public void exception(Throwable throwable) {
+ exception("An exception occurred while running scripts.", throwable);
+ }
+
/**
* Logs an exception to the groovy log AND Minecraft's log. It does NOT throw the exception! The stacktrace for the groovy log will be
* stripped for better readability.
@@ -257,11 +262,12 @@ public void errorMC(String msg, Object... args) {
* @param throwable exception
*/
@Override
- public void exception(Throwable throwable) {
- String msg = throwable.toString();
- this.errors.add(msg);
- writeLogLine(formatLine("ERROR", "An exception occurred while running scripts. Look at latest.log for a full stacktrace:"));
- writeLogLine("\t" + msg);
+ public void exception(String msg, Throwable throwable) {
+ String throwableMsg = throwable.toString();
+ this.errors.add(throwableMsg);
+ msg += " Look at latest.log for a full stacktrace:";
+ writeLogLine(formatLine("ERROR", msg));
+ writeLogLine("\t" + throwableMsg);
Pattern pattern = Pattern.compile("(\\w*).run\\(\\1(\\.\\w*):(\\d*)\\)");
for (String line : prepareStackTrace(throwable.getStackTrace())) {
Matcher matcher = pattern.matcher(line);
@@ -271,6 +277,7 @@ public void exception(Throwable throwable) {
writeLogLine("\t\tat " + line);
}
}
+ GroovyScript.LOGGER.error(msg);
GroovyScript.LOGGER.throwing(throwable);
}
diff --git a/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovySandbox.java b/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovySandbox.java
index 267521087..d66b44943 100644
--- a/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovySandbox.java
+++ b/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovySandbox.java
@@ -259,8 +259,7 @@ protected Class> loadScriptClass(GroovyScriptEngine engine, File file) {
// if the file is still not found something went wrong
} catch (Exception e) {
- GroovyLog.get().fatalMC("An error occurred while trying to load script class {}", file.toString());
- GroovyLog.get().exception(e);
+ GroovyLog.get().exception("An error occurred while trying to load script class " + file.toString(), e);
}
return scriptClass;
}
diff --git a/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovyScriptSandbox.java b/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovyScriptSandbox.java
index 91b976d1e..1b8804f1b 100644
--- a/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovyScriptSandbox.java
+++ b/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovyScriptSandbox.java
@@ -161,8 +161,7 @@ public void run(LoadStage currentLoadStage) {
try {
super.load();
} catch (IOException | ScriptException | ResourceException e) {
- GroovyLog.get().errorMC("An exception occurred while trying to run groovy code! This is might be a internal groovy issue.");
- GroovyLog.get().exception(e);
+ GroovyLog.get().exception("An exception occurred while trying to run groovy code! This is might be a internal groovy issue.", e);
} catch (Throwable t) {
GroovyLog.get().exception(t);
} finally {
@@ -194,11 +193,16 @@ public T runClosure(Closure closure, Object... args) {
try {
result = runClosureInternal(closure, args);
} catch (Throwable t) {
- this.storedExceptions.computeIfAbsent(Arrays.asList(t.getStackTrace()), k -> {
- GroovyLog.get().error("An exception occurred while running a closure!");
- GroovyLog.get().exception(t);
- return new AtomicInteger();
- }).addAndGet(1);
+ List stackTrace = Arrays.asList(t.getStackTrace());
+ AtomicInteger counter = this.storedExceptions.get(stackTrace);
+ if (counter == null) {
+ GroovyLog.get().exception("An exception occurred while running a closure at least once!", t);
+ this.storedExceptions.put(stackTrace, new AtomicInteger(1));
+ UncheckedThrow.rethrow(t);
+ return null; // unreachable statement
+ } else {
+ counter.getAndIncrement();
+ }
} finally {
if (!wasRunning) stopRunning();
}
@@ -206,14 +210,13 @@ public T runClosure(Closure closure, Object... args) {
}
@GroovyBlacklist
- private static T runClosureInternal(Closure closure, Object[] args) {
+ private static T runClosureInternal(Closure closure, Object[] args) throws Throwable {
// original Closure.call(Object... arguments) code
try {
//noinspection unchecked
return (T) closure.getMetaClass().invokeMethod(closure, "doCall", args);
} catch (InvokerInvocationException e) {
- UncheckedThrow.rethrow(e.getCause());
- return null; // unreachable statement
+ throw e.getCause();
} catch (Exception e) {
if (e instanceof RuntimeException) {
throw e;