From d0b43487c28450959678e0d582e2d905b2689612 Mon Sep 17 00:00:00 2001 From: 502647092 Date: Tue, 10 Oct 2017 21:01:43 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20Console=20?= =?UTF-8?q?=E5=92=8C=20reflect=20=E9=83=A8=E5=88=86=E5=AE=8C=E5=96=84=20co?= =?UTF-8?q?mmand?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 502647092 --- .../java/pw/yumc/MiaoScript/MiaoScript.java | 2 +- src/main/resources/bios.js | 3 +- src/main/resources/core/console.js | 21 ++++ src/main/resources/core/ext.js | 2 +- src/main/resources/core/fs.js | 2 +- src/main/resources/core/init.js | 3 +- src/main/resources/core/require.js | 114 ++++++++++------- src/main/resources/core/static.js | 24 ---- src/main/resources/kit/reflect.js | 119 ++++++++++++++++++ src/main/resources/modules/command.js | 45 +++++++ src/main/resources/modules/event.js | 2 +- src/main/resources/modules/plugin.js | 32 +++-- .../{modules => plugins}/ext/papi.js | 0 src/main/resources/plugins/hello.js | 7 +- 14 files changed, 281 insertions(+), 95 deletions(-) create mode 100644 src/main/resources/core/console.js delete mode 100644 src/main/resources/core/static.js create mode 100644 src/main/resources/kit/reflect.js rename src/main/resources/{modules => plugins}/ext/papi.js (100%) diff --git a/src/main/java/pw/yumc/MiaoScript/MiaoScript.java b/src/main/java/pw/yumc/MiaoScript/MiaoScript.java index 3c6899a..509cd32 100644 --- a/src/main/java/pw/yumc/MiaoScript/MiaoScript.java +++ b/src/main/java/pw/yumc/MiaoScript/MiaoScript.java @@ -58,7 +58,7 @@ public class MiaoScript extends JavaPlugin implements Executor { } private void saveScript() { - P.saveFile(true, "core", "modules", "plugins"); + P.saveFile(true, "core", "modules", "kit"); } private void loadEngine() { diff --git a/src/main/resources/bios.js b/src/main/resources/bios.js index 5a7994a..a3d4289 100644 --- a/src/main/resources/bios.js +++ b/src/main/resources/bios.js @@ -18,7 +18,8 @@ var disable; } catch (ex) { log.w("MiaoScript 初始化失败! %s", ex); throw ex; + } finally { + disable = disablePlugins } - disable = disablePlugins }; })(); \ No newline at end of file diff --git a/src/main/resources/core/console.js b/src/main/resources/core/console.js new file mode 100644 index 0000000..5d30d86 --- /dev/null +++ b/src/main/resources/core/console.js @@ -0,0 +1,21 @@ +/** + * 控制台输出类 + */ +/*global base*/ +var log = base.getLog().static; +var Level = Java.type('java.util.logging.Level'); +var console = { + log: function () { + log.i(arguments.join(' ')); + }, + warn: function () { + log.w(arguments.join(' ')); + }, + error: function () { + log.log(Level.SEVERE, arguments.join(' ')); + }, + debug: function () { + log.d(arguments.join(' ')); + } +}; +global.console = console; \ No newline at end of file diff --git a/src/main/resources/core/ext.js b/src/main/resources/core/ext.js index da9b561..5bed8a5 100644 --- a/src/main/resources/core/ext.js +++ b/src/main/resources/core/ext.js @@ -10,7 +10,7 @@ var ext = {}; * @returns {*} */ ext.getStatic = function (name) { - return base.getClass(name).static; + return base.class(name).static; }; /** * 获得随机数 diff --git a/src/main/resources/core/fs.js b/src/main/resources/core/fs.js index a6d0a6f..5d82b65 100644 --- a/src/main/resources/core/fs.js +++ b/src/main/resources/core/fs.js @@ -96,7 +96,7 @@ exports.list = function (path) { if (dir.isDirectory()) { return Files.list(dir.toPath()); } - log.w("路径 %s 不是一个目录 返回空数组!"); + log.w("路径 %s 不是一个目录 返回空数组!", path); return []; }; /** diff --git a/src/main/resources/core/init.js b/src/main/resources/core/init.js index 3e9b226..ea56c94 100644 --- a/src/main/resources/core/init.js +++ b/src/main/resources/core/init.js @@ -30,7 +30,6 @@ function initDir() { function loadCore() { // 加载基础模块 load(core_dir + '/ext.js'); - load(core_dir + '/static.js'); load(core_dir + '/console.js'); } @@ -39,7 +38,7 @@ function loadCore() { */ function loadRequire() { // 初始化加载器 - global.require = load(core_dir + '/require.js')(root, core_dir, miao_module_dir); + global.require = load(core_dir + '/require.js')(root); } function loadLib4Bukkit() { diff --git a/src/main/resources/core/require.js b/src/main/resources/core/require.js index 6816e93..031e6c2 100644 --- a/src/main/resources/core/require.js +++ b/src/main/resources/core/require.js @@ -3,7 +3,7 @@ * */ /*global Java, base*/ -(function (parent, core_dir, miao_module_dir) { +(function (parent) { 'use strict'; var File = Java.type("java.io.File"); @@ -16,35 +16,37 @@ * 模块目录 /modules * @param name 模块名称 */ - function findModule(name) { + function resolve(name) { if (_canonical(name)) { name = _canonical(name); } - // 如果不是 .js 结尾就加上 - if (!name.match(/.*\.js/)) { - name += ".js"; + name = normalizeName(name, '.js'); + return resolveAsFile(parent, name) || + resolveAsFile(name) || + resolveAsFile(core_dir, name) || + resolveAsFile(miao_module_dir, name) || + undefined; + } + + /** + * 解析文件 + * @constructor(file) + * @constructor(dir,file) + * @returns {*} + */ + function resolveAsFile() { + var file = arguments.length > 1 ? new File(arguments[0], arguments[1]) : new File(arguments[0]); + if (file.exists()) { + return file; } - var jsFile = new File(name); - if (jsFile.exists()) { - return jsFile; + } + + function normalizeName(fileName, ext) { + var extension = ext || '.js'; + if (fileName.endsWith(extension)) { + return fileName; } - var parentFile = new File(parent, name); - if (parentFile.exists()) { - return parentFile; - } - var coreFile = new File(core_dir, name); - if (coreFile.exists()) { - return coreFile; - } - var moduleFile = new File(miao_module_dir, name); - if (moduleFile.exists()) { - return moduleFile; - } - log.w("模块 %s 加载失败! 下列目录中未找到该模块!", name); - log.w("当前目录: %s", _canonical(jsFile)); - log.w("上级目录: %s", _canonical(parentFile)); - log.w("核心目录: %s", _canonical(coreFile)); - log.w("模块目录: %s", _canonical(moduleFile)); + return fileName + extension; } /** @@ -55,11 +57,43 @@ function compileJs(file) { var cacheFile = _cacheFile(file); base.save(cacheFile, "(function (module, exports, require) {" + base.read(file) + "});"); + // 使用 load 可以保留行号和文件名称 var obj = load(cacheFile); base.delete(cacheFile); return obj; } + /** + * 编译模块 + * @param id + * @param name + * @param file + * @returns {Object} + */ + function compileModule(id, name, file) { + log.d('加载模块 %s 位于 %s', name, id); + // noinspection JSUnresolvedVariable + var module = { + id: id, + exports: {}, + loaded: false, + require: exports(file.parentFile) + }; + try { + // 预编译模块 + var compiledWrapper = compileJs(file); + compiledWrapper.apply(module.exports, [ + module, module.exports, module.require + ]); + log.d('模块 %s 编译成功!', name); + module.loaded = true; + } catch (ex) { + log.w("模块 %s 编译失败!", name); + log.d(ex); + } + return module; + } + /** * 获得文件规范路径 * @param file @@ -83,7 +117,11 @@ * @private */ function _require(name, path) { - var file = findModule(name, path); + var file = resolve(name, path); + if (file === undefined) { + log.w("模块 %s 加载失败! 未找到该模块!", name); + return; + } // 重定向文件名称 name = file.name.split(".")[0]; var id = _canonical(file); @@ -91,27 +129,7 @@ if (module) { return module; } - log.d('加载模块 %s 位于 %s', name, id); - // noinspection JSUnresolvedVariable - module = { - loaded: false, - id: id, - exports: {}, - require: exports(file.parentFile) - }; - try { - // 预编译模块 - var compiledWrapper = compileJs(file); - compiledWrapper.apply(module.exports, [ - module, module.exports, module.require - ]); - log.d('模块 %s 编译成功!', name); - module.loaded = true; - } catch (ex) { - log.w("模块 %s 编译失败!", name); - log.d(ex); - } - cacheModules[id] = module; + cacheModules[id] = module = compileModule(id, name, file); return module; } @@ -126,7 +144,7 @@ }; } - var cacheDir = parent + "/cache"; + var cacheDir = parent + "/runtime"; // 等于 undefined 说明 parent 是一个字符串 需要转成File // 可能有更加准确的方案 diff --git a/src/main/resources/core/static.js b/src/main/resources/core/static.js deleted file mode 100644 index 6256b03..0000000 --- a/src/main/resources/core/static.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * 基础静态类 - * Created by 蒋天蓓 on 2017/2/9 0009. - */ -/** - * 日志类 - */ -var log = base.getLog().static; -/** - * ActionBar类 - */ -var actionbar = base.getActionBar().static; -/** - * Title类 - */ -var title = base.getTitle().static; -/** - * 玩家兼容类 - */ -var cplayer = base.getPlayer().static; -/** - * 工具类 - */ -var mctools = base.getTools().static; \ No newline at end of file diff --git a/src/main/resources/kit/reflect.js b/src/main/resources/kit/reflect.js new file mode 100644 index 0000000..1d00434 --- /dev/null +++ b/src/main/resources/kit/reflect.js @@ -0,0 +1,119 @@ +'use strict'; +/** + * 反射工具类 + * Created by 蒋天蓓 on 2017/2/9 0009. + */ + +/*global Java, base, module, exports, require, __FILE__*/ +var Class = Java.type('java.lang.Class'); +var NoSuchFieldException = Java.type('java.lang.NoSuchFieldException'); + +function Reflect(obj) { + this.obj = obj; + this.class = obj instanceof Class ? obj : obj.class; +} + +/** + * Get an array of types for an array of objects + */ +function types(values) { + if (values === null) { + return []; + } + var result = []; + values.forEach(function (t) { + result.push(t === null ? Object.class : t.class) + }); + return result; +} + +function accessible(accessible) { + if (accessible === null) { + return null; + } + if (!accessible.isAccessible()) { + accessible.setAccessible(true); + } + return accessible; +} + +function declaredConstructor() { + return accessible(arguments[0].declaredConstructor(arguments.slice(1))); +} + +function declaredField(clazz, name) { + var field = null; + // noinspection JSUnresolvedVariable + while (clazz !== java.lang.Object.class) { + try { + field = clazz.declaredField(name); + if (field !== null) { + break; + } + } catch (e) { + clazz = clazz.superclass(); + } + } + if (field === null) { + throw new NoSuchFieldException(name + " is not found in " + clazz.name); + } + return field; +} + +Reflect.field = function (name) { + try { + // Try getting a public field + var field = this.class.field(name); + return on(field.get(this.obj)); + } catch (ex) { + // Try again, getting a non-public field + try { + return on(accessible(declaredField(this.class, name)).get(this.obj)); + } catch (ex) { + throw new NoSuchFieldException(ex); + } + } +}; + +Reflect.method = function () { + var name = arguments[0]; + var clazzs = arguments.slice(1); + try { + return this.class.method(name, clazzs); + } catch (ex) { + return this.class.declaredMethod(name, clazzs); + } +}; + +var methodCache = []; + +Reflect.cacheMethod = function () { + var name = arguments[0]; + var mkey = this.class.name + '.' + name; + if (!methodCache[mkey]) { + methodCache[mkey] = this.method(name, arguments.slice(1)); + } + return methodCache[mkey]; +}; + +Reflect.call = function () { + var name = arguments[0]; + var params = arguments.slice(1); + var method = this.method(name, types(params)); + return exports.on(method.invoke(this.get(), params)); +}; + +Reflect.get = function () { + return arguments.length === 1 ? this.field(arguments[0]) : this.obj; +}; + +Reflect.create = function () { + return on(declaredConstructor(this.class, arguments).newInstance(arguments)); +}; + +function on(obj) { + return new Reflect(obj); +} + +exports.on = on; +exports.accessible = accessible; \ No newline at end of file diff --git a/src/main/resources/modules/command.js b/src/main/resources/modules/command.js index be79e42..760d4d3 100644 --- a/src/main/resources/modules/command.js +++ b/src/main/resources/modules/command.js @@ -2,4 +2,49 @@ /** * Bukkit 命令相关类 */ + /*global Java, base, module, exports, require, __FILE__*/ +var plugin = base.plugin; +var bukkit = require('bukkit'); +var ref = require('kit/reflect'); +var lookupNames = ref.on(bukkit.plugin.manager).get('lookupNames').get(); +var knownCommands = ref.on(bukkit.plugin.manager).get('commandMap').get('knownCommands').get(); +var PluginCommand = Java.type('org.bukkit.command.PluginCommand'); + +function create(jsp, name) { + var cmd = ref.on(PluginCommand).create(name, plugin).get(); + register(jsp, name, cmd); +} + +function register(jsp, name, cmd) { + if (name.isEmpty()) { + return; + } + knownCommands.put(name, cmd); + knownCommands.computeIfAbsent(jsp.description.name + ":" + name, function () { + return cmd; + }); + knownCommands.computeIfAbsent('ms:' + jsp.description.name + ":" + name, function () { + return cmd; + }); + lookupNames.put(name, plugin); +} + +// var exec = { +// onCommand: function (sender, cmd, command, args) { +// +// }, +// onTabComplete: function (sender, cmd, command, args) { +// +// } +// }; + +exports.on = function (plugin, name, exec) { + var c = create(plugin, name); + if (exec.onCommand) { + c.setExecutor(exec); + } + if (exec.onTabComplete) { + c.setTabCompleter(exec); + } +}; \ No newline at end of file diff --git a/src/main/resources/modules/event.js b/src/main/resources/modules/event.js index 70ce3de..3fd8fc8 100644 --- a/src/main/resources/modules/event.js +++ b/src/main/resources/modules/event.js @@ -80,7 +80,7 @@ function listen(event, exec, priority, ignoreCancel) { try { eventCls = base.getClass(eventCls); } catch (ex) { - log.w("事件 %s 未找到!"); + log.w("事件 %s 未找到!", event); return; } } diff --git a/src/main/resources/modules/plugin.js b/src/main/resources/modules/plugin.js index 4a51132..84448e5 100644 --- a/src/main/resources/modules/plugin.js +++ b/src/main/resources/modules/plugin.js @@ -11,15 +11,19 @@ var fs = require('core/fs'); * @param path */ function loadPlugins(path) { - path = fs.file(path); - log.i("开始扫描 %s 下的插件...", path); - updatePlugins(path); - var files = []; - fs.list(path).forEach(function (file) { - files.push(file.toFile()); - }); - loadZipPlugin(files); - loadJsPlugin(files); + var plugin = fs.file(path); + if (!plugin) { + log.i("首次加载 创建文件夹 %s ...", path); + } else { + log.i("开始扫描 %s 下的插件 ...", path); + updatePlugins(path); + var files = []; + fs.list(path).forEach(function (file) { + files.push(file.toFile()); + }); + loadZipPlugin(files); + loadJsPlugin(files); + } } /** @@ -28,9 +32,13 @@ function loadPlugins(path) { */ function updatePlugins(path) { var update = fs.file(path, "update"); - fs.list(update).forEach(function (file) { - fs.move(fs.file(update, file.name), fs.file(path, file.name), true); - }) + if (!update.exists()) { + update.mkdirs(); + } else { + fs.list(update).forEach(function (file) { + fs.move(fs.file(update, file.name), fs.file(path, file.name), true); + }) + } } /** diff --git a/src/main/resources/modules/ext/papi.js b/src/main/resources/plugins/ext/papi.js similarity index 100% rename from src/main/resources/modules/ext/papi.js rename to src/main/resources/plugins/ext/papi.js diff --git a/src/main/resources/plugins/hello.js b/src/main/resources/plugins/hello.js index 814cfb3..2bc1940 100644 --- a/src/main/resources/plugins/hello.js +++ b/src/main/resources/plugins/hello.js @@ -4,7 +4,6 @@ */ /*global Java, base, module, exports, require*/ -var papi = require("modules/ext/papi"); var event = require('modules/event'); var join; @@ -14,17 +13,17 @@ var description = { }; function load() { - log.i('载入 Hello Wrold 测试插件!'); + console.log('载入 Hello Wrold 测试插件!'); } function enable() { - log.i('启用 Hello Wrold 测试插件!'); + console.log('启用 Hello Wrold 测试插件!'); join = event.on('playerloginevent', function join(event) { // noinspection JSUnresolvedVariable log.d('玩家 %s 触发事件 %s', event.player.name, event.name); setTimeout(function () { // noinspection JSUnresolvedVariable - event.player.sendMessage(papi.$(event.player, "§a欢迎来到 §bMiaoScript §a的世界! 当前在线: %server_online%")); + event.player.sendMessage(require("plugins/ext/papi").$(event.player, "§a欢迎来到 §bMiaoScript §a的世界! 当前在线: %server_online%")); }, 10); }); }