feat: 允许使用JavaScript监听事件
This commit is contained in:
@@ -2,11 +2,10 @@
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("java")
|
id("java")
|
||||||
id("com.github.johnrengelman.shadow") version "8+"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "cn.hamster3.mc.plugin"
|
group = "cn.hamster3.mc.plugin"
|
||||||
version = "1.0.6"
|
version = "1.1.0"
|
||||||
description = "为Minecraft服务器导入 Nashorn 引擎来执行 JavaScript 脚本"
|
description = "为Minecraft服务器导入 Nashorn 引擎来执行 JavaScript 脚本"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
@@ -23,9 +22,6 @@ dependencies {
|
|||||||
annotationProcessor("org.projectlombok:lombok:1.18.30")
|
annotationProcessor("org.projectlombok:lombok:1.18.30")
|
||||||
|
|
||||||
compileOnly("org.spigotmc:spigot-api:1.18.2-R0.1-SNAPSHOT")
|
compileOnly("org.spigotmc:spigot-api:1.18.2-R0.1-SNAPSHOT")
|
||||||
|
|
||||||
// https://mvnrepository.com/artifact/org.openjdk.nashorn/nashorn-core
|
|
||||||
implementation("org.openjdk.nashorn:nashorn-core:15.4")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
@@ -43,9 +39,6 @@ tasks {
|
|||||||
jar {
|
jar {
|
||||||
destinationDirectory = rootProject.layout.buildDirectory
|
destinationDirectory = rootProject.layout.buildDirectory
|
||||||
}
|
}
|
||||||
shadowJar {
|
|
||||||
destinationDirectory = rootProject.layout.buildDirectory
|
|
||||||
}
|
|
||||||
withType<JavaCompile>().configureEach {
|
withType<JavaCompile>().configureEach {
|
||||||
options.encoding = "UTF-8"
|
options.encoding = "UTF-8"
|
||||||
}
|
}
|
||||||
@@ -54,7 +47,4 @@ tasks {
|
|||||||
from(rootProject.file("LICENSE"))
|
from(rootProject.file("LICENSE"))
|
||||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
}
|
}
|
||||||
build {
|
|
||||||
dependsOn(shadowJar)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -1,208 +1,55 @@
|
|||||||
package cn.hamster3.mc.plugin.script;
|
package cn.hamster3.mc.plugin.script;
|
||||||
|
|
||||||
|
import cn.hamster3.mc.plugin.script.command.ScriptCommand;
|
||||||
|
import cn.hamster3.mc.plugin.script.core.ScriptManager;
|
||||||
|
import cn.hamster3.mc.plugin.script.listener.MainListener;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.bukkit.command.Command;
|
import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.configuration.ConfigurationSection;
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.bukkit.plugin.RegisteredListener;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import javax.script.Bindings;
|
import java.util.List;
|
||||||
import javax.script.Invocable;
|
|
||||||
import javax.script.ScriptEngine;
|
|
||||||
import javax.script.ScriptEngineManager;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.StandardCopyOption;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@SuppressWarnings("CallToPrintStackTrace")
|
|
||||||
public class HamsterScriptPlugin extends JavaPlugin {
|
public class HamsterScriptPlugin extends JavaPlugin {
|
||||||
private static File codeFolder;
|
|
||||||
@Getter
|
@Getter
|
||||||
private static ScriptEngine scriptEngine;
|
private static HamsterScriptPlugin instance;
|
||||||
@Getter
|
|
||||||
private static Invocable invocable;
|
|
||||||
|
|
||||||
private boolean enableEvalCommand;
|
@Override
|
||||||
private Map<String, String> importClass;
|
public void onLoad() {
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
reload();
|
ScriptManager.init();
|
||||||
}
|
for (HandlerList list : HandlerList.getHandlerLists()) {
|
||||||
|
list.register(new RegisteredListener(
|
||||||
private void reload() {
|
MainListener.INSTANCE,
|
||||||
saveDefaultConfig();
|
(listener, event) -> MainListener.INSTANCE.onEvent(event),
|
||||||
reloadConfig();
|
EventPriority.NORMAL,
|
||||||
FileConfiguration config = getConfig();
|
this,
|
||||||
enableEvalCommand = config.getBoolean("enable-eval-command", false);
|
false
|
||||||
scriptEngine = new ScriptEngineManager(getClassLoader()).getEngineByName("JavaScript");
|
));
|
||||||
invocable = (Invocable) scriptEngine;
|
|
||||||
|
|
||||||
Logger logger = getLogger();
|
|
||||||
importClass = new HashMap<>();
|
|
||||||
ConfigurationSection importConfig = config.getConfigurationSection("import");
|
|
||||||
if (importConfig != null) {
|
|
||||||
for (String simpleName : importConfig.getKeys(false)) {
|
|
||||||
String className = importConfig.getString(simpleName);
|
|
||||||
importClass.put(simpleName, className);
|
|
||||||
try {
|
|
||||||
Class<?> clazz = Class.forName(className);
|
|
||||||
scriptEngine.put(simpleName, clazz);
|
|
||||||
scriptEngine.eval(String.format("%s = %s.static;", simpleName, simpleName));
|
|
||||||
logger.info("已导入 " + className);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
logger.log(Level.WARNING, "导入 " + className + " 失败:未找到这个类", e);
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.WARNING, "导入 " + className + " 失败", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
codeFolder = new File(getDataFolder(), "code");
|
public ClassLoader getPluginClassLoader() {
|
||||||
if (codeFolder.mkdirs()) {
|
return getClassLoader();
|
||||||
getLogger().info("创建代码文件夹: " + codeFolder.getAbsolutePath());
|
|
||||||
try {
|
|
||||||
Files.copy(
|
|
||||||
Objects.requireNonNull(getResource("code/example.js")),
|
|
||||||
new File(codeFolder, "example.js").toPath(),
|
|
||||||
StandardCopyOption.REPLACE_EXISTING
|
|
||||||
);
|
|
||||||
} catch (IOException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
if (!sender.hasPermission("hamster.script.admin")) {
|
return ScriptCommand.INSTANCE.onCommand(sender, command, label, args);
|
||||||
sender.sendMessage("§c你没有这个权限");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (args.length < 1) {
|
|
||||||
sender.sendMessage("§c请输入命令");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
switch (args[0]) {
|
|
||||||
case "run": {
|
|
||||||
if (args.length < 2) {
|
|
||||||
sender.sendMessage("§c请输入 JavaScript 文件名称");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
File file = new File(codeFolder, args[1]);
|
|
||||||
if (!file.exists() && !args[1].endsWith(".js")) {
|
|
||||||
file = new File(codeFolder, args[1] + ".js");
|
|
||||||
}
|
|
||||||
if (!file.exists()) {
|
|
||||||
sender.sendMessage("§c未找到 JavaScript 文件: " + file.getAbsolutePath());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
String code;
|
|
||||||
try {
|
|
||||||
List<String> lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
|
|
||||||
code = String.join("\n", lines);
|
|
||||||
} catch (IOException e) {
|
|
||||||
sender.sendMessage("§c读取 JavaScript 文件内容 " + file.getAbsolutePath() + " 时出错!");
|
|
||||||
e.printStackTrace();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
try {
|
|
||||||
Bindings bindings = scriptEngine.createBindings();
|
|
||||||
for (String simpleName : importClass.keySet()) {
|
|
||||||
bindings.put(simpleName, scriptEngine.get(simpleName));
|
|
||||||
}
|
|
||||||
String[] scriptArgs = Arrays.copyOfRange(args, 2, args.length);
|
|
||||||
bindings.put("sender", sender);
|
|
||||||
bindings.put("args", scriptArgs);
|
|
||||||
Object eval = scriptEngine.eval(code, bindings);
|
|
||||||
long time = System.currentTimeMillis() - start;
|
|
||||||
sender.sendMessage("§aJavaScript 代码执行完成, 耗时: " + time + " 毫秒");
|
|
||||||
sender.sendMessage("§a返回值: §f" + eval);
|
|
||||||
} catch (Exception e) {
|
|
||||||
long time = System.currentTimeMillis() - start;
|
|
||||||
sender.sendMessage("§cJavaScript 代码执行出错, 耗时: " + time + " 毫秒");
|
|
||||||
sender.sendMessage("§c异常原因: " + e.getMessage());
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "eval": {
|
|
||||||
if (!enableEvalCommand) {
|
|
||||||
sender.sendMessage("§c当前不允许直接执行 JavaScript");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (args.length < 2) {
|
|
||||||
sender.sendMessage("§c请输入 JavaScript 代码内容");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
for (int i = 1; i < args.length; i++) {
|
|
||||||
builder.append(args[i]).append(" ");
|
|
||||||
}
|
|
||||||
String code = builder.toString();
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
try {
|
|
||||||
Bindings bindings = scriptEngine.createBindings();
|
|
||||||
for (String simpleName : importClass.keySet()) {
|
|
||||||
bindings.put(simpleName, scriptEngine.get(simpleName));
|
|
||||||
}
|
|
||||||
bindings.put("sender", sender);
|
|
||||||
Object eval = scriptEngine.eval(code, bindings);
|
|
||||||
long time = System.currentTimeMillis() - start;
|
|
||||||
sender.sendMessage("§aJavaScript 代码执行完成, 耗时: " + time + " 毫秒");
|
|
||||||
sender.sendMessage("§a返回值: §f" + eval);
|
|
||||||
} catch (Exception e) {
|
|
||||||
long time = System.currentTimeMillis() - start;
|
|
||||||
sender.sendMessage("§cJavaScript 代码执行出错, 耗时: " + time + " 毫秒");
|
|
||||||
sender.sendMessage("§c异常原因: " + e.getMessage());
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "reload": {
|
|
||||||
reload();
|
|
||||||
sender.sendMessage("§a插件重载完成");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
sender.sendMessage("§c未找到该命令");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
|
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
|
||||||
if (args.length == 1) {
|
return ScriptCommand.INSTANCE.onTabComplete(sender, command, alias, args);
|
||||||
List<String> list = new ArrayList<>();
|
|
||||||
list.add("run");
|
|
||||||
list.add("eval");
|
|
||||||
list.add("reload");
|
|
||||||
String startWith = args[0].toLowerCase();
|
|
||||||
list.removeIf(o -> !o.startsWith(startWith));
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
if (args[0].equalsIgnoreCase("run")) {
|
|
||||||
File[] files = codeFolder.listFiles();
|
|
||||||
if (files != null) {
|
|
||||||
String startWith = args[1].toLowerCase();
|
|
||||||
return Arrays.stream(files)
|
|
||||||
.map(File::getName)
|
|
||||||
.filter(o -> o.toLowerCase().startsWith(startWith))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,119 @@
|
|||||||
|
package cn.hamster3.mc.plugin.script.command;
|
||||||
|
|
||||||
|
import cn.hamster3.mc.plugin.script.HamsterScriptPlugin;
|
||||||
|
import cn.hamster3.mc.plugin.script.core.ScriptManager;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.command.TabExecutor;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class ScriptCommand implements TabExecutor {
|
||||||
|
public static final ScriptCommand INSTANCE = new ScriptCommand();
|
||||||
|
|
||||||
|
private ScriptCommand() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
|
if (!sender.hasPermission("hamster.script.admin")) {
|
||||||
|
sender.sendMessage("§c你没有这个权限");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (args.length < 1) {
|
||||||
|
sender.sendMessage("§c请输入命令");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
switch (args[0]) {
|
||||||
|
case "run": {
|
||||||
|
if (args.length < 2) {
|
||||||
|
sender.sendMessage("§c请输入 JavaScript 文件名称");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
File file = new File(ScriptManager.getCodeFolder(), args[1]);
|
||||||
|
if (!file.exists() && !args[1].endsWith(".js")) {
|
||||||
|
file = new File(ScriptManager.getCodeFolder(), args[1] + ".js");
|
||||||
|
}
|
||||||
|
if (!file.exists()) {
|
||||||
|
sender.sendMessage("§c未找到 JavaScript 文件: " + file.getAbsolutePath());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String code;
|
||||||
|
try {
|
||||||
|
List<String> lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
|
||||||
|
code = String.join("\n", lines);
|
||||||
|
} catch (IOException e) {
|
||||||
|
sender.sendMessage("§c读取 JavaScript 文件内容 " + file.getAbsolutePath() + " 时出错!");
|
||||||
|
HamsterScriptPlugin.getInstance().getLogger().log(Level.SEVERE, "", e);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
String[] scriptArgs = Arrays.copyOfRange(args, 2, args.length);
|
||||||
|
ScriptManager.eval(sender, code, scriptArgs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "eval": {
|
||||||
|
if (!ScriptManager.isEnableEvalCommand()) {
|
||||||
|
sender.sendMessage("§c当前不允许直接执行 JavaScript");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (args.length < 2) {
|
||||||
|
sender.sendMessage("§c请输入 JavaScript 代码内容");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
for (int i = 1; i < args.length; i++) {
|
||||||
|
builder.append(args[i]).append(" ");
|
||||||
|
}
|
||||||
|
String code = builder.toString();
|
||||||
|
ScriptManager.eval(sender, code);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "reload": {
|
||||||
|
ScriptManager.init();
|
||||||
|
sender.sendMessage("§a插件重载完成");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
sender.sendMessage("§c未找到该命令");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
||||||
|
if (args.length == 1) {
|
||||||
|
ArrayList<String> list = new ArrayList<>();
|
||||||
|
list.add("run");
|
||||||
|
list.add("eval");
|
||||||
|
list.add("reload");
|
||||||
|
String startWith = args[0].toLowerCase();
|
||||||
|
list.removeIf(o -> !o.toLowerCase().startsWith(startWith));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
if (args[0].equalsIgnoreCase("run")) {
|
||||||
|
File[] files = ScriptManager.getCodeFolder().listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
String startWith = args[1].toLowerCase();
|
||||||
|
return Arrays.stream(files)
|
||||||
|
.map(File::getName)
|
||||||
|
.filter(o -> o.toLowerCase().startsWith(startWith))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,148 @@
|
|||||||
|
package cn.hamster3.mc.plugin.script.core;
|
||||||
|
|
||||||
|
import cn.hamster3.mc.plugin.script.HamsterScriptPlugin;
|
||||||
|
import cn.hamster3.mc.plugin.script.data.EventCode;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import javax.script.*;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class ScriptManager {
|
||||||
|
@Getter
|
||||||
|
private static File codeFolder;
|
||||||
|
@Getter
|
||||||
|
private static ScriptEngine scriptEngine;
|
||||||
|
@Getter
|
||||||
|
private static Invocable invocable;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private static boolean enableEvalCommand;
|
||||||
|
@Getter
|
||||||
|
private static boolean enableEventCode;
|
||||||
|
@Getter
|
||||||
|
private static Map<String, String> importClass;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private static List<EventCode> eventCodes;
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
HamsterScriptPlugin plugin = HamsterScriptPlugin.getInstance();
|
||||||
|
plugin.saveDefaultConfig();
|
||||||
|
plugin.reloadConfig();
|
||||||
|
|
||||||
|
FileConfiguration config = plugin.getConfig();
|
||||||
|
|
||||||
|
enableEvalCommand = config.getBoolean("enable-eval-command", false);
|
||||||
|
enableEventCode = config.getBoolean("enable-event-code", false);
|
||||||
|
scriptEngine = new ScriptEngineManager(plugin.getPluginClassLoader()).getEngineByName("JavaScript");
|
||||||
|
invocable = (Invocable) scriptEngine;
|
||||||
|
|
||||||
|
Logger logger = plugin.getLogger();
|
||||||
|
importClass = new HashMap<>();
|
||||||
|
ConfigurationSection importConfig = config.getConfigurationSection("import");
|
||||||
|
if (importConfig != null) {
|
||||||
|
for (String simpleName : importConfig.getKeys(false)) {
|
||||||
|
String className = importConfig.getString(simpleName);
|
||||||
|
importClass.put(simpleName, className);
|
||||||
|
try {
|
||||||
|
Class<?> clazz = Class.forName(className);
|
||||||
|
scriptEngine.put(simpleName, clazz);
|
||||||
|
scriptEngine.eval(String.format("%s = %s.static;", simpleName, simpleName));
|
||||||
|
logger.info("已导入 " + className);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
logger.log(Level.WARNING, "导入 " + className + " 失败:未找到这个类", e);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.WARNING, "导入 " + className + " 失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
codeFolder = new File(plugin.getDataFolder(), "code");
|
||||||
|
if (codeFolder.mkdirs()) {
|
||||||
|
plugin.getLogger().info("创建代码文件夹: " + codeFolder.getAbsolutePath());
|
||||||
|
try {
|
||||||
|
Files.copy(
|
||||||
|
Objects.requireNonNull(plugin.getResource("code/example.js")),
|
||||||
|
new File(codeFolder, "example.js").toPath()
|
||||||
|
);
|
||||||
|
} catch (IOException e) {
|
||||||
|
HamsterScriptPlugin.getInstance().getLogger().log(Level.SEVERE, "", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
File eventFolder = new File(plugin.getDataFolder(), "event");
|
||||||
|
if (eventFolder.mkdirs()) {
|
||||||
|
plugin.getLogger().info("创建事件文件夹: " + codeFolder.getAbsolutePath());
|
||||||
|
try {
|
||||||
|
Files.copy(
|
||||||
|
Objects.requireNonNull(plugin.getResource("event/example.js")),
|
||||||
|
new File(eventFolder, "example.js").toPath()
|
||||||
|
);
|
||||||
|
} catch (IOException e) {
|
||||||
|
HamsterScriptPlugin.getInstance().getLogger().log(Level.SEVERE, "", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eventCodes = loadEventCodes(eventFolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<EventCode> loadEventCodes(@NotNull File file) {
|
||||||
|
ArrayList<EventCode> list = new ArrayList<>();
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
File[] files = file.listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
for (File subFile : files) {
|
||||||
|
List<EventCode> loaded = loadEventCodes(subFile);
|
||||||
|
list.addAll(loaded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
EventCode code = new EventCode(file);
|
||||||
|
list.add(code);
|
||||||
|
} catch (Exception e) {
|
||||||
|
HamsterScriptPlugin.getInstance().getLogger().log(Level.WARNING, "加载事件代码 " + file.getAbsolutePath() + " 失败", e);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bindings createBindings() {
|
||||||
|
Bindings bindings = ScriptManager.getScriptEngine().createBindings();
|
||||||
|
for (String simpleName : importClass.keySet()) {
|
||||||
|
bindings.put(simpleName, ScriptManager.getScriptEngine().get(simpleName));
|
||||||
|
}
|
||||||
|
return bindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object eval(@NotNull String code) throws ScriptException {
|
||||||
|
Bindings bindings = createBindings();
|
||||||
|
return ScriptManager.getScriptEngine().eval(code, bindings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void eval(@NotNull CommandSender sender, @NotNull String code, @NotNull String... args) {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
try {
|
||||||
|
Bindings bindings = createBindings();
|
||||||
|
bindings.put("sender", sender);
|
||||||
|
bindings.put("args", args);
|
||||||
|
Object eval = ScriptManager.getScriptEngine().eval(code, bindings);
|
||||||
|
long time = System.currentTimeMillis() - start;
|
||||||
|
sender.sendMessage("§aJavaScript 代码执行完成, 耗时: " + time + " 毫秒");
|
||||||
|
sender.sendMessage("§a返回值: §f" + eval);
|
||||||
|
} catch (Exception e) {
|
||||||
|
long time = System.currentTimeMillis() - start;
|
||||||
|
sender.sendMessage("§cJavaScript 代码执行出错, 耗时: " + time + " 毫秒");
|
||||||
|
sender.sendMessage("§c异常原因: " + e.getMessage());
|
||||||
|
HamsterScriptPlugin.getInstance().getLogger().log(Level.SEVERE, "", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,33 @@
|
|||||||
|
package cn.hamster3.mc.plugin.script.data;
|
||||||
|
|
||||||
|
import cn.hamster3.mc.plugin.script.core.ScriptManager;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import javax.script.ScriptException;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
public class EventCode {
|
||||||
|
@NotNull
|
||||||
|
private final String id;
|
||||||
|
@NotNull
|
||||||
|
private final Class<?> clazz;
|
||||||
|
@NotNull
|
||||||
|
private final Object object;
|
||||||
|
|
||||||
|
public EventCode(@NotNull File file) throws IOException, ScriptException, NoSuchMethodException, ClassNotFoundException {
|
||||||
|
String code = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
|
||||||
|
object = ScriptManager.eval(code);
|
||||||
|
id = ScriptManager.getInvocable().invokeMethod(object, "getID").toString();
|
||||||
|
clazz = Class.forName(ScriptManager.getInvocable().invokeMethod(object, "getEventType").toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void invoke(@NotNull Event event) throws ScriptException, NoSuchMethodException {
|
||||||
|
ScriptManager.getInvocable().invokeMethod(object, "invoke", event);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,33 @@
|
|||||||
|
package cn.hamster3.mc.plugin.script.listener;
|
||||||
|
|
||||||
|
import cn.hamster3.mc.plugin.script.HamsterScriptPlugin;
|
||||||
|
import cn.hamster3.mc.plugin.script.core.ScriptManager;
|
||||||
|
import cn.hamster3.mc.plugin.script.data.EventCode;
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
public class MainListener implements Listener {
|
||||||
|
public static final MainListener INSTANCE = new MainListener();
|
||||||
|
|
||||||
|
private MainListener() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler(ignoreCancelled = true)
|
||||||
|
public void onEvent(Event event) {
|
||||||
|
if (!ScriptManager.isEnableEventCode()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (EventCode code : ScriptManager.getEventCodes()) {
|
||||||
|
if (code.getClazz().isAssignableFrom(event.getClass())) {
|
||||||
|
try {
|
||||||
|
code.invoke(event);
|
||||||
|
} catch (Exception e) {
|
||||||
|
HamsterScriptPlugin.getInstance().getLogger().log(Level.WARNING, "处理事件代码 " + code.getId() + " 失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,6 +1,9 @@
|
|||||||
# 是否允许通过指令执行 JavaScript 代码
|
# 是否允许通过指令执行 JavaScript 代码
|
||||||
enable-eval-command: false
|
enable-eval-command: false
|
||||||
|
|
||||||
|
# 是否启用事件监听执行代码
|
||||||
|
enable-event-code: false
|
||||||
|
|
||||||
# 导入的 Java 代码
|
# 导入的 Java 代码
|
||||||
import:
|
import:
|
||||||
Math: java.lang.Math
|
Math: java.lang.Math
|
||||||
|
13
src/main/resources/event/example.js
Normal file
13
src/main/resources/event/example.js
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
(function () {
|
||||||
|
return {
|
||||||
|
getID: function () {
|
||||||
|
return "test";
|
||||||
|
},
|
||||||
|
getEventType: function () {
|
||||||
|
return "org.bukkit.event.player.AsyncPlayerChatEvent";
|
||||||
|
},
|
||||||
|
invoke: function (event) {
|
||||||
|
print(event.getPlayer().getName() + " says: " + event.getMessage());
|
||||||
|
},
|
||||||
|
};
|
||||||
|
})();
|
@@ -18,6 +18,9 @@ Plugin:
|
|||||||
# HamsterScript 需要访问其他插件的类路径
|
# HamsterScript 需要访问其他插件的类路径
|
||||||
join-classpath: true
|
join-classpath: true
|
||||||
|
|
||||||
|
libraries:
|
||||||
|
- org.openjdk.nashorn:nashorn-core:15.4
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
hamster-script:
|
hamster-script:
|
||||||
aliases: [ hscript, scripts, script ]
|
aliases: [ hscript, scripts, script ]
|
||||||
|
Reference in New Issue
Block a user