├── .idea ├── .gitignore ├── JavaScriptLibraryPlugin.iml ├── codeStyles │ └── codeStyleConfig.xml ├── vcs.xml ├── encodings.xml ├── runConfigurations │ └── server.xml ├── compiler.xml └── misc.xml ├── src └── main │ ├── resources │ ├── config.yml │ ├── lib │ │ ├── info.json │ │ ├── load.js │ │ ├── util.js │ │ └── event.js │ └── plugin.yml │ └── java │ └── xingchen │ └── jslib │ ├── event │ ├── EventHolder.java │ ├── EventLoader.java │ └── register │ │ ├── JavaScriptFilesEvalledEvent.java │ │ ├── AbstractJavaScriptPluginEvent.java │ │ └── JavaScriptPreRegisterEvent.java │ ├── js │ ├── IScriptHolder.java │ ├── ScriptHolderBase.java │ ├── event │ │ ├── JavaScriptCancellableEvent.java │ │ └── JavaScriptEvent.java │ ├── ScriptFiles.java │ ├── JavaScriptUtil.java │ ├── JavaScriptLoader.java │ └── JavaScriptInfo.java │ ├── export │ ├── KeyValue.java │ ├── LinkageLoader.java │ └── PluginScripts.java │ ├── command │ ├── CommandLoader.java │ ├── EnumJsSubCommand.java │ └── JsCommand.java │ ├── JSApi.java │ ├── JavaScriptLibrary.java │ └── config │ └── ConfigManager.java ├── README.md ├── JavaScriptLibraryPlugin.iml ├── MinecraftPlugin.iml └── pom.xml /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /workspace.xml -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | linkage: false 2 | command: 3 | run: true 4 | book: true -------------------------------------------------------------------------------- /.idea/JavaScriptLibraryPlugin.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/main/resources/lib/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "libraries", 3 | "order": [ 4 | "util", 5 | "load", 6 | "event" 7 | ] 8 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JavaScriptLibraryPlugin 2 | A Bukkit Plugin to provide a environment for users to use JavaScript code 3 | 4 | Open Source License is LGPL3 License.Please follow it. 5 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/event/EventHolder.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib.event; 2 | 3 | import org.bukkit.event.Listener; 4 | 5 | /** 6 | * 无方法 7 | * 仅为JavaScript提供监听器标记 8 | */ 9 | public class EventHolder implements Listener { 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/js/IScriptHolder.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib.js; 2 | 3 | /** 4 | * 本地脚本接口 5 | * 可标记本地脚本的文件/文件夹 6 | */ 7 | public interface IScriptHolder { 8 | /**脚本文件/文件夹(可有多个)*/ 9 | public ScriptFiles[] getScriptFiles(); 10 | } 11 | -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: JavaScriptLibrary 2 | main: xingchen.jslib.JavaScriptLibrary 3 | version: 1.0.2 4 | permissions: 5 | jslib.command.help: 6 | default: op 7 | jslib.command.run: 8 | default: op 9 | jslib.command.book: 10 | default: op -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /JavaScriptLibraryPlugin.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | SPIGOT 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /MinecraftPlugin.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | SPIGOT 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/js/ScriptHolderBase.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib.js; 2 | 3 | public class ScriptHolderBase implements IScriptHolder { 4 | protected ScriptFiles[] scriptFiles; 5 | 6 | public ScriptHolderBase(ScriptFiles[] scriptFiles) { 7 | this.scriptFiles = scriptFiles; 8 | } 9 | 10 | @Override 11 | public ScriptFiles[] getScriptFiles() { 12 | return this.scriptFiles; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/export/KeyValue.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib.export; 2 | 3 | /**键值对*/ 4 | public class KeyValue { 5 | protected K key; 6 | protected V value; 7 | 8 | public KeyValue(K key, V value) { 9 | this.key = key; 10 | this.value = value; 11 | } 12 | 13 | public K getKey() { 14 | return this.key; 15 | } 16 | 17 | public void setKey(K key) { 18 | this.key = key; 19 | } 20 | 21 | public V getValue() { 22 | return this.value; 23 | } 24 | 25 | public void setValue(V value) { 26 | this.value = value; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/event/EventLoader.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib.event; 2 | 3 | import org.bukkit.event.Listener; 4 | import org.bukkit.plugin.Plugin; 5 | 6 | /** 7 | * 事件监听器(暂时无用) 8 | */ 9 | public class EventLoader implements Listener { 10 | private Plugin plugin; 11 | 12 | public EventLoader(Plugin plugin) { 13 | this.plugin = plugin; 14 | } 15 | 16 | public static void init(Plugin plugin) { 17 | plugin.getServer().getPluginManager().registerEvents(new EventLoader(plugin), plugin); 18 | } 19 | 20 | public Plugin getPlugin() { 21 | return this.plugin; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.idea/runConfigurations/server.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 11 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/event/register/JavaScriptFilesEvalledEvent.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib.event.register; 2 | 3 | import org.bukkit.event.HandlerList; 4 | 5 | import xingchen.jslib.export.LinkageLoader; 6 | 7 | public class JavaScriptFilesEvalledEvent extends AbstractJavaScriptPluginEvent { 8 | private static HandlerList handlerList = new HandlerList(); 9 | 10 | public JavaScriptFilesEvalledEvent(LinkageLoader linkageLoader, String scriptName) { 11 | super(linkageLoader, scriptName); 12 | } 13 | 14 | @Override 15 | public HandlerList getHandlers() { 16 | return handlerList; 17 | } 18 | 19 | public static HandlerList getHandlerList() { 20 | return handlerList; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/event/register/AbstractJavaScriptPluginEvent.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib.event.register; 2 | 3 | import org.bukkit.event.Event; 4 | import xingchen.jslib.export.LinkageLoader; 5 | 6 | public abstract class AbstractJavaScriptPluginEvent extends Event { 7 | protected LinkageLoader linkageLoader; 8 | protected String scriptName; 9 | 10 | public AbstractJavaScriptPluginEvent(LinkageLoader linkageLoader, String scriptName) { 11 | this.linkageLoader = linkageLoader; 12 | this.scriptName = scriptName; 13 | } 14 | 15 | public LinkageLoader getLinkageLoader() { 16 | return this.linkageLoader; 17 | } 18 | 19 | public void setLinkageLoader(LinkageLoader linkageLoader) { 20 | this.linkageLoader = linkageLoader; 21 | } 22 | 23 | public String getScriptName() { 24 | return this.scriptName; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 12 | 13 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/main/resources/lib/load.js: -------------------------------------------------------------------------------- 1 | var load = null; 2 | (function() { 3 | var File = java.io.File; 4 | 5 | global.load = function (dir, name) { 6 | if(dir instanceof java.io.File && name == undefined) { 7 | return eval(dir); 8 | } 9 | 10 | if(dir == undefined || name == undefined) { 11 | name = dir || name; 12 | dir = JsLibPlugin.JavaScriptLibrary.instance.getDataFolder().getParent(); 13 | } 14 | 15 | if(typeof(dir) == "string") { 16 | dir = new File(dir); 17 | } 18 | if(typeof(name) != "string") { 19 | name = name.toString(); 20 | } 21 | 22 | var path = new File(dir, name); 23 | if(path.exists()) { 24 | if(path.isDirectory()) { 25 | var files = path.listFiles(); 26 | var result = []; 27 | for(var i in files) { 28 | result.push(global.load(files[i])); 29 | } 30 | return result; 31 | } else { 32 | return eval(path); 33 | } 34 | } 35 | 36 | return null; 37 | } 38 | })(); -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/command/CommandLoader.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib.command; 2 | 3 | import java.lang.reflect.InvocationTargetException; 4 | 5 | import org.bukkit.Bukkit; 6 | import org.bukkit.Server; 7 | import org.bukkit.command.CommandMap; 8 | 9 | import xingchen.jslib.JavaScriptLibrary; 10 | 11 | public class CommandLoader { 12 | public static CommandMap commandMap; 13 | 14 | public static JsCommand jsCommand; 15 | 16 | public static void init(JavaScriptLibrary plugin) { 17 | Server server = Bukkit.getServer(); 18 | try { 19 | commandMap = (CommandMap) server.getClass().getMethod("getCommandMap").invoke(server); 20 | } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { 21 | e.printStackTrace(); 22 | } 23 | 24 | if(commandMap == null) { 25 | return; 26 | } 27 | 28 | jsCommand = new JsCommand(); 29 | commandMap.register(plugin.getPluginName(), jsCommand); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/event/register/JavaScriptPreRegisterEvent.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib.event.register; 2 | 3 | import org.bukkit.event.Cancellable; 4 | import org.bukkit.event.HandlerList; 5 | 6 | import xingchen.jslib.export.LinkageLoader; 7 | 8 | public class JavaScriptPreRegisterEvent extends AbstractJavaScriptPluginEvent implements Cancellable { 9 | private static HandlerList handlerList = new HandlerList(); 10 | 11 | protected boolean isCancelled; 12 | 13 | public JavaScriptPreRegisterEvent(LinkageLoader linkageLoader, String scriptName) { 14 | super(linkageLoader, scriptName); 15 | } 16 | 17 | @Override 18 | public boolean isCancelled() { 19 | return this.isCancelled; 20 | } 21 | 22 | @Override 23 | public void setCancelled(boolean cancel) { 24 | this.isCancelled = cancel; 25 | } 26 | 27 | @Override 28 | public HandlerList getHandlers() { 29 | return handlerList; 30 | } 31 | 32 | public static HandlerList getHandlerList() { 33 | return handlerList; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/js/event/JavaScriptCancellableEvent.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib.js.event; 2 | 3 | import org.bukkit.event.Cancellable; 4 | import org.bukkit.event.HandlerList; 5 | 6 | /** 7 | * 实现了{#Cancellable}的事件 8 | * 见:{#JavaScriptEvent} 9 | */ 10 | public class JavaScriptCancellableEvent extends JavaScriptEvent implements Cancellable { 11 | private static HandlerList handlerList = new HandlerList(); 12 | 13 | private boolean isCancelled; 14 | 15 | public JavaScriptCancellableEvent(String name, Object object) { 16 | super(name, object); 17 | this.isCancelled = false; 18 | } 19 | 20 | @Override 21 | public HandlerList getHandlers() { 22 | return handlerList; 23 | } 24 | 25 | @Override 26 | public boolean isCancelled() { 27 | return this.isCancelled; 28 | } 29 | 30 | @Override 31 | public void setCancelled(boolean isCancelled) { 32 | this.isCancelled = isCancelled; 33 | } 34 | 35 | public static HandlerList getHandlerList() { 36 | return handlerList; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/command/EnumJsSubCommand.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib.command; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /**js命令的子命令*/ 7 | public enum EnumJsSubCommand { 8 | HELP("help", "jslib.command.help"), 9 | RUN("run", "jslib.command.run"), 10 | BOOK("book", "jslib.command.book"); 11 | 12 | public static Map lookup; 13 | 14 | private String name; 15 | private String permission; 16 | 17 | private EnumJsSubCommand(String name, String permission) { 18 | this.name = name; 19 | this.permission = permission; 20 | } 21 | 22 | public boolean isSubCommand(String arg) { 23 | return this.name.equalsIgnoreCase(arg); 24 | } 25 | 26 | public String getName() { 27 | return this.name; 28 | } 29 | 30 | public String getPermission() { 31 | return this.permission; 32 | } 33 | 34 | static { 35 | lookup = new HashMap<>(); 36 | for(EnumJsSubCommand subCommand : values()) { 37 | lookup.put(subCommand.getName(), subCommand); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/js/event/JavaScriptEvent.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib.js.event; 2 | 3 | import org.bukkit.event.Event; 4 | import org.bukkit.event.HandlerList; 5 | 6 | /** 7 | * 由于在JavaScript中继承时不能为类添加超类以外的方法,所以创建类这个类以在JavaScript中实现自定义事件 8 | */ 9 | public class JavaScriptEvent extends Event { 10 | private static HandlerList handlerList = new HandlerList(); 11 | 12 | /**事件唯一标识符(最好不要重复)*/ 13 | protected String name; 14 | /**数据对象(一般是JavaScript对象)*/ 15 | protected Object object; 16 | 17 | public JavaScriptEvent(String name, Object object) { 18 | this.name = name; 19 | this.object = object; 20 | } 21 | 22 | @Override 23 | public HandlerList getHandlers() { 24 | return handlerList; 25 | } 26 | 27 | public String getName() { 28 | return this.name; 29 | } 30 | 31 | public Object getObject() { 32 | return this.object; 33 | } 34 | 35 | public void setObject(Object object) { 36 | this.object = object; 37 | } 38 | 39 | public static HandlerList getHandlerList() { 40 | return handlerList; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/js/ScriptFiles.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib.js; 2 | 3 | import java.io.File; 4 | 5 | import javax.annotation.Nullable; 6 | 7 | import xingchen.jslib.config.ConfigManager; 8 | 9 | /** 10 | * 脚本文件信息 11 | * 包含了信息文件和代码文件 12 | */ 13 | public class ScriptFiles { 14 | /**信息文件*/ 15 | @Nullable 16 | protected File info; 17 | protected File jsFile; 18 | 19 | public ScriptFiles(File jsFile) { 20 | this(null, jsFile); 21 | } 22 | 23 | public ScriptFiles(File info, File jsFile) { 24 | this.info = info; 25 | this.jsFile = jsFile; 26 | } 27 | 28 | public File getInfo() { 29 | return this.info; 30 | } 31 | 32 | public File getJsFile() { 33 | return this.jsFile; 34 | } 35 | 36 | /** 37 | * 寻找文件夹中的信息文件,并标记 38 | * 39 | * @param directory 目标文件夹 40 | * @return 可能包含信息文件的{#ScriptFiles} 41 | */ 42 | public static ScriptFiles fromDirectory(File directory) { 43 | if(directory.exists() && directory.isDirectory()) { 44 | File info = new File(directory, ConfigManager.INFOFILENAME); 45 | if(!info.exists() || info.isDirectory()) { 46 | info = null; 47 | } 48 | return new ScriptFiles(info, directory); 49 | } 50 | 51 | return null; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/JSApi.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib; 2 | 3 | import java.io.File; 4 | 5 | import org.bukkit.plugin.Plugin; 6 | 7 | import xingchen.jslib.export.LinkageLoader; 8 | import xingchen.jslib.js.ScriptFiles; 9 | import xingchen.jslib.js.ScriptHolderBase; 10 | 11 | public class JSApi { 12 | private static JSApi instance; 13 | 14 | /** 15 | * 快速注册js 16 | * 17 | * @param plugin 注册js的插件 18 | * @param pluginJsName 插件提供的js的名字(为null则不进行插件js注册) 19 | * @param pluginJsFile 插件提供的js所在的文件夹 20 | * @param userJsName 使用者的js的名字(为null则不进行使用者js注册) 21 | * @param userJsFile 使用者的js所在的文件夹 22 | */ 23 | public void registerJavaScript(Plugin plugin, String pluginJsName, File pluginJsFile, String userJsName, File userJsFile) { 24 | if(pluginJsName != null) { 25 | LinkageLoader.instance.registerLinkage(pluginJsName, plugin, new ScriptHolderBase(new ScriptFiles[] {ScriptFiles.fromDirectory(pluginJsFile)})); 26 | } 27 | 28 | if(userJsName != null) { 29 | LinkageLoader.instance.registerLinkage(userJsName, plugin, new ScriptHolderBase(new ScriptFiles[] {ScriptFiles.fromDirectory(userJsFile)})); 30 | } 31 | } 32 | 33 | public static JSApi getApi() { 34 | return instance; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/JavaScriptLibrary.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib; 2 | 3 | import org.bukkit.plugin.ServicePriority; 4 | import org.bukkit.plugin.java.JavaPlugin; 5 | 6 | import xingchen.jslib.command.CommandLoader; 7 | import xingchen.jslib.config.ConfigManager; 8 | import xingchen.jslib.export.LinkageLoader; 9 | import xingchen.jslib.js.JavaScriptLoader; 10 | 11 | public class JavaScriptLibrary extends JavaPlugin { 12 | public static JavaScriptLibrary instance; 13 | 14 | /**插件名*/ 15 | private String pluginName; 16 | /**配置管理器对象*/ 17 | private ConfigManager config; 18 | 19 | @Override 20 | public void onEnable() { 21 | instance = this; 22 | this.pluginName = "javaScriptLibrary"; 23 | 24 | this.config = new ConfigManager(this); 25 | //EventLoader.init(this); 26 | CommandLoader.init(this); 27 | 28 | JavaScriptLoader.instance = new JavaScriptLoader(this.getClassLoader()); 29 | LinkageLoader.instance = new LinkageLoader(this); 30 | JavaScriptLoader.init(); 31 | if(this.config.isLinkage()) { 32 | this.getServer().getServicesManager().register(LinkageLoader.class, LinkageLoader.instance, this, ServicePriority.Normal); 33 | } 34 | } 35 | 36 | @Override 37 | public void onDisable() { 38 | this.getServer().getServicesManager().unregisterAll(this); 39 | } 40 | 41 | public String getPluginName() { 42 | return this.pluginName; 43 | } 44 | 45 | public ConfigManager getConfigManager() { 46 | return this.config; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/js/JavaScriptUtil.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib.js; 2 | 3 | import org.bukkit.event.Event; 4 | import org.bukkit.event.EventPriority; 5 | import org.bukkit.event.HandlerList; 6 | import org.bukkit.event.Listener; 7 | import org.bukkit.plugin.EventExecutor; 8 | import org.bukkit.plugin.Plugin; 9 | import org.bukkit.plugin.RegisteredListener; 10 | 11 | import jdk.nashorn.api.scripting.ScriptObjectMirror; 12 | 13 | /** 14 | * JavaScript工具库 15 | * 为JavaScript的使用添加了一些便捷的方法 16 | */ 17 | public class JavaScriptUtil { 18 | /** 19 | * 注册事件 20 | * 21 | * @param eventClass handlerList 可通过事件类的getHandlerList()方法获取 22 | * @param callback 当事件触发时回调的JavaScript函数 23 | * @param priority 事件优先级(低优先级的代码先执行) 24 | * @param ignoreCancelled 代码是否被已经取消的事件触发(如果事件被低优先级的取消,那高优先级的代码将不会执行) 25 | * @param key 事件监听器(每种事件只能被每个监听器注册一次) 26 | * @param plugin 注册事件的插件 27 | * @return {#EventExecutor} 28 | */ 29 | public static EventExecutor registerEvent(HandlerList handlerList, ScriptObjectMirror callback, EventPriority priority, boolean ignoreCancelled, Listener key, Plugin plugin) { 30 | EventExecutor eventExecutor = new EventExecutor() { 31 | public void execute(Listener listener, Event event) { 32 | callback.call(callback, event); 33 | } 34 | }; 35 | handlerList.register(new RegisteredListener(key, eventExecutor, priority, plugin, ignoreCancelled)); 36 | return eventExecutor; 37 | } 38 | 39 | /** 40 | * 注销事件 41 | * 42 | * @param handlerList 可通过事件类的getHandlerList()方法获取 43 | * @param key 事件监听器 44 | */ 45 | public static void removeEvent(HandlerList handlerList, Listener key) { 46 | handlerList.unregister(key); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/resources/lib/util.js: -------------------------------------------------------------------------------- 1 | /************************************************************ 2 | provide some function to simply the development 3 | 4 | variable: 5 | global: points the global scope 6 | Lib: contains function of this library 7 | eval: eval the code or the file contents 8 | Lib.getClassloader: get ClassLoader of target plugin 9 | Lib.loadType: load a class by classloader and return a JavaPackage 10 | ************************************************************/ 11 | 12 | var global = this; 13 | var Lib = {}; 14 | var JsLibPlugin = Packages.xingchen.jslib; 15 | var eval = null; 16 | (function() { 17 | var File = Packages.java.io.File; 18 | var JavaPlugin = Packages.org.bukkit.plugin.java.JavaPlugin; 19 | 20 | Lib.engine = JsLibPlugin.js.JavaScriptLoader.instance.getEngine(); 21 | global.eval = function(code) { 22 | if(code instanceof File) { 23 | JsLibPlugin.js.JavaScriptLoader.instance["eval(java.io.File)"](code); 24 | } else { 25 | JsLibPlugin.js.JavaScriptLoader.instance["eval(java.lang.String)"](code); 26 | } 27 | }; 28 | Lib.getClassloader = function(name, force) { 29 | var linkages = JsLibPlugin.export.LinkageLoader.instance.getLinkages(); 30 | if(linkages.containsKey(name) && linkages.get(name).getClassloader() != null) { 31 | return linkages.get(name).getClassloader(); 32 | } 33 | if(force == true) { 34 | var plugins = Packages.org.bukkit.Bukkit.getServer().getPluginManager().getPlugins(); 35 | for(var i in plugins) { 36 | if(plugins[i].getName() == name) { 37 | if(plugins[i] instanceof JavaPlugin) { 38 | var method = JavaPlugin.class.getDeclaredMethod("getClassLoader"); 39 | method.setAccessible(true); 40 | return method.invoke(plugins[i]); 41 | } 42 | } 43 | } 44 | } 45 | return null; 46 | } 47 | Lib.loadType = function(name, classloader) { 48 | if(classloader == undefined) { 49 | return Java.type(name); 50 | } 51 | 52 | var class_ = undefined; 53 | try { 54 | class_ = classloader.loadClass(name); 55 | } catch(e) { 56 | class_ = undefined; 57 | } 58 | if(class_ == undefined) { 59 | return Java.type(name); 60 | } else { 61 | return class_.static; 62 | } 63 | } 64 | })(); -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | xingchen 6 | JavaScriptLibraryPlugin 7 | 1.0.2 8 | 9 | JavaScriptLibraryPlugin 10 | http://maven.apache.org 11 | 12 | 13 | UTF-8 14 | 1.8 15 | 1.8 16 | JavaScriptLibraryPlugin-${project.version} 17 | 1.15.2 18 | E:\Minecraft资源库\服务器\服务端\${debug.mcversion}\plugins 19 | 20 | 21 | 22 | 23 | org.spigotmc 24 | spigot 25 | ${debug.mcversion} 26 | system 27 | E:/Minecraft资源库/服务器/核心/spigot-${debug.mcversion}.jar 28 | 29 | 30 | 31 | 32 | ${out.name} 33 | 34 | 35 | org.apache.maven.plugins 36 | maven-jar-plugin 37 | 38 | 39 | false 40 | 41 | 42 | 43 | 44 | maven-antrun-plugin 45 | 46 | 47 | copy 48 | package 49 | 50 | run 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/export/LinkageLoader.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib.export; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import org.bukkit.plugin.Plugin; 6 | 7 | import xingchen.jslib.event.register.JavaScriptPreRegisterEvent; 8 | import xingchen.jslib.js.IScriptHolder; 9 | import xingchen.jslib.event.register.JavaScriptFilesEvalledEvent; 10 | 11 | public class LinkageLoader { 12 | public static LinkageLoader instance; 13 | 14 | private Plugin plugin; 15 | 16 | private Map linkages; 17 | 18 | public LinkageLoader(Plugin plugin) { 19 | this.plugin = plugin; 20 | this.linkages = new HashMap<>(); 21 | } 22 | 23 | /*public static void create(Plugin plugin) { 24 | instance = new LinkageLoader(plugin); 25 | for(Plugin other : plugin.getServer().getPluginManager().getPlugins()) { 26 | Method method = null; 27 | try { 28 | method = other.getClass().getMethod("getJsHolder"); 29 | } catch (NoSuchMethodException | SecurityException e) { 30 | continue; 31 | } 32 | try { 33 | Object object = method.invoke(other); 34 | if(object instanceof IJsHolder) { 35 | instance.addLinkage(other, (IJsHolder) object); 36 | } 37 | } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { 38 | e.printStackTrace(); 39 | } 40 | } 41 | } 42 | 43 | public void evalAll() { 44 | this.linkages.entrySet().stream().forEach(i -> i.getValue().evalAll()); 45 | }*/ 46 | 47 | /** 48 | * 添加路径 49 | * {#IScriptHolder}实现类:{#ScriptHolderBase} 50 | * 51 | * @reture 注册是否成功 52 | */ 53 | public boolean registerLinkage(String name, Plugin plugin, IScriptHolder jsHolder, ClassLoader classLoader) { 54 | if(this.getLinkages().containsKey(name)) { 55 | return false; 56 | } 57 | 58 | JavaScriptPreRegisterEvent preEvent = new JavaScriptPreRegisterEvent(this, name); 59 | this.plugin.getServer().getPluginManager().callEvent(preEvent); 60 | if(preEvent.isCancelled()) { 61 | return false; 62 | } 63 | 64 | PluginScripts scripts = new PluginScripts(plugin, jsHolder); 65 | scripts.setClassLoader(classLoader); 66 | this.linkages.put(name, scripts); 67 | scripts.loadScripts(); 68 | scripts.evalAll(); 69 | 70 | this.plugin.getServer().getPluginManager().callEvent(new JavaScriptFilesEvalledEvent(this, name)); 71 | 72 | return true; 73 | } 74 | 75 | public boolean registerLinkage(String name, Plugin plugin, IScriptHolder jsHolder) { 76 | return registerLinkage(name, plugin, jsHolder, null); 77 | } 78 | 79 | public Plugin getPlugin() { 80 | return this.plugin; 81 | } 82 | 83 | public Map getLinkages() { 84 | return this.linkages; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/resources/lib/event.js: -------------------------------------------------------------------------------- 1 | Lib.Event = {}; 2 | (function() { 3 | Lib.Event.priority = Packages.org.bukkit.event.EventPriority; 4 | Lib.Event.createKey = function() { 5 | return new JsLibPlugin.event.EventHolder(); 6 | }; 7 | Lib.Event.defaultKey = Lib.Event.createKey(); 8 | Lib.Event.register = function(event, callback, priority_, ignoreCancelled, key, plugin) { 9 | if(priority_ == undefined) { 10 | priority_ = Lib.Event.priority.NORMAL; 11 | } 12 | if(ignoreCancelled == undefined) { 13 | ignoreCancelled = false; 14 | } 15 | if(key == undefined) { 16 | key = Lib.Event.defaultKey; 17 | } 18 | if(plugin == undefined) { 19 | plugin = JsLibPlugin.JavaScriptLibrary.instance; 20 | } 21 | 22 | var result = {}; 23 | var handlerList = event.getHandlerList(); 24 | result["listener"] = key; 25 | result["executor"] = JsLibPlugin.js.JavaScriptUtil.registerEvent(handlerList, callback, priority_, ignoreCancelled, key, plugin); 26 | result["unregister"] = function() { 27 | JsLibPlugin.js.JavaScriptUtil.removeEvent(handlerList, result["listener"]); 28 | } 29 | 30 | return result; 31 | }; 32 | Lib.Event.unregister = function(event, key) { 33 | if(key == undefined) { 34 | key = Lib.Event.defaultKey; 35 | } 36 | JsLibPlugin.js.JavaScriptUtil.removeEvent(event.getHandlerList(), key); 37 | }; 38 | Lib.Event.events = {}; 39 | Lib.Event.addDepend = function(scriptNames, callback) { 40 | var linkages = JsLibPlugin.export.LinkageLoader.instance.getLinkages(); 41 | var need = scriptNames; 42 | if(typeof(scriptNames) == "string") { 43 | var need = [scriptNames]; 44 | } 45 | 46 | for (var i in need) { 47 | if(linkages.containsKey(i) && linkages.get(i).isEvalled()) { 48 | need.splice(i, 1); 49 | } 50 | } 51 | if(need.length <= 0) { 52 | callback(); 53 | } else { 54 | if(!("jsEvalled" in Lib.Event.events)) { 55 | Lib.Event.events["jsEvalled"] = {}; 56 | Lib.Event.events["jsEvalled"].evalList = []; 57 | Lib.Event.events["jsEvalled"].event = Lib.Event.register(JsLibPlugin.event.register.JavaScriptFilesEvalledEvent, function(evt) { 58 | for(var i=0;i map) { 37 | ConfigManager config = JavaScriptLibrary.instance.getConfigManager(); 38 | String name = ConfigManager.getMainJsName(map); 39 | 40 | if(name != null) { 41 | String script = (String) map.get(name); 42 | try { 43 | this.engine.eval(script); 44 | } catch(ScriptException e2) { 45 | config.getLogger().log(Level.WARNING, "Unable to eval " + name + ".js", e2); 46 | } 47 | } 48 | } 49 | 50 | /** 51 | * 调用文件里的代码 52 | * 53 | * @param file 目标文件 54 | * @return 引擎eval方法的返回值 55 | * @throws IOException 读取文件时发生异常 56 | * @throws RuntimeException {#ScriptException} 57 | */ 58 | public Object eval(File file) throws IOException { 59 | String code = JavaScriptLibrary.instance.getConfigManager().readFrom(file); 60 | if(code != null) { 61 | return this.eval(code); 62 | } 63 | 64 | return null; 65 | } 66 | 67 | /** 68 | * 通过引擎编译并执行代码 69 | * 70 | * @param code JavaScript代码 71 | * @return 引擎eval方法的返回值 72 | * @throws RuntimeException 执行代码时出现的异常(包装了{#ScriptException}) 73 | */ 74 | public Object eval(String code) { 75 | try { 76 | return this.engine.eval(code); 77 | } catch(ScriptException e) { 78 | throw new RuntimeException(e); 79 | } 80 | } 81 | 82 | /** 83 | * 根据列表获取指定层的代码 84 | * 85 | * @param map JavaScript表 86 | * @param path 层列表 87 | * @return Object(可能为代码) 88 | */ 89 | public Object getMapCode(Map map, String[] path) { 90 | Object object = map; 91 | for(int i = 0; i < path.length; i++) { 92 | if(object instanceof Map) { 93 | object = ((Map) object).get(path[i]); 94 | } else { 95 | return null; 96 | } 97 | } 98 | return object; 99 | } 100 | 101 | public ScriptEngine getEngine() { 102 | return this.engine; 103 | } 104 | 105 | public static void init() { 106 | ConfigManager config = JavaScriptLibrary.instance.getConfigManager(); 107 | 108 | if(config.getLib() != null) { 109 | config.getLib().loadScripts(); 110 | config.getLib().evalAll(); 111 | } 112 | 113 | if(config.getScripts() != null) { 114 | config.getScripts().loadScripts(); 115 | config.getScripts().evalAll(); 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/export/PluginScripts.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib.export; 2 | 3 | import java.io.File; 4 | import java.io.FileNotFoundException; 5 | import java.io.UnsupportedEncodingException; 6 | import java.util.ArrayList; 7 | import java.util.Arrays; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.logging.Level; 11 | 12 | import org.bukkit.plugin.Plugin; 13 | 14 | import xingchen.jslib.JavaScriptLibrary; 15 | import xingchen.jslib.js.IScriptHolder; 16 | import xingchen.jslib.js.JavaScriptInfo; 17 | import xingchen.jslib.js.JavaScriptLoader; 18 | import xingchen.jslib.js.ScriptHolderBase; 19 | import xingchen.jslib.js.ScriptFiles; 20 | 21 | /** 22 | * 插件全部的JavaScript代码 23 | */ 24 | public class PluginScripts { 25 | protected Plugin plugin; 26 | protected IScriptHolder jsHolder; 27 | protected ClassLoader classLoader; 28 | 29 | /** 30 | * 结构: 31 | * [ 32 | * "KeyValue": { 33 | * "key": {#JavaScriptInfo}, 34 | * "value": {#String} / {#Map} 35 | * if value instanceof {#Map}: 36 | * "value": { 37 | * "codeName": {#String} / {#Map} 38 | * if value instanceof {#Map}:...... 39 | * } 40 | * } 41 | * ] 42 | */ 43 | protected List> scripts; 44 | protected boolean isEvalled; 45 | 46 | public PluginScripts(Plugin plugin, File... directory) { 47 | this(plugin, new ScriptHolderBase(Arrays.stream(directory).map(i -> ScriptFiles.fromDirectory(i)).filter(i -> i != null).toArray(ScriptFiles[]::new))); 48 | } 49 | 50 | public PluginScripts(Plugin plugin, IScriptHolder jsHolder) { 51 | this.plugin = plugin; 52 | this.jsHolder = jsHolder; 53 | this.scripts = new ArrayList<>(); 54 | this.isEvalled = false; 55 | } 56 | 57 | /** 58 | * 将JavaScript代码读取到内存({@link #scripts}) 59 | */ 60 | public void loadScripts() { 61 | Arrays.stream(this.jsHolder.getScriptFiles()).forEach(script -> { 62 | File file = script.getJsFile(); 63 | if(file.exists()) { 64 | Object object = JavaScriptLibrary.instance.getConfigManager().parseScriptFile(file, "js"); 65 | JavaScriptInfo info = null; 66 | if(script.getInfo() != null) { 67 | try { 68 | info = JavaScriptInfo.parse(this.plugin, script.getInfo()); 69 | } catch (UnsupportedEncodingException | FileNotFoundException e) { 70 | JavaScriptLibrary.instance.getConfigManager().getLogger().log(Level.WARNING, "Unable to parse the js info belonging to the plugin: " + this.plugin.getName(), e); 71 | return; 72 | } 73 | } 74 | 75 | scripts.add(new KeyValue<>(info, object)); 76 | } 77 | }); 78 | } 79 | 80 | /** 81 | * 编译并执行当前对象内存中的JavaScript代码(必须先通过{@link #loadScripts()}读取代码) 82 | */ 83 | public void evalAll() { 84 | this.scripts.stream().forEach(i -> { 85 | Object value = i.getValue(); 86 | if(value instanceof String) { 87 | JavaScriptLoader.instance.eval(value.toString()); 88 | } else if(value instanceof Map) { 89 | Map map = (Map) value; 90 | if(i.getKey() == null) { 91 | JavaScriptLoader.instance.evalMap(map); 92 | } else { 93 | i.getKey().invokeByOrder(map); 94 | } 95 | } 96 | }); 97 | this.isEvalled = true; 98 | } 99 | 100 | public Plugin getPlugin() { 101 | return this.plugin; 102 | } 103 | 104 | public IScriptHolder getJsHolder() { 105 | return this.jsHolder; 106 | } 107 | 108 | public void setJsHolder(IScriptHolder jsHolder) { 109 | this.jsHolder = jsHolder; 110 | } 111 | 112 | public List> getScripts() { 113 | return this.scripts; 114 | } 115 | 116 | public void setScripts(List> scripts) { 117 | this.scripts = scripts; 118 | } 119 | 120 | public ClassLoader getClassLoader() { 121 | return this.classLoader; 122 | } 123 | 124 | public void setClassLoader(ClassLoader classLoader) { 125 | this.classLoader = classLoader; 126 | } 127 | 128 | public void setEvalled(boolean evalled) { 129 | isEvalled = evalled; 130 | } 131 | 132 | public boolean isEvalled() { 133 | return this.isEvalled; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/js/JavaScriptInfo.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib.js; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.FileNotFoundException; 7 | import java.io.InputStreamReader; 8 | import java.io.UnsupportedEncodingException; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.logging.Level; 13 | 14 | import javax.script.ScriptException; 15 | 16 | import org.bukkit.plugin.Plugin; 17 | 18 | import com.google.gson.JsonArray; 19 | import com.google.gson.JsonElement; 20 | import com.google.gson.JsonObject; 21 | import com.google.gson.JsonParser; 22 | 23 | import xingchen.jslib.JavaScriptLibrary; 24 | 25 | /** 26 | * 为null时为根据默认主JavaScript名调用代码 27 | * 为EMPTY对象时不调用代码 28 | * 当名字非空时根据给定的顺序进行调用 29 | * 30 | * 例(info.json): 31 | * { 32 | * name:"名字", 33 | * order:[ 34 | * "代码文件1", 35 | * "代码文件2" 36 | * ] 37 | * } 38 | */ 39 | public class JavaScriptInfo { 40 | public static final JavaScriptInfo EMPTY = new JavaScriptInfo(null, null); 41 | 42 | protected String name; 43 | protected List invokeOrder; 44 | 45 | public JavaScriptInfo(String name, List invokeOrder) { 46 | this.name = name; 47 | this.invokeOrder = invokeOrder; 48 | } 49 | 50 | /*@Override 51 | public boolean equals(Object object) { 52 | if(this == object) { 53 | return true; 54 | } 55 | 56 | if(object instanceof JavaScriptInfo) { 57 | JavaScriptInfo info = (JavaScriptInfo) object; 58 | if(this.getName() == info.getName()) { 59 | return true; 60 | } 61 | if(this.getName() == null) { 62 | return false; 63 | } 64 | 65 | return this.getName().equals(info.getName()); 66 | } 67 | 68 | return false; 69 | } 70 | 71 | @Override 72 | public int hashCode() { 73 | if(this.name == null) { 74 | return 0; 75 | } 76 | return this.name.hashCode(); 77 | }*/ 78 | 79 | /** 80 | * 解析指定文件夹中的脚本信息文件 81 | * 82 | * @param plugin 调用该方法的插件 83 | * @param infoFile 信息文件所在的文件夹 84 | * @return 脚本信息对象 85 | */ 86 | public static JavaScriptInfo parse(Plugin plugin, File infoFile) throws UnsupportedEncodingException, FileNotFoundException { 87 | if(infoFile == null || !infoFile.exists() || infoFile.isDirectory()) { 88 | return EMPTY; 89 | } 90 | 91 | BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(infoFile), "utf-8")); 92 | 93 | JsonParser parse = new JsonParser(); 94 | JsonElement json = parse.parse(reader); 95 | if(!json.isJsonObject()) { 96 | return EMPTY; 97 | } 98 | JsonObject object = json.getAsJsonObject(); 99 | 100 | String name; 101 | if(object.has("name")) { 102 | name = object.get("name").getAsString(); 103 | } else { 104 | name = plugin.getName(); 105 | } 106 | 107 | List invokeOrder = new ArrayList<>(); 108 | if(object.has("order") && object.get("order").isJsonArray()) { 109 | JsonArray array = object.get("order").getAsJsonArray(); 110 | for(int i = 0; i < array.size(); i++) { 111 | invokeOrder.add(array.get(i).getAsString()); 112 | } 113 | } 114 | 115 | return new JavaScriptInfo(name, invokeOrder); 116 | } 117 | 118 | /** 119 | * 按照信息对象上的顺序调用JavaScript代码 120 | * 121 | * @param map JavaScript代码表 122 | */ 123 | public void invokeByOrder(Map map) { 124 | if(this == EMPTY) { 125 | return; 126 | } 127 | 128 | this.invokeOrder.stream().forEach(i -> { 129 | String code = null; 130 | if(i.lastIndexOf("/") >= 0) { 131 | Object object = JavaScriptLoader.instance.getMapCode(map, i.split("/")); 132 | if(object != null) { 133 | code = (String) object; 134 | } 135 | } else if(map.get(i) instanceof String) { 136 | code = (String) map.get(i); 137 | } 138 | 139 | if(code != null) { 140 | try { 141 | JavaScriptLoader.instance.getEngine().eval(code); 142 | } catch(ScriptException e2) { 143 | JavaScriptLibrary.instance.getConfigManager().getLogger().log(Level.WARNING, "Unable to eval " + i + ".js", e2); 144 | } 145 | } 146 | }); 147 | } 148 | 149 | public String getName() { 150 | return this.name; 151 | } 152 | 153 | public List getInvokeOrder() { 154 | return this.invokeOrder; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/command/JsCommand.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib.command; 2 | 3 | import java.util.Arrays; 4 | import java.util.logging.Level; 5 | import java.util.regex.Pattern; 6 | import java.util.stream.Collectors; 7 | import java.util.stream.IntStream; 8 | 9 | import javax.script.ScriptContext; 10 | import javax.script.ScriptException; 11 | import javax.script.SimpleScriptContext; 12 | 13 | import org.bukkit.ChatColor; 14 | import org.bukkit.command.Command; 15 | import org.bukkit.command.CommandSender; 16 | import org.bukkit.entity.Player; 17 | import org.bukkit.inventory.ItemStack; 18 | import org.bukkit.inventory.meta.BookMeta; 19 | import org.bukkit.inventory.meta.ItemMeta; 20 | 21 | import jdk.nashorn.api.scripting.ScriptObjectMirror; 22 | import jdk.nashorn.internal.runtime.Undefined; 23 | import xingchen.jslib.JavaScriptLibrary; 24 | import xingchen.jslib.js.JavaScriptLoader; 25 | 26 | public class JsCommand extends Command { 27 | public static final String CODEWRAP = "function(me) {%s}"; 28 | public static final Pattern UNCOLOR = Pattern.compile("§."); 29 | 30 | public static final String COMMANDTIP = "§2请使用 §6/js help §2来查看帮助"; 31 | public static final String ONLYPLAYER = "§4只有玩家才能使用此命令"; 32 | public static final String UNABLE = "§4此命令未开启"; 33 | 34 | public JsCommand() { 35 | super("javascriptlib", "Command of JavaScriptLibrary plugin", "/js help", Arrays.asList("javascript", "js")); 36 | } 37 | 38 | @Override 39 | public boolean execute(CommandSender sender, String capital, String[] args) { 40 | if(args.length <= 0 || "help".equalsIgnoreCase(args[0])) { 41 | this.sendHelp(sender); 42 | } else { 43 | String subcommand = args[0].toLowerCase(); 44 | if(EnumJsSubCommand.RUN.isSubCommand(subcommand)) { 45 | if(!JavaScriptLibrary.instance.getConfigManager().getCommandRunState()) { 46 | sender.sendMessage(UNABLE); 47 | return true; 48 | } 49 | if(args.length >= 2) { 50 | String code = IntStream.range(1, args.length).mapToObj(i -> args[i]).collect(Collectors.joining(" ")); 51 | this.eval(sender, code); 52 | } 53 | } else if(EnumJsSubCommand.BOOK.isSubCommand(subcommand)) { 54 | if(!JavaScriptLibrary.instance.getConfigManager().getCommandBookState()) { 55 | sender.sendMessage(UNABLE); 56 | return true; 57 | } 58 | if(sender instanceof Player) { 59 | Player player = (Player) sender; 60 | ItemStack itemStack = player.getEquipment().getItemInMainHand(); 61 | if(itemStack != null && itemStack.hasItemMeta()) { 62 | ItemMeta meta = itemStack.getItemMeta(); 63 | if(meta instanceof BookMeta) { 64 | StringBuilder sb = new StringBuilder(); 65 | BookMeta bookmeta = (BookMeta) meta; 66 | bookmeta.getPages().stream().forEach(i -> sb.append(ChatColor.stripColor(i))); 67 | String code = sb.toString(); 68 | if(code != null && !code.isEmpty()) { 69 | this.eval(player, code); 70 | } 71 | } else { 72 | sender.sendMessage("§4手上的物品不是代码书"); 73 | } 74 | } else { 75 | sender.sendMessage("§4手上的物品不是代码书"); 76 | } 77 | } else { 78 | sender.sendMessage(ONLYPLAYER); 79 | } 80 | } else { 81 | sender.sendMessage(COMMANDTIP); 82 | } 83 | } 84 | 85 | return true; 86 | } 87 | 88 | public void eval(CommandSender sender, String code) { 89 | try { 90 | Object function = JavaScriptLoader.instance.getEngine().eval(String.format(CODEWRAP, code)); 91 | if(function != null && function instanceof ScriptObjectMirror) { 92 | Object back = ((ScriptObjectMirror) function).call(function, sender); 93 | if(back != null && back != Undefined.getUndefined()) { 94 | sender.sendMessage(back.toString()); 95 | } 96 | } 97 | } catch (ScriptException e) { 98 | JavaScriptLibrary.instance.getConfigManager().getLogger().log(Level.WARNING, "Unable to eval javascript code: " + code, e); 99 | sender.sendMessage("§4在执行此js代码时出错"); 100 | sender.sendMessage(e.getMessage()); 101 | } 102 | } 103 | 104 | public void buildCommandJsLib(CommandSender sender, ScriptContext context) { 105 | context.setAttribute("me", sender, SimpleScriptContext.ENGINE_SCOPE); 106 | } 107 | 108 | public void sendHelp(CommandSender sender) { 109 | if(sender.hasPermission(EnumJsSubCommand.HELP.getPermission())) { 110 | sender.sendMessage(new String[] { 111 | " ", 112 | "§2§l/js run §6运行一段js代码", 113 | "§2§l/js book §6运行主手上拿着的书里的js代码", 114 | " " 115 | }); 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/xingchen/jslib/config/ConfigManager.java: -------------------------------------------------------------------------------- 1 | package xingchen.jslib.config; 2 | 3 | import java.io.BufferedInputStream; 4 | import java.io.BufferedReader; 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.IOException; 8 | import java.io.InputStreamReader; 9 | import java.net.URL; 10 | import java.util.ArrayList; 11 | import java.util.Arrays; 12 | import java.util.HashMap; 13 | import java.util.LinkedList; 14 | import java.util.List; 15 | import java.util.Map; 16 | import java.util.jar.JarInputStream; 17 | import java.util.logging.Level; 18 | import java.util.logging.Logger; 19 | import java.util.stream.Collectors; 20 | import java.util.zip.ZipEntry; 21 | 22 | import org.bukkit.configuration.ConfigurationSection; 23 | import org.bukkit.configuration.file.FileConfiguration; 24 | import org.bukkit.plugin.Plugin; 25 | 26 | import xingchen.jslib.JavaScriptLibrary; 27 | import xingchen.jslib.export.PluginScripts; 28 | 29 | /** 30 | * 配置管理器 31 | */ 32 | public class ConfigManager { 33 | /**脚本信息文件名*/ 34 | public static final String INFOFILENAME = "info.json"; 35 | public static List MAINJSNAME = new ArrayList<>(); 36 | 37 | private Plugin plugin; 38 | private Logger logger; 39 | 40 | private FileConfiguration configFile; 41 | 42 | /**run子命令是否开启*/ 43 | private boolean commandRun; 44 | /**book子命令是否开启*/ 45 | private boolean commandBook; 46 | /**是否开启和其他插件的联动*/ 47 | private boolean linkage; 48 | 49 | /**支持库代码*/ 50 | private PluginScripts libraries; 51 | /**用户代码*/ 52 | private PluginScripts scripts; 53 | 54 | public ConfigManager(Plugin plugin) { 55 | this.plugin = plugin; 56 | this.logger = plugin.getLogger(); 57 | if(!this.checkCongig("config.yml")) { 58 | this.logger.info("配置文件未创建,正在创建..."); 59 | plugin.saveDefaultConfig(); 60 | } else { 61 | this.logger.info("配置文件已经创建,开始加载..."); 62 | } 63 | 64 | this.checkLibraries(); 65 | this.configFile = this.plugin.getConfig(); 66 | 67 | Object command = this.configFile.get("command"); 68 | if(command instanceof ConfigurationSection) { 69 | ConfigurationSection commandCS = (ConfigurationSection) command; 70 | this.commandRun = commandCS.getBoolean("run", false); 71 | this.commandBook = commandCS.getBoolean("book", false); 72 | } else if(command instanceof Boolean) { 73 | this.setAllCommand(((Boolean)command).booleanValue()); 74 | } else { 75 | this.setAllCommand(false); 76 | } 77 | 78 | //加载支持库和用户代码 79 | this.linkage = this.configFile.getBoolean("linkage", false); 80 | this.libraries = this.loadScript("lib"); 81 | if(this.libraries != null) { 82 | this.scripts = this.loadScript("scripts"); 83 | } else { 84 | this.logger.info("发现js支持库损坏。"); 85 | this.logger.info("请删除原支持库后重新启动。插件将会自动修复。"); 86 | } 87 | } 88 | 89 | /** 90 | * 读取文件中的内容 91 | * 92 | * @param file 目标文件 93 | * 94 | * @return 文件中的内容(如果文件不存在或者为文件夹,则返回null) 95 | * 96 | * @exception IOException 如果文件读取时出现异常 97 | */ 98 | public String readFrom(File file) throws IOException { 99 | if(file.exists() && !file.isDirectory()) { 100 | BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "utf-8")); 101 | LinkedList stringList = new LinkedList<>(); 102 | 103 | String line; 104 | while((line = reader.readLine()) != null) { 105 | stringList.add(line); 106 | } 107 | 108 | reader.close(); 109 | return stringList.stream().collect(Collectors.joining("\n")); 110 | } 111 | 112 | return null; 113 | } 114 | 115 | /** 116 | * 根据{@link ConfigManager#MAINJSNAME}中的顺序,获取代码表中的主脚本名 117 | */ 118 | public static String getMainJsName(Map map) { 119 | for(int i=0;i checkLibrary(target, dir, name + File.separator + i.getName())); 166 | } else { 167 | this.saveLibrary(target, name); 168 | } 169 | } 170 | }*/ 171 | 172 | /** 173 | * 检查并修复支持库文件 174 | */ 175 | public void checkLibraries() { 176 | try { 177 | JarInputStream jarZip = new JarInputStream(new BufferedInputStream(this.getJarURL().openStream())); 178 | ZipEntry entry; 179 | while((entry = jarZip.getNextEntry()) != null) { 180 | if(!entry.isDirectory() && entry.getName().startsWith("lib/")) { 181 | this.saveLibrary(this.plugin.getDataFolder(), entry.getName()); 182 | } 183 | } 184 | jarZip.close(); 185 | } catch (IOException e) { 186 | this.logger.log(Level.SEVERE, "Failed to check JavaScript Libraries.", e); 187 | } 188 | } 189 | 190 | /** 191 | * 加载用户插件 192 | */ 193 | public PluginScripts loadScript(String fileName) { 194 | File file = new File(this.plugin.getDataFolder(), fileName); 195 | if(file.exists()) { 196 | return new PluginScripts(this.plugin, new File[] {file}); 197 | } 198 | 199 | return null; 200 | } 201 | 202 | /** 203 | * 解析脚本文件,并返回其代码 204 | * 205 | * @param file 目标文件 206 | * @param suffix 脚本文件扩展名 207 | * 208 | * @return 如果文件为文件夹,则返回{#Map},否则返回{#String} 209 | */ 210 | public Object parseScriptFile(File file, String suffix) { 211 | if(file.isDirectory()) { 212 | HashMap map = new HashMap<>(); 213 | Arrays.stream(file.listFiles()).forEach(i -> { 214 | Object script = this.parseScriptFile(i, suffix); 215 | if(script != null && (!(script instanceof Map) || !((Map) script).isEmpty())) { 216 | String fileName = i.getName(); 217 | if(i.isDirectory()) { 218 | map.put(fileName, script); 219 | } else { 220 | int lastp = fileName.lastIndexOf("."); 221 | if(suffix.equalsIgnoreCase(fileName.substring(lastp + 1))) { 222 | String name = fileName.substring(0, lastp); 223 | map.put(name, script); 224 | } 225 | } 226 | } 227 | }); 228 | 229 | return map; 230 | } else { 231 | String name = file.getName(); 232 | if(suffix.equalsIgnoreCase(name.substring(name.lastIndexOf(".") + 1))) { 233 | try { 234 | return this.readFrom(file); 235 | } catch (IOException e) { 236 | e.printStackTrace(); 237 | } 238 | } 239 | 240 | return null; 241 | } 242 | } 243 | 244 | public Plugin getPlugin() { 245 | return this.plugin; 246 | } 247 | 248 | public void setPlugin(Plugin plugin) { 249 | this.plugin = plugin; 250 | } 251 | 252 | public Logger getLogger() { 253 | return this.logger; 254 | } 255 | 256 | public void setLogger(Logger logger) { 257 | this.logger = logger; 258 | } 259 | 260 | public FileConfiguration getConfigFile() { 261 | return this.configFile; 262 | } 263 | 264 | public void setConfigFile(FileConfiguration configFile) { 265 | this.configFile = configFile; 266 | } 267 | 268 | public void setAllCommand(boolean state) { 269 | this.commandRun = state; 270 | this.commandBook = state; 271 | } 272 | 273 | public boolean getCommandRunState() { 274 | return this.commandRun; 275 | } 276 | 277 | public void setCommandRunState(boolean commandRun) { 278 | this.commandRun = commandRun; 279 | } 280 | 281 | public boolean getCommandBookState() { 282 | return this.commandBook; 283 | } 284 | 285 | public void setCommandBookState(boolean commandBook) { 286 | this.commandBook = commandBook; 287 | } 288 | 289 | public boolean isLinkage() { 290 | return this.linkage; 291 | } 292 | 293 | public void setLinkage(boolean linkage) { 294 | this.linkage = linkage; 295 | } 296 | 297 | public PluginScripts getScripts() { 298 | return this.scripts; 299 | } 300 | 301 | public void setScripts(PluginScripts scripts) { 302 | this.scripts = scripts; 303 | } 304 | 305 | public PluginScripts getLib() { 306 | return this.libraries; 307 | } 308 | 309 | static { 310 | MAINJSNAME.add("main"); 311 | MAINJSNAME.add("root"); 312 | } 313 | } 314 | --------------------------------------------------------------------------------