feat: 初版提交
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
6
src/main/resources/code/example.js
Normal file
6
src/main/resources/code/example.js
Normal file
@@ -0,0 +1,6 @@
|
||||
function sayHi(param) {
|
||||
param.sendMessage("Hi!");
|
||||
}
|
||||
|
||||
// 执行命令的对象会自动设置为变量 sender
|
||||
sayHi(sender);
|
6
src/main/resources/config.yml
Normal file
6
src/main/resources/config.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
# 是否允许通过指令执行 JavaScript 代码
|
||||
enable-eval-command: false
|
||||
|
||||
# 导入的 Java 代码
|
||||
import:
|
||||
Bukkit: org.bukkit.Bukkit
|
13
src/main/resources/plugin.yml
Normal file
13
src/main/resources/plugin.yml
Normal file
@@ -0,0 +1,13 @@
|
||||
name: HamsterScript
|
||||
main: cn.hamster3.mc.plugin.script.HamsterScriptPlugin
|
||||
version: ${version}
|
||||
api-version: 1.13
|
||||
|
||||
commands:
|
||||
scripts:
|
||||
aliases: script
|
||||
|
||||
permissions:
|
||||
hamster.script.admin:
|
||||
description: Admin permission
|
||||
default: op
|
Reference in New Issue
Block a user