From 5ca2c2b02feb84a4f8a8fccc95ff94c4e79ba854 Mon Sep 17 00:00:00 2001 From: coding Date: Thu, 16 Nov 2017 12:28:18 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8E=BB=E9=99=A4Object=E7=9A=84?= =?UTF-8?q?=E6=89=A9=E5=B1=95=E6=96=B9=E6=B3=95=20=E5=87=8F=E5=B0=91?= =?UTF-8?q?=E5=86=B2=E7=AA=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/api/plugin.js | 260 ++++++++++++++++++++++++++- src/main/resources/bios.js | 11 +- src/main/resources/core/ext/patch.js | 19 +- src/main/resources/core/init.js | 1 - 4 files changed, 273 insertions(+), 18 deletions(-) diff --git a/src/main/resources/api/plugin.js b/src/main/resources/api/plugin.js index 628f5d1..1d23ad5 100644 --- a/src/main/resources/api/plugin.js +++ b/src/main/resources/api/plugin.js @@ -1,2 +1,258 @@ -/*global Java, base, module, exports, require*/ -module.exports = require('./mserver').plugin; \ No newline at end of file +'use strict'; +/** + * MiaoScript脚本插件加载类 + */ +/*global Java, base, module, exports, require, __FILE__*/ +// var zip = require("core/zip"); +var fs = require('core/fs'); +var yaml = require('modules/yaml'); +var event = require('./event'); +var bukkit = require('./server'); +var command = require('./command'); +var permission = require('./permission'); + +/** + * 载入插件 + * @param dir + */ +function loadPlugins(dir) { + var plugin = fs.file(root, dir); + if (!plugin) { + console.info("首次加载 创建文件夹 %s ...".format(plugin)); + } else { + console.info("开始扫描 %s 下的插件 ...".format(plugin)); + createUpdate(plugin); + var files = []; + fs.list(plugin).forEach(function (file) { + files.push(file.toFile()); + }); + loadZipPlugins(files); + loadJsPlugins(files); + } +} + +/** + * 更新插件 + * @param path + */ +function createUpdate(path) { + var update = fs.file(path, "update"); + if (!update.exists()) { + update.mkdirs(); + } +} + +/** + * ZIP类型插件预加载 + * @param files + */ +function loadZipPlugins(files) { + // // TODO ZIP类型插件加载 + // files.filter(function (file) { + // return file.name.endsWith(".zip"); + // }).forEach(function (file) { + // zip.unzip(fs.file(plugins_dir, file)); + // var dir = new File(plugins_dir, file.name.split(".")[0]); + // // TODO 添加文件夹类型的插件兼容 + // }); +} + +/** + * JS类型插件预加载 + */ +function loadJsPlugins(files) { + files.filter(function (file) { + return file.name.endsWith(".js") + }).forEach(function (file) { + loadPlugin(file); + }) +} + +function loadPlugin(file) { + var update = fs.file(fs.file(file.parentFile, 'update'), file.name); + if (update.exists()) { + console.info('自动升级插件 %s'.format(file.name)); + fs.move(update, file, true); + } + var plugin = require(file, { + cache: false, + hook: function (origin) { + return beforeLoadHook(origin); + } + }); + console.debug("插件编译结果: %s".format(JSON.stringify(plugin))); + var desc = plugin.description; + if (!desc || !desc.name) { + console.warn("文件 %s 不存在 description 描述信息 无法加载插件!".format(file)); + } else { + initPlugin(file, plugin); + afterLoadHook(plugin); + plugins.push(plugin); + plugins[plugin.description.name] = plugin; + console.info('载入插件 %s 版本 %s By %s'.format(desc.name, desc.version || '未知', desc.author || '未知')); + } + return plugin; +} + +function beforeLoadHook(origin) { + var result = origin; + // 处理 event 为了不影响 正常逻辑 event 还是手动require吧 + // result = result + 'var event = {}; module.exports.event = event;'; + // 注入 console 对象 // 给插件注入单独的 console + result = result + 'var console = Console.createNew(); module.exports.console = console;'; + // 插件注入 self 对象 + result = result + 'var self = {}; module.exports.self = self;'; + return result; +} + +function afterLoadHook(plugin) { + // plugin.event.on = event.on.bind(plugin); + // 给 console 添加插件名称 + plugin.console.name = plugin.description.name; + // 赋值 self + for (var i in plugin) { + plugin.self[i] = plugin[i]; + } +} + +/** + * 初始化插件内容(提供config,__DATA__等参数) + */ +function initPlugin(file, plugin) { + // 初始化 __FILE__ + plugin.__FILE__ = file; + // 初始化 __DATA__ + plugin.__DATA__ = fs.file(file.parentFile, plugin.description.name); + // 初始化 getDataFolder() + plugin.getDataFolder = function () { + return plugin.__DATA__; + }; + // 初始化 getFile() + plugin.getFile = function (name) { + return fs.file(plugin.getDataFolder(), name); + }; + + // 初始化插件配置相关方法 + initPluginConfig(plugin); + + command.enable(plugin); + permission.enable(plugin); +} + +/** + * 初始化插件配置 + */ +function initPluginConfig(plugin) { + // 初始化 config + plugin.configFile = plugin.getFile('config.yml'); + /** + * 获取配置文件 + * @constructor + * @constructor (file|string) + */ + plugin.getConfig = function () { + switch (arguments.length) { + case 0: + return plugin.config; + case 1: + var file = arguments[0]; + if (!file.isFile) { + file = plugin.getFile(file); + } + return yaml.safeLoad(base.read(file)); + } + }; + /** + * 重载配置文件 + * @constructor + * @constructor (file|string) + */ + plugin.reloadConfig = function () { + plugin.config = plugin.getConfig(plugin.configFile); + }; + /** + * 保存配置文件 + * @constructor + * @constructor (file, content) + */ + plugin.saveConfig = function () { + switch (arguments.length) { + case 0: + plugin.configFile.parentFile.mkdirs(); + base.save(plugin.configFile, yaml.safeDump(plugin.config)); + break; + case 2: + base.save(arguments[0], yaml.safeDump(arguments[1])); + break; + } + }; + if (plugin.configFile.isFile()) { + plugin.config = plugin.getConfig('config.yml'); + } else if (plugin.description.config) { + plugin.config = plugin.description.config; + plugin.saveConfig(); + } +} + +function runAndCatch(jsp, exec, ext) { + if (exec) { + try { + // 绑定方法的this到插件自身 + exec.bind(jsp)(); + if (ext) { + ext(); + } + } catch (ex) { + console.console('§6插件 §b%s §6执行 §d%s §6方法时发生错误 §4%s'.format(jsp.description.name, exec.name, ex.message)); + console.ex(ex); + } + } +} + +function checkAndGet(args) { + if (args.length === 0) { + return plugins; + } + var name = args[0]; + // 如果是插件 则直接返回 + if (name.description) { + return [name]; + } + if (!exports.plugins[name]) { + throw new Error("插件 " + name + " 不存在!"); + } + return [exports.plugins[name]]; +} + +var plugins = []; + +exports.plugins = plugins; +exports.init = function (path) { + var plugin = bukkit.plugin.self; + if (plugin !== null) { + // 如果过plugin不等于null 则代表是正式环境 + exports.$ = plugin; + console.info("初始化 MiaoScript 插件系统 版本: %s".format(plugin.description.version)); + } + loadPlugins(path); +}; +exports.load = function () { + checkAndGet(arguments).forEach(function (p) runAndCatch(p, p.load)); +}; +exports.enable = function () { + checkAndGet(arguments).forEach(function (p) runAndCatch(p, p.enable)); +}; +exports.disable = function () { + checkAndGet(arguments).forEach(function (p) runAndCatch(p, p.disable, function () { + event.disable(p); + // task.cancel(); + })); +}; +exports.reload = function () { + checkAndGet(arguments).forEach(function (p) { + exports.disable(p); + p = loadPlugin(p.__FILE__); + exports.load(p); + exports.enable(p); + }); +}; \ No newline at end of file diff --git a/src/main/resources/bios.js b/src/main/resources/bios.js index db7d8be..11e2a11 100644 --- a/src/main/resources/bios.js +++ b/src/main/resources/bios.js @@ -1,29 +1,28 @@ 'use strict'; var log; var boot; -var loader; var disable; +var global = this; /** * 初始化框架引擎 */ (function () { + var loader; + boot = function (root, logger) { log = logger; // 开发环境下初始化 root = root || "src/main/resources"; - var debug = false; if (__FILE__ !== "") { logger.info('载入自定义 BIOS 文件 ' + __FILE__); - debug = true; + global.debug = true; } // 检查类加载器 防止找不到核心文件 loader = checkClassLoader(); // 解压文件到根目录 非调试模式直接从jar解压覆盖 - release(root, "[api|core|internal|modules]/.*", !debug); + release(root, "[api|core|internal|modules]/.*", !global.debug); release(root, "plugins/.*"); load(root + '/core/init.js'); - // 初始化必须在load之后 不然global找不到 - global.debug = debug; try { init(root); } catch (ex) { diff --git a/src/main/resources/core/ext/patch.js b/src/main/resources/core/ext/patch.js index 4feb55d..bb7c12e 100644 --- a/src/main/resources/core/ext/patch.js +++ b/src/main/resources/core/ext/patch.js @@ -9,16 +9,17 @@ return str.format(this, Array.prototype.slice.call(arguments, 0)) }; - // JSON快捷方法 - Object.prototype.toJson = function () { - return JSON.stringify(this); - }; + // ========== 暂不扩展Object ========== + // // JSON快捷方法 + // Object.prototype.toJson = function () { + // return JSON.stringify(this); + // }; - // YAML快速生成 - var yaml = require('modules/yaml'); - Object.prototype.toYaml = function () { - return yaml.safeDump(this); - }; + // // YAML快速生成 + // var yaml = require('modules/yaml'); + // Object.prototype.toYaml = function () { + // return yaml.safeDump(this); + // }; /** * 日期格式化 diff --git a/src/main/resources/core/init.js b/src/main/resources/core/init.js index 0f39ccc..1eecbf8 100644 --- a/src/main/resources/core/init.js +++ b/src/main/resources/core/init.js @@ -1,5 +1,4 @@ 'use strict'; -var global = this; /*global base*/ (function (global) {