|
|
|
@@ -0,0 +1,197 @@
|
|
|
|
|
package cn.hamster3.mc.plugin.script;
|
|
|
|
|
|
|
|
|
|
import lombok.Getter;
|
|
|
|
|
import org.bukkit.command.Command;
|
|
|
|
|
import org.bukkit.command.CommandSender;
|
|
|
|
|
import org.bukkit.configuration.ConfigurationSection;
|
|
|
|
|
import org.bukkit.configuration.file.FileConfiguration;
|
|
|
|
|
import org.bukkit.plugin.java.JavaPlugin;
|
|
|
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
|
|
|
|
|
|
import javax.script.*;
|
|
|
|
|
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.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
@SuppressWarnings("CallToPrintStackTrace")
|
|
|
|
|
public class HamsterScriptPlugin extends JavaPlugin {
|
|
|
|
|
@Getter
|
|
|
|
|
private static ScriptEngine engine;
|
|
|
|
|
@Getter
|
|
|
|
|
private static Invocable invocable;
|
|
|
|
|
private static File codeFolder;
|
|
|
|
|
private boolean enableEvalCommand;
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onEnable() {
|
|
|
|
|
reload();
|
|
|
|
|
codeFolder = new File(getDataFolder(), "code");
|
|
|
|
|
if (codeFolder.mkdirs()) {
|
|
|
|
|
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) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void reload() {
|
|
|
|
|
saveDefaultConfig();
|
|
|
|
|
reloadConfig();
|
|
|
|
|
FileConfiguration config = getConfig();
|
|
|
|
|
enableEvalCommand = config.getBoolean("enable-eval-command", false);
|
|
|
|
|
engine = new ScriptEngineManager(getClassLoader()).getEngineByName("JavaScript");
|
|
|
|
|
invocable = (Invocable) engine;
|
|
|
|
|
ConfigurationSection importConfig = config.getConfigurationSection("import");
|
|
|
|
|
if (importConfig != null) {
|
|
|
|
|
for (String key : importConfig.getKeys(false)) {
|
|
|
|
|
String string = importConfig.getString(key);
|
|
|
|
|
try {
|
|
|
|
|
Class<?> clazz = Class.forName(string);
|
|
|
|
|
engine.put(key, clazz);
|
|
|
|
|
engine.eval(String.format("%s = %s.static;", key, key));
|
|
|
|
|
getLogger().info("将 " + string + " 导入为 " + key);
|
|
|
|
|
} catch (ClassNotFoundException e) {
|
|
|
|
|
getLogger().warning("将 " + string + " 导入为 " + key + " 失败:未找到这个类");
|
|
|
|
|
} catch (ScriptException e) {
|
|
|
|
|
getLogger().warning("将 " + string + " 导入为 " + key + " 失败");
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@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 "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 = engine.createBindings();
|
|
|
|
|
bindings.put("sender", sender);
|
|
|
|
|
Object eval = engine.eval(code, bindings);
|
|
|
|
|
long time = System.currentTimeMillis() - start;
|
|
|
|
|
sender.sendMessage("§aJavaScript 代码执行完成, 耗时: " + time + " 毫秒");
|
|
|
|
|
sender.sendMessage("§a返回值: §f" + eval);
|
|
|
|
|
} catch (ScriptException e) {
|
|
|
|
|
long time = System.currentTimeMillis() - start;
|
|
|
|
|
sender.sendMessage("§cJavaScript 代码执行出错, 耗时: " + time + " 毫秒");
|
|
|
|
|
sender.sendMessage("§c异常原因: " + e.getMessage());
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
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 = engine.createBindings();
|
|
|
|
|
bindings.put("sender", sender);
|
|
|
|
|
Object eval = engine.eval(code, bindings);
|
|
|
|
|
long time = System.currentTimeMillis() - start;
|
|
|
|
|
sender.sendMessage("§aJavaScript 代码执行完成, 耗时: " + time + " 毫秒");
|
|
|
|
|
sender.sendMessage("§a返回值: §f" + eval);
|
|
|
|
|
} catch (ScriptException e) {
|
|
|
|
|
long time = System.currentTimeMillis() - start;
|
|
|
|
|
sender.sendMessage("§cJavaScript 代码执行出错, 耗时: " + time + " 毫秒");
|
|
|
|
|
sender.sendMessage("§c异常原因: " + e.getMessage());
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case "reset": {
|
|
|
|
|
engine = new ScriptEngineManager().getEngineByName("JavaScript");
|
|
|
|
|
invocable = (Invocable) engine;
|
|
|
|
|
sender.sendMessage("§a已重设 JavaScript 引擎环境");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case "reload": {
|
|
|
|
|
reload();
|
|
|
|
|
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 alias, @NotNull String[] args) {
|
|
|
|
|
if (args.length == 1) {
|
|
|
|
|
List<String> list = new ArrayList<>();
|
|
|
|
|
list.add("eval");
|
|
|
|
|
list.add("run");
|
|
|
|
|
list.add("reset");
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|