feat: 独立Bukkit插件部分 完善console输出 完善format格式化

This commit is contained in:
coding 2017-10-26 16:40:01 +00:00
parent e387863061
commit c7293370ea
22 changed files with 663 additions and 654 deletions

View File

@ -29,7 +29,6 @@ public class MiaoScript extends JavaPlugin implements Executor {
@SneakyThrows @SneakyThrows
public void onEnable() { public void onEnable() {
new CommandSub("ms", this); new CommandSub("ms", this);
saveScript();
engine = new ScriptEngine(getDataFolder().getCanonicalPath(), getClassLoader(), getLogger()); engine = new ScriptEngine(getDataFolder().getCanonicalPath(), getClassLoader(), getLogger());
} }
@ -73,11 +72,6 @@ public class MiaoScript extends JavaPlugin implements Executor {
} }
} }
private void saveScript() {
P.saveFile(true, "core", "modules");
P.saveFile("plugins");
}
@Override @Override
public void onDisable() { public void onDisable() {
engine.disableEngine(); engine.disableEngine();

View File

@ -17,14 +17,17 @@ var disable;
try { try {
init(root); init(root);
} catch (ex) { } catch (ex) {
throw ex; if(console.ex){
console.ex(ex);
}else{
throw ex;
}
} finally { } finally {
disable = disablePlugins disable = disablePlugins
} }
}; };
function release(root, regex, replace) { function release(root, regex, replace) {
print(Array.prototype.join.call(arguments, ' '));
var Files = Java.type("java.nio.file.Files"); var Files = Java.type("java.nio.file.Files");
var Paths = Java.type("java.nio.file.Paths"); var Paths = Java.type("java.nio.file.Paths");
var StandardCopyOption = Java.type("java.nio.file.StandardCopyOption"); var StandardCopyOption = Java.type("java.nio.file.StandardCopyOption");
@ -55,7 +58,6 @@ var disable;
} }
}) })
} catch (ex) { } catch (ex) {
} finally { } finally {
} }
} }

View File

@ -20,6 +20,7 @@
this.log = function () { this.log = function () {
log.info(this.name + Array.prototype.join.call(arguments, ' ')); log.info(this.name + Array.prototype.join.call(arguments, ' '));
}; };
this.info = this.log;
this.warn = function () { this.warn = function () {
log.warning(this.name + Array.prototype.join.call(arguments, ' ')); log.warning(this.name + Array.prototype.join.call(arguments, ' '));
}; };
@ -71,9 +72,9 @@
} }
track.forEach(function (stack) { track.forEach(function (stack) {
if (stack.className.startsWith('<')) { if (stack.className.startsWith('<')) {
this.console(String.format(' §e位于 §c%s => §c%s §4行%s', stack.fileName, stack.methodName, stack.lineNumber)); this.console(' §e位于 §c%s => §c%s §4行%s'.format(stack.fileName, stack.methodName, stack.lineNumber));
} else { } else {
this.console(String.format(' §e位于 §c%s.%s(§4%s:%s§c)', stack.className, stack.methodName, stack.fileName, stack.lineNumber)); this.console(' §e位于 §c%s.%s(§4%s:%s§c)'.format(stack.className, stack.methodName, stack.fileName, stack.lineNumber));
} }
}.bind(this)); }.bind(this));
} }

View File

@ -21,7 +21,7 @@ exports.concat = function () {
*/ */
exports.file = function () { exports.file = function () {
if (!arguments[0]) { if (!arguments[0]) {
log.w("文件名称不得为 undefined 或者 null !"); console.warn("文件名称不得为 undefined 或者 null !");
} }
switch (arguments.length) { switch (arguments.length) {
case 1: case 1:
@ -77,7 +77,7 @@ exports.copy = function (inputStream, target, override) {
exports.read = function (file) { exports.read = function (file) {
file = exports.file(file); file = exports.file(file);
if (!file.exists()) { if (!file.exists()) {
log.w("读取文件 %s 错误 文件不存在!", file); console.warn("读取文件 %s 错误 文件不存在!".format(file));
return; return;
} }
// noinspection JSPrimitiveTypeWrapperUsage // noinspection JSPrimitiveTypeWrapperUsage
@ -103,7 +103,7 @@ exports.list = function (path) {
if (dir.isDirectory()) { if (dir.isDirectory()) {
return Files.list(dir.toPath()); return Files.list(dir.toPath());
} }
log.w("路径 %s 不是一个目录 返回空数组!", path); console.warn("路径 %s 不是一个目录 返回空数组!".format(path));
return []; return [];
}; };
/** /**

View File

@ -64,7 +64,7 @@ function loadLib4Bukkit() {
function loadPlugins() { function loadPlugins() {
// 初始化本体插件 // 初始化本体插件
global.manager = require('modules/plugin'); global.manager = require('modules/plugin');
manager.init(base.plugin, 'plugins'); manager.init('plugins');
// 只有当在正式环境运行的时候才加载 // 只有当在正式环境运行的时候才加载
if (manager.$) { if (manager.$) {
manager.load(); manager.load();
@ -77,7 +77,7 @@ function loadPlugins() {
* 关闭插件Hook * 关闭插件Hook
*/ */
function disablePlugins() { function disablePlugins() {
if (manager.$) { if (manager && manager.$) {
manager.disable(); manager.disable();
} }
} }

View File

@ -3,6 +3,10 @@
*/ */
(function(){ (function(){
// Java格式化方法
var str = Java.type('java.lang.String');
String.prototype.format = function(){ return str.format(this, Array.prototype.slice.call(arguments, 0))}
// JSON快捷方法 // JSON快捷方法
Object.prototype.toJson = function(){ return JSON.stringify(this); } Object.prototype.toJson = function(){ return JSON.stringify(this); }

View File

@ -107,7 +107,7 @@
* @returns {Object} * @returns {Object}
*/ */
function compileModule(id, name, file, optional) { function compileModule(id, name, file, optional) {
console.debug('加载模块 %s 位于 %s Optional %s', name, id, optional.toJson()); console.debug('加载模块 %s 位于 %s Optional %s'.format(name, id, optional.toJson()));
// noinspection JSUnresolvedVariable // noinspection JSUnresolvedVariable
var module = { var module = {
id: id, id: id,
@ -120,10 +120,10 @@
compiledWrapper.apply(module.exports, [ compiledWrapper.apply(module.exports, [
module, module.exports, module.require, file.parentFile, file module, module.exports, module.require, file.parentFile, file
]); ]);
console.debug('模块 %s 编译成功!', name); console.debug('模块 %s 编译成功!'.format(name));
module.loaded = true; module.loaded = true;
} catch (ex) { } catch (ex) {
console.console("§4警告! §b模块 §a%s §4编译失败! ERR: %s", name, ex); console.console("§4警告! §c模块 §a%s §c编译失败! §4ERR: %s".format(name, ex));
console.ex(ex); console.ex(ex);
} }
return module; return module;
@ -155,7 +155,7 @@
function _require(name, path, optional) { function _require(name, path, optional) {
var file = _canonical(name) ? name : resolve(name, path); var file = _canonical(name) ? name : resolve(name, path);
if (file === undefined) { if (file === undefined) {
console.console("§c模块 §a%s §c加载失败! §4未找到该模块!", name); console.console("§c模块 §a%s §c加载失败! §4未找到该模块!".format(name));
return {exports: {}}; return {exports: {}};
} }
if (!optional) optional = {cache: true}; if (!optional) optional = {cache: true};
@ -189,6 +189,6 @@
parent = new File(parent); parent = new File(parent);
} }
var cacheModules = []; var cacheModules = [];
console.debug("初始化 require 模块组件 父目录 %s", _canonical(parent)); console.debug("初始化 require 模块组件 父目录 ", _canonical(parent));
return exports(parent); return exports(parent);
}); });

View File

@ -12,7 +12,7 @@ var fs = require('fs');
*/ */
function unzip(zipFile, target) { function unzip(zipFile, target) {
if (!zipFile.exists()) { if (!zipFile.exists()) {
log.w("解压文件 %s 错误 文件不存在!", zipFile); console.warn("解压文件 %s 错误 文件不存在!".format(zipFile));
return; return;
} }
if (target === undefined) { if (target === undefined) {
@ -20,7 +20,7 @@ function unzip(zipFile, target) {
// noinspection JSUnresolvedVariable // noinspection JSUnresolvedVariable
target = fs.file(zipFile.parentFile.canonicalPath, fname.substring(0, fname.length() - 4)); target = fs.file(zipFile.parentFile.canonicalPath, fname.substring(0, fname.length() - 4));
} }
log.d("解压文件 %s 到目录 %s", zipFile.canonicalPath, target); console.debug("解压文件 %s 到目录 %s".format(zipFile.canonicalPath, target));
var zipObj = new ZipFile(zipFile); var zipObj = new ZipFile(zipFile);
var e = zipObj.entries(); var e = zipObj.entries();
while (e.hasMoreElements()) { while (e.hasMoreElements()) {

View File

@ -0,0 +1,93 @@
'use strict';
/**
* Bukkit 命令相关类
*/
/*global Java, base, module, exports, require, __FILE__*/
var ref = require('core/reflect');
var bukkit = require('./server');
var plugin = bukkit.plugin.self;
var commandMap = ref.on(bukkit.plugin.manager).get('commandMap').get();
var PluginCommand = Java.type('org.bukkit.command.PluginCommand');
var StringUtil = Java.type('org.bukkit.util.StringUtil');
var ArrayList = Java.type('java.util.ArrayList');
var Arrays = Java.type('java.util.Arrays');
function enable(jsp) {
var commands = jsp.description.commands;
if (commands) {
var pluginCmds = [];
for (var name in commands) {
var command = commands[name];
if (typeof command !== 'object') continue;
var newCmd = create(jsp, name);
if (command.description) newCmd.setDescription(command.description);
if (command.usage) newCmd.setUsage(command.usage);
if (command.aliases) newCmd.setAliases(Arrays.asList(command.aliases));
if (command.permission) newCmd.setPermission(command.permission);
if (command['permission-message']) newCmd.setPermissionMessage(command['permission-message']);
pluginCmds.push(newCmd);
console.debug('插件 %s 注册命令 %s ...'.format(jsp.description.name, name));
}
commandMap.registerAll(jsp.description.name, Arrays.asList(pluginCmds));
}
}
function get(name) {
return commandMap.getCommand(name);
}
function create(jsp, name) {
return register(jsp, ref.on(PluginCommand).create(name, plugin).get());
}
function register(jsp, cmd) {
commandMap.register(jsp.description.name, cmd);
return cmd;
}
// var exec = {
// cmd: function (sender, command, args) {
//
// },
// tab: function (sender, command, args) {
//
// }
// };
function on(jsp, name, exec) {
var c = get(name) || create(jsp, name);
console.debug('插件 %s 设置命令 %s(%s) 执行器 ...'.fotmat(jsp.description.name, name, c));
if (exec.cmd) {
c.setExecutor(function (sender, cmd, command, args) {
try {
return exec.cmd(sender, command, args);
} catch (ex) {
console.console('§6玩家 §a%s §6执行 §b%s §6插件 §d%s %s §6命令时发生异常 §4%s'.fotmat(sender.name, jsp.description.name, command, Java.from(args).join(' '), ex));
console.ex(ex);
}
});
}
if (exec.tab) {
c.setTabCompleter(function (sender, cmd, command, args) {
try {
var completions = new ArrayList();
var token = args[args.length - 1];
StringUtil.copyPartialMatches(token, Arrays.asList(exec.tab(sender, command, args)), completions);
return completions;
} catch (ex) {
console.console('§6玩家 §a%s §6执行 §b%s §6插件 §d%s %s §6补全时发生异常 §4%s'.fotmat(sender.name, jsp.description.name, command, Java.from(args).join(' '), ex));
console.ex(ex);
}
});
}
}
exports.enable = enable;
exports.on = on;
exports.off = function () {
};

View File

@ -0,0 +1,158 @@
'use strict';
/**
* Bukkit 事件相关类
*/
/*global Java, base, module, exports, require, __FILE__*/
var Thread = Java.type("java.lang.Thread");
var Bukkit = Java.type("org.bukkit.Bukkit");
var Listener = Java.type("org.bukkit.event.Listener");
var Modifier = Java.type("java.lang.reflect.Modifier");
var BukkitEvent = Java.type("org.bukkit.event.Event");
var HandlerList = Java.type('org.bukkit.event.HandlerList');
var EventPriority = Java.type("org.bukkit.event.EventPriority");
var EventExecutor = Java.type("org.bukkit.plugin.EventExecutor");
var IllegalStateException = Java.type("java.lang.IllegalStateException");
var plugin = require('./server').plugin.self;
var ref = require('reflect');
var listenerMap = [];
/**
* 扫描包 org.bukkit.event 下的所有事件
* 映射简写名称 org.bukkit.event.player.PlayerLoginEvent => playerloginevent
*/
function mapEventName() {
var eventPackageDir = "org/bukkit/event";
var count = 0;
var dirs = Thread.currentThread().getContextClassLoader().getResources(eventPackageDir);
while (dirs.hasMoreElements()) {
var url = dirs.nextElement();
var protocol = url.protocol;
if (protocol === "jar") {
// noinspection JSUnresolvedVariable
var jar = url.openConnection().jarFile;
var entries = jar.entries();
while (entries.hasMoreElements()) {
var entry = entries.nextElement();
var name = entry.name;
// 以 org/bukkit/event 开头 并且以 .class 结尾
if (name.startsWith(eventPackageDir) && name.endsWith(".class")) {
var i = name.replaceAll('/', '.');
try {
var clz = base.getClass(i.substring(0, i.length - 6));
// 继承于 org.bukkit.event.Event 访问符为Public
if (isVaildEvent(clz)) {
// noinspection JSUnresolvedVariable
var simpleName = clz.simpleName.toLowerCase();
console.debug("Mapping Event [%s] => %s".format(clz.name, simpleName));
mapEvent[simpleName] = clz;
count++;
}
} catch (ex) {
//ignore already loaded class
}
}
}
}
}
return count;
}
/**
* 判断是否为一个有效的事件类
* @param clz
* @returns {*|boolean}
*/
function isVaildEvent(clz) {
// noinspection JSUnresolvedVariable 继承于 org.bukkit.event.Event
return BukkitEvent.class.isAssignableFrom(clz) &&
// 访问符为Public
Modifier.isPublic(clz.getModifiers()) &&
// 不是抽象类
!Modifier.isAbstract(clz.getModifiers());
}
/**
* 添加事件监听
* @param jsp
* @param event
* @param exec {function}
* @param priority
* @param ignoreCancel
*/
function listen(jsp, event, exec, priority, ignoreCancel) {
var name = jsp.description.name;
if (ext.isNull(name)) throw new TypeError('插件名称为空 请检查传入参数!');
var eventCls = mapEvent[event] || mapEvent[event.toLowerCase()] || mapEvent[event + 'Event'] || mapEvent[event.toLowerCase() + 'event'];
if (!eventCls) {
try {
eventCls = base.getClass(eventCls);
} catch (ex) {
console.warn("事件 %s 未找到!".format(event));
return;
}
}
if (typeof priority === 'boolean') {
ignoreCancel = priority
}
priority = priority || 'NORMAL';
ignoreCancel = ignoreCancel || false;
var listener = new Listener({});
// noinspection JSUnusedGlobalSymbols
/**
* @param event Event type to register
* @param listener Listener to register
* @param priority Priority to register this event at
* @param executor EventExecutor to register
* @param plugin Plugin to register
* @param ignoreCancel
*/
Bukkit.getPluginManager().registerEvent(
eventCls,
listener,
EventPriority[priority],
new EventExecutor({
execute: function (listener, event) {
try {
exec(event);
} catch (ex) {
console.console('§6插件 §b%s §6处理 §d%s §6事件时发生异常 §4%s'.format(name, event.class.simpleName, ex));
console.ex(ex);
}
}
}),
plugin,
ignoreCancel);
// 添加到缓存 用于关闭插件的时候关闭事件
if (!listenerMap[name]) listenerMap[name] = []
var listeners = listenerMap[name];
var off = {
event: eventCls,
listener: listener,
off: function () {
ref.on(this.event).call('getHandlerList').get().unregister(this.listener);
console.debug('插件 %s 注销事件 %s'.format(name, this.event.simpleName));
}
}
listeners.push(off);
// noinspection JSUnresolvedVariable
console.debug('插件 %s 注册事件 %s 方法 %s'.format(name, eventCls.simpleName, exec.name === '' ? '匿名方法' : exec.name));
return off;
}
var mapEvent = [];
// 映射事件名称
console.info('Bukkit 事件映射完毕 共计 %s 个事件!'.format(mapEventName().toFixed(0)));
module.exports = {
on: listen,
disable: function (jsp) {
var jspl = listenerMap[jsp.description.name];
if (jspl) {
jspl.forEach(function (t) t.off());
delete listenerMap[jsp.description.name];
}
}
};

View File

@ -0,0 +1,48 @@
'use strict';
/**
* Bukkit 权限相关类
*/
/*global Java, base, module, exports, require, __FILE__*/
var manager = require('./server').plugin.manager;
/**
* Permission(String name, String description)
*/
var Permission = Java.type("org.bukkit.permissions.Permission");
var PermissionDefault = Java.type('org.bukkit.permissions.PermissionDefault');
function enable(plugin) {
var permissions = plugin.description.permissions;
if (permissions) {
for (var name in permissions) {
var permission = permissions[name];
if (typeof permission !== 'object') continue;
var desc = permission.description;
var def = permission.default || 'OP';
try {
manager.addPermission(new Permission(name, desc, PermissionDefault.getByName(def)));
} catch (ex) {
// ignore eg: java.lang.IllegalArgumentException: The permission xxxxxx.default is already defined!
}
console.debug('插件 %s 注册权限 %s Default %s ...'.format(plugin.description.name, name, def));
}
}
}
function disable(plugin) {
var permissions = plugin.description.permissions;
if (permissions) {
for (var name in permissions) {
try {
manager.removePermission(name);
} catch (ex) {
// ignore eg: java.lang.IllegalArgumentException: The permission xxxxxx.default is already defined!
}
console.debug('插件 %s 注销权限 %s ...'.format(plugin.description.name, name));
}
}
}
exports.enable = enable;
exports.disable = disable;

View File

@ -0,0 +1,259 @@
'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('modules/event');
var bukkit = require('./server');
var command = require('./command');
var permission = require('./permission');
/**
* 载入插件
* @param path
*/
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(plugin.toJson()));
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 = new Console(); 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, plugin.config.toYaml());
break;
case 2:
base.save(arguments[0], arguments[1].toYaml());
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.$ = undefined;
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);
});
};

View File

@ -75,7 +75,8 @@ exports.plugin = {
PluginManager.enablePlugin(plugin); PluginManager.enablePlugin(plugin);
} }
return PluginManager.isPluginEnabled(name); return PluginManager.isPluginEnabled(name);
} },
self: PluginManager.getPlugin('MiaoScript')
}; };
/** /**
* 公告 * 公告

View File

@ -0,0 +1,71 @@
'use strict';
/*global Java, base, module, exports, require, __FILE__*/
/**
* 任务计划
* Created by 蒋天蓓 on 2017/2/9 0009.
*/
var plugin = require('./server').plugin.self;
var BukkitRunnable = Java.type("org.bukkit.scheduler.BukkitRunnable");
/**
* 创建任务对象
* @param func 任务
*/
exports.create = function (func) {
return new BukkitRunnable(func);
};
/**
* 运行任务
* @param func 任务
*/
exports.run = function (func) {
return exports.create(func).runTask(plugin);
};
/**
* 延时运行任务
* @param func 任务
* @param time 延时时间
*/
exports.later = function (func, time) {
return exports.create(func).runTaskLater(plugin, time);
};
/**
* 运行循环任务
* @constructor (任务,执行间隔).
* @constructor (任务,首次延时,执行间隔)
*/
exports.timer = function () {
switch (arguments.length) {
case 2:
return exports.create(arguments[0]).runTaskTimer(plugin, 0, arguments[1]);
case 3:
return exports.create(arguments[0]).runTaskTimer(plugin, arguments[1], arguments[2]);
}
};
/**
* 运行异步任务
* @param func function 任务
*/
exports.async = function (func) {
return exports.create(func).runTaskAsynchronously(plugin);
};
/**
* 延时运行异步任务
* @param func 任务
* @param time 延时时间
*/
exports.laterAsync = function (func, time) {
return exports.create(func).runTaskLaterAsynchronously(plugin, time);
};
/**
* 运行异步循环任务
* @constructor (任务,执行间隔).
* @constructor (任务,首次延时,执行间隔)
*/
exports.timerAsync = function () {
switch (arguments.length) {
case 2:
return exports.create(arguments[0]).runTaskTimerAsynchronously(plugin, 0, arguments[1]);
case 3:
return exports.create(arguments[0]).runTaskTimerAsynchronously(plugin, arguments[1], arguments[2]);
}
};

View File

@ -1,93 +1 @@
'use strict'; module.exports = require('./bukkit/command');
/**
* Bukkit 命令相关类
*/
/*global Java, base, module, exports, require, __FILE__*/
var plugin = base.plugin;
var ref = require('core/reflect');
var bukkit = require('./bukkit');
var commandMap = ref.on(bukkit.plugin.manager).get('commandMap').get();
var PluginCommand = Java.type('org.bukkit.command.PluginCommand');
var StringUtil = Java.type('org.bukkit.util.StringUtil');
var ArrayList = Java.type('java.util.ArrayList');
var Arrays = Java.type('java.util.Arrays');
function enable(jsp) {
var commands = jsp.description.commands;
if (commands) {
var pluginCmds = [];
for (var name in commands) {
var command = commands[name];
if (typeof command !== 'object') continue;
var newCmd = create(jsp, name);
if (command.description) newCmd.setDescription(command.description);
if (command.usage) newCmd.setUsage(command.usage);
if (command.aliases) newCmd.setAliases(Arrays.asList(command.aliases));
if (command.permission) newCmd.setPermission(command.permission);
if (command['permission-message']) newCmd.setPermissionMessage(command['permission-message']);
pluginCmds.push(newCmd);
console.debug('插件 %s 注册命令 %s ...', jsp.description.name, name);
}
commandMap.registerAll(jsp.description.name, Arrays.asList(pluginCmds));
}
}
function get(name) {
return commandMap.getCommand(name);
}
function create(jsp, name) {
return register(jsp, ref.on(PluginCommand).create(name, plugin).get());
}
function register(jsp, cmd) {
commandMap.register(jsp.description.name, cmd);
return cmd;
}
// var exec = {
// cmd: function (sender, command, args) {
//
// },
// tab: function (sender, command, args) {
//
// }
// };
function on(jsp, name, exec) {
var c = get(name) || create(jsp, name);
console.debug('插件 %s 设置命令 %s(%s) 执行器 ...', jsp.description.name, name, c);
if (exec.cmd) {
c.setExecutor(function (sender, cmd, command, args) {
try {
return exec.cmd(sender, command, args);
} catch (ex) {
console.console('§6玩家 §a%s §6执行 §b%s §6插件 §d%s %s §6命令时发生异常 §4%s', sender.name, jsp.description.name, command, Java.from(args).join(' '), ex);
console.ex(ex);
}
});
}
if (exec.tab) {
c.setTabCompleter(function (sender, cmd, command, args) {
try {
var completions = new ArrayList();
var token = args[args.length - 1];
StringUtil.copyPartialMatches(token, Arrays.asList(exec.tab(sender, command, args)), completions);
return completions;
} catch (ex) {
console.console('§6玩家 §a%s §6执行 §b%s §6插件 §d%s %s §6补全时发生异常 §4%s', sender.name, jsp.description.name, command, Java.from(args).join(' '), ex);
console.ex(ex);
}
});
}
}
exports.enable = enable;
exports.on = on;
exports.off = function () {
};

View File

@ -1,158 +1 @@
'use strict'; module.exports = require('./bukkit/event');
/**
* Bukkit 事件相关类
*/
/*global Java, base, module, exports, require, __FILE__*/
var Thread = Java.type("java.lang.Thread");
var Bukkit = Java.type("org.bukkit.Bukkit");
var Listener = Java.type("org.bukkit.event.Listener");
var Modifier = Java.type("java.lang.reflect.Modifier");
var BukkitEvent = Java.type("org.bukkit.event.Event");
var HandlerList = Java.type('org.bukkit.event.HandlerList');
var EventPriority = Java.type("org.bukkit.event.EventPriority");
var EventExecutor = Java.type("org.bukkit.plugin.EventExecutor");
var IllegalStateException = Java.type("java.lang.IllegalStateException");
var plugin = base.plugin;
var ref = require('reflect');
var listenerMap = [];
/**
* 扫描包 org.bukkit.event 下的所有事件
* 映射简写名称 org.bukkit.event.player.PlayerLoginEvent => playerloginevent
*/
function mapEventName() {
var eventPackageDir = "org/bukkit/event";
var count = 0;
var dirs = Thread.currentThread().getContextClassLoader().getResources(eventPackageDir);
while (dirs.hasMoreElements()) {
var url = dirs.nextElement();
var protocol = url.protocol;
if (protocol === "jar") {
// noinspection JSUnresolvedVariable
var jar = url.openConnection().jarFile;
var entries = jar.entries();
while (entries.hasMoreElements()) {
var entry = entries.nextElement();
var name = entry.name;
// 以 org/bukkit/event 开头 并且以 .class 结尾
if (name.startsWith(eventPackageDir) && name.endsWith(".class")) {
var i = name.replaceAll('/', '.');
try {
var clz = base.getClass(i.substring(0, i.length - 6));
// 继承于 org.bukkit.event.Event 访问符为Public
if (isVaildEvent(clz)) {
// noinspection JSUnresolvedVariable
var simpleName = clz.simpleName.toLowerCase();
console.debug("Mapping Event [%s] => %s", clz.name, simpleName);
mapEvent[simpleName] = clz;
count++;
}
} catch (ex) {
//ignore already loaded class
}
}
}
}
}
return count;
}
/**
* 判断是否为一个有效的事件类
* @param clz
* @returns {*|boolean}
*/
function isVaildEvent(clz) {
// noinspection JSUnresolvedVariable 继承于 org.bukkit.event.Event
return BukkitEvent.class.isAssignableFrom(clz) &&
// 访问符为Public
Modifier.isPublic(clz.getModifiers()) &&
// 不是抽象类
!Modifier.isAbstract(clz.getModifiers());
}
/**
* 添加事件监听
* @param jsp
* @param event
* @param exec {function}
* @param priority
* @param ignoreCancel
*/
function listen(jsp, event, exec, priority, ignoreCancel) {
var name = jsp.description.name;
if (ext.isNull(name)) throw new TypeError('插件名称为空 请检查传入参数!');
var eventCls = mapEvent[event] || mapEvent[event.toLowerCase()] || mapEvent[event + 'Event'] || mapEvent[event.toLowerCase() + 'event'];
if (!eventCls) {
try {
eventCls = base.getClass(eventCls);
} catch (ex) {
console.warn("事件 %s 未找到!", event);
return;
}
}
if (typeof priority === 'boolean') {
ignoreCancel = priority
}
priority = priority || 'NORMAL';
ignoreCancel = ignoreCancel || false;
var listener = new Listener({});
// noinspection JSUnusedGlobalSymbols
/**
* @param event Event type to register
* @param listener Listener to register
* @param priority Priority to register this event at
* @param executor EventExecutor to register
* @param plugin Plugin to register
* @param ignoreCancel
*/
Bukkit.getPluginManager().registerEvent(
eventCls,
listener,
EventPriority[priority],
new EventExecutor({
execute: function (listener, event) {
try {
exec(event);
} catch (ex) {
console.console('§6插件 §b%s §6处理 §d%s §6事件时发生异常 §4%s', name, event.class.simpleName, ex);
console.ex(ex);
}
}
}),
plugin,
ignoreCancel);
// 添加到缓存 用于关闭插件的时候关闭事件
if (!listenerMap[name]) listenerMap[name] = []
var listeners = listenerMap[name];
var off = {
event: eventCls,
listener: listener,
off: function () {
ref.on(this.event).call('getHandlerList').get().unregister(this.listener);
console.debug('插件 %s 注销事件 %s', name, this.event.simpleName);
}
}
listeners.push(off);
// noinspection JSUnresolvedVariable
console.debug('插件 %s 注册事件 %s 方法 %s', name, eventCls.simpleName, exec.name === '' ? '匿名方法' : exec.name);
return off;
}
var mapEvent = [];
// 映射事件名称
console.info('Bukkit 事件映射完毕 共计 %s 个事件!', mapEventName().toFixed(0));
module.exports = {
on: listen,
disable: function (jsp) {
var jspl = listenerMap[jsp.description.name];
if (jspl) {
jspl.forEach(function (t) t.off());
delete listenerMap[jsp.description.name];
}
}
};

View File

@ -1,48 +1 @@
'use strict'; module.exports = require('./bukkit/permission');
/**
* Bukkit 权限相关类
*/
/*global Java, base, module, exports, require, __FILE__*/
var manager = require('./bukkit').plugin.manager;
/**
* Permission(String name, String description)
*/
var Permission = Java.type("org.bukkit.permissions.Permission");
var PermissionDefault = Java.type('org.bukkit.permissions.PermissionDefault');
function enable(plugin) {
var permissions = plugin.description.permissions;
if (permissions) {
for (var name in permissions) {
var permission = permissions[name];
if (typeof permission !== 'object') continue;
var desc = permission.description;
var def = permission.default || 'OP';
try {
manager.addPermission(new Permission(name, desc, PermissionDefault.getByName(def)));
} catch (ex) {
// ignore eg: java.lang.IllegalArgumentException: The permission xxxxxx.default is already defined!
}
console.debug('插件 %s 注册权限 %s Default %s ...', plugin.description.name, name, def);
}
}
}
function disable(plugin) {
var permissions = plugin.description.permissions;
if (permissions) {
for (var name in permissions) {
try {
manager.removePermission(name);
} catch (ex) {
// ignore eg: java.lang.IllegalArgumentException: The permission xxxxxx.default is already defined!
}
console.debug('插件 %s 注销权限 %s ...', plugin.description.name, name);
}
}
}
exports.enable = enable;
exports.disable = disable;

View File

@ -1,258 +1 @@
'use strict'; module.exports = require('./bukkit/plugin');
/**
* 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('modules/event');
var bukkit = require('./bukkit');
var command = require('./command');
var permission = require('./permission');
/**
* 载入插件
* @param path
*/
function loadPlugins(dir) {
var plugin = fs.file(root, dir);
if (!plugin) {
console.info("首次加载 创建文件夹 %s ...", plugin);
} else {
console.info("开始扫描 %s 下的插件 ...", 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', file.name);
fs.move(update, file, true);
}
var plugin = require(file, {
cache: false,
hook: function (origin) {
return beforeLoadHook(origin);
}
});
console.debug("插件编译结果: %s", plugin.toJson());
var desc = plugin.description;
if (!desc || !desc.name) {
console.warn("文件 %s 不存在 description 描述信息 无法加载插件!", file);
} else {
initPlugin(file, plugin);
afterLoadHook(plugin);
plugins.push(plugin);
plugins[plugin.description.name] = plugin;
console.info('载入插件 %s 版本 %s By %s', 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 = new Console(); 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, plugin.config.toYaml());
break;
case 2:
base.save(arguments[0], arguments[1].toYaml());
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', 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.$ = undefined;
exports.plugins = plugins;
exports.init = function (plugin, path) {
if (plugin !== null) {
// 如果过plugin不等于null 则代表是正式环境
exports.$ = plugin;
console.info("初始化 MiaoScript 插件系统 版本: %s", 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);
});
};

View File

@ -0,0 +1 @@
module.exports = require('./bukkit/server');

View File

@ -1,71 +1 @@
'use strict'; module.exports = require('./bukkit/task');
/*global Java, base, module, exports, require, __FILE__*/
/**
* 任务计划
* Created by 蒋天蓓 on 2017/2/9 0009.
*/
var plugin = base.plugin;
var BukkitRunnable = Java.type("org.bukkit.scheduler.BukkitRunnable");
/**
* 创建任务对象
* @param func 任务
*/
exports.create = function (func) {
return new BukkitRunnable(func);
};
/**
* 运行任务
* @param func 任务
*/
exports.run = function (func) {
return exports.create(func).runTask(plugin);
};
/**
* 延时运行任务
* @param func 任务
* @param time 延时时间
*/
exports.later = function (func, time) {
return exports.create(func).runTaskLater(plugin, time);
};
/**
* 运行循环任务
* @constructor (任务,执行间隔).
* @constructor (任务,首次延时,执行间隔)
*/
exports.timer = function () {
switch (arguments.length) {
case 2:
return exports.create(arguments[0]).runTaskTimer(plugin, 0, arguments[1]);
case 3:
return exports.create(arguments[0]).runTaskTimer(plugin, arguments[1], arguments[2]);
}
};
/**
* 运行异步任务
* @param func function 任务
*/
exports.async = function (func) {
return exports.create(func).runTaskAsynchronously(plugin);
};
/**
* 延时运行异步任务
* @param func 任务
* @param time 延时时间
*/
exports.laterAsync = function (func, time) {
return exports.create(func).runTaskLaterAsynchronously(plugin, time);
};
/**
* 运行异步循环任务
* @constructor (任务,执行间隔).
* @constructor (任务,首次延时,执行间隔)
*/
exports.timerAsync = function () {
switch (arguments.length) {
case 2:
return exports.create(arguments[0]).runTaskTimerAsynchronously(plugin, 0, arguments[1]);
case 3:
return exports.create(arguments[0]).runTaskTimerAsynchronously(plugin, arguments[1], arguments[2]);
}
};

View File

@ -7,7 +7,7 @@
var fs = require('core/fs'); var fs = require('core/fs');
var event = require('modules/event'); var event = require('modules/event');
var bukkit = require('modules/bukkit'); var bukkit = require('modules/server');
var command = require('modules/command'); var command = require('modules/command');
var papi = require('./ext/papi'); var papi = require('./ext/papi');

View File

@ -4,7 +4,7 @@
*/ */
/*global Java, base, module, exports, require, __FILE__*/ /*global Java, base, module, exports, require, __FILE__*/
var PlaceholderAPI; var PlaceholderAPI;
var bukkit = require('modules/bukkit'); var bukkit = require('modules/server');
if (bukkit.plugin.load("PlaceholderAPI")) { if (bukkit.plugin.load("PlaceholderAPI")) {
PlaceholderAPI = ext.getStatic("me.clip.placeholderapi.PlaceholderAPI"); PlaceholderAPI = ext.getStatic("me.clip.placeholderapi.PlaceholderAPI");
} else { } else {