SuperbVote icon indicating copy to clipboard operation
SuperbVote copied to clipboard

Script matchers are always unable to create matcher

Open Proximyst opened this issue 5 years ago • 5 comments

If you have a script in your SuperbVotes directory, as such:

function matchVote(ctx) {
    return true;
}

SuperbVote will not find it if you specify either script.js or ./plugins/SuperbVote/script.js (when launched from the same dir as plugins).

Proximyst avatar Jan 25 '20 10:01 Proximyst

Here's a patch in form of a git diff: (note this makes a hard dependency on java versions with Nashorn - Java 12+ will not work)

diff --git a/src/main/java/io/minimum/minecraft/superbvote/SuperbVote.java b/src/main/java/io/minimum/minecraft/superbvote/SuperbVote.java
index 1a199ed..5598383 100644
--- a/src/main/java/io/minimum/minecraft/superbvote/SuperbVote.java
+++ b/src/main/java/io/minimum/minecraft/superbvote/SuperbVote.java
@@ -14,6 +14,8 @@ import io.minimum.minecraft.superbvote.util.cooldowns.CooldownHandler;
 import io.minimum.minecraft.superbvote.util.cooldowns.VoteServiceCooldown;
 import io.minimum.minecraft.superbvote.votes.SuperbVoteListener;
 import io.minimum.minecraft.superbvote.votes.VoteReminder;
+import javax.script.ScriptEngineManager;
+import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
 import lombok.Getter;
 import org.bukkit.plugin.java.JavaPlugin;
 import org.bukkit.scheduler.BukkitTask;
@@ -37,9 +39,25 @@ public class SuperbVote extends JavaPlugin {
     @Getter
     private TopPlayerSignStorage topPlayerSignStorage;
     private BukkitTask voteReminderTask;
+    @Getter
+    private ScriptEngineManager scriptEngineManager;
 
     @Override
     public void onEnable() {
+        ClassLoader previousCtx = Thread.currentThread().getContextClassLoader();
+        Thread.currentThread().setContextClassLoader(getClassLoader());
+        try {
+            scriptEngineManager = new ScriptEngineManager();
+            if (scriptEngineManager.getEngineByExtension("js") == null) {
+                final NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
+                factory.getNames().forEach(name -> scriptEngineManager.registerEngineName(name, factory));
+                factory.getExtensions().forEach(ext -> scriptEngineManager.registerEngineExtension(ext, factory));
+                factory.getMimeTypes().forEach(mime -> scriptEngineManager.registerEngineMimeType(mime, factory));
+            }
+        } finally {
+            Thread.currentThread().setContextClassLoader(previousCtx);
+        }
+
         plugin = this;
         saveDefaultConfig();
         configuration = new SuperbVoteConfiguration(getConfig());
diff --git a/src/main/java/io/minimum/minecraft/superbvote/votes/rewards/matchers/ScriptRewardMatcher.java b/src/main/java/io/minimum/minecraft/superbvote/votes/rewards/matchers/ScriptRewardMatcher.java
index 8f8015b..e979610 100644
--- a/src/main/java/io/minimum/minecraft/superbvote/votes/rewards/matchers/ScriptRewardMatcher.java
+++ b/src/main/java/io/minimum/minecraft/superbvote/votes/rewards/matchers/ScriptRewardMatcher.java
@@ -3,6 +3,9 @@ package io.minimum.minecraft.superbvote.votes.rewards.matchers;
 import io.minimum.minecraft.superbvote.SuperbVote;
 import io.minimum.minecraft.superbvote.util.PlayerVotes;
 import io.minimum.minecraft.superbvote.votes.Vote;
+import java.io.File;
+import javax.script.Bindings;
+import javax.script.ScriptContext;
 import lombok.NonNull;
 import lombok.Value;
 import org.bukkit.Bukkit;
@@ -40,28 +43,40 @@ public class ScriptRewardMatcher implements RewardMatcher {
     public ScriptRewardMatcher(Path path) throws IOException, ScriptException {
         this.path = path;
 
-        // Yes, we have to switch the context classloader.
-        ClassLoader previousCtx = Thread.currentThread().getContextClassLoader();
-        Thread.currentThread().setContextClassLoader(SuperbVote.getPlugin()._exposeClassLoader());
-        try {
-            ScriptEngineManager manager = new ScriptEngineManager();
-            engine = manager.getEngineByName("JavaScript");
+        File file = path.toFile();
+        if (!file.isFile()) {
+            SuperbVote.getPlugin().getLogger().warning("There is no script located at " + path.toString());
+            engine = null;
+            throw new IllegalStateException();
+        }
 
-            // Read SuperbVote helper library first
-            try (Reader reader = new BufferedReader(new InputStreamReader(SuperbVote.getPlugin().getResource("superbvote_lib.js")))) {
-                engine.eval(reader);
-            }
+        ScriptEngineManager manager = SuperbVote.getPlugin().getScriptEngineManager();
+        engine = manager.getEngineByExtension("js");
+        if (engine == null) {
+            SuperbVote.getPlugin().getLogger().warning("Cannot find a Nashorn engine.");
+            throw new IllegalStateException();
+        }
+        Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
+        bindings.put("server", Bukkit.getServer());
+        bindings.put("plugin", SuperbVote.getPlugin());
 
-            try (Reader reader = Files.newBufferedReader(path)) {
-                engine.eval(reader);
-            }
-        } finally {
-            Thread.currentThread().setContextClassLoader(previousCtx);
+        // Read SuperbVote helper library first
+        try (Reader reader = new BufferedReader(new InputStreamReader(SuperbVote.getPlugin().getResource("superbvote_lib.js")))) {
+            engine.eval(reader);
+        }
+
+        try (Reader reader = Files.newBufferedReader(path)) {
+            engine.eval(reader);
         }
     }
 
     @Override
     public boolean matches(Vote vote, PlayerVotes pv) {
+        if (engine == null) {
+            SuperbVote.getPlugin().getLogger().warning("There is no script located at " + path.toString());
+            return false;
+        }
+
         VoteContext ctx = new VoteContext(
                 vote,
                 pv.getType() == PlayerVotes.Type.FUTURE ? pv.getVotes() - 1 : pv.getVotes()
diff --git a/src/main/resources/superbvote_lib.js b/src/main/resources/superbvote_lib.js
index 9781461..c45501e 100644
--- a/src/main/resources/superbvote_lib.js
+++ b/src/main/resources/superbvote_lib.js
@@ -1,7 +1,3 @@
-// Defines a few functions to help create JS-based matchers.
-var server = Java.type('org.bukkit.Bukkit').getServer();
-var _SuperbVotePlugin = Java.type('io.minimum.minecraft.superbvote.SuperbVote');
-
 // Assorted Bukkit helpers
 
 /**
@@ -9,8 +5,7 @@ var _SuperbVotePlugin = Java.type('io.minimum.minecraft.superbvote.SuperbVote');
  * @param f the function to call
  */
 function callSync(f) {
-    var pl = _SuperbVotePlugin.getPlugin();
-    var future = server.scheduler.callSyncMethod(pl, f);
+    var future = server.scheduler.callSyncMethod(plugin, f);
     return future.get();
 }

Proximyst avatar Feb 02 '20 09:02 Proximyst

Nashorn is deprecated and is getting removed in the latest JDK version. It's not worth it for me to try and continue to support it.

I'm open to support for other scripting languages, but I haven't had time (or motivation) to maintain SuperbVote.

astei avatar Feb 02 '20 21:02 astei

Is using Groovy perhaps a good alternative? It's essentially JavaScript outside of the whole Java.type stuff and works the same if not for that, and it works well even on Java 14.

Proximyst avatar Mar 28 '20 16:03 Proximyst

Groovy does seem to be a viable alternative, but it's quite big. I'd have to implement runtime dependency downloading for it to work.

astei avatar Mar 28 '20 16:03 astei

Given my lack of time it is easier for me to just deprecate the script matcher.

astei avatar Nov 05 '20 19:11 astei