diff --git a/gradle.properties b/gradle.properties index 1148b27a..2cad0c57 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ mod_version=1.0.1 minecraft_version=1.19.2 forge_version=43.0.8 cyclopscore_version=1.19.0-401 -integrateddynamics_version=1.19.2-1.21.0-696 +integrateddynamics_version=1.19.2-1.21.2-717 release_type=release fingerprint=bd0353b3e8a2810d60dd584e256e364bc3bedd44 diff --git a/src/main/java/org/cyclops/integratedscripting/core/network/GraalScriptFactory.java b/src/main/java/org/cyclops/integratedscripting/core/network/GraalScriptFactory.java index 316c79f8..98b65149 100644 --- a/src/main/java/org/cyclops/integratedscripting/core/network/GraalScriptFactory.java +++ b/src/main/java/org/cyclops/integratedscripting/core/network/GraalScriptFactory.java @@ -7,6 +7,7 @@ import org.cyclops.integratedscripting.api.network.IScript; import org.cyclops.integratedscripting.api.network.IScriptFactory; import org.cyclops.integratedscripting.api.network.IScriptingData; +import org.cyclops.integratedscripting.evaluate.EvaluationExceptionResolutionHelpers; import org.cyclops.integratedscripting.evaluate.ScriptHelpers; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.PolyglotException; @@ -48,7 +49,9 @@ public IScript getScript(int disk, Path path) throws EvaluationException { try { graalContext.eval(source); } catch (PolyglotException e) { - throw new EvaluationException(Component.translatable("script.integratedscripting.error.script_read", path.toString(), disk, e.getMessage())); + throw EvaluationExceptionResolutionHelpers.resolveOnScriptChange( + new EvaluationException(Component.translatable("script.integratedscripting.error.script_read", path.toString(), disk, e.getMessage())), + disk, path); } Wrapper diskListener = new Wrapper<>(); return new GraalScript(graalContext, languageBinding, scriptInvalidateListener -> { @@ -68,7 +71,9 @@ public IScript getScript(int disk, Path path) throws EvaluationException { } }, disk, path, null); } catch (IOException e) { - throw new EvaluationException(Component.translatable("script.integratedscripting.error.script_read", path.toString(), disk, e.getMessage())); + throw EvaluationExceptionResolutionHelpers.resolveOnScriptChange( + new EvaluationException(Component.translatable("script.integratedscripting.error.script_read", path.toString(), disk, e.getMessage())), + disk, path); } } } diff --git a/src/main/java/org/cyclops/integratedscripting/evaluate/EvaluationExceptionResolutionHelpers.java b/src/main/java/org/cyclops/integratedscripting/evaluate/EvaluationExceptionResolutionHelpers.java new file mode 100644 index 00000000..398d3312 --- /dev/null +++ b/src/main/java/org/cyclops/integratedscripting/evaluate/EvaluationExceptionResolutionHelpers.java @@ -0,0 +1,77 @@ +package org.cyclops.integratedscripting.evaluate; + +import org.cyclops.cyclopscore.datastructure.Wrapper; +import org.cyclops.integrateddynamics.api.evaluate.EvaluationException; +import org.cyclops.integratedscripting.api.network.IScriptingData; +import org.cyclops.integratedscripting.core.network.ScriptingNetworkHelpers; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.nio.file.Path; + +/** + * @author rubensworks + */ +public class EvaluationExceptionResolutionHelpers { + + // Holds weak references of created EvaluationExceptions + private static final ReferenceQueue EVALUATION_EXCEPTION_REFERENCE_QUEUE = new ReferenceQueue<>(); + + /** + * Indicate that the given EvaluationException must be resolved when the given script is changed. + * @param evaluationException An evaluation exception. + * @param disk A script disk. + * @param path A script path. + * @return The given exception. + */ + public static EvaluationException resolveOnScriptChange(EvaluationException evaluationException, int disk, Path path) { + Wrapper listener = new Wrapper<>(); + listener.set(createListener(new EvaluationExceptionReference(evaluationException, EVALUATION_EXCEPTION_REFERENCE_QUEUE, disk, listener), disk, path)); + ScriptingNetworkHelpers.getScriptingData().addListener(disk, listener.get()); + return evaluationException; + } + + /** + * Call this periodically to flush stale entries in + * {@link EvaluationExceptionResolutionHelpers#EVALUATION_EXCEPTION_REFERENCE_QUEUE}. + */ + public static void expungeStaleEvaluationExceptions() { + for (Object x; (x = EVALUATION_EXCEPTION_REFERENCE_QUEUE.poll()) != null; ) { + ((EvaluationExceptionReference) x).removeListener(); + } + } + + protected static IScriptingData.IDiskScriptsChangeListener createListener(EvaluationExceptionReference evaluationExceptionReference, int disk, Path path) { + return scriptPathRelative -> { + if (scriptPathRelative.equals(path)) { + EvaluationException exception = evaluationExceptionReference.get(); + if (exception != null) { + exception.resolve(); + } + ScriptingNetworkHelpers.getScriptingData().removeListener(disk, evaluationExceptionReference.listener.get()); + } + }; + } + + public static class EvaluationExceptionReference extends WeakReference { + + private final int disk; + private final Wrapper listener; + + public EvaluationExceptionReference( + EvaluationException referent, + ReferenceQueue queue, + int disk, + Wrapper listener + ) { + super(referent, queue); + this.disk = disk; + this.listener = listener; + } + + public void removeListener() { + ScriptingNetworkHelpers.getScriptingData().removeListener(disk, listener.get()); + } + } + +} diff --git a/src/main/java/org/cyclops/integratedscripting/evaluate/ScriptHelpers.java b/src/main/java/org/cyclops/integratedscripting/evaluate/ScriptHelpers.java index 2c98ddaf..6cb0ba9a 100644 --- a/src/main/java/org/cyclops/integratedscripting/evaluate/ScriptHelpers.java +++ b/src/main/java/org/cyclops/integratedscripting/evaluate/ScriptHelpers.java @@ -87,7 +87,11 @@ public static IEvaluationExceptionFactory getDummyEvaluationExceptionFactory() { } public static IEvaluationExceptionFactory getEvaluationExceptionFactory(int disk, Path path, String member) { - return message -> new EvaluationException(Component.translatable("script.integratedscripting.error.script_exec", member, path.toString(), disk, message)); + EvaluationExceptionResolutionHelpers.expungeStaleEvaluationExceptions(); + + return message -> EvaluationExceptionResolutionHelpers.resolveOnScriptChange( + new EvaluationException(Component.translatable("script.integratedscripting.error.script_exec", member, path.toString(), disk, message)), + disk, path); } }