24 Commits

Author SHA1 Message Date
f7b97f3e84 feat: 迁移配置 完善reload命令 2018-05-15 13:47:03 +00:00
89cab251c7 feat: 分离TellRaw类库 2018-05-15 13:33:52 +00:00
3d3bf20acd feat: 完善MiaoChat的Bukkit版本 2018-05-14 16:42:55 +00:00
423c7cc844 feat: 补全内部引入方法的参数 2018-05-14 16:42:35 +00:00
8df9ad9ec7 feat: 调整Event载入提示 完善Bukkit的聊天发送 2018-05-14 16:42:08 +00:00
39d9c67c75 feat: 调整API引入结构 2018-05-14 16:41:33 +00:00
6f1a103aca feat: 新增MiaoChat插件 2018-05-13 16:18:26 +00:00
f79acd43c5 feat: 更新API相关类 2018-05-13 16:18:14 +00:00
f19e51d8a7 feat: 调整相关API名称 2018-05-13 16:17:48 +00:00
d5aa98b716 feat: 新增Object.values垫片 2018-05-13 16:16:01 +00:00
04a7b99ce5 feat: 新增工具类 2018-05-13 16:14:35 +00:00
a672b85678 feat: 更新MiaoScriptPackageManager 2018-05-13 16:14:14 +00:00
288619ddb7 fix: 修复命令执行相关BUG 2018-05-13 16:13:57 +00:00
3df2625e65 feat: 新增聊天相关API 2018-05-13 16:13:32 +00:00
a041e8e2d2 feat: 优化方法调用 2018-03-18 12:06:52 +00:00
320cc0479e feat: 调整get方法 data 参数自动转query 2018-03-18 12:06:27 +00:00
755d4b005d feat: 优化插件代码结构 2018-03-18 12:04:56 +00:00
e290f17771 fix: 修复玩家人数获取错误 更新插件 2018-01-11 14:47:34 +00:00
be95acd001 feat: 更新http类库 server通过orElse返回undefined 2018-01-11 14:46:47 +00:00
75340fd824 feat: 更新基础类库 2018-01-11 13:47:49 +00:00
51499b3b52 feat: 新增插件管理模块 2018-01-10 12:59:55 +00:00
54b5909875 fix: 修复主线程加载的BUG 2018-01-10 12:59:29 +00:00
fe6d0e7250 feat: 修复fs相关BUG 优化插件加载 优化命令补全 2018-01-10 12:58:58 +00:00
bf6d52d8cc feat: 更新.gitignore文件 2018-01-10 01:57:19 +00:00
31 changed files with 964 additions and 201 deletions

97
.gitignore vendored
View File

@ -1,44 +1,53 @@
# Eclipse stuff
/.settings
# netbeans
/nbproject
# we use maven!
/build.xml
# maven
/target
/repo
# vim
.*.sw[a-p]
# various other potential build files
/build
/bin
/dist
/manifest.mf
/world
# Mac filesystem dust
*.DS_Store
# intellij
*.iml
*.ipr
*.iws
.idea/
# Project Stuff
/src/main/resources/Soulbound
# Atlassian Stuff
/atlassian-ide-plugin.xml
/src/main/resources/cache/
# ThinkPHP
vendor/
composer.lock
# Eclipse stuff
/.settings
# netbeans
/nbproject
# we use maven!
/build.xml
# maven
/target
/repo
# vim
.*.sw[a-p]
# various other potential build files
/build
/bin
/dist
/manifest.mf
# Mac filesystem dust
*.DS_Store
# intellij
*.iml
*.ipr
*.iws
.idea/
# Project Stuff
/src/main/resources/Soulbound
# Atlassian Stuff
/atlassian-ide-plugin.xml
# Eclipse
.project
.classpath
.settings
# Visual Studio Code
.vscode
# NodeJs PHP LOCK File
*.lock
# PHP Vendor
vendor/
# Minecraft Data
/world

View File

@ -0,0 +1,9 @@
/*global Java, base, module, exports, require*/
function ChatHandlerDefault() {
this.tellraw = function(sender, raw) {
this.json(sender, JSON.stringify(raw));
}
}
var ChatHandler = Object.assign(new ChatHandlerDefault(), requireInternal('chat'));
exports = module.exports = ChatHandler;

View File

@ -1,2 +1,2 @@
/*global Java, base, module, exports, require*/
module.exports = require('./msp.js').command;
module.exports = requireInternal('command');

View File

@ -12,6 +12,8 @@ function EventHandlerDefault() {
this.listenerMap = [];
this.baseEventDir = '';
var self = this;
/**
* 扫描包 org.bukkit.event 下的所有事件
* 映射简写名称 org.bukkit.event.player.PlayerLoginEvent => playerloginevent
@ -40,8 +42,8 @@ function EventHandlerDefault() {
// 继承于 org.bukkit.event.Event 访问符为Public
if (this.isVaildEvent(clz)) {
// noinspection JSUnresolvedVariable
var simpleName = this.class2Name(clz);
console.debug("Mapping Event [%s] => %s".format(clz.name, simpleName));
var simpleName = this.class2Name(clz).toLowerCase();
console.debug("Mapping Event [%s] => %s".format(clz.canonicalName, simpleName));
this.mapEvent[simpleName] = clz;
count++;
}
@ -56,11 +58,11 @@ function EventHandlerDefault() {
}
this.class2Name = function class2Name(clazz) {
return clazz.simpleName.toLowerCase();
return clazz.simpleName;
}
this.name2Class = function name2Class(name, event) {
var eventCls = this.mapEvent[event] || this.mapEvent[event.toLowerCase()] || this.mapEvent[event + 'Event'] || this.mapEvent[event.toLowerCase() + 'event'];
var eventCls = this.mapEvent[event.toLowerCase()] || this.mapEvent[event.toLowerCase() + 'event'];
if (!eventCls) {
try {
eventCls = base.getClass(eventCls);
@ -128,7 +130,7 @@ function EventHandlerDefault() {
if (!listenerMap[name]) listenerMap[name] = [];
var offExec = function () {
this.unregister(eventCls, listener);
console.debug('插件 %s 注销事件 %s'.format(name, eventCls.name.substring(eventCls.name.lastIndexOf(".") + 1)));
console.debug('插件 %s 注销事件 %s'.format(name, this.class2Name(eventCls)));
}.bind(this);
var off = {
event: eventCls,
@ -137,7 +139,7 @@ function EventHandlerDefault() {
};
listenerMap[name].push(off);
// noinspection JSUnresolvedVariable
console.debug('插件 %s 注册事件 %s => %s'.format(name, eventCls.name.substring(eventCls.name.lastIndexOf(".") + 1), exec.name === '' ? '匿名方法' : exec.name));
console.debug('插件 %s 注册事件 %s => %s'.format(name, this.class2Name(eventCls), exec.name === '' ? '匿名方法' : exec.name));
return off;
}
}
@ -147,9 +149,9 @@ console.info('%s 事件映射完毕 共计 %s 个事件!'.format(DetectServerTyp
module.exports = {
on: EventHandler.listen.bind(EventHandler),
disable: function (jsp) {
var jspl = EventHandler.listenerMap[jsp.description.name];
if (jspl) {
jspl.forEach(function (t) t.off.call(EventHandler));
var eventCache = EventHandler.listenerMap[jsp.description.name];
if (eventCache) {
eventCache.forEach(function (t) t.off.call(EventHandler));
delete EventHandler.listenerMap[jsp.description.name];
}
}

View File

@ -1,2 +1,2 @@
/*global Java, base, module, exports, require*/
module.exports = require('./msp.js').item;
module.exports = requireInternal('item');

View File

@ -1,13 +0,0 @@
/*global Java, base, module, exports, require*/
function impl(name) {
return require('../internal/' + DetectServerType + '/' + name, {warnNotFound: false});
}
exports = module.exports = {
command: impl('command'),
event: impl('event'),
permission: impl('permission'),
server: impl('server'),
task: impl('task'),
item: impl('item')
};

View File

@ -1,2 +1,2 @@
/*global Java, base, module, exports, require*/
module.exports = require('./msp.js').permission;
module.exports = requireInternal('permission', {warnNotFound: false});

View File

@ -50,14 +50,15 @@ function createUpdate(path) {
* @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 添加文件夹类型的插件兼容
// });
files.filter(function (file) {
return file.name.endsWith(".zip");
}).forEach(function (file) {
// console.log(file);
// console.log(fs.file(file,"!package.json"))
// zip.unzip(fs.file(plugins_dir, file));
// var dir = new File(plugins_dir, file.name.split(".")[0]);
// TODO 添加文件夹类型的插件兼容
});
}
/**
@ -67,16 +68,23 @@ function loadJsPlugins(files) {
files.filter(function (file) {
return file.name.endsWith(".js")
}).forEach(function (file) {
try {
loadPlugin(file);
} catch (ex) {
console.console('§6插件 §b%s §6初始化时发生错误 §4%s'.format(fs.path(file), ex.message));
console.ex(ex);
}
loadPlugin(file)
})
}
function loadPlugin(file) {
try {
var plugin = readPlugin(file);
initPlugin(plugin);
plugins[plugin.description.name] = plugin;
return plugin
} catch (ex) {
console.console('§6插件 §b%s §6初始化时发生错误 §4%s'.format(file.name, ex.message));
console.ex(ex);
}
}
function readPlugin(file) {
var update = fs.file(fs.file(file.parentFile, 'update'), file.name);
if (update.exists()) {
console.info('自动升级插件 %s'.format(file.name));
@ -89,13 +97,17 @@ function loadPlugin(file) {
}
})
console.debug("插件编译结果: %s".format(JSON.stringify(plugin)));
plugin.__FILE__ = file;
return plugin;
}
function initPlugin(plugin) {
var desc = plugin.description;
if (!desc || !desc.name) {
console.warn("文件 %s 不存在 description 描述信息 无法加载插件!".format(file));
throw new Error("文件 %s 不存在 description 描述信息 无法加载插件!".format(plugin.__FILE__));
} else {
initPlugin(file, plugin);
internalInitPlugin(plugin);
afterLoadHook(plugin);
plugins[plugin.description.name] = plugin;
console.info('载入插件 %s 版本 %s By %s'.format(desc.name, desc.version || '未知', desc.author || '未知'));
}
return plugin;
@ -106,9 +118,9 @@ function beforeLoadHook(origin) {
// 处理 event 为了不影响 正常逻辑 event 还是手动require吧
// result = result + 'var event = {}; module.exports.event = event;';
// 注入 console 对象 // 给插件注入单独的 console
result = result + 'var console = new Console(); module.exports.console = console;';
result += '\nvar console = new Console(); module.exports.console = console;';
// 插件注入 self 对象
result = result + 'var self = {}; module.exports.self = self;';
result += '\nvar self = {}; module.exports.self = self;';
return result;
}
@ -123,11 +135,9 @@ function afterLoadHook(plugin) {
/**
* 初始化插件内容(提供config,__DATA__等参数)
*/
function initPlugin(file, plugin) {
// 初始化 __FILE__
plugin.__FILE__ = file;
function internalInitPlugin(plugin) {
// 初始化 __DATA__
plugin.__DATA__ = plugin.dataFolder = fs.file(file.parentFile, plugin.description.name);
plugin.__DATA__ = plugin.dataFolder = fs.file(plugin.__FILE__.parentFile, plugin.description.name);
// 初始化 getDataFolder()
plugin.getDataFolder = function getDataFolder() {
return plugin.__DATA__;
@ -180,9 +190,13 @@ function initPluginConfig(plugin) {
* @constructor (file, content)
*/
plugin.saveConfig = function () {
// 判断插件目录是否存在 并且不为文件 否则删除重建
if (!plugin.configFile.parentFile.isDirectory()) {
fs.del(plugin.configFile.parentFile);
}
plugin.configFile.parentFile.mkdirs();
switch (arguments.length) {
case 0:
plugin.configFile.parentFile.mkdirs();
fs.save(plugin.configFile, yaml.safeDump(plugin.config));
break;
case 2:
@ -204,13 +218,14 @@ function checkAndGet(args) {
}
var name = args[0];
// 如果是插件 则直接返回
if (name.description) {
if (name && name.description) {
return [name];
}
if (!exports.plugins[name]) {
var plugin = exports.plugins[name];
if (!plugin) {
throw new Error("插件 " + name + " 不存在!");
}
return [exports.plugins[name]];
return [plugin];
}
function checkAndRun(args, name, ext) {
@ -221,7 +236,7 @@ function checkAndRun(args, name, ext) {
try {
// 绑定方法的this到插件自身
if (typeof exec === "function") exec.call(jsp);
if (ext) ext.call(jsp);
if (typeof ext === "function") ext.call(jsp);
} catch (ex) {
console.console('§6插件 §b%s §6执行 §d%s §6方法时发生错误 §4%s'.format(jsp.description.name, name, ex.message));
console.ex(ex);
@ -270,5 +285,6 @@ exports = module.exports = {
load: load,
enable: enable,
disable: disable,
reload: reload
reload: reload,
loadPlugin: loadPlugin
}

View File

@ -1,2 +1,2 @@
/*global Java, base, module, exports, require*/
module.exports = require('./msp.js').server;
module.exports = requireInternal('server');

View File

@ -1,2 +1,2 @@
/*global Java, base, module, exports, require*/
module.exports = require('./msp.js').task;
module.exports = requireInternal('task');

View File

@ -35,7 +35,7 @@ var global = this;
var pluginYml;
function checkClassLoader() {
var classLoader = java.lang.Thread.currentThread().getContextClassLoader();
var classLoader = java.lang.Thread.currentThread().contextClassLoader;
pluginYml = classLoader.getResource("plugin.yml");
if (pluginYml === null) {
log.info("==================== ERROR ====================");

View File

@ -45,19 +45,19 @@ function file() {
* 创建目录
* @param file
*/
function mkdirs(file) {
function mkdirs(path) {
// noinspection JSUnresolvedVariable
file.parentFile.mkdirs();
fs.file(path).parentFile.mkdirs();
};
/**
* 创建文件
* @param file
*/
function create(file) {
f = file(file);
if (!f.exists()) {
mkdirs(f);
f.createNewFile();
function create(path) {
var file = fs.file(path)
if (!file.exists()) {
mkdirs(file);
file.createNewFile();
}
};
/**
@ -67,7 +67,7 @@ function create(file) {
*/
function path(file) {
// noinspection JSUnresolvedVariable
return file.canonicalPath;
return fs.file(file).canonicalPath;
};
/**
* 复制文件
@ -80,10 +80,10 @@ function copy(inputStream, target, override) {
};
/**
* 读取文件
* @param file 文件路径
* @param path 文件路径
*/
function read(f) {
var file = exports.file(f);
function read(path) {
var file = fs.file(path);
if (!file.exists()) {
console.warn('读取文件', file, '错误 文件不存在!');
return;
@ -98,11 +98,9 @@ function read(f) {
* @param override 是否覆盖
*/
function save(path, content, override) {
var file = new File(path);
var file = fs.file(path);
file.getParentFile().mkdirs();
Files.write(file.toPath(),
content.getBytes("UTF-8"),
override ? StandardCopyOption['REPLACE_EXISTING'] : StandardCopyOption['ATOMIC_MOVE']);
Files.write(file.toPath(), new java.lang.String(content).getBytes("UTF-8"));
};
/**
* 列出目录文件
@ -123,12 +121,12 @@ function list(path) {
* @param override 是否覆盖
*/
function move(src, des, override) {
Files.move(file(src).toPath(), file(des).toPath(),
Files.move(fs.file(src).toPath(), fs.file(des).toPath(),
override ? StandardCopyOption['REPLACE_EXISTING'] : StandardCopyOption['ATOMIC_MOVE'])
};
function del(file) {
file = exports.file(file);
file = fs.file(file);
if (!file.exists()) { return; }
if (file.isDirectory()) {
Files.list(file.toPath()).collect(Collectors.toList()).forEach(function (f) { del(f); })
@ -136,17 +134,25 @@ function del(file) {
Files.delete(file.toPath());
}
exports = module.exports = {
canonical: path,
function exists(file) {
return fs.file(file).exists()
}
var fs = {};
fs.path = fs.canonical = fs.realpath = path
fs.write = fs.save = save
fs.readdir = fs.list = list
fs.rename = fs.move = move
fs.delete = fs.del = del
Object.assign(fs, {
concat: concat,
create: create,
mkdirs: mkdirs,
file: file,
path: path,
copy: copy,
read: read,
save: save,
list: list,
move: move,
del: del
}
read: read
})
exports = module.exports = fs

View File

@ -8,7 +8,7 @@
global.noop = function () {
};
loadCore();
loadExt();
loadPatch();
loadRequire();
try {
loadServerLib();
@ -42,15 +42,15 @@
// 初始化加载器
global.require = engineLoad(root + '/core/require.js')(root);
global.requireInternal = function requireInternal(name) {
return require(root + '/internal/' + DetectServerType + '/' + name + '.js');
return require(root + '/internal/' + DetectServerType + '/' + name + '.js', arguments[1]);
}
}
/**
* 加载补丁
*/
function loadExt() {
java.nio.file.Files.list(new java.io.File(root, 'core/ext').toPath()).forEach(function (path) {
function loadPatch() {
java.nio.file.Files.list(new java.io.File(root, 'core/patch').toPath()).forEach(function (path) {
console.log('加载扩展类库', path);
try {
load(path.toFile());

View File

@ -0,0 +1,18 @@
/**
* 补丁和方法扩展
*/
(function () {
if (!Array.prototype.copyPartialMatches) {
Object.defineProperty(Array.prototype, "copyPartialMatches", {
enumerable: false,
value: function (token, array) {
this.forEach(function (e) {
if (e.toLowerCase().startsWith(token.toLowerCase())) {
array.push(e)
}
})
return array
}
});
}
})();

View File

@ -28,16 +28,37 @@
}
});
}
// // JSON快捷方法
if (!Object.values) {
Object.defineProperty(Object, "values", {
enumerable: false,
configurable: true,
writable: true,
value: function(target) {
"use strict";
var vals = [];
for (var key in target) {
var desc = Object.getOwnPropertyDescriptor(target, key);
if (desc !== undefined && desc.enumerable) vals.push(target[key]);
}
return vals;
}
});
}
// JSON快捷方法
if(!Object.toJson){
Object.defineProperty(Object.prototype, "toJson", {
enumerable: false,
configurable: true,
writable: true,
value: function() {
return JSON.stringify(this);
}
});
}
// Object.prototype.toJson = function () {
// return JSON.stringify(this);
// };

View File

@ -0,0 +1,52 @@
/*global Java, base, module, exports, require*/
var bukkit = require('api/server');
var nmsChatSerializerClass;
var nmsIChatBaseComponentClass;
var packetTypeClass;
var nmsChatMessageTypeClass;
var chatMessageTypes;
var String = Java.type('java.lang.String');
function init () {
nmsChatSerializerClass = bukkit.nmsCls(bukkit.nmsVersion.split("_")[1] > 7 ? "IChatBaseComponent$ChatSerializer" : "ChatSerializer");
nmsIChatBaseComponentClass = bukkit.nmsCls('IChatBaseComponent');
packetTypeClass = bukkit.nmsCls("PacketPlayOutChat");
var packetTypeConstructor;
Java.from(packetTypeClass.class.constructors).forEach(function (c) {
if (c.parameterTypes.length == 2) { packetTypeConstructor = c };
})
nmsChatMessageTypeClass = packetTypeConstructor.parameterTypes[1];
if (nmsChatMessageTypeClass.isEnum()) {
chatMessageTypes = nmsChatMessageTypeClass.getEnumConstants();
} else {
switch (nmsChatMessageTypeClass.name) {
case "int":
nmsChatMessageTypeClass = java.lang.Integer;
case "byte":
nmsChatMessageTypeClass = java.lang.Byte;
}
}
}
function json(sender, json) {
send(sender, json, 0);
}
function send(sender, json, type) {
var serialized = nmsChatSerializerClass.a(json)
var typeObj = chatMessageTypes == null ? nmsChatMessageTypeClass.valueOf(String.valueOf(type)) : chatMessageTypes[type];
sendPacket(sender, new packetTypeClass(serialized, typeObj))
}
function sendPacket(player, p) {
player.handle.playerConnection.sendPacket(p);
}
init();
exports = module.exports = {
json: json
};

View File

@ -67,7 +67,8 @@ function on(jsp, name, exec) {
try {
return exec.cmd(sender, command, args);
} catch (ex) {
console.console('§6玩家 §a%s §6执行 §b%s §6插件 §d%s %s §6命令时发生异常 §4%s'.format(sender.name, jsp.description.name, command, Java.from(args).join(' '), ex));
console.console('§6玩家 §a%s §6执行 §b%s §6插件 §d%s %s §6命令时发生异常 §4%s'
.format(sender.name, jsp.description.name, command, Java.from(args).join(' '), ex));
console.ex(ex);
}
}
@ -78,12 +79,12 @@ function on(jsp, name, exec) {
c.setTabCompleter(new org.bukkit.command.TabCompleter({
onTabComplete: 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;
var complate = exec.tab(sender, command, args) || []
return Arrays.asList(complate.copyPartialMatches(token, []));
} catch (ex) {
console.console('§6玩家 §a%s §6执行 §b%s §6插件 §d%s %s §6补全时发生异常 §4%s'.format(sender.name, jsp.description.name, command, Java.from(args).join(' '), ex));
console.console('§6玩家 §a%s §6执行 §b%s §6插件 §d%s %s §6补全时发生异常 §4%s'
.format(sender.name, jsp.description.name, command, Java.from(args).join(' '), ex));
console.ex(ex);
}
}

View File

@ -19,6 +19,12 @@ exports.nmsVersion = Bukkit.server.class.name.split('.')[3];
exports.nmsCls = function (name) {
return Java.type(['net.minecraft.server', exports.nmsVersion, name].join('.'));
};
/**
* 获取OBC类
*/
exports.obcCls = function (name) {
return Java.type(['org.bukkit.craftbukkit', exports.nmsVersion, name].join('.'));
};
/**
* 获取玩家
*/

View File

@ -0,0 +1,9 @@
/*global Java, base, module, exports, require*/
var TextSerializers = Java.type('org.spongepowered.api.text.serializer.TextSerializers');
function json(sender, json) {
sender.sendMessage(TextSerializers.JSON.deserialize(json));
}
exports = module.exports = {
json: json
};

View File

@ -23,19 +23,19 @@ var Arrays = Java.type('java.util.Arrays');
var commandMap=[];
var SimpleCommandCallable = function (name) {
var SimpleCommandCallable = function (command) {
var that = this;
this.name = name;
this.name = command.name;
this.cmd = noop;
this.tab = function() { return new ArrayList(); };
this.callable = new CommandCallable({
//CommandResult process(CommandSource source, String arguments) throws CommandException;
process: function (src, args) {
return that.cmd(src, name, args.split(" ")) ? CommandResult.success() : CommandResult.empty();
return that.cmd(src, that.name, args.length === 0 ? [] : args.split(" ")) ? CommandResult.success() : CommandResult.empty();
},
//List<String> getSuggestions(CommandSource source, String arguments, @Nullable Location<World> targetPosition) throws CommandException;
getSuggestions: function (src, args, target) {
return that.tab(src, name, args.split(" "));
return that.tab(src, that.name, args.length === 0 ? [] : args.split(" "));
},
//boolean testPermission(CommandSource source);
testPermission: function () {
@ -43,7 +43,7 @@ var SimpleCommandCallable = function (name) {
},
//Optional<Text> getShortDescription(CommandSource source);
getShortDescription: function () {
return Optional.of(Text.of(""));
return Optional.of(Text.of(command.description || '暂无描述!'));
},
//Optional<Text> getHelp(CommandSource source);
getHelp: function () {
@ -70,7 +70,8 @@ function enable(jsp) {
for (var name in commands) {
var command = commands[name];
if (typeof command !== 'object') continue;
create(jsp, name)
command.name = name
create(jsp, command)
console.debug('插件 %s 注册命令 %s ...'.format(jsp.description.name, name));
}
}
@ -79,37 +80,38 @@ function enable(jsp) {
function get(name) {
}
function create(jsp, name) {
var commandKey = jsp.description.name.toLowerCase() + ":" + name;
function create(jsp, command) {
var commandKey = jsp.description.name.toLowerCase() + ":" + command.name;
if(!commandMap[commandKey]){
commandMap[commandKey] = new SimpleCommandCallable();
commandMap[commandKey].name = name;
Sponge.getCommandManager().register(plugin, commandMap[commandKey].callable, name, commandKey);
commandMap[commandKey] = new SimpleCommandCallable(command);
Sponge.getCommandManager().register(plugin, commandMap[commandKey].callable, command.name, commandKey);
}
return commandMap[commandKey];
}
function on(jsp, name, exec) {
var c = create(jsp, name);
var c = create(jsp, {name: name});
console.debug('插件 %s 设置命令 %s 执行器 ...'.format(jsp.description.name, name));
if (exec.cmd) {
c.setExecutor(function (sender, command, args) {
c.setExecutor(function execCmd(sender, command, args) {
try {
return exec.cmd(sender, command, args);
} catch (ex) {
console.log(args)
console.console('§6玩家 §a%s §6执行 §b%s §6插件 §d%s %s §6命令时发生异常 §4%s'.format(sender.name, jsp.description.name, command, args, ex));
console.console('§6玩家 §a%s §6执行 §b%s §6插件 §d%s %s §6命令时发生异常'
.format(sender.name, jsp.description.name, command, args.join(' ')));
console.ex(ex);
}
});
}
if (exec.tab) {
c.setTabCompleter(function (sender, command, args) {
c.setTabCompleter(function execTab(sender, command, args) {
try {
var token = args[args.length - 1];
return Arrays.asList(exec.tab(sender, command, args));
var complate = exec.tab(sender, command, args) || []
return Arrays.asList(complate.copyPartialMatches(token, []));
} catch (ex) {
console.console('§6玩家 §a%s §6执行 §b%s §6插件 §d%s %s §6补全时发生异常 §4%s'.format(sender.name, jsp.description.name, command, args, ex));
console.console('§6玩家 §a%s §6执行 §b%s §6插件 §d%s %s §6补全时发生异常'
.format(sender.name, jsp.description.name, command, args.join(' ')));
console.ex(ex);
}
});

View File

@ -32,7 +32,7 @@ function isVaildEvent(clz) {
}
function class2Name(clazz) {
return clazz.name.substring(clazz.name.lastIndexOf(".") + 1).replace(/\$/g, '.').toLowerCase();
return clazz.canonicalName.substring(clazz.name.lastIndexOf(".") + 1);
}
function register(eventCls, exec, priority, ignoreCancel) {

View File

@ -24,7 +24,7 @@ exports.plugin = {
* @returns {*}
*/
get: function (name) {
return PluginManager.getPlugin(name);
return PluginManager.getPlugin(name).orElse(undefined);
},
/**
* 载入插件 并且返回结果
@ -38,7 +38,7 @@ exports.plugin = {
}
return PluginManager.isPluginEnabled(name);
},
self: PluginManager.getPlugin('miaoscript').get()
self: PluginManager.getPlugin('miaoscript').orElse(undefined)
};
/**
* 获取玩家
@ -48,9 +48,9 @@ exports.player = function () {
case 0:
return undefined;
case 1:
return Server.getPlayer(arguments[0]).get();
return Server.getPlayer(arguments[0]).orElse(undefined);
default:
return Server.getPlayer(arguments[0]).get();
return Server.getPlayer(arguments[0]).orElse(undefined);
}
};
/**
@ -59,8 +59,10 @@ exports.player = function () {
exports.players = function () {
switch (arguments.length) {
case 1:
// 此处的forEach是Collection接口的
return Server.onlinePlayers.forEach(arguments[0]);
default:
return Server.onlinePlayers;
// 此处会转换为JS原生的Array
return Java.from(Server.onlinePlayers.toArray());
}
};

View File

@ -39,7 +39,8 @@ var SSLSocketFactory = function initSSLSocketFactory() {
var config = {
Charset: 'UTF-8',
ConnectTimeout: 10000,
ReadTimeout: 10000
ReadTimeout: 10000,
Debug: false
}
function open(url, method, header) {
@ -54,8 +55,10 @@ function open(url, method, header) {
conn.setDoInput(true);
conn.setConnectTimeout(config.ConnectTimeout);
conn.setReadTimeout(config.ReadTimeout);
for (var key in header) {
conn.setRequestProperty(key, header[key]);
if (header) {
for (var key in header) {
conn.setRequestProperty(key, header[key]);
}
}
return conn;
}
@ -66,24 +69,28 @@ function buildUrl(url, params) {
if (queryStart == -1) {
url += '?';
}
for (var key in params) {
url += key;
url += '=';
url += params[key];
url += '&';
}
return url.substr(0, url.length - 1);
return url += object2URLSearchParams(params);
}
return url;
}
function request(url, method, header, params, body) {
var conn = open(buildUrl(url, params), method, header);
function request(config) {
var conn = open(buildUrl(config.url, config.query), config.method, config.header);
try {
conn.connect();
if (body) {
var data = config.data;
if (data) {
var out = conn.getOutputStream();
out.write(new String(body).getBytes(config.Charset));
if (typeof data === "object") {
var type = config.header['Content-Type'];
switch (type) {
case "application/x-www-form-urlencoded":
data = object2URLSearchParams(params);
default:
data = JSON.stringify(data)
}
}
out.write(new String(data).getBytes(config.Charset));
out.flush();
out.close();
}
@ -102,14 +109,37 @@ function response (conn) {
return result;
}
function object2URLSearchParams (params) {
var temp = []
for (var key in params) {
temp.push('%s=%s'.format(encodeURIComponent(key), encodeURIComponent(params[key])))
}
return temp.join('&')
}
var http = {
config: config
config: config,
request: request
};
['GET', 'POST', 'PUT', 'DELETE', 'HEADER'].forEach(function(method){
http[method.toLowerCase()] = function (url, header, params, body) {
return request(url, method, header, params, body);
['GET', 'DELETE', 'HEAD', 'OPTIONS'].forEach(function (method) {
http[method.toLowerCase()] = function __likeGet__(url, data, config) {
return this.request(Object.assign(config || {}, {
url: url,
method: method,
query: data
}));
}
})
});
['POST', 'PUT', 'PATCH'].forEach(function (method) {
http[method.toLowerCase()] = function __likePost__(url, data, config) {
return this.request(Object.assign(config || {}, {
url: url,
method: method,
data: data
}));
}
});
exports = module.exports = http;

View File

@ -0,0 +1,139 @@
/*global Java, base, module, exports, require*/
var chat = require('api/chat');
var ChatMessagePart = function () {
var text;
var clickEventAction;
var clickEventValue;
var hoverEventAction;
var hoverEventValue;
var insertion;
this.click = function (action, value) {
this.clickEventAction = action;
this.clickEventValue = value;
}
this.hover = function (action, value) {
this.hoverEventAction = action;
this.hoverEventValue = value;
console.log(this.toJson());
}
this.convert = function () {
var str = {};
if (this.text) {
str.text = this.text;
}
if (this.clickEventAction) {
str.clickEvent = {
"action": this.clickEventAction,
"value": this.clickEventValue
}
}
if (this.hoverEventAction) {
str.hoverEvent = {
"action": this.hoverEventAction,
"value": this.hoverEventValue
}
}
if (this.insertion) {
str.insertion = this.insertion;
}
return str;
}
}
var Tellraw = function () {
var parts = [new ChatMessagePart()];
var self = this;
var cache = null;
this.then = function (part) {
if (typeof part === "string") {
var newPart = new ChatMessagePart();
newPart.text = part;
this.then(newPart);
return self;
}
var last = this.latest();
if (!last.text) {
last.text = part.text;
} else {
parts.push(part);
}
this.cache = null;
}
this.text = function (text) {
this.latest().text = text;
return this;
}
this.tip = function (str) {
if (toString.call(str) === "[object Array]") {
str = str.join("\n");
}
this.latest().hover("show_text", str);
return this;
}
this.item = function (str) {
this.latest().hover("show_item", str);
return this;
}
this.cmd = this.command = function (command) {
this.latest().click("run_command", command);
return this;
}
this.suggest = function (url) {
this.latest().click("suggest_command", url);
return this;
}
this.file = function (path) {
this.latest().click("open_file", path);
return this;
}
this.link = function (url) {
this.latest().click("open_url", url);
return this;
}
this.latest = function () {
return parts[parts.length - 1];
}
this.json = function () {
if (!this.cache) {
var temp = [];
parts.forEach(function (t) {
temp.push(t.convert());
})
this.cache = JSON.stringify(temp);
console.debug(this.cache);
}
return this.cache;
}
this.send = function (player) {
chat.json(player, self.json());
}
this.sendAll = function () {
server.players(function sendAllMessage(p) {
self.send(p);
})
}
}
Tellraw.create = function () {
return new Tellraw().then(Tellraw.duplicateChar);
}
Tellraw.duplicateChar = '§卐';
exports = module.exports = Tellraw;

View File

@ -0,0 +1,35 @@
'use strict';
/**
* 常用工具类
* Created by 蒋天蓓 on 2018/5/12 0009.
*/
/*global Java, base, module, exports, require, __FILE__*/
var Arrays = Java.type('java.util.Arrays');
function toStr(obj) {
if (obj.class) {
return Arrays.toString()
}
}
function compare(prop) {
return function (obj1, obj2) {
var val1 = obj1[prop];
var val2 = obj2[prop];
if (!isNaN(Number(val1)) && !isNaN(Number(val2))) {
val1 = Number(val1);
val2 = Number(val2);
}
if (val1 < val2) {
return -1;
} else if (val1 > val2) {
return 1;
} else {
return 0;
}
}
}
exports = module.exports = {
compare: compare
}

View File

@ -52,7 +52,7 @@ function send(event, player){
console.debug('玩家', player.getName(), "触发事件", event.class.simpleName);
setTimeout(function () {
// noinspection JSUnresolvedVariable
player.sendMessage("§a欢迎来到 §bMiaoScript §a的世界! 当前在线: " + server.players.length)
player.sendMessage("§a欢迎来到 §bMiaoScript §a的世界! 当前在线: " + server.players().length)
}, 10);
}

View File

@ -1,14 +1,13 @@
'use strict';
/*global Java, base, module, exports, require*/
var event = require('api/event');
var wrapper = require('api/wrapper');
var command = require('api/command');
var server = require('api/server');
var event = require('api/event');
var task = require('api/task');
var http = require('http');
var fs = require('fs');
var nameMap = [];
var Keys;
var description = {
name: 'ItemTag',
@ -20,10 +19,12 @@ var itemConfig;
function load() {
var itemFile = self.file('item.yml');
if (!itemFile.exists()) {
base.save(itemFile, http.get('https://data.yumc.pw/config/Item_zh_CN.yml'));
}
itemConfig = self.getConfig('item.yml');
task.async(function () {
if (!itemFile.exists()) {
fs.save(itemFile, http.get('https://data.yumc.pw/config/Item_zh_CN.yml'))
}
itemConfig = self.getConfig('item.yml')
})
}
function enable() {
@ -39,10 +40,11 @@ function enable() {
})
break;
case ServerType.Sponge:
event.on(self, 'itemmergeitemevent', function (event) {
Keys = Java.type('org.spongepowered.api.data.key.Keys');
event.on(self, 'ItemMergeItemEvent', function (event) {
// Sponge 暂未实现当前事件
})
event.on(self, 'spawnentityevent', function (event) {
event.on(self, 'SpawnEntityEvent', function (event) {
event.entities.forEach(function (entity) {
if (entity.type.name === "item") sponge(entity);
})
@ -51,13 +53,8 @@ function enable() {
}
}
function getItemName(name) {
return itemConfig[(name + '').toUpperCase()] || name;
}
function bukkit(item , amount) {
var amounts = amount == 1 ? "" : "*" + amount;
item.setCustomName('§b' + getItemName(item.itemStack.type) + amounts);
item.setCustomName('§b' + getItemName(item.itemStack.type) + getItemCount(amount));
item.setCustomNameVisible(true);
}
@ -65,12 +62,20 @@ function sponge(entity) {
var itemOptional = entity.get(Keys.REPRESENTED_ITEM);
if (itemOptional.isPresent()) {
var item = itemOptional.get();
var amounts = item.count == 1 ? "" : "*" + item.count;
entity.offer(org.spongepowered.api.data.key.Keys.DISPLAY_NAME, org.spongepowered.api.text.Text.of('§b' + getItemName(item.type.name.split(':')[1]) + amounts));
entity.offer(org.spongepowered.api.data.key.Keys.CUSTOM_NAME_VISIBLE, true);
var itemName = '§b' + getItemName(item.type.name.split(':')[1]) + getItemCount(item.count);
entity.offer(Keys.DISPLAY_NAME, org.spongepowered.api.text.Text.of(itemName));
entity.offer(Keys.CUSTOM_NAME_VISIBLE, true);
}
}
function getItemName(name) {
return itemConfig[(name + '').toUpperCase()] || name;
}
function getItemCount(amount){
return amount == 1 ? "" : "*" + amount;
}
module.exports = {
description: description,
load: load,

View File

@ -0,0 +1,252 @@
'use strict';
/**
* MiaoChat 喵式聊天插件
*/
/*global Java, base, module, exports, require*/
var event = require('api/event');
var wrapper = require('api/wrapper');
var command = require('api/command');
var server = require('api/server');
var fs = require('fs');
var tellraw = require('tellraw');
var utils = require('utils')
var description = {
name: 'MiaoChat',
version: '1.0',
author: '喵呜',
commands: {
'mchat': {
description: 'MiaoChat登录命令'
}
},
permissions: {
'MiaoChat.default': {
default: true,
description: '默认权限 赋予玩家'
},
'MiaoChat.admin': {
default: false,
description: '管理权限'
}
},
config: {
"Version":"1.8.5",
"BungeeCord":true,
"Server":"生存服",
"ChatFormats":{
"default":{
"index":50,
"permission":"MiaoChat.default",
"range":0,
"format":"[world][player]: ",
"item":true,
"itemformat":"&6[&b%s&6]&r"
},
"admin":{
"index":49,
"permission":"MiaoChat.admin",
"format":"[admin][world][player][help]: ",
"range":0,
"item":true,
"itemformat":"&6[&b%s&6]&r"
}
},
StyleFormats: {
"world":{
"text":"&6[&a%player_world%&6]",
"hover":[
"&6当前所在位置:",
"&6世界: &d%player_world%",
"&6坐标: &aX:%player_x% Y: %player_y% Z: %player_z%",
"",
"&c点击即可TP我!"
],
"click":{
"type":"COMMAND",
"command":"/tpa %player_name%"
}
},
"player":{
"text":"&b%player_name%",
"hover":[
"&6玩家名称: &b%player_name%",
"&6玩家等级: &a%player_level%",
"&6玩家血量: &c%player_health%",
"&6玩家饥饿: &d%player_food_level%",
"&6游戏模式: &4%player_gamemode%",
"",
"&c点击与我聊天"
],
"click":{
"type":"SUGGEST",
"command":"/tell %player_name%"
}
},
"admin":{
"text":"&6[&c管理员&6]"
},
"help":{
"text":"&4[求助]",
"hover":[
"点击求助OP"
],
"click":{
"type":"COMMAND",
"command":"管理员@%player_name% 我需要你的帮助!"
}
}
}
}
};
var chat_formats;
var style_formats;
function load() {
chat_formats = Object.values(self.config.ChatFormats);
chat_formats.sort(utils.compare('index'));
initFormat(chat_formats);
style_formats = self.config.StyleFormats;
}
// 用于匹配 '[xx]' 聊天格式
var FORMAT_PATTERN = /[\[]([^\[\]]+)[\]]/ig;
function initFormat(chat_formats) {
chat_formats.forEach(function (chat_format) {
var chat_format_str = chat_format.format;
var temp = [];
var r = [];
while(r = FORMAT_PATTERN.exec(chat_format_str)) {
temp.push(r[1]);
}
var format_list = []
temp.forEach(function splitStyle(t) {
var arr = chat_format_str.split('[' + t + ']', 2);
if (arr[0]) {
format_list.push(arr[0]);
}
format_list.push(t);
chat_format_str = arr[1];
});
if (chat_format_str) {
format_list.push(chat_format_str);
}
chat_format.format_list = format_list;
})
}
function enable() {
registerCommand();
registerEvent();
}
function registerCommand() {
command.on(self, 'mchat', {
cmd: mchat
});
}
function mchat(sender, command, args) {
return true;
}
function registerEvent() {
switch (DetectServerType) {
case ServerType.Bukkit:
event.on(self, 'AsyncPlayerChatEvent', handlerBukkitChat);
break;
case ServerType.Sponge:
event.on(self, 'MessageChannelEvent.Chat', handlerSpongeChat);
break;
}
}
function handlerBukkitChat(event) {
sendChat(event.player, event.message, function() { event.setCancelled(true); });
}
function handlerSpongeChat(event) {
var player = event.getCause().first(org.spongepowered.api.entity.living.player.Player.class).orElse(null);
if (player == null) { return; }
var plain = event.getRawMessage().toPlain();
if (plain.startsWith(tellraw.duplicateChar)) {
return;
}
sendChat(player, plain, function() { event.setMessageCancelled(true) });
}
function sendChat(player, plain, callback) {
var chat_format = getChatFormat(player);
if (!chat_format) {
console.debug('未获得用户', player.name, '的 ChatRule 跳过执行...')
return;
}
callback();
var tr = tellraw.create();
chat_format.format_list.forEach(function setStyle(format) {
var style = style_formats[format];
if (style) {
tr.then(style.text);
if (style.hover) {
tr.tip(style.hover);
}
if (style.click && style.click.type && style.click.command) {
switch (style.click.type) {
case "COMMAND":
tr.command(style.click.command);
break;
case "OPENURL":
tr.link(style.click.command);
break;
case "SUGGEST":
tr.suggest(style.click.command);
break;
default:
}
}
} else {
tr.then(format);
}
})
tr.then(plain).sendAll();
}
function getChatFormat(player) {
for (var i in chat_formats){
var format = chat_formats[i];
if (player.hasPermission(format.permission)) {
return format;
}
}
return null;
}
function replace(target) {
if (toString.call(target) === "[object Array]") {
for (var i in target) {
target[i] = replaceStr(target[i]);
}
} else {
target = replaceStr(target);
}
return target;
}
function replaceStr(target) {
return target;
}
function disable() {
console.log('卸载', description.name, '插件!');
}
module.exports = {
description: description,
load: load,
enable: enable,
disable: disable
};

View File

@ -0,0 +1,162 @@
'use strict'
/*global Java, base, module, exports, require*/
var wrapper = require('api/wrapper')
var command = require('api/command')
var manager = require('api/plugin')
var task = require('api/task')
var http = require('http')
var fs = require('fs')
var pluginCache = []
var packageCache = []
var packageNameCache = []
var description = {
name: 'MiaoScriptPackageManager',
version: '1.0',
author: '喵♂呜',
description: 'MiaoScript包管理工具',
commands: {
'mpm': {
description: 'MiaoScriptPackageManager主命令'
}
},
config: {
center: 'https://ms.yumc.pw/api/package/list'
}
}
var help = [
'§6========= §a' + description.name + ' §6帮助 §aBy §b喵♂呜 §6=========',
'§6/mpm §ainstall <插件名称> §6- §3安装插件',
'§6/mpm §alist §6- §3列出仓库插件',
'§6/mpm §aupdate <插件名称> §6- §3更新插件(无插件名称则更新源)',
'§6/mpm §aupgrade <插件名称> §6- §3及时更新插件(update需要重启生效)',
'§6/mpm §areload <插件名称> §6- §3重载插件(无插件名称则重载自生)',
]
function load() {
task.async(function () {
JSON.parse(http.get(self.config.center)).data.forEach(function cachePackageName(pkg) {
packageCache[pkg.name] = pkg
packageNameCache.push(pkg.name)
})
pluginCache = Object.keys(manager.plugins)
})
}
function enable() {
command.on(this, 'mpm', {
cmd: function (sender, command, args) {
if (args.length > 0) {
switch (args[0]) {
case "list":
console.sender(sender, '§6当前 §bMiaoScriptPackageCenter §6中存在下列插件:')
for (var pkgName in packageCache) {
var pkg = packageCache[pkgName]
console.sender(sender, '§6插件名称: §b%s §6版本: §a%s'.format(pkg.name, pkg.version))
}
break
case "install":
if (args.length > 1) {
download(sender, args[1]);
} else {
console.sender(sender, '§c请输入插件名称!')
}
break
case "update":
if (args.length > 1) {
update(sender, args[1]);
} else {
load();
console.sender(sender, "§a仓库缓存刷新成功 共存在 §b" + pluginCache.length + " §a个插件!")
}
break
case "upgrade":
break
case "delete":
if (args.length > 1) {
del(sender, args[1]);
} else {
console.sender(sender, '§c请输入插件名称!')
}
break
case "reload":
if (args.length > 1) {
var pname = args[1]
if (pluginCache.indexOf(pname) !== -1) {
manager.reload(pname)
} else {
console.sender(sender, '§c插件 %s 不存在!'.format(pname))
}
} else {
self.reloadConfig();
load();
}
break
case "help":
sendHelp(sender);
break;
}
} else {
sendHelp(sender);
}
},
tab: function (sender, command, args) {
if (args.length === 1) return ['list', 'install', 'update', 'upgrade', 'reload']
if (args.length > 1) {
switch (args[0]) {
case "install":
return packageNameCache;
case "update":
case "upgrade":
case "reload":
return pluginCache;
}
}
}
})
}
function sendHelp(sender){
help.forEach(function (msg) {
console.sender(sender, msg);
})
}
function del(sender, name) {
if (pluginCache.indexOf(name) !== -1) {
console.sender(sender, '§c插件 %s 不存在!'.format(name));
return;
}
manager.disable(name);
fs.delete(plugin.__FILE__);
}
function download(sender, name) {
var plugin = packageCache[name];
if (!plugin) {
console.sender(sender, '§c插件§b', name, '§c不存在')
return;
}
var pfile = fs.file(__dirname, pname + '.js')
console.sender(sender, '§6开始下载插件: §b%s'.format(pkg.name))
console.sender(sender, '§6插件下载地址: §b%s'.format(pkg.url))
fs.save(pfile, http.get(pkg.url))
console.sender(sender, '§6插件 §b%s §a下载完毕 开始加载 ...'.format(pname))
manager.loadPlugin(pfile)
console.sender(sender, '§6插件 §b%s §a安装成功!'.format(pname))
}
function disable() {
}
module.exports = {
description: description,
load: load,
enable: enable,
disable: disable
}