Compare commits
72 Commits
v0.18.0
...
v0.28.0-be
| Author | SHA1 | Date | |
|---|---|---|---|
| e70c78a255 | |||
| 9cfac1672a | |||
| 9126ec8035 | |||
| 23bc6068b5 | |||
| 27b428fbe2 | |||
| c07f1131c4 | |||
| 002f2c47c6 | |||
| 8633d9ea95 | |||
| 07a5d0c8de | |||
| dd76e563c8 | |||
| 7b85ff5b7c | |||
| 359aeb9d63 | |||
| 3901d9fb5f | |||
| c2867da047 | |||
| 65832c9fae | |||
| d9dffa704d | |||
| b39f29de6a | |||
| 56334c6f6e | |||
| 72673b2a67 | |||
| 597bdb721a | |||
| 6e0456d777 | |||
| fb67b06230 | |||
| 203560dcf2 | |||
| 3f58f5992c | |||
| ac16754c9c | |||
| 42d637dd63 | |||
| df0d246136 | |||
| e563e1b507 | |||
| 3b822c613a | |||
| 2967c2a1fe | |||
| 1c579c9789 | |||
| 2fe9bce2ea | |||
| 496d278a93 | |||
| bdf674b678 | |||
| 67fe13deac | |||
| 30846cdc87 | |||
| d8d03149df | |||
| b6d7847a79 | |||
| 58f59f8260 | |||
| f3fa14990f | |||
| 15d1f8392b | |||
| b5fac23c5c | |||
| 148f6c28c4 | |||
| 880065495e | |||
| 7fc70a92d5 | |||
| df6da12a8a | |||
| 082f2b8f73 | |||
| 7cd85f3f34 | |||
| 073cf6aaac | |||
| 43aa39b86f | |||
| cb58fbdb6c | |||
| 86aacf1a1f | |||
| 47413c6766 | |||
| 4ee8fc9a20 | |||
| 8d0484eefb | |||
| 579d89ae89 | |||
| 010f561766 | |||
| 848aacd991 | |||
| ab5559b26f | |||
| 46729b9cf0 | |||
| 83cad2f52e | |||
| a5cb084767 | |||
| 16ab108186 | |||
| a1df719dc9 | |||
| 41e5754492 | |||
| 866d1dd62c | |||
| 8056d3060d | |||
| b8440b83de | |||
| b55e662f81 | |||
| db526e9444 | |||
| 1b0ea9fa05 | |||
| 143c960da5 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
.yarn*
|
||||
.vscode
|
||||
.theia
|
||||
node_modules
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
src
|
||||
test
|
||||
typings
|
||||
bundled
|
||||
|
||||
47
README.MD
47
README.MD
@@ -8,27 +8,28 @@
|
||||
|
||||
```txt
|
||||
└─packages
|
||||
├─api 全平台兼容的接口
|
||||
├─core 核心代码 用于引导加载
|
||||
├─common 公共类库代码 例如 http reflect 模块
|
||||
├─client NodeJS的Minecraft客户端 用于调试插件
|
||||
├─container IOC容器 用于注入具体实现
|
||||
├─ployfill Nashorn 的一些自定义增强
|
||||
├─nashorn Nashorn 的类型定义
|
||||
├─bungee BungeeCordAPI内部实现
|
||||
├─bukkit BukkitAPI内部实现
|
||||
├─sponge SpongeAPI内部实现
|
||||
├─nukkit NukkitAPI内部实现
|
||||
├─plugin 插件管理器
|
||||
├─websocket Netty的WebSocket注入
|
||||
├─type Java的类型定义
|
||||
| ├─bungee BungeeCord类型定义
|
||||
| ├─bukkit Bukkit类型定义
|
||||
| ├─sponge Sponge类型定义
|
||||
| └─nukkit Nukkit类型定义
|
||||
└─plugins 这里当然是插件啦
|
||||
├─bungee 只兼容BungeeCord的插件
|
||||
├─bukkit 只兼容Bukkit的插件
|
||||
├─sponge 只兼容Sponge的插件
|
||||
└─nukkit 只兼容Nukkit的插件
|
||||
├─api 全平台兼容的接口
|
||||
├─core 核心代码 用于引导加载
|
||||
├─common 公共类库代码 例如 http reflect 模块
|
||||
├─compile 编译器相关功能
|
||||
├─client NodeJS 的 Minecraft 客户端 已迁移至 ms-client
|
||||
├─container IOC容器 用于注入具体实现
|
||||
├─database 数据库相关功能
|
||||
├─protocol 协议处理相关功能
|
||||
├─service 服务相关功能
|
||||
├─i18n 多语言环境相关支持
|
||||
├─polyfill Nashorn 的一些自定义增强
|
||||
├─nashorn Nashorn 的类型定义
|
||||
├─nodejs NodeJS 的部分 Java 实现
|
||||
├─bungee BungeeCordAPI 内部实现
|
||||
├─bukkit BukkitAPI 内部实现
|
||||
├─sponge SpongeAPI 内部实现
|
||||
├─nukkit NukkitAPI 内部实现
|
||||
├─molang MoLang 解析库
|
||||
├─qrcode 二维码相关类库
|
||||
├─plugin 插件管理器
|
||||
├─websocket WebSocket 相关实现
|
||||
| ├─client 基于 Netty 的 WebSocket 客户端
|
||||
| └─server 基于 Netty 的 WebSocket 服务端
|
||||
└─type 类型定义 已迁移到 @javatypes
|
||||
```
|
||||
|
||||
26
lerna.json
26
lerna.json
@@ -1,17 +1,15 @@
|
||||
{
|
||||
"version": "0.18.0",
|
||||
"useWorkspaces": true,
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"command": {
|
||||
"run": {
|
||||
"stream": true
|
||||
},
|
||||
"publish": {
|
||||
"access": "public",
|
||||
"registry": "https://repo.yumc.pw/repository/npm-hosted/"
|
||||
}
|
||||
"version": "0.28.0-beta.2",
|
||||
"npmClient": "yarn",
|
||||
"packages": [
|
||||
"packages/*"
|
||||
],
|
||||
"command": {
|
||||
"run": {
|
||||
"stream": true
|
||||
}
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
|
||||
12
package.json
12
package.json
@@ -10,15 +10,19 @@
|
||||
"clean": "lerna run clean",
|
||||
"watch": "lerna run watch --parallel",
|
||||
"build": "lerna run build",
|
||||
"ug": "yarn upgrade-interactive --latest",
|
||||
"ug": "yarn upgrade-interactive",
|
||||
"np": "./script/push.sh",
|
||||
"lsp": "npm login --registry=https://registry.npmjs.org --scope=@ccms",
|
||||
"lp": "lerna publish --registry https://registry.npmjs.org"
|
||||
"lsp": "npm login -scope=@ccms",
|
||||
"lp": "lerna publish --force-publish",
|
||||
"lpb": "lerna publish --preid beta --dist-tag beta --force-publish",
|
||||
"lpc": "lerna publish --canary --preid beta --pre-dist-tag beta --force-publish",
|
||||
"lpf": "lerna publish from-package --yes",
|
||||
"sync": "./script/sync.sh"
|
||||
},
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
],
|
||||
"devDependencies": {
|
||||
"lerna": "^4.0.0"
|
||||
"lerna": "^7.1.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ccms/amqp",
|
||||
"version": "0.18.0",
|
||||
"version": "0.28.0-beta.2",
|
||||
"description": "MiaoScript amqp package",
|
||||
"keywords": [
|
||||
"miaoscript",
|
||||
@@ -19,17 +19,17 @@
|
||||
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ccms/api": "^0.18.0",
|
||||
"@ccms/common": "^0.18.0",
|
||||
"@ccms/container": "^0.18.0"
|
||||
"@ccms/api": "^0.28.0-beta.2",
|
||||
"@ccms/common": "^0.28.0-beta.2",
|
||||
"@ccms/container": "^0.28.0-beta.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ccms/nashorn": "^0.18.0",
|
||||
"@ccms/nashorn": "^0.28.0-beta.2",
|
||||
"@javatypes/amqp-client": "^0.0.3",
|
||||
"@javatypes/spring-amqp": "^0.0.3",
|
||||
"@javatypes/spring-rabbit": "^0.0.3",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.5.5"
|
||||
"rimraf": "^4.1.2",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ccms/api",
|
||||
"version": "0.18.0",
|
||||
"version": "0.28.0-beta.2",
|
||||
"description": "MiaoScript api package",
|
||||
"keywords": [
|
||||
"miaoscript",
|
||||
@@ -19,16 +19,16 @@
|
||||
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ccms/common": "^0.18.0",
|
||||
"@ccms/container": "^0.18.0",
|
||||
"@ccms/polyfill": "^0.18.0",
|
||||
"@ccms/common": "^0.28.0-beta.2",
|
||||
"@ccms/container": "^0.28.0-beta.2",
|
||||
"@ccms/polyfill": "^0.28.0-beta.2",
|
||||
"base64-js": "^1.5.1",
|
||||
"source-map-builder": "^0.0.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/base64-js": "^1.3.0",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.5.5"
|
||||
"rimraf": "^4.1.2",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,13 @@ import { plugin } from './plugin'
|
||||
export namespace command {
|
||||
@injectable()
|
||||
export abstract class Command {
|
||||
/**
|
||||
* first time script engine need optimize jit code
|
||||
* so ignore first slow exec notify
|
||||
*/
|
||||
private cacheSlowCommandKey = {};
|
||||
private cacheSlowCompleteKey = {};
|
||||
|
||||
/**
|
||||
* 注册插件命令
|
||||
* @param plugin 插件
|
||||
@@ -44,12 +51,33 @@ export namespace command {
|
||||
protected setExecutor(plugin: plugin.Plugin, command: any, executor: Function) {
|
||||
return (sender: any, _: any, command: string, args: string[]) => {
|
||||
try {
|
||||
return executor(sender, command, Java.from(args))
|
||||
let time = Date.now()
|
||||
let result = executor(sender, command, Java.from(args))
|
||||
let cost = Date.now() - time
|
||||
if (cost > global.ScriptSlowExecuteTime) {
|
||||
let commandKey = `${plugin.description.name}-${command}-${sender.name}`
|
||||
if (!this.cacheSlowCommandKey[commandKey]) { return this.cacheSlowCommandKey[commandKey] = cost }
|
||||
console.i18n("ms.api.command.execute.slow", {
|
||||
player: sender.name,
|
||||
plugin: plugin.description.name,
|
||||
command,
|
||||
args: Java.from(args).join(' '),
|
||||
cost
|
||||
})
|
||||
}
|
||||
return result
|
||||
} catch (ex: any) {
|
||||
console.i18n("ms.api.command.execute.error", { player: sender.name, plugin: plugin.description.name, command, args: Java.from(args).join(' '), ex })
|
||||
let message = i18n.translate("ms.api.command.execute.error", {
|
||||
player: sender.name,
|
||||
plugin: plugin.description.name,
|
||||
command,
|
||||
args: Java.from(args).join(' '),
|
||||
ex
|
||||
})
|
||||
console.console(message)
|
||||
console.ex(ex)
|
||||
if (sender.name != 'CONSOLE') {
|
||||
console.sender(sender, [i18n.translate("ms.api.command.execute.error", { player: sender.name, plugin: plugin.description.name, command, args: Java.from(args).join(' '), ex }), ...console.stack(ex)])
|
||||
console.sender(sender, [message, ...console.stack(ex)])
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -58,13 +86,36 @@ export namespace command {
|
||||
protected setTabCompleter(plugin: plugin.Plugin, command: any, tabCompleter: Function) {
|
||||
return (sender: any, _: any, command: string, args: string[]) => {
|
||||
try {
|
||||
let time = Date.now()
|
||||
var token = args[args.length - 1]
|
||||
var complete = tabCompleter(sender, command, Java.from(args)) || []
|
||||
return this.copyPartialMatches(complete, token)
|
||||
let result = this.copyPartialMatches(complete, token)
|
||||
let cost = Date.now() - time
|
||||
if (cost > global.ScriptSlowExecuteTime) {
|
||||
let completerKey = `${plugin.description.name}-${command}-${sender.name}`
|
||||
if (!this.cacheSlowCompleteKey[completerKey]) { return this.cacheSlowCompleteKey[completerKey] = cost }
|
||||
console.i18n("ms.api.command.tab.completer.slow", {
|
||||
player: sender.name,
|
||||
plugin: plugin.description.name,
|
||||
command,
|
||||
args: Java.from(args).join(' '),
|
||||
cost
|
||||
})
|
||||
}
|
||||
return result
|
||||
} catch (ex: any) {
|
||||
console.i18n("ms.api.command.tab.completer.error", { player: sender.name, plugin: plugin.description.name, command, args: Java.from(args).join(' '), ex })
|
||||
let message = i18n.translate("ms.api.command.tab.completer.error", {
|
||||
player: sender.name,
|
||||
plugin: plugin.description.name,
|
||||
command,
|
||||
args: Java.from(args).join(' '),
|
||||
ex
|
||||
})
|
||||
console.console(message)
|
||||
console.ex(ex)
|
||||
console.sender(sender, [i18n.translate("ms.api.command.tab.completer.error", { player: sender.name, plugin: plugin.description.name, command, args: Java.from(args).join(' '), ex }), ...console.stack(ex)])
|
||||
if (sender.name != 'CONSOLE') {
|
||||
console.sender(sender, [message, ...console.stack(ex)])
|
||||
}
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import * as base64 from 'base64-js'
|
||||
const Arrays = Java.type('java.util.Arrays')
|
||||
const Level = Java.type('java.util.logging.Level')
|
||||
const Paths = Java.type('java.nio.file.Paths')
|
||||
const ignoreLogPrefix = ['java.', 'javax.', 'sun.', 'net.minecraft.', 'org.bukkit.', 'jdk.nashorn.', 'org.openjdk.nashorn', 'io.netty.', 'org.spongepowered.', 'org.apache', 'org.springframework']
|
||||
const ignoreLogPrefix = ['java.', 'javax.', 'sun.', 'net.minecraft.', 'org.bukkit.', 'jdk.internal.dynalink.', 'jdk.nashorn.', 'org.openjdk.nashorn', 'io.netty.', 'org.spongepowered.', 'org.apache', 'org.springframework']
|
||||
|
||||
enum LogLevel {
|
||||
ALL,
|
||||
@@ -18,12 +18,114 @@ enum LogLevel {
|
||||
OFF
|
||||
}
|
||||
|
||||
const sourceMaps: { [key: string]: SourceMapBuilder } = {}
|
||||
const sourceFileMaps: { [key: string]: string } = {}
|
||||
|
||||
global.setGlobal('MiaoScriptSourceMaps', sourceMaps)
|
||||
global.setGlobal('MiaoScriptSourceFileMaps', sourceFileMaps)
|
||||
|
||||
export namespace jsconsole {
|
||||
export function readSourceMap(fileName: string, lineNumber: any) {
|
||||
try {
|
||||
if (fileName.endsWith('js') || fileName.endsWith('ms')) {
|
||||
if (sourceMaps[fileName] === undefined) {
|
||||
sourceMaps[fileName] = null
|
||||
let sourceLine = base.read(fileName).split('\n')
|
||||
let lastLine = sourceLine[sourceLine.length - 1] || sourceLine[sourceLine.length - 2]
|
||||
// lastLine is similar //# sourceMappingURL=data:application/json;base64,
|
||||
if (lastLine.startsWith('//# sourceMappingURL=')) {
|
||||
let sourceContent = null
|
||||
let sourceMappingURL = lastLine.split('sourceMappingURL=', 2)[1]
|
||||
if (sourceMappingURL.startsWith('data:application/json;base64,')) {
|
||||
sourceContent = String.fromCharCode(...Array.from(base64.toByteArray(sourceMappingURL.split(',', 2)[1])))
|
||||
} else if (sourceMappingURL.startsWith('http://') || sourceMappingURL.startsWith('https://')) {
|
||||
// TODO
|
||||
} else {
|
||||
let file = Paths.get(Paths.get(fileName, '..', sourceMappingURL).toFile().getCanonicalPath()).toFile()
|
||||
if (file.exists()) {
|
||||
sourceContent = base.read(file)
|
||||
sourceFileMaps[fileName] = file.getCanonicalPath()
|
||||
} else if (global.debug) {
|
||||
console.debug('readSourceMap can\'t found', fileName, 'source map file', sourceMappingURL)
|
||||
}
|
||||
}
|
||||
if (sourceContent) {
|
||||
sourceMaps[fileName] = new SourceMapBuilder(JSON.parse(sourceContent))
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sourceMaps[fileName]) {
|
||||
let sourceMapping = sourceMaps[fileName].getSource(lineNumber, 25, true, true)
|
||||
if (sourceMapping) {
|
||||
fileName = Paths.get(fileName, '..', sourceMapping.sourcePath).toFile().getCanonicalPath()
|
||||
lineNumber = sourceMapping.mapping.sourceLine
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.debug('search source map', fileName, 'line', lineNumber, 'error:', error)
|
||||
if (global.debug) {
|
||||
console.ex(error)
|
||||
}
|
||||
}
|
||||
return {
|
||||
fileName,
|
||||
lineNumber
|
||||
}
|
||||
}
|
||||
|
||||
export function getStackTrace(ex: Error, color: boolean = true): string[] {
|
||||
if (!ex) return []
|
||||
let stack = ex.getStackTrace()
|
||||
let cache = [(color ? '§c' : '') + ex]
|
||||
//@ts-ignore
|
||||
if (stack.class) {
|
||||
stack = Arrays.asList(stack)
|
||||
}
|
||||
stack.forEach(trace => {
|
||||
if (!trace.fileName || trace.fileName.startsWith('jar:file:') || trace.fileName.startsWith('file:')) { return }
|
||||
if (trace.className.startsWith('<')) {
|
||||
let { fileName, lineNumber } = readSourceMap(trace.fileName, trace.lineNumber)
|
||||
if (fileName.startsWith(root)) { fileName = fileName.split(root)[1] }
|
||||
if (color) {
|
||||
cache.push(` §e->§c ${fileName}:${lineNumber}(${trace.lineNumber}) => §4${trace.methodName}`)
|
||||
} else {
|
||||
cache.push(` -> ${fileName}:${lineNumber}(${trace.lineNumber}) => ${trace.methodName}`)
|
||||
}
|
||||
} else {
|
||||
let className = trace.className
|
||||
var fileName = trace.fileName as string
|
||||
var lineNumber = trace.lineNumber
|
||||
if (className.startsWith('jdk.nashorn.internal.scripts') || className.startsWith('org.openjdk.nashorn.internal.scripts')) {
|
||||
className = className.substr(className.lastIndexOf('$') + 1)
|
||||
var { fileName, lineNumber } = readSourceMap(fileName, lineNumber)
|
||||
if (fileName.startsWith(root)) { fileName = fileName.split(root)[1] }
|
||||
} else {
|
||||
if (!global.debug) {
|
||||
for (let prefix in ignoreLogPrefix) {
|
||||
if (className.startsWith(ignoreLogPrefix[prefix])) {
|
||||
return
|
||||
}
|
||||
}
|
||||
} else if (className.startsWith('jdk.nashorn.internal.') || className.startsWith('org.openjdk.nashorn.internal.')) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if (color) {
|
||||
cache.push(` §e->§c ${className}.${trace.methodName}(§4${fileName}:${lineNumber}§c)`)
|
||||
} else {
|
||||
cache.push(` -> ${className}.${trace.methodName}(${fileName}:${lineNumber})`)
|
||||
}
|
||||
}
|
||||
})
|
||||
return cache
|
||||
}
|
||||
}
|
||||
|
||||
export class MiaoScriptConsole implements Console {
|
||||
Console: any
|
||||
memory: any
|
||||
|
||||
private static sourceMaps: { [key: string]: SourceMapBuilder } = {}
|
||||
private static sourceFileMaps: { [key: string]: string } = {}
|
||||
private _name: string = ''
|
||||
private _level: LogLevel = LogLevel.INFO
|
||||
|
||||
@@ -92,91 +194,8 @@ export class MiaoScriptConsole implements Console {
|
||||
ex(ex: Error) {
|
||||
this.stack(ex).forEach(line => this.console(line))
|
||||
}
|
||||
readSourceMap(fileName: string, lineNumber: any) {
|
||||
try {
|
||||
if (fileName.endsWith('js')) {
|
||||
if (MiaoScriptConsole.sourceMaps[fileName] === undefined) {
|
||||
MiaoScriptConsole.sourceMaps[fileName] = null
|
||||
let sourceLine = base.read(fileName).split('\n')
|
||||
let lastLine = sourceLine[sourceLine.length - 1]
|
||||
// lastLine is similar //# sourceMappingURL=data:application/json;base64,
|
||||
if (lastLine.startsWith('//# sourceMappingURL=')) {
|
||||
let sourceContent = null
|
||||
let sourceMappingURL = lastLine.split('sourceMappingURL=', 2)[1]
|
||||
if (sourceMappingURL.startsWith('data:application/json;base64,')) {
|
||||
sourceContent = String.fromCharCode(...Array.from(base64.toByteArray(sourceMappingURL.split(',', 2)[1])))
|
||||
} else if (sourceMappingURL.startsWith('http://') || sourceMappingURL.startsWith('https://')) {
|
||||
// TODO
|
||||
} else {
|
||||
let file = Paths.get(Paths.get(fileName, '..', sourceMappingURL).toFile().getCanonicalPath()).toFile()
|
||||
if (file.exists()) { sourceContent = base.read(file) }
|
||||
}
|
||||
if (sourceContent) {
|
||||
MiaoScriptConsole.sourceMaps[fileName] = new SourceMapBuilder(JSON.parse(sourceContent))
|
||||
MiaoScriptConsole.sourceFileMaps[fileName] = Paths.get(fileName, '..', MiaoScriptConsole.sourceMaps[fileName].sources[0]).toFile().getCanonicalPath()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (MiaoScriptConsole.sourceMaps[fileName]) {
|
||||
let sourceMapping = MiaoScriptConsole.sourceMaps[fileName].getSource(lineNumber, 25, true, true)
|
||||
fileName = MiaoScriptConsole.sourceFileMaps[fileName]
|
||||
if (sourceMapping && lineNumber != sourceMapping.mapping.sourceLine) { lineNumber = sourceMapping.mapping.sourceLine }
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.debug('search source map', fileName, 'line', lineNumber, 'error:', error)
|
||||
if (global.debug) {
|
||||
console.ex(error)
|
||||
}
|
||||
}
|
||||
return {
|
||||
fileName,
|
||||
lineNumber
|
||||
}
|
||||
}
|
||||
stack(ex: Error, color: boolean = true): string[] {
|
||||
if (!ex) return []
|
||||
let stack = ex.getStackTrace()
|
||||
let cache = [(color ? '§c' : '') + ex]
|
||||
//@ts-ignore
|
||||
if (stack.class) {
|
||||
stack = Arrays.asList(stack)
|
||||
}
|
||||
stack.forEach(trace => {
|
||||
if (!trace.fileName || trace.fileName.startsWith('jar:file:') || trace.fileName.startsWith('file:')) { return }
|
||||
if (trace.className.startsWith('<')) {
|
||||
let { fileName, lineNumber } = this.readSourceMap(trace.fileName, trace.lineNumber)
|
||||
if (fileName.startsWith(root)) { fileName = fileName.split(root)[1] }
|
||||
if (color) {
|
||||
cache.push(` §e->§c ${fileName}:${lineNumber} => §4${trace.methodName}`)
|
||||
} else {
|
||||
cache.push(` -> ${fileName}:${lineNumber} => ${trace.methodName}`)
|
||||
}
|
||||
} else {
|
||||
let className = trace.className
|
||||
var fileName = trace.fileName as string
|
||||
var lineNumber = trace.lineNumber
|
||||
if (className.startsWith('jdk.nashorn.internal.scripts') || className.startsWith('org.openjdk.nashorn.internal.scripts')) {
|
||||
className = className.substr(className.lastIndexOf('$') + 1)
|
||||
var { fileName, lineNumber } = this.readSourceMap(fileName, lineNumber)
|
||||
if (fileName.startsWith(root)) { fileName = fileName.split(root)[1] }
|
||||
} else {
|
||||
if (!global.debug) {
|
||||
for (let prefix in ignoreLogPrefix) {
|
||||
if (className.startsWith(ignoreLogPrefix[prefix])) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (color) {
|
||||
cache.push(` §e->§c ${className}.${trace.methodName}(§4${fileName}:${lineNumber}§c)`)
|
||||
} else {
|
||||
cache.push(` -> ${className}.${trace.methodName}(${fileName}:${lineNumber})`)
|
||||
}
|
||||
}
|
||||
})
|
||||
return cache
|
||||
return jsconsole.getStackTrace(ex, color)
|
||||
}
|
||||
assert(value: any, message?: string, ...optionalParams: any[]): void {
|
||||
throw new Error("Method not implemented.")
|
||||
|
||||
@@ -11,10 +11,21 @@ export namespace constants {
|
||||
}
|
||||
export namespace Reflect {
|
||||
export const Method = {
|
||||
getServerConnection: [/*spigot 1.8.8*/'aq',/*spigot 1.12.2*/ 'an', /*spigot 1.14.4+*/'getServerConnection', /*catserver 1.12.2*/'func_147137_ag']
|
||||
getServerConnection: [
|
||||
/*spigot 1.8.8*/'aq',
|
||||
/*spigot 1.12.2*/ 'an',
|
||||
/*spigot 1.14.4+*/'getServerConnection',
|
||||
/*spigot 1.19+*/'ad',
|
||||
/*catserver 1.12.2*/'func_147137_ag'
|
||||
]
|
||||
}
|
||||
export const Field = {
|
||||
listeningChannels: [/*spigot 1.8.8-1.12.2*/'g', /*spigot 1.14.4*/'f', /*spigot 1.15.2+*/'listeningChannels', /*catserver 1.12.2*/'field_151274_e']
|
||||
listeningChannels: [
|
||||
/*spigot 1.8.8-1.12.2*/'g',
|
||||
/*spigot 1.14.4*/'f',
|
||||
/*spigot 1.15.2+*/'listeningChannels',
|
||||
/*catserver 1.12.2*/'field_151274_e'
|
||||
]
|
||||
}
|
||||
}
|
||||
export enum ServerType {
|
||||
|
||||
@@ -1,5 +1,56 @@
|
||||
import { injectable } from "@ccms/container"
|
||||
|
||||
export namespace database {
|
||||
export const DataBaseManager = Symbol("DataBaseManager");
|
||||
export const DataSource = Symbol("DataSource");
|
||||
export const DataBase = Symbol("DataBase");
|
||||
export const DataSource = Symbol("DataSource")
|
||||
/**
|
||||
* 数据库配置
|
||||
*/
|
||||
export interface DataBaseConfig {
|
||||
/**
|
||||
* 数据库类型
|
||||
*/
|
||||
type: 'h2' | 'mysql' | 'mongodb' | 'sqlite' | 'postgres' | 'redis'
|
||||
/**
|
||||
* 数据库连接串
|
||||
*/
|
||||
url: string | javax.sql.DataSource
|
||||
/**
|
||||
* 数据库驱动
|
||||
*/
|
||||
driverClassName?: string
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
username?: string
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
password?: string
|
||||
/**
|
||||
* 链接属性
|
||||
*/
|
||||
properties?: { [key: string]: any }
|
||||
/**
|
||||
* 调试模式
|
||||
*/
|
||||
debug?: boolean
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export abstract class DataBaseManager {
|
||||
abstract setMainDatabase(mainDatabase: DataBase): void
|
||||
abstract getMainDatabase(): DataBase
|
||||
abstract createDatabase(name: string, config: DataBaseConfig): DataBase
|
||||
abstract removeDatabase(name: string): boolean
|
||||
abstract getDatabase(name: string): DataBase
|
||||
abstract startWebManager(...args: string[])
|
||||
abstract stopWebManager()
|
||||
abstract shutdown()
|
||||
}
|
||||
@injectable()
|
||||
export abstract class DataBase {
|
||||
abstract query<T>(sql: string, ...args: any[]): Array<T>
|
||||
abstract update(sql: string, ...args: any[]): number
|
||||
abstract execute(sql: string): void
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,8 @@ export namespace event {
|
||||
public EventPriority = EventPriority;
|
||||
|
||||
private mapEvent = [];
|
||||
private listenerMap = [];
|
||||
private pluginEventMap = [];
|
||||
private cacheSlowEventKey = {};
|
||||
|
||||
protected baseEventDir = '';
|
||||
|
||||
@@ -92,17 +93,23 @@ export namespace event {
|
||||
return eventCls
|
||||
}
|
||||
|
||||
execute(name, exec, eventCls) {
|
||||
/**
|
||||
* 创建命令执行器
|
||||
* @param name 插件名称
|
||||
* @param exec 执行方法
|
||||
* @param eventCls 事件类
|
||||
* @returns
|
||||
*/
|
||||
createExecute(name, exec, eventCls) {
|
||||
return (...args: any[]) => {
|
||||
let event = args[args.length - 1]
|
||||
try {
|
||||
let event = args[args.length - 1]
|
||||
if (eventCls.isAssignableFrom(event.getClass())) {
|
||||
let time = Date.now()
|
||||
exec(event)
|
||||
let cost = Date.now() - time
|
||||
if (cost > 20) {
|
||||
console.i18n("ms.api.event.execute.slow", { name, event: this.class2Name(eventCls), cost })
|
||||
}
|
||||
if (!eventCls.isAssignableFrom(event.getClass())) { return }
|
||||
let time = Date.now(); exec(event); let cost = Date.now() - time
|
||||
if (cost > global.ScriptSlowExecuteTime && !event.async) {
|
||||
let eventKey = `${name}-${this.class2Name(eventCls)}`
|
||||
if (!this.cacheSlowEventKey[eventKey]) { return this.cacheSlowEventKey[eventKey] = cost }
|
||||
console.i18n("ms.api.event.execute.slow", { name, event: this.class2Name(eventCls), cost })
|
||||
}
|
||||
} catch (ex: any) {
|
||||
console.i18n("ms.api.event.execute.error", { name, event: this.class2Name(eventCls), ex })
|
||||
@@ -113,17 +120,17 @@ export namespace event {
|
||||
|
||||
/**
|
||||
* 添加事件监听
|
||||
* @param plugin {any}
|
||||
* @param event {string}
|
||||
* @param exec {function}
|
||||
* @param priority {string} [LOWEST,LOW,NORMAL,HIGH,HIGHEST,MONITOR]
|
||||
* @param ignoreCancel
|
||||
* @param plugin {any} 插件
|
||||
* @param event {string} 事件名称
|
||||
* @param exec {function} 事件执行器
|
||||
* @param priority {string} [LOWEST,LOW,NORMAL,HIGH,HIGHEST,MONITOR] 优先级
|
||||
* @param ignoreCancel 是否忽略已取消事件
|
||||
*/
|
||||
listen(plugin: any, event: string, exec: (event: any) => void, priority: EventPriority = EventPriority.NORMAL, ignoreCancel = false) {
|
||||
if (!plugin || !plugin.description || !plugin.description.name) throw new TypeError(i18n.translate("ms.api.event.listen.plugin.name.empty"))
|
||||
var name = plugin.description.name
|
||||
var eventCls = this.name2Class(name, event)
|
||||
if (!eventCls) { return }
|
||||
if (!eventCls) { return () => { console.warn('event ' + event + ' not found ignore off listener.') } }
|
||||
if (typeof priority === 'boolean') {
|
||||
ignoreCancel = priority
|
||||
priority = EventPriority.NORMAL
|
||||
@@ -133,19 +140,33 @@ export namespace event {
|
||||
// @ts-ignore
|
||||
let executor = exec.name || exec.executor || '[anonymous]'
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
var listener = this.register(eventCls, this.execute(name, exec, eventCls), priority, ignoreCancel)
|
||||
var listenerMap = this.listenerMap
|
||||
let listener = this.register(
|
||||
eventCls,
|
||||
this.createExecute(name, exec, eventCls),
|
||||
priority,
|
||||
ignoreCancel
|
||||
)
|
||||
// add to cache Be used for close plugin to close event
|
||||
if (!listenerMap[name]) listenerMap[name] = []
|
||||
var off = () => {
|
||||
if (!this.pluginEventMap[name]) this.pluginEventMap[name] = []
|
||||
let off = () => {
|
||||
if (off['offed']) return
|
||||
off['offed'] = true
|
||||
this.unregister(eventCls, listener)
|
||||
console.debug(i18n.translate("ms.api.event.unregister", { name, event: this.class2Name(eventCls), exec: executor }))
|
||||
console.debug(i18n.translate("ms.api.event.unregister", {
|
||||
name,
|
||||
event: this.class2Name(eventCls),
|
||||
exec: executor
|
||||
}))
|
||||
}
|
||||
listenerMap[name].push(off)
|
||||
this.pluginEventMap[name].push(off)
|
||||
// noinspection JSUnresolvedVariable
|
||||
console.debug(i18n.translate("ms.api.event.register", { name, event: this.class2Name(eventCls), exec: executor }))
|
||||
console.debug(i18n.translate("ms.api.event.register", {
|
||||
name,
|
||||
event: this.class2Name(eventCls),
|
||||
exec: executor,
|
||||
priority,
|
||||
ignore: ignoreCancel
|
||||
}))
|
||||
return off
|
||||
}
|
||||
|
||||
@@ -154,10 +175,10 @@ export namespace event {
|
||||
* @param plugin 插件
|
||||
*/
|
||||
disable(plugin: any) {
|
||||
var eventCache = this.listenerMap[plugin.description.name]
|
||||
var eventCache = this.pluginEventMap[plugin.description.name]
|
||||
if (eventCache) {
|
||||
eventCache.forEach(off => off())
|
||||
delete this.listenerMap[plugin.description.name]
|
||||
eventCache.forEach((off: () => any) => off())
|
||||
delete this.pluginEventMap[plugin.description.name]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,13 @@ export * from './web'
|
||||
export * from './amqp'
|
||||
export * from './chat'
|
||||
export * from './task'
|
||||
export * from './item'
|
||||
export * from './event'
|
||||
export * from './proxy'
|
||||
export * from './plugin'
|
||||
export * from './server'
|
||||
export * from './console'
|
||||
export { jsconsole as console } from './console'
|
||||
export * from './channel'
|
||||
export * from './command'
|
||||
export * from './database'
|
||||
|
||||
20
packages/api/src/item.ts
Normal file
20
packages/api/src/item.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { injectable } from '@ccms/container'
|
||||
|
||||
export namespace item {
|
||||
@injectable()
|
||||
export abstract class Item {
|
||||
abstract builder(): ItemBuilder
|
||||
abstract toJson(item: any): string
|
||||
abstract fromJson(json: string): any
|
||||
}
|
||||
export interface ItemBuilder {
|
||||
from(item: any): ItemBuilder
|
||||
create(type: string | number): ItemBuilder
|
||||
name(name: string): ItemBuilder
|
||||
lore(...lores: string[]): ItemBuilder
|
||||
amount(amount: number): ItemBuilder
|
||||
durability(durability: number): ItemBuilder
|
||||
clone(): any
|
||||
build(): any
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,12 @@ const UUID = Java.type('java.util.UUID')
|
||||
const Math = Java.type('java.lang.Math')
|
||||
|
||||
export namespace particle {
|
||||
@injectable()
|
||||
export abstract class ParticleSpawner {
|
||||
abstract spawn(location: any, particle: Particle)
|
||||
abstract spawnToPlayer(player: any, location: any, particle: Particle)
|
||||
}
|
||||
|
||||
/**
|
||||
* 表示一个特效对象
|
||||
*
|
||||
@@ -23,6 +29,11 @@ export namespace particle {
|
||||
private extra: number = 0;
|
||||
private data: Object = null;
|
||||
|
||||
/**
|
||||
* Only Show To Player
|
||||
*/
|
||||
private player: any
|
||||
|
||||
constructor() {
|
||||
this.uuid = UUID.randomUUID().toString()
|
||||
}
|
||||
@@ -105,6 +116,15 @@ export namespace particle {
|
||||
return this
|
||||
}
|
||||
|
||||
getPlayer() {
|
||||
return this.player
|
||||
}
|
||||
|
||||
setPlayer(player) {
|
||||
this.player = player
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过给定一个坐标就可以使用已经指定的参数来播放粒子
|
||||
*
|
||||
@@ -112,9 +132,14 @@ export namespace particle {
|
||||
*/
|
||||
spawn(location: any) {
|
||||
if (!this.spawner) throw new Error(`particle ${this.uuid} not set spawner can't spawn!`)
|
||||
this.spawner.spawn(location, this)
|
||||
if (this.player) {
|
||||
this.spawner.spawnToPlayer(this.player, location, this)
|
||||
} else {
|
||||
this.spawner.spawn(location, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 表示一条线
|
||||
*
|
||||
@@ -158,8 +183,7 @@ export namespace particle {
|
||||
|
||||
show() {
|
||||
for (let i = 0; i < this.length; i += this.step) {
|
||||
let vectorTemp = this.vector.clone().multiply(i)
|
||||
this.spawn(this.start.clone().add(vectorTemp))
|
||||
this.spawn(this.start.clone().add(this.vector.clone().multiply(i)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,15 +258,6 @@ export namespace particle {
|
||||
this.length = this.vector.length()
|
||||
this.vector.normalize()
|
||||
}
|
||||
|
||||
public static buildLine(locA: any, locB: any, step: number, particle: any) {
|
||||
let vectorAB = locB.clone().subtract(locA).toVector()
|
||||
let vectorLength = vectorAB.length()
|
||||
vectorAB.normalize()
|
||||
for (let i = 0; i < vectorLength; i += step) {
|
||||
ParticleManager.globalSpawner.spawn(locA.clone().add(vectorAB.clone().multiply(i)), particle)
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 表示一个弧
|
||||
@@ -331,9 +346,10 @@ export namespace particle {
|
||||
|
||||
@injectable()
|
||||
export abstract class ParticleManager {
|
||||
public static globalSpawner: ParticleSpawner = undefined
|
||||
@Autowired()
|
||||
private taskManager: task.TaskManager
|
||||
@Autowired()
|
||||
private particleSpawner: particle.ParticleSpawner
|
||||
|
||||
protected taskId: java.util.concurrent.atomic.AtomicInteger
|
||||
protected cacheTasks = new Map<string, ParticleTask>()
|
||||
@@ -354,6 +370,10 @@ export namespace particle {
|
||||
return this.taskManager
|
||||
}
|
||||
|
||||
public getParticleSpawner() {
|
||||
return this.particleSpawner
|
||||
}
|
||||
|
||||
public create(particle: Particle, plugin?: plugin.Plugin) {
|
||||
let uuid = particle.getUUID()
|
||||
if (this.cacheTasks.has(uuid)) {
|
||||
@@ -389,14 +409,12 @@ export namespace particle {
|
||||
}
|
||||
}
|
||||
protected create0(owner: plugin.Plugin, particle: Particle): ParticleTask {
|
||||
particle.setSpawner(this.getGlobalSpawner())
|
||||
particle.setSpawner(this.getParticleSpawner())
|
||||
return new ParticleTask(owner, particle, this)
|
||||
}
|
||||
protected abstract getGlobalSpawner(): ParticleSpawner
|
||||
}
|
||||
|
||||
export class ParticleTask {
|
||||
|
||||
private particle: Particle
|
||||
private isAsync: boolean = false
|
||||
private interval: number = 0
|
||||
@@ -486,9 +504,4 @@ export namespace particle {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class ParticleSpawner {
|
||||
abstract spawnParticle(location: any, particle: any, count: number)
|
||||
abstract spawn(location: any, particle: Particle)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ export namespace plugin {
|
||||
export abstract class PluginManager {
|
||||
abstract scan(folder: string): void
|
||||
abstract build(): void
|
||||
abstract loadFromFile(file: string, scanner?: plugin.PluginScanner): Plugin
|
||||
abstract loadFromFile(file: string, ext?: any): Plugin
|
||||
abstract load(...args: any[]): void
|
||||
abstract enable(...args: any[]): void
|
||||
abstract disable(...args: any[]): void
|
||||
@@ -149,7 +149,19 @@ export namespace plugin {
|
||||
/**
|
||||
* 插件名称 不填默认为类名
|
||||
*/
|
||||
name?: string
|
||||
name: string
|
||||
/**
|
||||
* 插件中文名称
|
||||
*/
|
||||
cname?: string
|
||||
/**
|
||||
* 付费插件ID
|
||||
*/
|
||||
pid?: number
|
||||
/**
|
||||
* 付费插件等级 付费插件自动注入
|
||||
*/
|
||||
level?: number
|
||||
/**
|
||||
* 前缀
|
||||
*/
|
||||
|
||||
@@ -29,6 +29,7 @@ export namespace server {
|
||||
origin: any
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export abstract class NativePluginManager {
|
||||
list(): NativePlugin[] {
|
||||
@@ -40,19 +41,20 @@ export namespace server {
|
||||
get(name: string): NativePlugin {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
load(name: string): boolean {
|
||||
enable(name: string): NativePlugin {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
unload(name: string): boolean {
|
||||
disable(name: string): NativePlugin {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
reload(name: string): boolean {
|
||||
reload(name: string): NativePlugin {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
delete(name: string): boolean {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MiaoScript Server
|
||||
*/
|
||||
@@ -98,6 +100,7 @@ export namespace server {
|
||||
throw new Error("Method not implemented.")
|
||||
}
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class ServerChecker {
|
||||
@Autowired(ServerType)
|
||||
@@ -116,6 +119,22 @@ export namespace server {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class NativePluginChecker {
|
||||
@Autowired(NativePluginManager)
|
||||
private nativePluginManager: NativePluginManager
|
||||
|
||||
check(plugins: string[]) {
|
||||
// Not set plugins -> allow
|
||||
if (!plugins || !plugins.length) return true
|
||||
for (const plugin of plugins) {
|
||||
if (!this.nativePluginManager.has(plugin)) { return false }
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export abstract class ReflectServer extends server.Server {
|
||||
@Autowired(ContainerInstance)
|
||||
@@ -172,13 +191,23 @@ export namespace server {
|
||||
}
|
||||
protected reflectRootLogger(consoleServer: any) {
|
||||
try {
|
||||
this.rootLogger = reflect.on(consoleServer).get('LOGGER').get().parent
|
||||
this.rootLogger = reflect.on(consoleServer).get('LOGGER').get()
|
||||
} catch (error: any) {
|
||||
if (global.debug) {
|
||||
console.ex(error)
|
||||
}
|
||||
try {
|
||||
this.rootLogger = reflect.on(consoleServer).get(0).get().parent
|
||||
this.rootLogger = reflect.on(consoleServer).get(0).get()
|
||||
} catch (error: any) {
|
||||
if (global.debug) {
|
||||
console.ex(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.rootLogger.class.name.indexOf('slf4j') !== -1) {
|
||||
try {
|
||||
let LogManager = Java.type('org.apache.logging.log4j.LogManager')
|
||||
this.rootLogger = LogManager.getLogger('ROOT')
|
||||
} catch (error: any) {
|
||||
if (global.debug) {
|
||||
console.ex(error)
|
||||
@@ -189,11 +218,11 @@ export namespace server {
|
||||
console.error('Error Logger Class: ' + this.rootLogger.class.name)
|
||||
this.rootLogger = undefined
|
||||
}
|
||||
if (!this.rootLogger) { console.error("Can't found rootLogger!") }
|
||||
// get root logger
|
||||
for (let index = 0; index < 5 && this.rootLogger.parent; index++) {
|
||||
this.rootLogger = this.rootLogger.parent
|
||||
}
|
||||
if (!this.rootLogger) { console.error("Can't found rootLogger!") }
|
||||
this.container.bind(constants.ServiceIdentifier.RootLogger).toConstantValue(this.rootLogger)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { plugin } from './index'
|
||||
import { EventEmitter } from 'events'
|
||||
import { injectable } from '@ccms/container'
|
||||
|
||||
import { plugin } from './index'
|
||||
|
||||
const AtomicInteger = Java.type("java.util.concurrent.atomic.AtomicInteger")
|
||||
|
||||
export namespace task {
|
||||
@@ -79,7 +81,7 @@ export namespace task {
|
||||
/**
|
||||
* 任务抽象
|
||||
*/
|
||||
export abstract class Task implements Cancelable {
|
||||
export abstract class Task extends EventEmitter implements Cancelable {
|
||||
protected func: Function
|
||||
protected isAsync: boolean = false;
|
||||
protected laterTime: number = 0;
|
||||
@@ -88,7 +90,10 @@ export namespace task {
|
||||
protected taskId: number
|
||||
protected innerTask: any
|
||||
|
||||
private cancelled: boolean = false
|
||||
|
||||
constructor(owner: plugin.Plugin, func: Function, id: number) {
|
||||
super()
|
||||
this.owner = owner
|
||||
this.func = func
|
||||
this.taskId = id
|
||||
@@ -134,20 +139,35 @@ export namespace task {
|
||||
*/
|
||||
cancel(): boolean {
|
||||
let result = this.cancel0()
|
||||
process.emit('task.finish', this)
|
||||
this.finish()
|
||||
this.cancelled = true
|
||||
return result
|
||||
}
|
||||
|
||||
protected run(...args: any[]): void {
|
||||
try {
|
||||
this.emit('before', this)
|
||||
if (this.cancelled) { return }
|
||||
this.func(...args)
|
||||
!this.interval && process.emit('task.finish', this)
|
||||
} catch (ex: any) {
|
||||
console.console('§4插件执行任务时发生错误', ex)
|
||||
console.ex(ex)
|
||||
this.emit('after', this)
|
||||
} catch (error: any) {
|
||||
this.emit('error', error)
|
||||
if (!error.processed) {
|
||||
console.console('§4插件执行任务时发生错误', error)
|
||||
console.ex(error)
|
||||
this.cancel()
|
||||
}
|
||||
} finally {
|
||||
this.emit('finally', this)
|
||||
if (!this.interval && !this.cancelled) { this.finish() }
|
||||
}
|
||||
}
|
||||
|
||||
protected finish() {
|
||||
process.emit('task.finish', this)
|
||||
this.emit('finish', this)
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交任务
|
||||
* @param args 任务参数
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ccms/bukkit",
|
||||
"version": "0.18.0",
|
||||
"version": "0.28.0-beta.2",
|
||||
"description": "MiaoScript bukkit package",
|
||||
"keywords": [
|
||||
"miaoscript",
|
||||
@@ -21,12 +21,12 @@
|
||||
"devDependencies": {
|
||||
"@javatypes/spigot-api": "^0.0.3",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.5.5"
|
||||
"rimraf": "^4.1.2",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ccms/api": "^0.18.0",
|
||||
"@ccms/common": "^0.18.0",
|
||||
"@ccms/container": "^0.18.0"
|
||||
"@ccms/api": "^0.28.0-beta.2",
|
||||
"@ccms/common": "^0.28.0-beta.2",
|
||||
"@ccms/container": "^0.28.0-beta.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { channel, plugin } from '@ccms/api'
|
||||
import { inject, provideSingleton } from '@ccms/container'
|
||||
|
||||
const Bukkit = org.bukkit.Bukkit
|
||||
const Bukkit: typeof org.bukkit.Bukkit = Java.type('org.bukkit.Bukkit')
|
||||
const PluginMessageListener = Java.type("org.bukkit.plugin.messaging.PluginMessageListener")
|
||||
const Messenger = Bukkit.getMessenger()
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { chat } from '@ccms/api'
|
||||
import { provideSingleton } from '@ccms/container'
|
||||
import bukkitChat from './enhance/chat'
|
||||
import bukkitChat from './internal/chat'
|
||||
|
||||
@provideSingleton(chat.Chat)
|
||||
export class BukkitChat extends chat.Chat {
|
||||
get handle(): any {
|
||||
return bukkitChat
|
||||
}
|
||||
sendJson(sender: any, json: string | object, type = 0) {
|
||||
bukkitChat.send(sender, typeof json === "string" ? json : JSON.stringify(json), type)
|
||||
}
|
||||
|
||||
@@ -1,35 +1,38 @@
|
||||
import '@ccms/nashorn'
|
||||
|
||||
import { command, plugin } from '@ccms/api'
|
||||
import * as reflect from '@ccms/common/dist/reflect'
|
||||
import { provideSingleton, postConstruct, inject } from '@ccms/container'
|
||||
import * as reflect from '@ccms/common/dist/reflect'
|
||||
|
||||
let Bukkit = org.bukkit.Bukkit
|
||||
let TabCompleter = Java.type('org.bukkit.command.TabCompleter')
|
||||
let PluginCommand = Java.type('org.bukkit.command.PluginCommand')
|
||||
let CommandExecutor = Java.type('org.bukkit.command.CommandExecutor')
|
||||
const Bukkit: typeof org.bukkit.Bukkit = Java.type('org.bukkit.Bukkit')
|
||||
const TabCompleter = Java.type('org.bukkit.command.TabCompleter')
|
||||
const PluginCommand = Java.type('org.bukkit.command.PluginCommand')
|
||||
const CommandExecutor = Java.type('org.bukkit.command.CommandExecutor')
|
||||
|
||||
@provideSingleton(command.Command)
|
||||
export class BukkitCommand extends command.Command {
|
||||
@inject(plugin.PluginInstance)
|
||||
private pluginInstance: any
|
||||
private commandMap: any
|
||||
private knownCommands: any
|
||||
|
||||
@postConstruct()
|
||||
init() {
|
||||
this.commandMap = reflect.on(Bukkit.getPluginManager()).get('commandMap').get()
|
||||
this.knownCommands = reflect.on(this.commandMap).get('knownCommands').get()
|
||||
}
|
||||
create(plugin: any, command: string) {
|
||||
var cmd = this.commandMap.getCommand(command)
|
||||
if (cmd && cmd instanceof PluginCommand) { return cmd };
|
||||
if (cmd instanceof PluginCommand) { return cmd };
|
||||
cmd = reflect.on(PluginCommand).create(command, this.pluginInstance).get()
|
||||
this.commandMap.register(plugin.description.name, cmd)
|
||||
return cmd
|
||||
}
|
||||
remove(plugin: any, command: string) {
|
||||
var cmd = this.commandMap.getCommand(command)
|
||||
if (cmd && cmd instanceof PluginCommand) {
|
||||
if (cmd instanceof PluginCommand) {
|
||||
cmd.unregister(this.commandMap)
|
||||
this.knownCommands.remove(command)
|
||||
}
|
||||
}
|
||||
tabComplete(sender: any, input: string, index?: number): string[] {
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { MiaoScriptConsole } from '@ccms/api'
|
||||
|
||||
let Bukkit = org.bukkit.Bukkit;
|
||||
const Bukkit: typeof org.bukkit.Bukkit = Java.type('org.bukkit.Bukkit')
|
||||
|
||||
export class BukkitConsole extends MiaoScriptConsole {
|
||||
sender(sender, ...args) {
|
||||
if (!(sender instanceof Java.type('org.bukkit.command.CommandSender'))) {
|
||||
this.error(`First parameter ${sender} not instanceof org.bukkit.command.CommandSender can't send message!`)
|
||||
return;
|
||||
return
|
||||
}
|
||||
if (Object.prototype.toString.call(args[0]) === "[object Array]") {
|
||||
args[0].forEach(line => sender.sendMessage(this.prefix + line))
|
||||
} else {
|
||||
sender.sendMessage(this.prefix + args.join(' '));
|
||||
sender.sendMessage(this.prefix + args.join(' '))
|
||||
}
|
||||
}
|
||||
console(...args: string[]): void {
|
||||
this.sender(Bukkit.getConsoleSender(), args.join(' '));
|
||||
this.sender(Bukkit.getConsoleSender(), args.join(' '))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { event, plugin } from '@ccms/api'
|
||||
import { inject, provideSingleton } from '@ccms/container';
|
||||
import { inject, provideSingleton } from '@ccms/container'
|
||||
import * as reflect from '@ccms/common/dist/reflect'
|
||||
|
||||
const Bukkit = Java.type("org.bukkit.Bukkit");
|
||||
const Event = Java.type("org.bukkit.event.Event");
|
||||
const Modifier = Java.type("java.lang.reflect.Modifier");
|
||||
const Listener = Java.type("org.bukkit.event.Listener");
|
||||
const EventPriority = Java.type("org.bukkit.event.EventPriority");
|
||||
const EventExecutor = Java.type("org.bukkit.plugin.EventExecutor");
|
||||
const URL = Java.type('java.net.URL')
|
||||
const Bukkit = Java.type("org.bukkit.Bukkit")
|
||||
const Event = Java.type("org.bukkit.event.Event")
|
||||
const Modifier = Java.type("java.lang.reflect.Modifier")
|
||||
const Listener = Java.type("org.bukkit.event.Listener")
|
||||
const EventPriority = Java.type("org.bukkit.event.EventPriority")
|
||||
const EventExecutor = Java.type("org.bukkit.plugin.EventExecutor")
|
||||
|
||||
@provideSingleton(event.Event)
|
||||
export class BukkitEvent extends event.Event {
|
||||
@@ -15,11 +16,19 @@ export class BukkitEvent extends event.Event {
|
||||
private pluginInstance: any
|
||||
|
||||
constructor() {
|
||||
super('org/bukkit/event');
|
||||
super('org/bukkit/event')
|
||||
}
|
||||
|
||||
getJarFile(resource: string) {
|
||||
return super.getJarFile('org/bukkit/Bukkit.class', Bukkit.class.classLoader)
|
||||
try {
|
||||
return super.getJarFile('org/bukkit/Bukkit.class', Bukkit.class.classLoader)
|
||||
} catch (error) {
|
||||
// 兼容 LoliServer 的 Bukkit 包无法获取的问题
|
||||
let ModList = Java.type('net.minecraftforge.fml.ModList').get()
|
||||
let forgeFile = ModList.getModFileById("forge").getFile().getFilePath()
|
||||
let jarPath = `jar:file:${forgeFile}!/org/bukkit/Bukkit.class`
|
||||
return new URL(jarPath).openConnection().jarFile
|
||||
}
|
||||
}
|
||||
isValidEvent(clazz: any): boolean {
|
||||
// 继承于 org.bukkit.event.Event
|
||||
@@ -27,10 +36,10 @@ export class BukkitEvent extends event.Event {
|
||||
// 访问符为Public
|
||||
Modifier.isPublic(clazz.getModifiers()) &&
|
||||
// 不是抽象类
|
||||
!Modifier.isAbstract(clazz.getModifiers());
|
||||
!Modifier.isAbstract(clazz.getModifiers())
|
||||
}
|
||||
register(eventCls: any, exec: Function, priority: event.EventPriority, ignoreCancel: boolean) {
|
||||
let listener = new Listener({});
|
||||
let listener = new Listener({})
|
||||
Bukkit.pluginManager.registerEvent(
|
||||
eventCls,
|
||||
listener,
|
||||
@@ -39,10 +48,10 @@ export class BukkitEvent extends event.Event {
|
||||
execute: exec
|
||||
}),
|
||||
this.pluginInstance,
|
||||
ignoreCancel);
|
||||
return listener;
|
||||
ignoreCancel)
|
||||
return listener
|
||||
}
|
||||
unregister(event: any, listener: any): void {
|
||||
reflect.on(event).call('getHandlerList').get().unregister(listener);
|
||||
reflect.on(event).call('getHandlerList').get().unregister(listener)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { server } from '@ccms/api'
|
||||
import { Container } from '@ccms/container'
|
||||
|
||||
import { BukkitConsole } from './console'
|
||||
import './item'
|
||||
import './chat'
|
||||
import './task'
|
||||
import './event'
|
||||
|
||||
@@ -6,12 +6,14 @@ let bukkitChatInvoke: BukkitChatInvoke
|
||||
abstract class BukkitChatInvoke {
|
||||
private downgrade: boolean = false
|
||||
protected RemapUtils: any
|
||||
protected ComponentSerializer: any
|
||||
|
||||
protected ChatSerializer: any
|
||||
protected nmsChatSerializerMethodName: string
|
||||
protected PacketPlayOutChat: any
|
||||
protected chatMessageTypes: any
|
||||
protected playerConnectionFieldName: string
|
||||
protected playerFieldName: string
|
||||
protected sendPacketMethodName: string
|
||||
|
||||
constructor(private nmsVersion) {
|
||||
@@ -20,30 +22,31 @@ abstract class BukkitChatInvoke {
|
||||
init() {
|
||||
try {
|
||||
try {
|
||||
this.ComponentSerializer = Java.type('net.md_5.bungee.chat.ComponentSerializer')
|
||||
this.RemapUtils = Java.type('catserver.server.remapper.RemapUtils')
|
||||
} catch (ex: any) {
|
||||
}
|
||||
let nmsChatSerializerClass = this.getNmsChatSerializerClass()
|
||||
let nmsChatSerializerMethod = this.remapMethod(nmsChatSerializerClass, 'a', 'func_150699_a', base.getClass('java.lang.String'))
|
||||
this.nmsChatSerializerMethodName = nmsChatSerializerMethod.getName()
|
||||
this.nmsChatSerializerMethodName = this.getNmsChatSerializerMethodName(nmsChatSerializerClass)
|
||||
this.ChatSerializer = Java.type(nmsChatSerializerClass.getName())
|
||||
let packetTypeClass = this.getPacketPlayOutChatClass()
|
||||
this.PacketPlayOutChat = Java.type(packetTypeClass.getName())
|
||||
let packetTypeConstructor: { parameterTypes: any[] }
|
||||
let constructors = packetTypeClass.constructors
|
||||
Java.from(constructors).forEach(function (c) {
|
||||
if (c.parameterTypes.length === 2 || c.parameterTypes.length === 3) {
|
||||
packetTypeConstructor = c
|
||||
for (const constructor of Java.from(constructors)) {
|
||||
let parameterTypes = constructor.parameterTypes
|
||||
if (parameterTypes.length === 2 || parameterTypes.length === 3) {
|
||||
let nmsChatMessageTypeClass = parameterTypes[1]
|
||||
if (nmsChatMessageTypeClass.isEnum()) {
|
||||
this.chatMessageTypes = nmsChatMessageTypeClass.getEnumConstants()
|
||||
break
|
||||
} else if (nmsChatMessageTypeClass.getName() == 'int') {
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
let parameterTypes = packetTypeConstructor.parameterTypes
|
||||
let nmsChatMessageTypeClass = parameterTypes[1]
|
||||
if (nmsChatMessageTypeClass.isEnum()) {
|
||||
this.chatMessageTypes = nmsChatMessageTypeClass.getEnumConstants()
|
||||
}
|
||||
let playerConnectionField = this.getPlayerConnectionField()
|
||||
this.playerConnectionFieldName = playerConnectionField.getName()
|
||||
this.sendPacketMethodName = this.remapMethod(playerConnectionField.getType(), 'sendPacket', 'func_179290_a', this.getPacketClass()).getName()
|
||||
this.sendPacketMethodName = this.getSendPacketMethodName(playerConnectionField.getType())
|
||||
} catch (ex: any) {
|
||||
org.bukkit.Bukkit.getConsoleSender().sendMessage(`§6[§cMS§6][§bbukkit§6][§achat§6] §cNMS Inject Error §4${ex} §cDowngrade to Command Mode...`)
|
||||
this.downgrade = true
|
||||
@@ -51,10 +54,12 @@ abstract class BukkitChatInvoke {
|
||||
}
|
||||
|
||||
abstract getNmsChatSerializerClass()
|
||||
abstract getNmsChatSerializerMethodName(nmsChatSerializerClass: any)
|
||||
abstract getPacketPlayOutChatClass()
|
||||
abstract getPacketPlayOutChat(sender: any, json: any, type: number)
|
||||
abstract getPlayerConnectionField()
|
||||
abstract getPacketClass()
|
||||
abstract getSendPacketMethodName(playerConnectionClass: any)
|
||||
|
||||
nmsCls(name: string) {
|
||||
return base.getClass(['net.minecraft.server', this.nmsVersion, name].join('.'))
|
||||
@@ -84,9 +89,9 @@ abstract class BukkitChatInvoke {
|
||||
}
|
||||
}
|
||||
|
||||
json(sender: { name: string }, json: string) {
|
||||
json(sender: any, json: string) {
|
||||
if (this.downgrade) {
|
||||
return '/tellraw ' + sender.name + ' ' + json
|
||||
return sender.spigot().sendMessage(this.ComponentSerializer.parse(json))
|
||||
} else {
|
||||
this.send(sender, json, 0)
|
||||
return false
|
||||
@@ -101,6 +106,13 @@ abstract class BukkitChatInvoke {
|
||||
}
|
||||
|
||||
class BukkitChatInvokeBase extends BukkitChatInvoke {
|
||||
getSendPacketMethodName(playerConnectionClass: any) {
|
||||
return this.remapMethod(playerConnectionClass, 'sendPacket', 'func_179290_a', this.getPacketClass()).getName()
|
||||
}
|
||||
getNmsChatSerializerMethodName(nmsChatSerializerClass: any) {
|
||||
let nmsChatSerializerMethod = this.remapMethod(nmsChatSerializerClass, 'a', 'func_150699_a', base.getClass('java.lang.String'))
|
||||
return nmsChatSerializerMethod.getName()
|
||||
}
|
||||
getPacketPlayOutChat(sender: any, json: any, type: number) {
|
||||
return new this.PacketPlayOutChat(this.ChatSerializer[this.nmsChatSerializerMethodName](json), type)
|
||||
}
|
||||
@@ -149,17 +161,35 @@ class BukkitChatInvoke_1_17_1 extends BukkitChatInvoke_1_16_5 {
|
||||
return base.getClass('net.minecraft.network.protocol.Packet')
|
||||
}
|
||||
}
|
||||
class BukkitChatInvoke_1_18_2 extends BukkitChatInvoke_1_17_1 {
|
||||
getSendPacketMethodName(playerConnectionClass: any) {
|
||||
return playerConnectionClass.getMethod('a', this.getPacketClass()).getName()
|
||||
}
|
||||
}
|
||||
class BukkitChatInvoke_1_19 extends BukkitChatInvoke_1_18_2 {
|
||||
getPacketPlayOutChatClass() {
|
||||
return base.getClass('net.minecraft.network.protocol.game.ClientboundSystemChatPacket')
|
||||
}
|
||||
getPacketPlayOutChat(sender: any, json: any, type: number) {
|
||||
return new this.PacketPlayOutChat(this.ChatSerializer[this.nmsChatSerializerMethodName](json), type)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
//@ts-ignore
|
||||
let nmsVersion = org.bukkit.Bukkit.server.class.name.split('.')[3]
|
||||
let Bukkit: typeof org.bukkit.Bukkit = Java.type('org.bukkit.Bukkit')
|
||||
// @ts-ignore
|
||||
let nmsVersion = Bukkit.getServer().class.name.split('.')[3]
|
||||
let nmsSubVersion = nmsVersion.split("_")[1]
|
||||
if (nmsSubVersion >= 8) {
|
||||
bukkitChatInvoke = new BukkitChatInvoke_1_8(nmsVersion)
|
||||
} else if (nmsSubVersion >= 16) {
|
||||
bukkitChatInvoke = new BukkitChatInvoke_1_16_5(nmsVersion)
|
||||
if (nmsSubVersion >= 19) {
|
||||
bukkitChatInvoke = new BukkitChatInvoke_1_19(nmsVersion)
|
||||
} else if (nmsSubVersion >= 18) {
|
||||
bukkitChatInvoke = new BukkitChatInvoke_1_18_2(nmsVersion)
|
||||
} else if (nmsSubVersion >= 17) {
|
||||
bukkitChatInvoke = new BukkitChatInvoke_1_17_1(nmsVersion)
|
||||
} else if (nmsSubVersion >= 16) {
|
||||
bukkitChatInvoke = new BukkitChatInvoke_1_16_5(nmsVersion)
|
||||
} else if (nmsSubVersion >= 8) {
|
||||
bukkitChatInvoke = new BukkitChatInvoke_1_8(nmsVersion)
|
||||
} else {
|
||||
bukkitChatInvoke = new BukkitChatInvoke_1_7_10(nmsVersion)
|
||||
}
|
||||
@@ -168,6 +198,7 @@ try {
|
||||
}
|
||||
|
||||
let chat = {
|
||||
invoke: bukkitChatInvoke,
|
||||
json: bukkitChatInvoke.json.bind(bukkitChatInvoke),
|
||||
send: bukkitChatInvoke.send.bind(bukkitChatInvoke)
|
||||
}
|
||||
2270
packages/bukkit/src/internal/item.ts
Normal file
2270
packages/bukkit/src/internal/item.ts
Normal file
File diff suppressed because it is too large
Load Diff
128
packages/bukkit/src/item.ts
Normal file
128
packages/bukkit/src/item.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import { item } from "@ccms/api"
|
||||
import { provideSingleton } from "@ccms/container"
|
||||
|
||||
import { itemIds } from './internal/item'
|
||||
|
||||
const Material: typeof org.bukkit.Material = Java.type('org.bukkit.Material')
|
||||
const ItemStack: typeof org.bukkit.inventory.ItemStack = Java.type('org.bukkit.inventory.ItemStack')
|
||||
|
||||
@provideSingleton(item.Item)
|
||||
export class BukkitItem extends item.Item {
|
||||
private CraftItemStack: any
|
||||
private NBTTagCompound: any
|
||||
private nmsSaveNBTMethodName: any
|
||||
private MojangsonParser: any
|
||||
private nmsItemStack: any
|
||||
private mpParseMethodName: any
|
||||
private nmsVersion: any
|
||||
constructor() {
|
||||
super()
|
||||
this.reflect()
|
||||
}
|
||||
builder(): item.ItemBuilder {
|
||||
return new BukkitItemBuilder()
|
||||
}
|
||||
toJson(item: any): string {
|
||||
let nbt = new this.NBTTagCompound()
|
||||
return this.CraftItemStack.asNMSCopy(item)[this.nmsSaveNBTMethodName](nbt).toString()
|
||||
}
|
||||
fromJson(json: string) {
|
||||
return this.CraftItemStack.asBukkitCopy(new this.nmsItemStack(this.MojangsonParser[this.mpParseMethodName](json)))
|
||||
}
|
||||
private obcCls(name: string) {
|
||||
return base.getClass(['org.bukkit.craftbukkit', this.nmsVersion, name].join('.'))
|
||||
}
|
||||
private nmsCls(name: string) {
|
||||
return base.getClass(['net.minecraft.server', this.nmsVersion, name].join('.'))
|
||||
}
|
||||
private reflect() {
|
||||
try {
|
||||
let Bukkit: typeof org.bukkit.Bukkit = Java.type('org.bukkit.Bukkit')
|
||||
// @ts-ignore
|
||||
this.nmsVersion = Bukkit.getServer().class.name.split('.')[3]
|
||||
let CraftItemStackClass = this.obcCls('inventory.CraftItemStack')
|
||||
this.CraftItemStack = Java.type(CraftItemStackClass.getName())
|
||||
// @ts-ignore
|
||||
let asNMSCopyMethod = CraftItemStackClass.getMethod('asNMSCopy', ItemStack.class)
|
||||
let nmsItemStackClass = asNMSCopyMethod.getReturnType()
|
||||
this.nmsItemStack = Java.type(nmsItemStackClass.getName())
|
||||
let nmsNBTTagCompoundClass = undefined
|
||||
for (let method of Java.from(nmsItemStackClass.getMethods())) {
|
||||
let rt = method.getReturnType()
|
||||
if (method.getParameterTypes().length == 0 && "NBTTagCompound" == rt.getSimpleName()) {
|
||||
nmsNBTTagCompoundClass = rt
|
||||
}
|
||||
}
|
||||
this.NBTTagCompound = Java.type(nmsNBTTagCompoundClass.getName())
|
||||
for (let method of Java.from(nmsItemStackClass.getMethods())) {
|
||||
let params = method.getParameterTypes()
|
||||
let rt = method.getReturnType()
|
||||
if (params.length == 1 && "NBTTagCompound" == params[0].getSimpleName() && "NBTTagCompound" == rt.getSimpleName()) {
|
||||
this.nmsSaveNBTMethodName = method.getName()
|
||||
break
|
||||
}
|
||||
}
|
||||
try {
|
||||
this.MojangsonParser = this.nmsCls('MojangsonParser').static
|
||||
} catch (error) {
|
||||
this.MojangsonParser = Java.type('net.minecraft.nbt.MojangsonParser')
|
||||
}
|
||||
for (let method of Java.from(this.MojangsonParser.class.getMethods())) {
|
||||
let params = method.getParameterTypes()
|
||||
let rt = method.getReturnType()
|
||||
if (params.length == 1 && "String" == params[0].getSimpleName() && "NBTTagCompound" == rt.getSimpleName()) {
|
||||
this.mpParseMethodName = method.getName()
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.log('Bukkit 物品管理器初始化失败:', error)
|
||||
if (global.debug) {
|
||||
console.ex(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class BukkitItemBuilder implements item.ItemBuilder {
|
||||
private itemStack: org.bukkit.inventory.ItemStack
|
||||
private itemMeta: org.bukkit.inventory.meta.ItemMeta
|
||||
|
||||
from(itemStack: any): item.ItemBuilder {
|
||||
this.itemStack = itemStack
|
||||
this.itemMeta = this.itemStack.getItemMeta()
|
||||
return this
|
||||
}
|
||||
create(type: string | number): item.ItemBuilder {
|
||||
let material = undefined
|
||||
if (typeof type == 'number') {
|
||||
type = itemIds[type]
|
||||
}
|
||||
material = Material[type] || Material[Material['LEGACY_PREFIX'] + type]
|
||||
this.itemStack = new ItemStack(material)
|
||||
this.itemMeta = this.itemStack.getItemMeta()
|
||||
return this
|
||||
}
|
||||
name(name: string): item.ItemBuilder {
|
||||
this.itemMeta.setDisplayName(name)
|
||||
return this
|
||||
}
|
||||
lore(...lores: string[]): item.ItemBuilder {
|
||||
this.itemMeta.setLore(lores)
|
||||
return this
|
||||
}
|
||||
amount(amount: number): item.ItemBuilder {
|
||||
this.itemStack.setAmount(amount)
|
||||
return this
|
||||
}
|
||||
durability(durability: number): item.ItemBuilder {
|
||||
this.itemStack.setDurability(durability)
|
||||
return this
|
||||
}
|
||||
clone() {
|
||||
return this.build().clone()
|
||||
}
|
||||
build() {
|
||||
this.itemStack.setItemMeta(this.itemMeta)
|
||||
return this.itemStack
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,13 @@
|
||||
import { provideSingleton } from '@ccms/container'
|
||||
import { particle, plugin } from '@ccms/api'
|
||||
import { particle } from '@ccms/api'
|
||||
|
||||
@provideSingleton(particle.ParticleManager)
|
||||
export class BukkitParticleManager extends particle.ParticleManager {
|
||||
private globalSpawner = new BukkitParticleSpawner()
|
||||
constructor() {
|
||||
super()
|
||||
particle.ParticleManager.globalSpawner = this.globalSpawner
|
||||
}
|
||||
protected getGlobalSpawner() {
|
||||
return this.globalSpawner
|
||||
}
|
||||
}
|
||||
|
||||
@provideSingleton(particle.ParticleSpawner)
|
||||
export class BukkitParticleSpawner extends particle.ParticleSpawner {
|
||||
spawnParticle(location: any, particle: any, count: number = 1) {
|
||||
location.getWorld().spawnParticle(particle, location, count)
|
||||
}
|
||||
spawn(location: any, particle: particle.Particle) {
|
||||
spawn(location: org.bukkit.Location, particle: particle.Particle) {
|
||||
location.getWorld().spawnParticle(
|
||||
particle.getParticle(),
|
||||
location,
|
||||
@@ -28,4 +19,15 @@ export class BukkitParticleSpawner extends particle.ParticleSpawner {
|
||||
particle.getData()
|
||||
)
|
||||
}
|
||||
spawnToPlayer(player: org.bukkit.entity.Player, location: org.bukkit.Location, particle: particle.Particle) {
|
||||
player.spawnParticle(
|
||||
particle.getParticle(),
|
||||
location,
|
||||
particle.getCount(),
|
||||
particle.getOffsetX(),
|
||||
particle.getOffsetY(),
|
||||
particle.getOffsetZ(),
|
||||
particle.getExtra(),
|
||||
particle.getData())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,22 @@ export class BukkitNativePluginManager extends server.NativePluginManager {
|
||||
get(name: string): server.NativePlugin {
|
||||
return this.convert(this.bukkitPluginManager.getPlugin(name))
|
||||
}
|
||||
enable(name: string): server.NativePlugin {
|
||||
let origin = this.bukkitPluginManager.getPlugin(name)
|
||||
if (!origin) { throw new Error(`Native Plugin ${name} not found.`) }
|
||||
if (!origin.isEnabled()) {
|
||||
this.bukkitPluginManager.enablePlugin(origin)
|
||||
}
|
||||
return this.convert(origin)
|
||||
}
|
||||
disable(name: string): server.NativePlugin {
|
||||
let origin = this.bukkitPluginManager.getPlugin(name)
|
||||
if (!origin) { throw new Error(`Native Plugin ${name} not found.`) }
|
||||
if (origin.isEnabled()) {
|
||||
this.bukkitPluginManager.disablePlugin(origin)
|
||||
}
|
||||
return this.convert(origin)
|
||||
}
|
||||
|
||||
private convert(plugin: org.bukkit.plugin.Plugin): server.NativePlugin {
|
||||
if (!plugin) return plugin as any
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { server, constants } from '@ccms/api'
|
||||
import { server } from '@ccms/api'
|
||||
import { provideSingleton } from '@ccms/container'
|
||||
|
||||
import * as reflect from '@ccms/common/dist/reflect'
|
||||
import chat from './enhance/chat'
|
||||
|
||||
let Bukkit: typeof org.bukkit.Bukkit = org.bukkit.Bukkit
|
||||
const Bukkit: typeof org.bukkit.Bukkit = Java.type('org.bukkit.Bukkit')
|
||||
|
||||
@provideSingleton(server.Server)
|
||||
export class BukkitServer extends server.ReflectServer {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { task, plugin } from '@ccms/api'
|
||||
import { inject, provideSingleton } from '@ccms/container'
|
||||
import { provideSingleton } from '@ccms/container'
|
||||
|
||||
const Bukkit = Java.type('org.bukkit.Bukkit')
|
||||
const BukkitRunnable = Java.type('org.bukkit.scheduler.BukkitRunnable')
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "src",
|
||||
"outDir": "dist"
|
||||
"outDir": "dist",
|
||||
"resolveJsonModule": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ccms/bungee",
|
||||
"version": "0.18.0",
|
||||
"version": "0.28.0-beta.2",
|
||||
"description": "MiaoScript bungee package",
|
||||
"keywords": [
|
||||
"miaoscript",
|
||||
@@ -21,12 +21,12 @@
|
||||
"devDependencies": {
|
||||
"@javatypes/bungee-api": "^0.0.3",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.5.5"
|
||||
"rimraf": "^4.1.2",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ccms/api": "^0.18.0",
|
||||
"@ccms/common": "^0.18.0",
|
||||
"@ccms/container": "^0.18.0"
|
||||
"@ccms/api": "^0.28.0-beta.2",
|
||||
"@ccms/common": "^0.28.0-beta.2",
|
||||
"@ccms/container": "^0.28.0-beta.2"
|
||||
}
|
||||
}
|
||||
|
||||
1
packages/client/.gitignore
vendored
1
packages/client/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
src/emp.ts
|
||||
@@ -1,37 +0,0 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "@ccms/client",
|
||||
"version": "0.18.0",
|
||||
"description": "MiaoScript client package",
|
||||
"keywords": [
|
||||
"miaoscript",
|
||||
"minecraft",
|
||||
"bukkit",
|
||||
"sponge"
|
||||
],
|
||||
"author": "MiaoWoo <admin@yumc.pw>",
|
||||
"homepage": "https://github.com/circlecloud/ms.git",
|
||||
"license": "ISC",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"dev": "ts-node-dev --respawn --debounce=1500 src/index.ts",
|
||||
"clean": "rimraf dist",
|
||||
"watch": "tsc --watch",
|
||||
"build": "yarn clean && tsc",
|
||||
"start": "node dist/index.js",
|
||||
"debug": "DEBUG=minecraft-protocol node dist/index.js",
|
||||
"emp": "node dist/emp.js",
|
||||
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.25.0",
|
||||
"minecraft-protocol": "^1.30.0",
|
||||
"minecraft-protocol-forge": "^1.0.0",
|
||||
"proxy-agent": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^17.0.17",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.5.5"
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
class MessagePart {
|
||||
text: string
|
||||
color: string
|
||||
clickEvent: MessagePartEvent
|
||||
hoverEvent: MessagePartEvent
|
||||
translate: string
|
||||
with: MessagePart[]
|
||||
extra: MessagePart[]
|
||||
}
|
||||
|
||||
class MessagePartEvent {
|
||||
action: string
|
||||
value: string
|
||||
}
|
||||
|
||||
var colorMap = []
|
||||
colorMap['0'] = '38;5;0'
|
||||
colorMap['1'] = '38;5;4'
|
||||
colorMap['2'] = '38;5;2'
|
||||
colorMap['3'] = '38;5;6'
|
||||
colorMap['4'] = '38;5;1'
|
||||
colorMap['5'] = '38;5;5'
|
||||
colorMap['6'] = '38;5;3'
|
||||
colorMap['7'] = '38;5;7'
|
||||
colorMap['8'] = '38;5;8'
|
||||
colorMap['9'] = '38;5;12'
|
||||
colorMap['a'] = '38;5;10'
|
||||
colorMap['b'] = '38;5;14'
|
||||
colorMap['c'] = '38;5;9'
|
||||
colorMap['d'] = '38;5;13'
|
||||
colorMap['e'] = '38;5;11'
|
||||
colorMap['f'] = '38;5;15'
|
||||
colorMap['r'] = '0'
|
||||
colorMap['l'] = '1'
|
||||
colorMap['n'] = '4'
|
||||
var regexMap = []
|
||||
for (const c in colorMap) {
|
||||
regexMap[colorMap[c]] = new RegExp(`§${c}`, "g")
|
||||
}
|
||||
function mcColor2ANSI(str) {
|
||||
for (const regex in regexMap) {
|
||||
str = str.replace(regexMap[regex], `\u001b[${regex}m`)
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
let jsonColorMap = {
|
||||
"black": '0',
|
||||
"dark_blue": '1',
|
||||
"dark_green": '2',
|
||||
"dark_aqua": '3',
|
||||
"dark_red": '4',
|
||||
"dark_purple": '5',
|
||||
"gold": '6',
|
||||
"gray": '7',
|
||||
"dark_gray": '8',
|
||||
"blue": '9',
|
||||
"green": 'a',
|
||||
"aqua": 'b',
|
||||
"red": 'c',
|
||||
"light_purple": 'd',
|
||||
"yellow": 'e',
|
||||
"white": 'f',
|
||||
"obfuscated": 'k',
|
||||
"bold": 'l',
|
||||
"strikethrough": 'm',
|
||||
"underline": 'n',
|
||||
"italic": 'o',
|
||||
"reset": 'r',
|
||||
};
|
||||
|
||||
function json2text(json: MessagePart): string {
|
||||
let temp = "";
|
||||
if (json.color) {
|
||||
temp += `§${jsonColorMap[json.color]}`
|
||||
}
|
||||
temp += json.text || json.translate || ''
|
||||
if (json.extra) {
|
||||
json.extra.forEach((ext) => {
|
||||
temp += json2text(ext)
|
||||
})
|
||||
}
|
||||
return temp += '§r'
|
||||
}
|
||||
|
||||
function $(input: any) {
|
||||
if (typeof input === "string") {
|
||||
input = JSON.parse(input)
|
||||
}
|
||||
input = json2text(input) + '§r'
|
||||
if (input.startsWith('§卐')) {
|
||||
input = input.substring(2)
|
||||
}
|
||||
return mcColor2ANSI(input)
|
||||
}
|
||||
|
||||
export {
|
||||
json2text,
|
||||
mcColor2ANSI,
|
||||
$
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
import { $ } from './color'
|
||||
|
||||
export function attachEvents(client) {
|
||||
client.on('chat', (packet) => {
|
||||
// Listen for chat messages and echo them back.
|
||||
var jsonMsg = JSON.parse(packet.message)
|
||||
console.log($(jsonMsg))
|
||||
})
|
||||
client.on('state', (newState, oldState) => {
|
||||
console.log('Client Change State', oldState, 'to', newState)
|
||||
let targetServer = process.argv[6]
|
||||
if (newState == "play" && targetServer) {
|
||||
setTimeout(() => {
|
||||
client.write('chat', {
|
||||
message: '/server ' + targetServer
|
||||
})
|
||||
}, 3000)
|
||||
}
|
||||
})
|
||||
client.on('update_health', (packet) => {
|
||||
if (packet.health <= 0) {
|
||||
console.log("Player Dead Auto Respawn...")
|
||||
client.write('client_command', { payload: 0 })
|
||||
} else if (packet.health > 0) {
|
||||
}
|
||||
})
|
||||
client.on('kick_disconnect', (packet) => {
|
||||
console.log($(packet.reason))
|
||||
})
|
||||
client.on('disconnect', (packet) => {
|
||||
console.log($(packet.reason))
|
||||
})
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
export function attachForge(client) {
|
||||
client.on('custom_payload', function(packet) {
|
||||
if (packet.channel === 'FML|HS') {
|
||||
client.write('custom_payload', {
|
||||
channel: 'FML|HS',
|
||||
data: Buffer.of(0x01, 0x02)
|
||||
});
|
||||
client.write('custom_payload', {
|
||||
channel: 'FML|HS',
|
||||
data: Buffer.of(0x02, 0x00)
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
import { createInterface } from 'readline'
|
||||
import { Client, createClient } from 'minecraft-protocol'
|
||||
|
||||
import { attachForge } from './forge'
|
||||
import { attachEvents } from './event'
|
||||
|
||||
let readUserInfo = process.argv[2] || 'Mr_jtb'
|
||||
let realUserInfo = readUserInfo.split(":")
|
||||
let username = realUserInfo[0]
|
||||
let password = realUserInfo[1] || ''
|
||||
let version = process.argv[3] || '1.12.2'
|
||||
let readAddress = process.argv[4] || '192.168.2.25:25565'
|
||||
let realAddress = readAddress.split(":")
|
||||
let address = realAddress[0]
|
||||
let port = parseInt(realAddress[1] || "25565")
|
||||
let client = commandLineCreateClient()
|
||||
|
||||
function commandLineCreateClient() {
|
||||
return createConnection(address, port, username, password)
|
||||
}
|
||||
|
||||
function createConnection(host: string, port: number, username: string, password: string) {
|
||||
let clientOptions: any = {
|
||||
version,
|
||||
host,
|
||||
port,
|
||||
username,
|
||||
password,
|
||||
// clientToken: 'd02c7f39-2376-45da-a5a5-50e24fa8b185',
|
||||
//@ts-ignore
|
||||
// authServer: 'https://skin.yumc.pw/api/yggdrasil/authserver',
|
||||
// sessionServer: 'https://skin.yumc.pw/api/yggdrasil/sessionserver'
|
||||
}
|
||||
if (clientOptions.password) {
|
||||
clientOptions.clientToken = 'd02c7f39-2376-45da-a5a5-50e24fa8b185'
|
||||
clientOptions.authServer = 'https://skin.yumc.pw/api/yggdrasil/authserver'
|
||||
clientOptions.sessionServer = 'https://skin.yumc.pw/api/yggdrasil/sessionserver'
|
||||
}
|
||||
let client = createClient(clientOptions)
|
||||
|
||||
attachCommon(client)
|
||||
attachForge(client)
|
||||
attachEvents(client)
|
||||
return client
|
||||
}
|
||||
|
||||
function attachCommon(client: Client) {
|
||||
client.on('login', () => {
|
||||
// client.registerChannel('updater', ['string', []])
|
||||
// client.registerChannel('updater-enabled', ['string', []])
|
||||
// client.registerChannel('dragoncore', ['string', []])
|
||||
// client.registerChannel('dragoncore:main', ['string', []])
|
||||
client.on('REGISTER', (array) => {
|
||||
for (const channel of array) {
|
||||
client.on('channel', console.log)
|
||||
}
|
||||
})
|
||||
// client.on('dragoncore:main', (data) => {
|
||||
// console.log(data)
|
||||
// })
|
||||
})
|
||||
client.on('custom_payload', (data) => {
|
||||
console.log('custom_payload' + JSON.stringify(data))
|
||||
})
|
||||
client.on('error', (error) => {
|
||||
console.log("Client Error", error)
|
||||
})
|
||||
client.on('end', (resone) => {
|
||||
console.log("Client End Resone:", resone)
|
||||
if (`${resone}` != "SocketClosed") {
|
||||
setTimeout(() => {
|
||||
client = commandLineCreateClient()
|
||||
}, 500)
|
||||
} else {
|
||||
process.exit(0)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const rl = createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout,
|
||||
completer: (line, func) => {
|
||||
let args = line.split(' ')
|
||||
let comp = args[args.length - 1]
|
||||
client.once('tab_complete', (msg) => {
|
||||
let mcts = msg.matches.filter(s => s)
|
||||
func(null, [mcts, comp])
|
||||
})
|
||||
client.write('tab_complete', {
|
||||
text: line
|
||||
})
|
||||
},
|
||||
terminal: true,
|
||||
prompt: ''
|
||||
})
|
||||
|
||||
rl.on('line', function (line) {
|
||||
switch (line) {
|
||||
case "":
|
||||
break
|
||||
case "eval":
|
||||
break
|
||||
case "write":
|
||||
break
|
||||
case "/respawn":
|
||||
client.write('client_command', { payload: 0 })
|
||||
break
|
||||
case "//reco":
|
||||
client.end("")
|
||||
client = commandLineCreateClient()
|
||||
break
|
||||
case "//quit":
|
||||
console.info('Disconnected')
|
||||
client.end("")
|
||||
break
|
||||
case "//end":
|
||||
console.info('Forcibly ended client')
|
||||
process.exit(0)
|
||||
default:
|
||||
client.write('chat', { message: line })
|
||||
}
|
||||
rl.prompt()
|
||||
})
|
||||
@@ -1,5 +0,0 @@
|
||||
while :; do
|
||||
yarn emp
|
||||
echo 进程退出 休眠120秒!
|
||||
sleep 120
|
||||
done
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@ccms/common",
|
||||
"version": "0.18.0",
|
||||
"description": "MiaoScript api package",
|
||||
"version": "0.28.0-beta.2",
|
||||
"description": "MiaoScript common package",
|
||||
"keywords": [
|
||||
"miaoscript",
|
||||
"minecraft",
|
||||
@@ -19,11 +19,11 @@
|
||||
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ccms/nashorn": "^0.18.0",
|
||||
"@ccms/nashorn": "^0.28.0-beta.2",
|
||||
"@javatypes/jdk": "^0.0.3",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.5.5"
|
||||
"rimraf": "^4.1.2",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"gitHead": "562e2d00175c9d3a99c8b672aa07e6d92706a027"
|
||||
}
|
||||
|
||||
@@ -19,12 +19,20 @@ interface RequestConfig {
|
||||
method?: Method
|
||||
headers?: { [key: string]: string }
|
||||
params?: { [key: string]: string }
|
||||
data?: any
|
||||
data?: any,
|
||||
connectTimeout?: number,
|
||||
readTimeout?: number,
|
||||
}
|
||||
|
||||
function request(config: RequestConfig) {
|
||||
// @ts-ignore XMLHttpRequest class only exist nashorn polyfill
|
||||
let xhr = new XMLHttpRequest()
|
||||
if (config.connectTimeout) {
|
||||
xhr.connectTimeout = config.connectTimeout
|
||||
}
|
||||
if (config.readTimeout) {
|
||||
xhr.readTimeout = config.readTimeout
|
||||
}
|
||||
xhr.open(config.method, config.url, false)
|
||||
for (const header in config.headers) {
|
||||
xhr.setRequestHeader(header, config.headers[header])
|
||||
|
||||
@@ -54,6 +54,7 @@ class Reflect {
|
||||
}
|
||||
}
|
||||
if (!field) throw new Error(`can't reflect field ${typeof nameOrIndex == "number" ? 'index' : 'name'} ${nameOrIndex} from ${this.class.getName()}!`)
|
||||
fieldCache.set(key, field)
|
||||
return accessible(field)
|
||||
}
|
||||
|
||||
@@ -129,12 +130,14 @@ function declaredField(clazz: java.lang.Class<any>, name: string | java.lang.Str
|
||||
let field = null
|
||||
// noinspection JSUnresolvedVariable
|
||||
while (target !== JavaObject.class) {
|
||||
console.debug(`reflect field ${name} from ${target.getName()}`)
|
||||
try {
|
||||
field = target.getDeclaredField(name)
|
||||
if (field !== null) { break }
|
||||
} catch (error: any) {
|
||||
if (target === undefined) { break }
|
||||
target = target.getSuperclass()
|
||||
console.debug(`switch to super class: ${target.getName()}`)
|
||||
}
|
||||
}
|
||||
if (field === null) {
|
||||
@@ -146,21 +149,32 @@ function declaredField(clazz: java.lang.Class<any>, name: string | java.lang.Str
|
||||
function declaredMethod(clazz: java.lang.Class<any>, nameOrIndex: string | number, ...clazzs: java.lang.Class<any>[]): java.lang.reflect.Method {
|
||||
let key = clazz.getName() + '.' + nameOrIndex + ':' + (clazzs || []).map(c => c.getName()).join(':')
|
||||
if (methodCache.has(key)) { return methodCache.get(key) }
|
||||
let target = clazz
|
||||
if (typeof nameOrIndex === "number") {
|
||||
methodCache.set(key, declaredMethods(clazz)[nameOrIndex])
|
||||
} else {
|
||||
try {
|
||||
methodCache.set(key, clazz.getMethod(nameOrIndex, clazzs as any))
|
||||
} catch (ex: any) {
|
||||
while (target !== JavaObject.class && !methodCache.has(key)) {
|
||||
try {
|
||||
methodCache.set(key, clazz.getDeclaredMethod(nameOrIndex, clazzs as any))
|
||||
} catch (ex: any) {
|
||||
for (const m of Java.from(declaredMethods(clazz))) {
|
||||
if (m.getName() == nameOrIndex) {
|
||||
methodCache.set(key, m)
|
||||
break
|
||||
console.debug(`reflect method ${typeof nameOrIndex == "number" ? 'index' : 'name'} ${nameOrIndex} from ${target.getName()}`)
|
||||
try {
|
||||
methodCache.set(key, target.getMethod(nameOrIndex, clazzs as any))
|
||||
} catch (ex: any) {
|
||||
try {
|
||||
methodCache.set(key, target.getDeclaredMethod(nameOrIndex, clazzs as any))
|
||||
} catch (ex: any) {
|
||||
for (const m of Java.from(declaredMethods(target))) {
|
||||
if (m.getName() == nameOrIndex) {
|
||||
methodCache.set(key, m)
|
||||
break
|
||||
}
|
||||
}
|
||||
throw new Error(`method ${typeof nameOrIndex == "number" ? 'index' : 'name'} ${nameOrIndex} not found.`)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (target === undefined) { break }
|
||||
target = target.getSuperclass()
|
||||
console.debug(`switch to super class: ${target.getName()}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,7 +187,7 @@ function declaredMethods(clazz: java.lang.Class<any>) {
|
||||
}
|
||||
|
||||
function mapToObject(javaObj) {
|
||||
if (!Java.isJavaObject(javaObj)) { throw new TypeError(`参数 ${javaObj} 不是一个Java对象!`) }
|
||||
if (!Java.isJavaObject(javaObj)) { throw new TypeError(`argument ${javaObj} is not a java object.`) }
|
||||
let target = Proxy.newProxy(javaObj, {
|
||||
apply: (target, name, args) => { return args ? javaObj[name](args) : javaObj[name]() }
|
||||
})
|
||||
|
||||
@@ -17,14 +17,14 @@ class ChatMessagePart {
|
||||
}
|
||||
|
||||
convert() {
|
||||
return this.internal;
|
||||
return this.internal
|
||||
}
|
||||
}
|
||||
|
||||
class Tellraw {
|
||||
static duplicateChar = '§卐'
|
||||
static create() {
|
||||
return new Tellraw().then(Tellraw.duplicateChar);
|
||||
return new Tellraw().then(Tellraw.duplicateChar)
|
||||
}
|
||||
|
||||
private cache: string = '';
|
||||
@@ -32,77 +32,81 @@ class Tellraw {
|
||||
|
||||
then(part: ChatMessagePart | string) {
|
||||
if (typeof part === "string") {
|
||||
var newPart = new ChatMessagePart();
|
||||
var newPart = new ChatMessagePart()
|
||||
newPart.text = part
|
||||
this.then(newPart);
|
||||
return this;
|
||||
this.then(newPart)
|
||||
return this
|
||||
}
|
||||
var last = this.latest();
|
||||
var last = this.latest()
|
||||
if (!last.text) {
|
||||
last.text = part.text;
|
||||
last.text = part.text
|
||||
} else {
|
||||
this.parts.push(part);
|
||||
this.parts.push(part)
|
||||
}
|
||||
this.cache = null;
|
||||
this.cache = null
|
||||
}
|
||||
|
||||
text(text: string) {
|
||||
this.latest().text = text;
|
||||
return this;
|
||||
this.latest().text = text
|
||||
return this
|
||||
}
|
||||
|
||||
tip(text: string) {
|
||||
this.latest().hover("show_text", text);
|
||||
return this;
|
||||
tip(texts: string) {
|
||||
return this.hover(texts)
|
||||
}
|
||||
|
||||
item(text: string) {
|
||||
this.latest().hover("show_item", text);
|
||||
return this;
|
||||
hover(texts: string) {
|
||||
this.latest().hover("show_text", texts)
|
||||
return this
|
||||
}
|
||||
|
||||
item(item: string) {
|
||||
this.latest().hover("show_item", item)
|
||||
return this
|
||||
}
|
||||
|
||||
command(command: string) {
|
||||
this.latest().click("run_command", command);
|
||||
return this;
|
||||
this.latest().click("run_command", command)
|
||||
return this
|
||||
}
|
||||
|
||||
suggest(url: string) {
|
||||
this.latest().click("suggest_command", url);
|
||||
return this;
|
||||
this.latest().click("suggest_command", url)
|
||||
return this
|
||||
}
|
||||
|
||||
file(path: string) {
|
||||
this.latest().click("open_file", path);
|
||||
return this;
|
||||
this.latest().click("open_file", path)
|
||||
return this
|
||||
}
|
||||
|
||||
link(url: string) {
|
||||
this.latest().click("open_url", url);
|
||||
return this;
|
||||
this.latest().click("open_url", url)
|
||||
return this
|
||||
}
|
||||
|
||||
latest() {
|
||||
return this.parts[this.parts.length - 1];
|
||||
return this.parts[this.parts.length - 1]
|
||||
}
|
||||
|
||||
json() {
|
||||
if (!this.cache) {
|
||||
var temp = [];
|
||||
var temp = []
|
||||
this.parts.forEach(t => {
|
||||
temp.push(t.convert());
|
||||
});
|
||||
this.cache = JSON.stringify(temp);
|
||||
console.trace(this.cache);
|
||||
temp.push(t.convert())
|
||||
})
|
||||
this.cache = JSON.stringify(temp)
|
||||
console.trace(this.cache)
|
||||
}
|
||||
return this.cache;
|
||||
return this.cache
|
||||
}
|
||||
|
||||
string() {
|
||||
var temp = '';
|
||||
var temp = ''
|
||||
this.parts.forEach(t => {
|
||||
temp += t.text
|
||||
});
|
||||
return temp;
|
||||
})
|
||||
return temp
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
35
packages/common/src/version.ts
Normal file
35
packages/common/src/version.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
export type Version = [string, string, string]
|
||||
|
||||
export class VersionUtils {
|
||||
static isEqual(version: string, targetVersion: string): boolean {
|
||||
return version == targetVersion
|
||||
}
|
||||
static isGreaterOrEqual(version: string, targetVersion: string): boolean {
|
||||
const v1 = parseVersion(version)
|
||||
const v2 = parseVersion(targetVersion)
|
||||
|
||||
return (
|
||||
v1[0] > v2[0] ||
|
||||
(v1[0] === v2[0] && v1[1] > v2[1]) ||
|
||||
(v1[0] === v2[0] && v1[1] === v2[1] && v1[2] >= v2[2])
|
||||
)
|
||||
}
|
||||
static isGreater(version: string, targetVersion: string): boolean {
|
||||
const v1 = parseVersion(version)
|
||||
const v2 = parseVersion(targetVersion)
|
||||
|
||||
return (
|
||||
v1[0] > v2[0] ||
|
||||
(v1[0] === v2[0] && v1[1] > v2[1]) ||
|
||||
(v1[0] === v2[0] && v1[1] === v2[1] && v1[2] > v2[2])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function parseVersion(version: string = ""): Version {
|
||||
const v: Version = ['0', '0', '0']
|
||||
|
||||
version.split(".").forEach((value, i) => (v[i] = value))
|
||||
|
||||
return v
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ccms/compile",
|
||||
"version": "0.18.0",
|
||||
"version": "0.28.0-beta.2",
|
||||
"description": "MiaoScript compile package",
|
||||
"keywords": [
|
||||
"miaoscript",
|
||||
@@ -20,7 +20,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.5.5"
|
||||
"rimraf": "^4.1.2",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ccms/container",
|
||||
"version": "0.18.0",
|
||||
"version": "0.28.0-beta.2",
|
||||
"description": "MiaoScript container package",
|
||||
"keywords": [
|
||||
"miaoscript",
|
||||
@@ -19,10 +19,10 @@
|
||||
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ccms/nashorn": "^0.18.0",
|
||||
"@ccms/nashorn": "^0.28.0-beta.2",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.5.5"
|
||||
"rimraf": "^4.1.2",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"inversify": "^6.0.1",
|
||||
|
||||
@@ -1,38 +1,9 @@
|
||||
import { interfaces, Container } from "inversify"
|
||||
import { _proxyGetter } from "./utils"
|
||||
|
||||
let _container: Container
|
||||
|
||||
const ContainerInstance = Symbol.for("@ccms/ioc:Container")
|
||||
const INJECTION = Symbol.for("INJECTION")
|
||||
|
||||
function _proxyGetter(
|
||||
proto: any,
|
||||
key: string,
|
||||
resolve: () => any,
|
||||
doCache: boolean
|
||||
) {
|
||||
function getter(this: object) {
|
||||
if (doCache && !Reflect.hasMetadata(INJECTION, this, key)) {
|
||||
Reflect.defineMetadata(INJECTION, resolve(), this, key)
|
||||
}
|
||||
if (Reflect.hasMetadata(INJECTION, this, key)) {
|
||||
return Reflect.getMetadata(INJECTION, this, key)
|
||||
} else {
|
||||
return resolve()
|
||||
}
|
||||
}
|
||||
|
||||
function setter(this: object, newVal: any) {
|
||||
Reflect.defineMetadata(INJECTION, newVal, this, key)
|
||||
}
|
||||
|
||||
Object.defineProperty(proto, key, {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get: getter,
|
||||
set: setter
|
||||
})
|
||||
}
|
||||
|
||||
function initContainer(container: Container) {
|
||||
Reflect.defineMetadata(ContainerInstance, container, Reflect)
|
||||
|
||||
@@ -5,6 +5,7 @@ import { initContainer, getContainer } from './decorators'
|
||||
import { interfaces, Container, inject, named } from 'inversify'
|
||||
import { fluentProvide } from 'inversify-binding-decorators'
|
||||
import { ioc } from "./constants"
|
||||
import { _proxyGetter } from "./utils"
|
||||
|
||||
/**
|
||||
* 注册一个命名对象
|
||||
@@ -49,9 +50,11 @@ export const JavaClass = (className: string) => {
|
||||
*/
|
||||
export const JSClass = (className: string) => {
|
||||
return function (target: object, propertyKey: string, index?: number) {
|
||||
try { target[propertyKey] = Java.type(className); return } catch (error: any) { }
|
||||
try { target[propertyKey] = base.getClass(className).static; return } catch (error: any) { }
|
||||
console.warn('JSClass', className, 'Inject target', target.constructor.name, 'propertyKey', propertyKey, 'failed!')
|
||||
_proxyGetter(target, propertyKey, () => {
|
||||
try { return Java.type(className) } catch (error: any) { }
|
||||
try { return base.getClass(className).static } catch (error: any) { }
|
||||
console.warn('JSClass', className, 'Inject target', target.constructor.name, 'propertyKey', propertyKey, 'failed!')
|
||||
}, true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,6 +91,59 @@ export const Resource = (resourceName?: string | any) => {
|
||||
}
|
||||
}
|
||||
|
||||
const DocumentBuilderFactory = Java.type('javax.xml.parsers.DocumentBuilderFactory')
|
||||
|
||||
export const MavenDepend = (groupId: string, artifactId: string, version: string, recursion = false) => {
|
||||
return function (target: any) {
|
||||
loadMavenDepend(groupId, artifactId, version, recursion)
|
||||
}
|
||||
}
|
||||
|
||||
const loadedMavenDepend = new Set<string>()
|
||||
|
||||
export function loadMavenDepend(groupId: string, artifactId: string, version: string, recursion = false) {
|
||||
const key = `${groupId}:${artifactId}:${version}`
|
||||
try {
|
||||
if (loadedMavenDepend.has(key)) { return }
|
||||
console.info('loading maven dependency', key)
|
||||
let [pom, _] = base.loadMavenDepend(groupId, artifactId, version)
|
||||
loadedMavenDepend.add(key)
|
||||
if (recursion) {
|
||||
let doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(pom)
|
||||
let dependencies = doc.getElementsByTagName("dependency")
|
||||
let size = dependencies.length
|
||||
if (!size) { return }
|
||||
console.debug(key, 'found', size, 'dependencies loading...')
|
||||
for (let i = 0; i < size; i++) {
|
||||
const dependency = dependencies.item(i)
|
||||
const gav = dependency.getChildNodes()
|
||||
const length = gav.length
|
||||
const dependencyVersion = { groupId: '', artifactId: '', version: '' }
|
||||
for (let j = 0; j < length; j++) {
|
||||
const prop = gav.item(j)
|
||||
switch (prop.getNodeName()) {
|
||||
case "groupId":
|
||||
dependencyVersion.groupId = prop.getTextContent()
|
||||
break
|
||||
case "artifactId":
|
||||
dependencyVersion.artifactId = prop.getTextContent()
|
||||
break
|
||||
case "version":
|
||||
dependencyVersion.version = prop.getTextContent()
|
||||
break
|
||||
}
|
||||
}
|
||||
loadMavenDepend(dependencyVersion.groupId, dependencyVersion.artifactId, dependencyVersion.version, recursion)
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.warn('load maven dependency', key, 'failed. Error:', error)
|
||||
if (global.debug) {
|
||||
console.ex(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const reduceMetadata = (ctx: interfaces.Context): any => {
|
||||
return ctx.currentRequest.target.metadata.reduce((result, entry, index) => {
|
||||
result[entry.key] = entry.value
|
||||
@@ -98,8 +154,10 @@ export const reduceMetadata = (ctx: interfaces.Context): any => {
|
||||
function initAutowired(container: Container) {
|
||||
container.bind(ioc.Autowired).toDynamicValue((ctx) => {
|
||||
var metadata: any = reduceMetadata(ctx)
|
||||
let key = Object.toString.call(metadata.named)
|
||||
let key = Object.prototype.toString.call(metadata.named)
|
||||
if (key === "[object Function]" || key === "[object Symbol]") { return container.get(metadata.named) }
|
||||
console.warn('container Autowired', metadata.named, 'failed. Error: illegal serviceIdentifier type', key)
|
||||
console.debug(metadata.named, 'metadata', JSON.stringify(metadata))
|
||||
return undefined
|
||||
})
|
||||
}
|
||||
|
||||
30
packages/container/src/utils.ts
Normal file
30
packages/container/src/utils.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
const INJECTION = Symbol.for("INJECTION")
|
||||
|
||||
export function _proxyGetter(
|
||||
proto: any,
|
||||
key: string,
|
||||
resolve: () => any,
|
||||
doCache: boolean
|
||||
) {
|
||||
function getter(this: object) {
|
||||
if (doCache && !Reflect.hasMetadata(INJECTION, this, key)) {
|
||||
Reflect.defineMetadata(INJECTION, resolve(), this, key)
|
||||
}
|
||||
if (Reflect.hasMetadata(INJECTION, this, key)) {
|
||||
return Reflect.getMetadata(INJECTION, this, key)
|
||||
} else {
|
||||
return resolve()
|
||||
}
|
||||
}
|
||||
|
||||
function setter(this: object, newVal: any) {
|
||||
Reflect.defineMetadata(INJECTION, newVal, this, key)
|
||||
}
|
||||
|
||||
Object.defineProperty(proto, key, {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
get: getter,
|
||||
set: setter
|
||||
})
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@ccms/core",
|
||||
"version": "0.18.0",
|
||||
"description": "MiaoScript api package",
|
||||
"version": "0.28.0-beta.2",
|
||||
"description": "MiaoScript core package",
|
||||
"keywords": [
|
||||
"miaoscript",
|
||||
"minecraft",
|
||||
@@ -20,12 +20,12 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.5.5"
|
||||
"rimraf": "^4.1.2",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ccms/api": "^0.18.0",
|
||||
"@ccms/container": "^0.18.0"
|
||||
"@ccms/api": "^0.28.0-beta.2",
|
||||
"@ccms/container": "^0.28.0-beta.2"
|
||||
},
|
||||
"gitHead": "781524f83e52cad26d7c480513e3c525df867121"
|
||||
}
|
||||
|
||||
1
packages/core/src/.gitignore
vendored
Normal file
1
packages/core/src/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
script
|
||||
@@ -1,9 +1,15 @@
|
||||
let containerStartTime = Date.now()
|
||||
console.i18n("ms.core.ioc.initialize", { scope: global.scope })
|
||||
import { plugin, server, task, constants } from '@ccms/api'
|
||||
import { plugin, server, task, constants, console as jsconsole } from '@ccms/api'
|
||||
import { DefaultContainer as container, provideSingleton, ContainerInstance, buildProviderModule, Autowired } from '@ccms/container'
|
||||
console.i18n("ms.core.ioc.completed", { scope: global.scope, time: (Date.now() - containerStartTime) / 1000 })
|
||||
import * as yaml from 'js-yaml'
|
||||
import http from '@ccms/common/dist/http'
|
||||
import * as fs from '@ccms/common/dist/fs'
|
||||
import { VersionUtils } from '@ccms/common/dist/version'
|
||||
|
||||
const UUID = Java.type('java.util.UUID')
|
||||
const MiaoScriptAPI = Java.type('pw.yumc.MiaoScript.api.MiaoScriptAPI')
|
||||
|
||||
@provideSingleton(MiaoScriptCore)
|
||||
class MiaoScriptCore {
|
||||
@@ -17,17 +23,31 @@ class MiaoScriptCore {
|
||||
private pluginManager: plugin.PluginManager
|
||||
|
||||
enable() {
|
||||
process.emit('core.before.enable')
|
||||
this.loadServerConsole()
|
||||
try {
|
||||
MiaoScriptAPI.setPluginManager(this.pluginManager)
|
||||
} catch (error) {
|
||||
}
|
||||
this.loadPlugins()
|
||||
process.emit('core.after.enable')
|
||||
console.i18n("ms.core.engine.completed", {
|
||||
loader: base.version,
|
||||
version: 'v' + global.ScriptEngineVersion,
|
||||
time: (Date.now() - global.ScriptEngineStartTime) / 1000
|
||||
})
|
||||
return () => this.disable()
|
||||
}
|
||||
|
||||
loadServerConsole() {
|
||||
process.emit('core.before.load.console')
|
||||
//@ts-ignore
|
||||
global.setGlobal('console', new this.Console(), { writable: false, configurable: false })
|
||||
process.emit('core.after.load.console')
|
||||
}
|
||||
|
||||
loadPlugins() {
|
||||
process.emit('core.before.load.plugins')
|
||||
let loadPluginStartTime = new Date().getTime()
|
||||
console.i18n("ms.core.plugin.initialize")
|
||||
this.pluginManager.scan(this.pluginFolder)
|
||||
@@ -35,15 +55,25 @@ class MiaoScriptCore {
|
||||
this.pluginManager.load(this.pluginManager.getPlugins())
|
||||
this.pluginManager.enable(this.pluginManager.getPlugins())
|
||||
console.i18n("ms.core.plugin.completed", { time: (new Date().getTime() - loadPluginStartTime) / 1000 })
|
||||
process.emit('core.after.load.plugins')
|
||||
}
|
||||
|
||||
disable() {
|
||||
process.emit('core.before.disable')
|
||||
let disableStartTime = Date.now()
|
||||
console.i18n("ms.core.engine.disable")
|
||||
this.pluginManager.disable(this.pluginManager.getPlugins())
|
||||
this.taskManager.disable()
|
||||
process.emit('core.after.disable')
|
||||
loadCoreScript('exit')
|
||||
process.emit('core.before.exit')
|
||||
process.exit(0)
|
||||
console.i18n("ms.core.engine.disable.finish", { version: 'v' + global.ScriptEngineVersion, time: (new Date().getTime() - disableStartTime) / 1000 })
|
||||
console.i18n("ms.core.engine.disable.finish", {
|
||||
loader: base.version,
|
||||
version: 'v' + global.ScriptEngineVersion,
|
||||
time: (new Date().getTime() - disableStartTime) / 1000
|
||||
})
|
||||
process.emit('core.after.exit')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,31 +106,76 @@ function detectServer(): constants.ServerType {
|
||||
throw Error('Unknow Server Type...')
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
global.ScriptEngineVersion = require('../package.json').version
|
||||
try { engineLoad({ script: http.get("http://ms.yumc.pw/api/plugin/download/name/initialize"), name: 'core/initialize.js' }) } catch (error: any) { console.debug(error) }
|
||||
function loadCoreScript(name) {
|
||||
try {
|
||||
let corePackageStartTime = new Date().getTime()
|
||||
container.bind(ContainerInstance).toConstantValue(container)
|
||||
container.bind(plugin.PluginInstance).toConstantValue(base.getInstance())
|
||||
container.bind(plugin.PluginFolder).toConstantValue('plugins')
|
||||
let type = detectServer()
|
||||
console.i18n("ms.core.initialize.detect", { scope: global.scope, type })
|
||||
container.bind(server.ServerType).toConstantValue(type)
|
||||
container.bind(server.ServerChecker).toSelf().inSingletonScope()
|
||||
container.bind(server.NativePluginManager).toSelf().inSingletonScope()
|
||||
console.i18n("ms.core.package.initialize", { scope: global.scope, type })
|
||||
require(`${global.scope}/${type}`).default(container)
|
||||
require(`${global.scope}/plugin`)
|
||||
container.load(buildProviderModule())
|
||||
console.i18n("ms.core.package.completed", { scope: global.scope, type, time: (Date.now() - corePackageStartTime) / 1000 })
|
||||
let disable = container.get<MiaoScriptCore>(MiaoScriptCore).enable()
|
||||
console.i18n("ms.core.engine.completed", { version: 'v' + global.ScriptEngineVersion, time: (Date.now() - global.ScriptEngineStartTime) / 1000 })
|
||||
return disable
|
||||
let scriptname = name + (global.debug ? '-debug' : '')
|
||||
engineLoad({
|
||||
script: http.get(`https://mscript.yumc.pw/api/plugin/download/name/${scriptname}`),
|
||||
name: `core/${scriptname}.js`
|
||||
})
|
||||
} catch (error: any) {
|
||||
console.i18n("ms.core.initialize.error", { error })
|
||||
console.ex(error)
|
||||
return () => console.i18n('ms.core.engine.disable.abnormal')
|
||||
if (global.debug) {
|
||||
console.debug(error)
|
||||
console.ex(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function loadMiaoScriptConfig() {
|
||||
let configFile = fs.concat(root, 'config.yml')
|
||||
if (!fs.exists(configFile)) {
|
||||
global.ScriptEngineConfig = base.save(configFile, yaml.dump({
|
||||
uuid: UUID.randomUUID().toString(),
|
||||
slow_execute: 50
|
||||
}))
|
||||
} else {
|
||||
global.ScriptEngineConfig = yaml.load(base.read(configFile))
|
||||
}
|
||||
global.ScriptSlowExecuteTime = global.ScriptEngineConfig.slow_execute || 50
|
||||
}
|
||||
|
||||
function createCore() {
|
||||
let corePackageStartTime = new Date().getTime()
|
||||
container.bind(ContainerInstance).toConstantValue(container)
|
||||
container.bind(plugin.PluginInstance).toConstantValue(base.getInstance())
|
||||
container.bind(plugin.PluginFolder).toConstantValue('plugins')
|
||||
let type = detectServer()
|
||||
|
||||
process.emit('core.before.initialize.detect')
|
||||
console.i18n("ms.core.initialize.detect", { scope: global.scope, type })
|
||||
container.bind(server.ServerType).toConstantValue(type)
|
||||
container.bind(server.ServerChecker).toSelf().inSingletonScope()
|
||||
container.bind(server.NativePluginManager).toSelf().inSingletonScope()
|
||||
container.bind(server.NativePluginChecker).toSelf().inSingletonScope()
|
||||
process.emit('core.after.initialize.detect')
|
||||
|
||||
process.emit('core.before.package.initialize')
|
||||
console.i18n("ms.core.package.initialize", { scope: global.scope, type })
|
||||
require(`${global.scope}/${type}`).default(container)
|
||||
require(`${global.scope}/plugin`)
|
||||
container.load(buildProviderModule())
|
||||
console.i18n("ms.core.package.completed", { scope: global.scope, type, time: (Date.now() - corePackageStartTime) / 1000 })
|
||||
process.emit('core.after.package.initialize')
|
||||
return container.get<MiaoScriptCore>(MiaoScriptCore)
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
process.emit('core.before.initialize')
|
||||
loadMiaoScriptConfig()
|
||||
global.ScriptEngineVersion = require('../package.json').version
|
||||
global.setGlobal('loadCoreScript', loadCoreScript)
|
||||
loadCoreScript('initialize')
|
||||
try {
|
||||
let core = createCore()
|
||||
return VersionUtils.isGreaterOrEqual(base.version, '0.22.0') ? core : core.enable()
|
||||
} catch (error: any) {
|
||||
let core = { enable: () => () => console.i18n('ms.core.engine.disable.abnormal') }
|
||||
console.i18n("core.initialize.error", { error })
|
||||
jsconsole.getStackTrace(error, false).forEach(line => console.log(line))
|
||||
process.emit('core.initialize.error')
|
||||
return VersionUtils.isGreaterOrEqual(base.version, '0.22.0') ? core : core.enable()
|
||||
} finally {
|
||||
process.emit('core.after.initialize')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
function initialize() {
|
||||
var mspmc = 'http://ms.yumc.pw/api/plugin/download/name/'
|
||||
|
||||
var http = require('@ccms/common/dist/http').default
|
||||
var fs = require('@ccms/common/dist/fs')
|
||||
|
||||
var pluginFolder = fs.concat(root, 'plugins')
|
||||
var updateFolder = fs.concat(pluginFolder, 'update')
|
||||
var pluginFile = fs.concat(pluginFolder, 'MiaoScriptPackageManager.js')
|
||||
if (!fs.exists(pluginFile)) {
|
||||
fs.mkdirs(pluginFile)
|
||||
base.save(fs.concat(updateFolder, 'MiaoScriptPackageManager.auto.install'), '.')
|
||||
}
|
||||
fs.list(updateFolder).forEach(function (path) {
|
||||
var file = path.toFile()
|
||||
if (file.exists()) {
|
||||
var filename = file.getName()
|
||||
if (filename.endsWith(".auto.install")) {
|
||||
var pluginName = filename.replace('.auto.install', '')
|
||||
var pluginFile = fs.concat(pluginFolder, pluginName + '.js')
|
||||
if (!fs.exists(pluginFile)) {
|
||||
var pluginTemp = pluginFile + '.tmp'
|
||||
http.download(mspmc + pluginName, pluginTemp)
|
||||
fs.move(pluginTemp, pluginFile, true)
|
||||
}
|
||||
base.delete(file)
|
||||
}
|
||||
}
|
||||
})
|
||||
var core = http.get('https://registry.npmmirror.com/@ccms/core')
|
||||
if (base.VERSION && global.ScriptEngineVersion != core['dist-tags']['latest']) {
|
||||
var Paths = Java.type('java.nio.file.Paths')
|
||||
base.save(Paths.get(root, "upgrade"), core['dist-tags']['latest'])
|
||||
console.info('@ccms/core found new version ' + core['dist-tags']['latest'] + ' will upgrade after reboot!')
|
||||
}
|
||||
console.debug('initialize finish!')
|
||||
}
|
||||
initialize()
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ccms/database",
|
||||
"version": "0.18.0",
|
||||
"version": "0.28.0-beta.2",
|
||||
"description": "MiaoScript database package",
|
||||
"keywords": [
|
||||
"miaoscript",
|
||||
@@ -21,11 +21,11 @@
|
||||
"devDependencies": {
|
||||
"@javatypes/spring-jdbc": "^0.0.3",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.5.5"
|
||||
"rimraf": "^4.1.2",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ccms/api": "^0.18.0",
|
||||
"@ccms/container": "^0.18.0"
|
||||
"@ccms/api": "^0.28.0-beta.2",
|
||||
"@ccms/container": "^0.28.0-beta.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,88 +1,109 @@
|
||||
import { Model } from './model'
|
||||
import { database } from '@ccms/api'
|
||||
import { JSClass } from '@ccms/container'
|
||||
|
||||
const HikariDataSource = Java.type('com.zaxxer.hikari.HikariDataSource')
|
||||
const HikariConfig = Java.type('com.zaxxer.hikari.HikariConfig')
|
||||
const JdbcTemplate = Java.type('org.springframework.jdbc.core.JdbcTemplate')
|
||||
|
||||
/**
|
||||
* 数据库配置
|
||||
*/
|
||||
export interface DataBaseConfig {
|
||||
/**
|
||||
* 数据库连接串
|
||||
*/
|
||||
url: string | javax.sql.DataSource
|
||||
/**
|
||||
* 数据库驱动
|
||||
*/
|
||||
driverClassName?: string
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
username?: string
|
||||
/**
|
||||
* 密码
|
||||
*/
|
||||
password?: string
|
||||
}
|
||||
const Thread = Java.type('java.lang.Thread')
|
||||
const JavaString = Java.type('java.lang.String')
|
||||
const Properties = Java.type('java.util.Properties')
|
||||
|
||||
/**
|
||||
* 数据库封装类
|
||||
*/
|
||||
export class DataBase {
|
||||
export class DataBase extends database.DataBase {
|
||||
private dataSource: javax.sql.DataSource
|
||||
private jdbcTemplate: org.springframework.jdbc.core.JdbcTemplate
|
||||
|
||||
constructor(dbConfig: DataBaseConfig) {
|
||||
@JSClass('com.zaxxer.hikari.HikariDataSource')
|
||||
private HikariDataSource: any
|
||||
@JSClass('com.zaxxer.hikari.HikariConfig')
|
||||
private HikariConfig: any
|
||||
@JSClass('org.springframework.jdbc.core.JdbcTemplate')
|
||||
private JdbcTemplate: typeof org.springframework.jdbc.core.JdbcTemplate
|
||||
|
||||
constructor(dbConfig: database.DataBaseConfig) {
|
||||
super()
|
||||
if (!dbConfig.url) { throw new Error('DataBase url can\'t be null!') }
|
||||
this.createDataSource(dbConfig)
|
||||
this.initialize()
|
||||
}
|
||||
|
||||
private createDataSource(dbConfig: DataBaseConfig) {
|
||||
private createDataSource(dbConfig: database.DataBaseConfig) {
|
||||
if (typeof dbConfig.url === "string") {
|
||||
if (!dbConfig.username || !dbConfig.password) {
|
||||
throw new Error('DataBase username or password can\'t be null!')
|
||||
}
|
||||
let config = new HikariConfig()
|
||||
let originClassLoader = Thread.currentThread().getContextClassLoader()
|
||||
Thread.currentThread().setContextClassLoader(base.getInstance().class.classLoader)
|
||||
let config = new this.HikariConfig()
|
||||
if (dbConfig.driverClassName) {
|
||||
config.setDriverClassName(dbConfig.driverClassName)
|
||||
} else {
|
||||
switch (dbConfig.type) {
|
||||
case "h2":
|
||||
config.setDriverClassName("org.h2.Driver")
|
||||
break
|
||||
case "sqlite":
|
||||
config.setDriverClassName("org.sqlite.JDBC")
|
||||
break
|
||||
default:
|
||||
}
|
||||
}
|
||||
if (dbConfig.username) {
|
||||
config.setUsername(dbConfig.username)
|
||||
}
|
||||
if (dbConfig.password) {
|
||||
config.setPassword(dbConfig.password)
|
||||
}
|
||||
config.setUsername(dbConfig.username)
|
||||
config.setPassword(dbConfig.password)
|
||||
config.setJdbcUrl(dbConfig.url)
|
||||
this.dataSource = new HikariDataSource(config)
|
||||
if (dbConfig.properties) {
|
||||
let properties = new Properties()
|
||||
for (const key in dbConfig.properties) {
|
||||
properties.setProperty(key, dbConfig.properties[key])
|
||||
}
|
||||
config.setDataSourceProperties(properties)
|
||||
}
|
||||
console.debug('createDataSource from config ' + JSON.stringify(dbConfig))
|
||||
this.dataSource = new this.HikariDataSource(config)
|
||||
Thread.currentThread().setContextClassLoader(originClassLoader)
|
||||
} else {
|
||||
this.dataSource = dbConfig.url
|
||||
}
|
||||
this.jdbcTemplate = new this.JdbcTemplate(this.dataSource)
|
||||
}
|
||||
|
||||
private initialize() {
|
||||
this.jdbcTemplate = new JdbcTemplate(this.dataSource)
|
||||
getDataSource() {
|
||||
return this.dataSource
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行SQL查询
|
||||
* @param sql SQL语句
|
||||
* @param args 参数
|
||||
*/
|
||||
query<T>(sql: string, ...args: any[]): Array<T> {
|
||||
let startTime = Date.now()
|
||||
let result = Java.from<any>(this.jdbcTemplate.queryForList(sql, args))
|
||||
console.debug(java.lang.String.format(`\n[DB] query \nSQL : ${sql.replace(/\?/ig, '%s')} \nCOST : ${Date.now() - startTime}ms`, args))
|
||||
console.debug(JavaString.format(`\n[DB] query \nSQL : ${sql.replace(/\?/ig, '%s')} \nCOST : ${Date.now() - startTime}ms`, args))
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行SQL更新
|
||||
* @param sql SQL语句
|
||||
* @param args 参数
|
||||
*/
|
||||
update(sql: string, ...args: any[]): number {
|
||||
let startTime = Date.now()
|
||||
let result = this.jdbcTemplate.update(sql, args)
|
||||
console.debug(java.lang.String.format(`\n[DB] update \nSQL : ${sql.replace(/\?/ig, '%s')} \nCOST : ${Date.now() - startTime}ms`, args))
|
||||
console.debug(JavaString.format(`\n[DB] update \nSQL : ${sql.replace(/\?/ig, '%s')} \nCOST : ${Date.now() - startTime}ms`, args))
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行SQL语句
|
||||
* @param sql SQL语句
|
||||
*/
|
||||
execute(sql: string): void {
|
||||
let startTime = Date.now()
|
||||
this.jdbcTemplate.execute(sql)
|
||||
console.debug(`\n[DB] execute \nSQL : ${sql} \nCOST : ${Date.now() - startTime}ms`)
|
||||
}
|
||||
|
||||
close() {
|
||||
//@ts-ignore
|
||||
this.dataSource.close()
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import 'reflect-metadata'
|
||||
|
||||
export function id() {
|
||||
return (target: Object, propertyKey: string | symbol) => void {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,5 +2,11 @@
|
||||
/// <reference types="@javatypes/jdk" />
|
||||
/// <reference types="@javatypes/spring-jdbc" />
|
||||
|
||||
import { loadMavenDepend } from '@ccms/container'
|
||||
|
||||
loadMavenDepend('com.h2database', 'h2', '2.1.212')
|
||||
loadMavenDepend("com.zaxxer", "HikariCP", "4.0.3")
|
||||
loadMavenDepend("org.springframework", "spring-jdbc", "5.3.19", true)
|
||||
|
||||
export * from './database'
|
||||
export * from './manager'
|
||||
export * from './manager'
|
||||
|
||||
@@ -1,27 +1,46 @@
|
||||
import { plugin, database } from '@ccms/api'
|
||||
import { provideSingleton, inject, postConstruct } from '@ccms/container'
|
||||
import { DataBase, DataBaseConfig } from './database'
|
||||
import { database } from '@ccms/api'
|
||||
import { JSClass, provideSingleton } from '@ccms/container'
|
||||
import { DataBase } from './database'
|
||||
|
||||
@provideSingleton(database.DataBaseManager)
|
||||
export class DataBaseManager {
|
||||
@inject(plugin.PluginInstance)
|
||||
private instance: any
|
||||
|
||||
private beanFactory: any
|
||||
export class DataBaseManager extends database.DataBaseManager {
|
||||
private mainDatabase: DataBase
|
||||
private databases: { [key: string]: DataBase } = {}
|
||||
private databases = new Map<string, DataBase>()
|
||||
|
||||
@postConstruct()
|
||||
initialize() {
|
||||
try {
|
||||
this.beanFactory = this.instance.getAutowireCapableBeanFactory()
|
||||
let mainDatasource = this.beanFactory.getBean(Packages.javax.sql.DataSource.class)
|
||||
this.mainDatabase = new DataBase({ url: mainDatasource })
|
||||
} catch (error: any) {
|
||||
console.ex(error)
|
||||
@JSClass('org.h2.tools.Server')
|
||||
private Server: any
|
||||
|
||||
private webManager: any
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
process.on('exit', () => this.shutdown())
|
||||
}
|
||||
|
||||
startWebManager(...args: string[]) {
|
||||
this.webManager = this.Server.createWebServer(args)
|
||||
this.webManager.start()
|
||||
}
|
||||
|
||||
stopWebManager() {
|
||||
if (this.webManager) {
|
||||
this.webManager.stop()
|
||||
this.webManager.shutdown()
|
||||
}
|
||||
}
|
||||
|
||||
shutdown() {
|
||||
this.stopWebManager()
|
||||
this.disable()
|
||||
}
|
||||
/**
|
||||
* 设置主数据库
|
||||
* @param mainDatabase 主数据库
|
||||
*/
|
||||
setMainDatabase(mainDatabase: DataBase) {
|
||||
this.mainDatabase = mainDatabase
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得主数据库
|
||||
* Get MainDatabase
|
||||
@@ -36,18 +55,28 @@ export class DataBaseManager {
|
||||
* @param name 数据库名称 用于代码 database Name use at code
|
||||
* @param config 数据库配置
|
||||
*/
|
||||
createDatabase(name: string, config: DataBaseConfig) {
|
||||
Java.synchronized(() => {
|
||||
if (this.databases[name]) return this.databases[name]
|
||||
return this.databases[name] = new DataBase(config)
|
||||
createDatabase(name: string, config: database.DataBaseConfig) {
|
||||
return Java.synchronized(() => {
|
||||
if (!this.databases.has(name)) {
|
||||
this.databases.set(name, new DataBase(config))
|
||||
}
|
||||
return this.databases.get(name)
|
||||
}, this.databases)()
|
||||
}
|
||||
|
||||
removeDatabase(name: string) {
|
||||
if (this.databases.has(name)) {
|
||||
this.databases.get(name).close()
|
||||
}
|
||||
return this.databases.delete(name)
|
||||
}
|
||||
|
||||
getDatabase(name: string) {
|
||||
return this.databases[name]
|
||||
return this.databases.get(name)
|
||||
}
|
||||
|
||||
disable() {
|
||||
Object.values(this.databases).forEach((ds) => ds?.close())
|
||||
this.databases.forEach((db) => db.close())
|
||||
this.databases.clear()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import { DataBase } from "./database"
|
||||
|
||||
export class Model<T> {
|
||||
constructor(private database: DataBase) {
|
||||
|
||||
}
|
||||
queryForList(): Array<T> {
|
||||
|
||||
return []
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ ms.core.plugin.initialize: "Initialization MiaoScript Plugin System. Please wait
|
||||
ms.core.plugin.completed: "MiaoScript Plugin System loading completed({time}s)!"
|
||||
ms.core.engine.completed: "MiaoScript ScriptEngine loading completed... Done({time}s)!"
|
||||
ms.core.engine.disable: "Disable MiaoScript Engine..."
|
||||
ms.core.engine.disable.finish: "MiaoScript framework {loader} engine {version} 关闭完成... 耗时({time}s)!"
|
||||
ms.core.engine.disable.abnormal: "abnormal Initialization MiaoScript Engine. Skip disable step..."
|
||||
|
||||
ms.api.event.resource.not.found: "Can't Mapping Event Because not found Resources {resource}!"
|
||||
@@ -21,16 +22,20 @@ ms.api.event.not.found: "§6Plugin §b{name} §6register {event} error. event no
|
||||
ms.api.event.execute.slow: "§cWARN! §6Plugin §b{name} §6execute §d{event} §6evnet §ccost §4{cost}ms !"
|
||||
ms.api.event.execute.error: "§6Plugin §b{name} §6execute §d{event} §6event error §4{ex}"
|
||||
ms.api.event.listen.plugin.name.empty: "Plugin name can't be empty!"
|
||||
ms.api.event.register: "[{name}] register event {event}"
|
||||
ms.api.event.register: "[{name}] register event {event} priority {priority} ignoreCancelled {ignore}"
|
||||
ms.api.event.unregister: "[{name}] unregister event {event}"
|
||||
|
||||
ms.api.command.register.input.error: "CommandExec Must be a function... Input: {exec}"
|
||||
ms.api.command.register: "[{plugin}] register command {name}({cmd})..."
|
||||
ms.api.command.unregister: "[{plugin}] unregister command {name}..."
|
||||
ms.api.command.execute.slow: "§cWarn. §6Player §a{player} §6exec §b{plugin} §6Plugin §d{command} {args} §6Command §cCost §4{cost}ms !"
|
||||
ms.api.command.execute.error: "§6Player {player} §6exec §b{plugin} §6Plugin Command §d{command} {args} §6error §4{ex}"
|
||||
ms.api.command.tab.completer.slow: "§cWarn. §6Player §a{player} §6exec §b{plugin} §6Plugin §d{command} {args} §6TabComplete §cCost §4{cost}ms !"
|
||||
ms.api.command.tab.completer.error: "§6Player {player} §6exec §b{plugin} §6Plugin TabComplete §d{command} {args} §6error §4{ex}"
|
||||
|
||||
ms.plugin.initialize: "Initialization MiaoScript Plugin System: Plugin: {plugin} Loader: {loader}..."
|
||||
ms.plugin.event.map: "Total {count} {type} Event Mapping Complate..."
|
||||
ms.plugin.event.map.error: "Mapping {type} Event Failed. Error: {error}"
|
||||
ms.plugin.manager.scan: "Scanner {scanner} Scanning Plugins in {folder} ..."
|
||||
ms.plugin.manager.scan.finish: "Scanner {scanner} Found {size} Plugins in {folder} Start Build..."
|
||||
ms.plugin.manager.initialize.error: "§6Plugin §b{name} §6initialize error §4{ex}"
|
||||
|
||||
@@ -10,9 +10,9 @@ ms.core.package.initialize: "初始化 MiaoScript 扩展 {scope}/core {scope}/{t
|
||||
ms.core.package.completed: "MiaoScript 扩展 {scope}/core {scope}/{type} {scope}/plugin 加载完成 耗时({time}s)"
|
||||
ms.core.plugin.initialize: "MiaoScript 开始引导插件系统. 请稍候..."
|
||||
ms.core.plugin.completed: "MiaoScript 插件加载完毕 耗时({time}s)!"
|
||||
ms.core.engine.completed: "MiaoScript 脚本引擎 {version} 加载完毕... 耗时({time}s)!"
|
||||
ms.core.engine.completed: "MiaoScript 框架 {loader} 引擎 {version} 加载完毕... 耗时({time}s)!"
|
||||
ms.core.engine.disable: "MiaoScript 关闭脚本引擎 请稍候..."
|
||||
ms.core.engine.disable.finish: "MiaoScript 脚本引擎 {version} 关闭完成... 耗时({time}s)!"
|
||||
ms.core.engine.disable.finish: "MiaoScript 框架 {loader} 引擎 {version} 关闭完成... 耗时({time}s)!"
|
||||
ms.core.engine.disable.abnormal: "引擎异常启动或初始化未完成 跳过关闭流程..."
|
||||
|
||||
ms.api.event.resource.not.found: "无法映射事件 未找到资源文件 {resource}!"
|
||||
@@ -22,18 +22,22 @@ ms.api.event.not.found: "§6插件 §b{name} §6注册事件 §c{event} §6失
|
||||
ms.api.event.execute.slow: "§c注意! §6插件 §b{name} §6处理 §d{event} §6事件 §c耗时 §4{cost}ms !"
|
||||
ms.api.event.execute.error: "§6插件 §b{name} §6处理 §d{event} §6事件时发生异常 §4{ex}"
|
||||
ms.api.event.listen.plugin.name.empty: "插件名称为空 请检查传入参数!"
|
||||
ms.api.event.register: "[{name}] 注册事件 {event} => 执行器 {exec}"
|
||||
ms.api.event.register: "[{name}] 注册事件 {event} => 执行器 {exec} 优先级 {priority} 忽略取消 {ignore}"
|
||||
ms.api.event.unregister: "[{name}] 注销事件 {event} => 执行器 {exec}"
|
||||
|
||||
ms.api.command.register.input.error: "CommandExec 必须为一个函数... 输入: {exec}"
|
||||
ms.api.command.register: "[{plugin}] 注册命令 {name}({cmd})..."
|
||||
ms.api.command.unregister: "[{plugin}] 注销命令 {name}..."
|
||||
ms.api.command.execute.slow: "§c注意! §6玩家 §a{player} §6执行 §b{plugin} §6插件 §d{command} {args} §6命令 §c耗时 §4{cost}ms !"
|
||||
ms.api.command.execute.error: "§6玩家 §a{player} §6执行 §b{plugin} §6插件 §d{command} {args} §6命令时发生异常 §4{ex}"
|
||||
ms.api.command.tab.completer.slow: "§c注意! §6玩家 §a{player} §6执行 §b{plugin} §6插件 §d{command} {args} §6补全 §c耗时 §4{cost}ms !"
|
||||
ms.api.command.tab.completer.error: "§6玩家 §a{player} §6执行 §b{plugin} §6插件 §d{command} {args} §6补全时发生异常 §4{ex}"
|
||||
|
||||
ms.plugin.initialize: "初始化 MiaoScript 插件系统: 实例: {plugin} 加载器: {loader}..."
|
||||
ms.plugin.event.map: "总计 {count} 个 {type} 事件 映射完成..."
|
||||
ms.plugin.event.map: "映射 {type} 事件 成功 总计 {count} 个 {type} 事件..."
|
||||
ms.plugin.event.map.error: "映射 {type} 事件 异常 将无法使用事件简称. Error: {error}"
|
||||
ms.plugin.manager.scan: "扫描器 {scanner} 扫描 {folder} 中的插件..."
|
||||
ms.plugin.manager.scan.finish: "扫描器 {scanner} 在 {folder} 中 发现 {size} 个插件 开始构建..."
|
||||
ms.plugin.manager.scan.finish: "扫描器 {scanner} 在 {folder} 中 发现 {size} 个插件 开始编译..."
|
||||
ms.plugin.manager.initialize.error: "§6插件 §b{name} §6初始化错误 §4{ex}"
|
||||
ms.plugin.manager.stage: "{stage} {plugin} 版本 {version} 作者 {author}"
|
||||
ms.plugin.manager.stage.exec: "[{plugin}] 执行 {stage} 阶段函数 {name} 匹配类型 {servers}..."
|
||||
@@ -41,7 +45,7 @@ ms.plugin.manager.stage.exec.error: "§6插件 §b{plugin} §6执行 §d{executo
|
||||
ms.plugin.manager.stage.load: "加载"
|
||||
ms.plugin.manager.stage.enable: "启用"
|
||||
ms.plugin.manager.stage.disable: "关闭"
|
||||
ms.plugin.manager.build: "插件 {name}({version}) 构建完成 来源: {file}({scanner}) 引导: {loader} 构建耗时: {cost}s."
|
||||
ms.plugin.manager.build: "插件 {name}({version}) 编译完成 来源: {file}({scanner}) 引导: {loader} 编译耗时: {cost}s."
|
||||
ms.plugin.manager.build.error: "§6从文件 §b{file} §6加载插件失败 §4错误: §c{error}"
|
||||
ms.plugin.manager.build.update: "自动更新插件 {name} ..."
|
||||
ms.plugin.manager.build.not.extends: "§4发现错误的插件 §b{source} §4未继承接口 interfaces.Plugin, 将不会被载入到服务器!"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ccms/i18n",
|
||||
"version": "0.18.0",
|
||||
"version": "0.28.0-beta.2",
|
||||
"description": "MiaoScript i18n package",
|
||||
"keywords": [
|
||||
"miaoscript",
|
||||
@@ -19,11 +19,11 @@
|
||||
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ccms/nashorn": "^0.18.0",
|
||||
"@ccms/nashorn": "^0.28.0-beta.2",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.5.5"
|
||||
"rimraf": "^4.1.2",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"js-yaml": "^4.1.0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ccms/keyvalue",
|
||||
"version": "0.18.0",
|
||||
"version": "0.28.0-beta.2",
|
||||
"description": "MiaoScript keyvalue package",
|
||||
"keywords": [
|
||||
"miaoscript",
|
||||
@@ -19,18 +19,18 @@
|
||||
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ccms/api": "^0.18.0",
|
||||
"@ccms/common": "^0.18.0",
|
||||
"@ccms/container": "^0.18.0"
|
||||
"@ccms/api": "^0.28.0-beta.2",
|
||||
"@ccms/common": "^0.28.0-beta.2",
|
||||
"@ccms/container": "^0.28.0-beta.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ccms/nashorn": "^0.18.0",
|
||||
"@ccms/nashorn": "^0.28.0-beta.2",
|
||||
"@javatypes/amqp-client": "^0.0.3",
|
||||
"@javatypes/spring-amqp": "^0.0.3",
|
||||
"@javatypes/spring-rabbit": "^0.0.3",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.5.5"
|
||||
"rimraf": "^4.1.2",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"gitHead": "2589633069d24f646ac09261b1b2304c21d4ea75"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ccms/molang",
|
||||
"version": "0.18.0",
|
||||
"version": "0.28.0-beta.2",
|
||||
"description": "A fast parser for Minecraft's MoLang",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
@@ -21,9 +21,9 @@
|
||||
},
|
||||
"homepage": "https://github.com/solvedDev/MoLang#readme",
|
||||
"devDependencies": {
|
||||
"@types/node": "^17.0.17",
|
||||
"rimraf": "^3.0.2",
|
||||
"tslib": "^2.3.1",
|
||||
"typescript": "^4.5.5"
|
||||
"@types/node": "^18.13.0",
|
||||
"rimraf": "^4.1.2",
|
||||
"tslib": "^2.5.0",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@ccms/nashorn",
|
||||
"version": "0.18.0",
|
||||
"description": "MiaoScript api package",
|
||||
"version": "0.28.0-beta.2",
|
||||
"description": "MiaoScript nashorn package",
|
||||
"keywords": [
|
||||
"miaoscript",
|
||||
"minecraft",
|
||||
@@ -21,7 +21,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.5.5"
|
||||
"rimraf": "^4.1.2",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,34 @@ declare global {
|
||||
scope: string
|
||||
logger: any
|
||||
debug: boolean
|
||||
level: string
|
||||
/**
|
||||
* 引擎日志等级
|
||||
*/
|
||||
ScriptEngineLoggerLevel: string
|
||||
/**
|
||||
* 引擎配置
|
||||
*/
|
||||
ScriptEngineConfig: any
|
||||
/**
|
||||
* 引擎版本
|
||||
*/
|
||||
ScriptEngineVersion: string
|
||||
/**
|
||||
* 引擎渠道
|
||||
*/
|
||||
ScriptEngineChannel: string
|
||||
/**
|
||||
* 慢执行检测时间
|
||||
*/
|
||||
ScriptSlowExecuteTime: number
|
||||
ScriptEngineStartTime: number
|
||||
/**
|
||||
* 设置全局对象
|
||||
* @param key 对象名称
|
||||
* @param value 对象值
|
||||
* @param config 对象属性
|
||||
* @returns
|
||||
*/
|
||||
setGlobal: (key: string, value: any, config?: PropertyDescriptor & ThisType<any>) => void
|
||||
noop: () => void
|
||||
console: Console
|
||||
@@ -65,10 +90,12 @@ declare global {
|
||||
const ScriptEngineContextHolder: any
|
||||
function engineLoad(str: string | { script: string, name: string }): any
|
||||
interface Core {
|
||||
version: string
|
||||
getClass(name: String): any
|
||||
getProxyClass(): any
|
||||
getJavaScriptTaskClass(): any
|
||||
getInstance(): any
|
||||
loadMavenDepend(groupId: string, artifactId: string, version: string): [any, any]
|
||||
read(path: string): string
|
||||
save(path: string, content: string): void
|
||||
delete(path: string): void
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ccms/nodejs",
|
||||
"version": "0.18.0",
|
||||
"version": "0.28.0-beta.2",
|
||||
"description": "MiaoScript nodejs package",
|
||||
"keywords": [
|
||||
"miaoscript",
|
||||
@@ -19,11 +19,11 @@
|
||||
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ccms/nashorn": "^0.18.0",
|
||||
"@ccms/nashorn": "^0.28.0-beta.2",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"tslib": "^2.3.1",
|
||||
"typescript": "^4.5.5"
|
||||
"rimraf": "^4.1.2",
|
||||
"tslib": "^2.5.0",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"gitHead": "781524f83e52cad26d7c480513e3c525df867121"
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
'use strict';
|
||||
var Throwable = Java.type('java.lang.Throwable')
|
||||
var R = typeof Reflect === 'object' ? Reflect : null
|
||||
var ReflectApply = R && typeof R.apply === 'function'
|
||||
? R.apply
|
||||
@@ -136,13 +137,19 @@ EventEmitter.prototype.emit = function emit(type) {
|
||||
var er;
|
||||
if (args.length > 0)
|
||||
er = args[0];
|
||||
if (er instanceof Error) {
|
||||
if (er instanceof Error || er instanceof Throwable) {
|
||||
// Note: The comments on the `throw` lines are intentional, they show
|
||||
// up in Node's output if this results in an unhandled exception.
|
||||
throw er; // Unhandled 'error' event
|
||||
}
|
||||
if (er.error instanceof Error || er.error instanceof Throwable) {
|
||||
throw er.error; // Unhandled 'error' event
|
||||
}
|
||||
if (er.cause instanceof Error || er.error instanceof Throwable) {
|
||||
throw er.error; // Unhandled 'error' event
|
||||
}
|
||||
// At least give some kind of context to the user
|
||||
var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));
|
||||
var err = new Error('Unhandled error.' + (er ? ' (' + (er.message || er.error || er.cause || er) + ')' : ''));
|
||||
// @ts-ignore
|
||||
err.context = er;
|
||||
throw err; // Unhandled 'error' event
|
||||
|
||||
@@ -5,6 +5,7 @@ const Path = Java.type("java.nio.file.Path");
|
||||
const JavaString = Java.type("java.lang.String");
|
||||
const File = Java.type("java.io.File");
|
||||
const Files = Java.type("java.nio.file.Files");
|
||||
const Paths = Java.type("java.nio.file.Paths");
|
||||
const Collector = Java.type("java.util.stream.Collector")
|
||||
const separatorChar = File.separatorChar;
|
||||
const StandardCopyOption = Java.type("java.nio.file.StandardCopyOption");
|
||||
@@ -37,7 +38,7 @@ function javaFile(...opts: any[]) {
|
||||
}
|
||||
|
||||
export function renameSync(oldPath: PathLike, newPath: PathLike): void {
|
||||
|
||||
Files.move(Paths.get(oldPath), Paths.get(oldPath), StandardCopyOption['ATOMIC_MOVE'])
|
||||
}
|
||||
export function truncateSync() {
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ccms/nukkit",
|
||||
"version": "0.18.0",
|
||||
"version": "0.28.0-beta.2",
|
||||
"description": "MiaoScript nukkit package",
|
||||
"keywords": [
|
||||
"miaoscript",
|
||||
@@ -21,12 +21,12 @@
|
||||
"devDependencies": {
|
||||
"@javatypes/nukkit-api": "^0.0.3",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.5.5"
|
||||
"rimraf": "^4.1.2",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ccms/api": "^0.18.0",
|
||||
"@ccms/common": "^0.18.0",
|
||||
"@ccms/container": "^0.18.0"
|
||||
"@ccms/api": "^0.28.0-beta.2",
|
||||
"@ccms/common": "^0.28.0-beta.2",
|
||||
"@ccms/container": "^0.28.0-beta.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@ccms/plugin",
|
||||
"version": "0.18.0",
|
||||
"description": "MiaoScript api package",
|
||||
"version": "0.28.0-beta.2",
|
||||
"description": "MiaoScript plugin package",
|
||||
"keywords": [
|
||||
"miaoscript",
|
||||
"minecraft",
|
||||
@@ -19,17 +19,19 @@
|
||||
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/crypto-js": "^4.1.1",
|
||||
"@types/js-yaml": "^4.0.5",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.5.5"
|
||||
"rimraf": "^4.1.2",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ccms/api": "^0.18.0",
|
||||
"@ccms/common": "^0.18.0",
|
||||
"@ccms/container": "^0.18.0",
|
||||
"@ccms/i18n": "^0.18.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"yaml": "^1.10.2"
|
||||
"@ccms/api": "^0.28.0-beta.2",
|
||||
"@ccms/common": "^0.28.0-beta.2",
|
||||
"@ccms/container": "^0.28.0-beta.2",
|
||||
"@ccms/i18n": "^0.28.0-beta.2",
|
||||
"@ccms/verify": "^0.25.1",
|
||||
"crypto-js": "^4.1.1",
|
||||
"js-yaml": "^4.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,52 +15,90 @@ export class PluginCommandManager {
|
||||
process.on('plugin.after.disable', this.unregistryCommand.bind(this))
|
||||
}
|
||||
|
||||
private registryCommand(pluginInstance: plugin.Plugin) {
|
||||
let cmds = getPluginCommandMetadata(pluginInstance)
|
||||
let tabs = getPluginTabCompleterMetadata(pluginInstance)
|
||||
public registryCommand(pluginInstance: plugin.Plugin, executor: any = pluginInstance) {
|
||||
let cmds = getPluginCommandMetadata(executor)
|
||||
let tabs = getPluginTabCompleterMetadata(executor)
|
||||
for (const cmd of cmds) {
|
||||
if (!this.ServerChecker.check(cmd.servers)) {
|
||||
console.debug(`[${pluginInstance.description.name}] ${cmd.target.constructor.name} incompatible command ${cmd.name} server(${cmd.servers}) ignore.`)
|
||||
continue
|
||||
}
|
||||
for (let command of [cmd.name, ...cmd.alias]) {
|
||||
let [cmdExecutor, cmdCompleter] = this.generateAutoMainCommand(pluginInstance, cmd, tabs.get(command))
|
||||
let [cmdExecutor, cmdCompleter] = this.generateAutoMainCommand(pluginInstance, executor, cmd, tabs.get(command))
|
||||
this.CommandManager.on(pluginInstance, command, {
|
||||
cmd: cmdExecutor.bind(pluginInstance),
|
||||
tab: cmdCompleter?.bind(pluginInstance)
|
||||
cmd: cmdExecutor.bind(executor),
|
||||
tab: cmdCompleter?.bind(executor)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private unregistryCommand(pluginInstance: plugin.Plugin) {
|
||||
let cmds = getPluginCommandMetadata(pluginInstance)
|
||||
cmds.forEach(cmd => this.CommandManager.off(pluginInstance, cmd.name))
|
||||
public unregistryCommand(pluginInstance: plugin.Plugin, executor: any = pluginInstance) {
|
||||
let cmds = getPluginCommandMetadata(executor)
|
||||
for (const cmd of cmds) {
|
||||
if (!this.ServerChecker.check(cmd.servers)) {
|
||||
console.debug(`[${pluginInstance.description.name}] ${cmd.target.constructor.name} incompatible command ${cmd.name} server(${cmd.servers}) ignore.`)
|
||||
continue
|
||||
}
|
||||
for (let command of [cmd.name, ...cmd.alias]) {
|
||||
this.CommandManager.off(executor, command)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private generateAutoMainCommand(pluginInstance: plugin.Plugin, cmd: interfaces.CommandMetadata, tab: interfaces.CommandMetadata) {
|
||||
let cmdExecutor = pluginInstance[cmd.executor]
|
||||
let cmdCompleter = tab ? pluginInstance[tab.executor] : undefined
|
||||
let cmdSubCache = Object.keys(pluginInstance.constructor.prototype).filter(s => s.startsWith('cmd')).map(s => s.substring(3))
|
||||
private generateAutoMainCommand(pluginInstance: plugin.Plugin, executor: any, cmd: interfaces.CommandMetadata, tab: interfaces.CommandMetadata) {
|
||||
let cmdExecutor = executor[cmd.executor]
|
||||
let cmdCompleter = tab ? executor[tab.executor] : undefined
|
||||
let cmdSubCache = Object.keys(executor.constructor.prototype).filter(s => s.startsWith('cmd')).map(s => s.substring(3))
|
||||
if (cmd.autoMain) {
|
||||
cmdExecutor = (sender: any, command: string, args: string[]) => {
|
||||
let subcommand = args[0]
|
||||
let cmdKey = 'cmd' + subcommand
|
||||
if (pluginInstance[cmdKey]) {
|
||||
args.shift()
|
||||
return pluginInstance[cmdKey].apply(pluginInstance, [sender, ...args])
|
||||
} else if (pluginInstance['cmdmain']) {
|
||||
return pluginInstance['cmdmain'].apply(pluginInstance, [sender, ...args])
|
||||
if (!cmdSubCache.includes(subcommand)) {
|
||||
if (!executor[cmd.executor].apply(executor, [sender, command, args])) {
|
||||
subcommand && pluginInstance.logger.sender(sender, `§4未知的命令: §b/${command} §c${subcommand}`)
|
||||
pluginInstance.logger.sender(
|
||||
sender,
|
||||
executor['cmdhelp'] ?
|
||||
`§6请执行 §b/${command} §ahelp §6查看帮助!` :
|
||||
[
|
||||
`§6插件: §b${pluginInstance.description.name}`,
|
||||
`§6版本: §a${pluginInstance.description.version}`
|
||||
]
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
pluginInstance.logger.sender(sender, '§4未知的子命令: §c' + subcommand)
|
||||
pluginInstance['cmdhelp'] && pluginInstance.logger.sender(sender, `§6请执行 §b/${command} §ahelp §6查看帮助!`)
|
||||
let subcommandexec = executor[cmdKey]
|
||||
let permission: string
|
||||
if (cmd.permission && sender.hasPermission) {
|
||||
if (typeof cmd.permission == "string") {
|
||||
permission = cmd.permission as string
|
||||
} else {
|
||||
permission = `${pluginInstance.description.name.toLocaleLowerCase()}.${command}.${subcommand || 'main'}`
|
||||
}
|
||||
if (!sender.hasPermission(permission)) {
|
||||
return pluginInstance.logger.sender(sender, `§c你需要 §4${permission} §c权限 才可执行此命令.`)
|
||||
}
|
||||
}
|
||||
args.shift()
|
||||
return subcommandexec.apply(executor, [sender, ...args])
|
||||
}
|
||||
let originCompleter = cmdCompleter
|
||||
cmdCompleter = (sender: any, command: string, args: string[]) => {
|
||||
return (args.length == 1 ? cmdSubCache : []).concat(originCompleter?.apply(pluginInstance, [sender, command, args]) || [])
|
||||
let permission: string
|
||||
if (cmd.permission && sender.hasPermission) {
|
||||
if (typeof cmd.permission == "string") {
|
||||
permission = cmd.permission as string
|
||||
} else {
|
||||
permission = `${pluginInstance.description.name.toLocaleLowerCase()}.${command}`
|
||||
}
|
||||
if (!sender.hasPermission(permission)) { return [] }
|
||||
}
|
||||
return (args.length == 1 ? cmdSubCache : []).concat(originCompleter?.apply(executor, [sender, command, args]) || [])
|
||||
}
|
||||
}
|
||||
if (!cmdCompleter) { console.warn(`[${pluginInstance.description.name}] command ${cmd.name} is not registry tabCompleter`) }
|
||||
if (!cmdCompleter) { console.debug(`[${pluginInstance.description.name}] command ${cmd.name} is not registry tabCompleter`) }
|
||||
return [cmdExecutor, cmdCompleter]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,59 +1,35 @@
|
||||
import * as yaml from 'js-yaml'
|
||||
import * as fs from '@ccms/common/dist/fs'
|
||||
import { plugin } from '@ccms/api'
|
||||
import { provideSingleton } from '@ccms/container'
|
||||
import { Autowired, Container, ContainerInstance, postConstruct, provideSingleton } from '@ccms/container'
|
||||
|
||||
import * as fs from '@ccms/common/dist/fs'
|
||||
|
||||
import { interfaces } from './interfaces'
|
||||
import { getPluginConfigMetadata } from './utils'
|
||||
|
||||
export interface PluginConfigLoader {
|
||||
load(content: string): any
|
||||
dump(variable: any): string
|
||||
}
|
||||
|
||||
export class YamlPluginConfig implements PluginConfigLoader {
|
||||
load(content: string) {
|
||||
return yaml.load(content)
|
||||
}
|
||||
dump(variable: any): string {
|
||||
return yaml.dump(variable, { skipInvalid: true, lineWidth: 120 })
|
||||
}
|
||||
}
|
||||
|
||||
export class JsonPluginConfig implements PluginConfigLoader {
|
||||
load(content: string) {
|
||||
return JSON.parse(content)
|
||||
}
|
||||
dump(variable: any): string {
|
||||
return JSON.stringify(variable, undefined, 4)
|
||||
}
|
||||
}
|
||||
|
||||
export interface PluginConfig {
|
||||
/**
|
||||
* Save Config to File
|
||||
*/
|
||||
readonly save?: () => void
|
||||
/**
|
||||
* Reload Config from File
|
||||
*/
|
||||
readonly reload?: () => void
|
||||
[key: string]: any
|
||||
}
|
||||
import { PluginConfigLoader } from './config/interfaces'
|
||||
import './config/loader'
|
||||
|
||||
@provideSingleton(PluginConfigManager)
|
||||
export class PluginConfigManager {
|
||||
@Autowired(ContainerInstance)
|
||||
private container: Container
|
||||
|
||||
private configLoaderMap = new Map<string, PluginConfigLoader>()
|
||||
|
||||
constructor() {
|
||||
this.configLoaderMap.set("json", new JsonPluginConfig())
|
||||
let yaml = new YamlPluginConfig()
|
||||
this.configLoaderMap.set("yml", yaml)
|
||||
this.configLoaderMap.set("yaml", yaml)
|
||||
process.on('plugin.before.load', this.loadConfig.bind(this))
|
||||
process.on('plugin.after.disable', this.saveConfig.bind(this))
|
||||
}
|
||||
|
||||
@postConstruct()
|
||||
initialize() {
|
||||
let configLoader = this.container.getAll<PluginConfigLoader>(PluginConfigLoader)
|
||||
configLoader.forEach((scanner) => {
|
||||
console.debug(`loading config loader ${scanner.type}...`)
|
||||
this.configLoaderMap.set(scanner.type, scanner)
|
||||
})
|
||||
}
|
||||
|
||||
getConfigLoader(format: string) {
|
||||
if (!this.configLoaderMap.has(format)) { throw new Error(`Unsupport config format ${format} !`) }
|
||||
return this.configLoaderMap.get(format)
|
||||
@@ -73,50 +49,65 @@ export class PluginConfigManager {
|
||||
}
|
||||
}
|
||||
|
||||
private defienConfigProp(plugin: plugin.Plugin, metadata: interfaces.ConfigMetadata, value: any) {
|
||||
createConfig(plugin: plugin.Plugin, metadata: interfaces.ConfigMetadata, value: any) {
|
||||
Object.defineProperties(value, {
|
||||
'save': { value: () => this.saveConfig0(plugin, metadata) },
|
||||
'reload': { value: () => this.loadConfig0(plugin, metadata) }
|
||||
})
|
||||
Object.defineProperty(plugin, metadata.variable, { value })
|
||||
return value
|
||||
}
|
||||
|
||||
private defienConfigProp(plugin: plugin.Plugin, metadata: interfaces.ConfigMetadata, value: any) {
|
||||
Object.defineProperty(plugin, metadata.variable, {
|
||||
value: this.createConfig(plugin, metadata, value),
|
||||
configurable: true
|
||||
})
|
||||
}
|
||||
|
||||
private loadConfig0(plugin: plugin.Plugin, metadata: interfaces.ConfigMetadata) {
|
||||
try {
|
||||
let defaultValue = metadata.default ?? plugin[metadata.variable]
|
||||
let configValue = defaultValue || {}
|
||||
if (defaultValue) {
|
||||
metadata.file = fs.concat(fs.file(plugin.description.loadMetadata.file).parent, plugin.description.name, metadata.filename)
|
||||
let configLoader = this.getConfigLoader(metadata.format)
|
||||
if (!fs.exists(metadata.file)) {
|
||||
base.save(metadata.file, configLoader.dump(defaultValue))
|
||||
console.i18n("ms.plugin.manager.config.save.default", { plugin: plugin.description.name, name: metadata.name, format: metadata.format })
|
||||
} else {
|
||||
configValue = configLoader.load(base.read(metadata.file)) || {}
|
||||
if (defaultValue && this.setDefaultValue(configValue, defaultValue)) {
|
||||
base.save(metadata.file, configLoader.dump(configValue))
|
||||
}
|
||||
console.debug(`[${plugin.description.name}] Load Config ${metadata.variable} from file ${metadata.file} =>\n${JSON.stringify(configValue, undefined, 4).substr(0, 500)}`)
|
||||
}
|
||||
metadata.file = fs.concat(
|
||||
fs.file(plugin.description.loadMetadata.file).parent,
|
||||
plugin.description.name,
|
||||
metadata.filename
|
||||
)
|
||||
let configLoader = this.getConfigLoader(metadata.format)
|
||||
if (!fs.exists(metadata.file) && defaultValue) {
|
||||
base.save(metadata.file, configLoader.dump(defaultValue))
|
||||
console.i18n("ms.plugin.manager.config.save.default", {
|
||||
plugin: plugin.description.name,
|
||||
name: metadata.name,
|
||||
format: metadata.format
|
||||
})
|
||||
}
|
||||
let configValue = configLoader.load(base.read(metadata.file)) || {}
|
||||
if (metadata.migrate && defaultValue && this.setDefaultValue(configValue, defaultValue, !!metadata.default)) {
|
||||
base.save(metadata.file, configLoader.dump(configValue))
|
||||
}
|
||||
console.debug(`[${plugin.description.name}] Load Config ${metadata.variable} from file ${metadata.file}`)
|
||||
this.defienConfigProp(plugin, metadata, configValue)
|
||||
} catch (error: any) {
|
||||
console.i18n("ms.plugin.manager.config.load.error", { plugin: plugin.description.name, name: metadata.name, format: metadata.format, error })
|
||||
console.i18n("ms.plugin.manager.config.load.error", {
|
||||
plugin: plugin.description.name,
|
||||
name: metadata.name,
|
||||
format: metadata.format,
|
||||
error
|
||||
})
|
||||
console.ex(error)
|
||||
}
|
||||
}
|
||||
|
||||
private setDefaultValue(configValue, defaultValue) {
|
||||
private setDefaultValue(configValue, defaultValue, deepCopy) {
|
||||
let needSave = false
|
||||
for (const key of Object.keys(defaultValue)) {
|
||||
// 当配置文件不存在当前属性时才进行赋值
|
||||
if (!Object.prototype.hasOwnProperty.call(configValue, key) && key != '____deep_copy____') {
|
||||
if (!Object.prototype.hasOwnProperty.call(configValue, key)) {
|
||||
configValue[key] = defaultValue[key]
|
||||
needSave = true
|
||||
} else if (Object.prototype.toString.call(configValue[key]) == "[object Object]"
|
||||
&& Object.prototype.hasOwnProperty.call(defaultValue[key], '____deep_copy____')) {
|
||||
// 对象需要递归检测 如果对象内存在 ____deep_copy____ 那就忽略设置
|
||||
needSave ||= this.setDefaultValue(configValue[key], defaultValue[key])
|
||||
} else if (Object.prototype.toString.call(configValue[key]) == "[object Object]" && deepCopy) {
|
||||
// 对象需要递归检测
|
||||
needSave ||= this.setDefaultValue(configValue[key], defaultValue[key], deepCopy)
|
||||
}
|
||||
}
|
||||
return needSave
|
||||
@@ -127,10 +118,16 @@ export class PluginConfigManager {
|
||||
metadata.file = fs.concat(fs.file(plugin.description.loadMetadata.file).parent, plugin.description.name, metadata.filename)
|
||||
let result = this.getConfigLoader(metadata.format).dump(plugin[metadata.variable])
|
||||
base.save(metadata.file, result)
|
||||
console.debug(`[${plugin.description.name}] Save Config ${metadata.variable} to file ${metadata.file} =>\n${result.substr(0, 500)}`)
|
||||
console.debug(`[${plugin.description.name}] Save Config ${metadata.variable} to file ${metadata.file} =>
|
||||
${result.substring(0, 500)}`)
|
||||
return true
|
||||
} catch (error: any) {
|
||||
console.i18n("ms.plugin.manager.config.save.error", { plugin: plugin.description.name, name: metadata.name, format: metadata.format, error })
|
||||
console.i18n("ms.plugin.manager.config.save.error", {
|
||||
plugin: plugin.description.name,
|
||||
name: metadata.name,
|
||||
format: metadata.format,
|
||||
error
|
||||
})
|
||||
console.ex(error)
|
||||
return false
|
||||
}
|
||||
|
||||
3
packages/plugin/src/config/config.ts
Normal file
3
packages/plugin/src/config/config.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from "./loader"
|
||||
export * from "./interfaces"
|
||||
export * from "./file-config"
|
||||
65
packages/plugin/src/config/file-config.ts
Normal file
65
packages/plugin/src/config/file-config.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import * as fs from '@ccms/common/dist/fs'
|
||||
|
||||
import { PluginConfig, PluginConfigLoader } from './interfaces'
|
||||
|
||||
export class PluginFileConfig implements PluginConfig {
|
||||
private loader: PluginConfigLoader
|
||||
private file: string
|
||||
constructor(loader: PluginConfigLoader, file: string, def = {}) {
|
||||
this.loader = loader
|
||||
this.file = file
|
||||
if (fs.exists(file)) {
|
||||
this.reload()
|
||||
} else {
|
||||
Object.assign(this, def)
|
||||
}
|
||||
this.initialize()
|
||||
}
|
||||
|
||||
initialize() {
|
||||
}
|
||||
|
||||
save() {
|
||||
base.save(this.file, this.loader.dump(this))
|
||||
}
|
||||
|
||||
reload() {
|
||||
Object.assign(this, this.loader.load(base.read(this.file)))
|
||||
}
|
||||
}
|
||||
|
||||
export class PluginConfigFolder {
|
||||
private loader: PluginConfigLoader
|
||||
private folder: string
|
||||
|
||||
private configCache = new Map<string, PluginFileConfig>()
|
||||
|
||||
constructor(loader: PluginConfigLoader, folder: string) {
|
||||
this.loader = loader
|
||||
this.folder = folder
|
||||
}
|
||||
|
||||
createConfig(path: string, def = {}) {
|
||||
return new PluginFileConfig(this.loader, path, def)
|
||||
}
|
||||
|
||||
getConfig(name: string, def = {}) {
|
||||
let path = fs.concat(this.folder, name)
|
||||
if (!this.configCache.has(path)) {
|
||||
this.configCache.set(path, this.createConfig(path, def))
|
||||
}
|
||||
return this.configCache.get(path)
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.configCache.clear()
|
||||
}
|
||||
|
||||
save() {
|
||||
this.configCache.forEach((config) => config.save())
|
||||
}
|
||||
|
||||
reload() {
|
||||
this.configCache.forEach((config) => config.reload())
|
||||
}
|
||||
}
|
||||
18
packages/plugin/src/config/interfaces.ts
Normal file
18
packages/plugin/src/config/interfaces.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
export const PluginConfigLoader = Symbol.for('PluginConfigLoader')
|
||||
export interface PluginConfigLoader {
|
||||
type: string
|
||||
load(content: string): any
|
||||
dump(variable: any): string
|
||||
}
|
||||
|
||||
export interface PluginConfig {
|
||||
/**
|
||||
* Save Config to File
|
||||
*/
|
||||
readonly save?: () => void
|
||||
/**
|
||||
* Reload Config from File
|
||||
*/
|
||||
readonly reload?: () => void
|
||||
[key: string]: any
|
||||
}
|
||||
2
packages/plugin/src/config/loader/index.ts
Normal file
2
packages/plugin/src/config/loader/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './json-loader'
|
||||
export * from './yaml-loader'
|
||||
18
packages/plugin/src/config/loader/json-loader.ts
Normal file
18
packages/plugin/src/config/loader/json-loader.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { provideSingletonNamed } from '@ccms/container'
|
||||
|
||||
import { PluginConfigLoader } from '../interfaces'
|
||||
|
||||
const LOADER_TYPE_NAME = 'json'
|
||||
|
||||
@provideSingletonNamed(PluginConfigLoader, LOADER_TYPE_NAME)
|
||||
export class JsonPluginConfig implements PluginConfigLoader {
|
||||
type: string = LOADER_TYPE_NAME
|
||||
|
||||
load(content: string) {
|
||||
return JSON.parse(content)
|
||||
}
|
||||
|
||||
dump(variable: any): string {
|
||||
return JSON.stringify(variable, undefined, 4)
|
||||
}
|
||||
}
|
||||
19
packages/plugin/src/config/loader/yaml-loader.ts
Normal file
19
packages/plugin/src/config/loader/yaml-loader.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import * as yaml from 'js-yaml'
|
||||
import { provideSingletonNamed } from '@ccms/container'
|
||||
|
||||
import { PluginConfigLoader } from '../interfaces'
|
||||
|
||||
const LOADER_TYPE_NAME = 'yml'
|
||||
|
||||
@provideSingletonNamed(PluginConfigLoader, LOADER_TYPE_NAME)
|
||||
export class YamlPluginConfig implements PluginConfigLoader {
|
||||
type: string = LOADER_TYPE_NAME
|
||||
|
||||
load(content: string) {
|
||||
return yaml.load(content)
|
||||
}
|
||||
|
||||
dump(variable: any): string {
|
||||
return yaml.dump(variable, { skipInvalid: true, lineWidth: 120 })
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ export const METADATA_KEY = {
|
||||
tab: Symbol.for("@ccms/plugin:tab"),
|
||||
listener: Symbol.for("@ccms/plugin:listener"),
|
||||
config: Symbol.for("@ccms/plugin:config"),
|
||||
playerdata: Symbol.for("@ccms/plugin:playerdata"),
|
||||
stage: {
|
||||
load: Symbol.for("@ccms/plugin:stage:load"),
|
||||
enable: Symbol.for("@ccms/plugin:stage:enable"),
|
||||
|
||||
@@ -2,7 +2,7 @@ import { plugin as pluginApi } from "@ccms/api"
|
||||
import { injectable, decorate } from "@ccms/container"
|
||||
import { interfaces } from './interfaces'
|
||||
import { METADATA_KEY } from './constants'
|
||||
import { getPluginMetadatas, getPluginCommandMetadata, getPluginListenerMetadata, getPluginTabCompleterMetadata, getPluginConfigMetadata, getPluginStageMetadata, getPluginSources } from './utils'
|
||||
import { getPluginMetadatas, getPluginCommandMetadata, getPluginListenerMetadata, getPluginTabCompleterMetadata, getPluginConfigMetadata, getPluginStageMetadata, getPluginSources, getPluginPlayerDataMetadata } from './utils'
|
||||
|
||||
/**
|
||||
* MiaoScript plugin
|
||||
@@ -76,6 +76,7 @@ export function config(metadata: interfaces.ConfigMetadata = {}) {
|
||||
metadata.variable = key
|
||||
metadata.version = metadata.version ?? 1
|
||||
metadata.format = metadata.format ?? 'yml'
|
||||
metadata.migrate = metadata.migrate ?? true
|
||||
metadata.autosave = metadata.autosave ?? false
|
||||
metadata.filename = metadata.filename ?? metadata.name + '.' + metadata.format
|
||||
let previousMetadata = getPluginConfigMetadata(target)
|
||||
@@ -84,6 +85,21 @@ export function config(metadata: interfaces.ConfigMetadata = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
export function playerdata(metadata: interfaces.PlayerDataMetadata = {}) {
|
||||
return function (target: any, key: string) {
|
||||
metadata.name = metadata.name || key
|
||||
metadata.variable = key
|
||||
metadata.version = metadata.version ?? 1
|
||||
metadata.format = metadata.format ?? 'yml'
|
||||
metadata.autosave = metadata.autosave ?? false
|
||||
metadata.filename = metadata.filename ?? "username"
|
||||
metadata.dir = metadata.dir ?? "playerdata"
|
||||
let previousMetadata = getPluginPlayerDataMetadata(target)
|
||||
previousMetadata.set(metadata.name, metadata)
|
||||
Reflect.defineMetadata(METADATA_KEY.playerdata, previousMetadata, target.constructor)
|
||||
}
|
||||
}
|
||||
|
||||
function stage(stage: string) {
|
||||
return (metadata: interfaces.ExecMetadata = {}) => {
|
||||
return function (target: any, key: string, value: any) {
|
||||
|
||||
@@ -5,9 +5,13 @@ import { getPluginListenerMetadata } from './utils'
|
||||
@provideSingleton(PluginEventManager)
|
||||
export class PluginEventManager {
|
||||
@Autowired()
|
||||
private EventManager: event.Event
|
||||
private eventManager: event.Event
|
||||
@Autowired()
|
||||
private ServerChecker: server.ServerChecker
|
||||
private serverChecker: server.ServerChecker
|
||||
@Autowired()
|
||||
private nativePluginChecker: server.NativePluginChecker
|
||||
|
||||
private listenerMap = [];
|
||||
|
||||
constructor() {
|
||||
process.on('plugin.before.enable', this.registryListener.bind(this))
|
||||
@@ -15,26 +19,44 @@ export class PluginEventManager {
|
||||
}
|
||||
|
||||
mapEventName() {
|
||||
return this.EventManager.mapEventName().toFixed(0)
|
||||
return this.eventManager.mapEventName().toFixed(0)
|
||||
}
|
||||
|
||||
private registryListener(pluginInstance: plugin.Plugin) {
|
||||
let events = getPluginListenerMetadata(pluginInstance)
|
||||
public registryListener(pluginInstance: plugin.Plugin, listener: any = pluginInstance) {
|
||||
let events = getPluginListenerMetadata(listener)
|
||||
let execes = []
|
||||
for (const event of events) {
|
||||
// ignore space listener
|
||||
if (!this.ServerChecker.check(event.servers)) {
|
||||
console.debug(`[${pluginInstance.description.name}] ${event.target.constructor.name} incompatible event ${event.name} server(${event.servers}) ignore.`)
|
||||
if (!this.serverChecker.check(event.servers)) {
|
||||
console.debug(`[${pluginInstance.description.name}] ${event.target.constructor.name} incompatible server(${event.servers}) ignore event ${event.name}.`)
|
||||
continue
|
||||
}
|
||||
// ignore space listener
|
||||
if (!this.nativePluginChecker.check(event.plugins)) {
|
||||
console.debug(`[${pluginInstance.description.name}] ${event.target.constructor.name} require native plugins(${event.plugins}) ignore event ${event.name}.`)
|
||||
continue
|
||||
}
|
||||
// here must bind this to pluginInstance
|
||||
let exec = event.target[event.executor]
|
||||
let execBinded = exec.bind(pluginInstance)
|
||||
let execBinded = exec.bind(listener)
|
||||
execBinded.executor = event.executor
|
||||
exec.off = this.EventManager.listen(pluginInstance, event.name, execBinded, event.priority, event.ignoreCancel)
|
||||
exec.off = this.eventManager.listen(pluginInstance, event.name, execBinded, event.priority, event.ignoreCancel)
|
||||
execes.push(exec)
|
||||
}
|
||||
let off = () => {
|
||||
if (off['offed']) return
|
||||
off['offed'] = true
|
||||
execes.forEach((exec: { off: () => void }) => exec.off())
|
||||
}
|
||||
listener.off = off
|
||||
}
|
||||
|
||||
private unregistryListener(pluginInstance: plugin.Plugin) {
|
||||
this.EventManager.disable(pluginInstance)
|
||||
private unregistryListener(pluginInstance: plugin.Plugin, listener: any = pluginInstance) {
|
||||
if (listener && listener.off) {
|
||||
listener.off()
|
||||
}
|
||||
if (pluginInstance) {
|
||||
this.eventManager.disable(pluginInstance)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
import './scanner/file-scanner'
|
||||
import '@ccms/verify'
|
||||
import './scanner/js-scanner'
|
||||
|
||||
import './loader/ioc-loader'
|
||||
import './loader/basic-loader'
|
||||
|
||||
export * from './config'
|
||||
export * from './config/config'
|
||||
export * from './manager'
|
||||
export * from './decorators'
|
||||
export * from './interfaces'
|
||||
|
||||
export * from './event'
|
||||
export * from './command'
|
||||
|
||||
export {
|
||||
plugin as JSPlugin,
|
||||
cmd as Cmd,
|
||||
tab as Tab,
|
||||
listener as Listener,
|
||||
config as Config
|
||||
config as Config,
|
||||
playerdata as PlayerData
|
||||
} from './decorators'
|
||||
|
||||
import '@ccms/database'
|
||||
|
||||
@@ -8,7 +8,7 @@ export namespace interfaces {
|
||||
@injectable()
|
||||
export abstract class Plugin implements plugin.Plugin {
|
||||
public description: plugin.PluginMetadata
|
||||
public logger: Console
|
||||
public logger: MiaoScriptConsole
|
||||
@inject(server.Console)
|
||||
private Console: MiaoScriptConsole
|
||||
|
||||
@@ -28,6 +28,11 @@ export namespace interfaces {
|
||||
return dataFolder.getAbsolutePath()
|
||||
}
|
||||
|
||||
public registryCommand(executor: any) { }
|
||||
public unregistryCommand(executor: any) { }
|
||||
public registryListener(listener: any) { }
|
||||
public unregistryListener(listener: any) { }
|
||||
|
||||
public load() { }
|
||||
public enable() { }
|
||||
public disable() { }
|
||||
@@ -59,6 +64,10 @@ export namespace interfaces {
|
||||
* 自动化主命令
|
||||
*/
|
||||
autoMain?: boolean
|
||||
/**
|
||||
* 子命令权限效验
|
||||
*/
|
||||
permission?: boolean | string
|
||||
}
|
||||
export interface ListenerMetadata extends ExecMetadata {
|
||||
/**
|
||||
@@ -69,8 +78,46 @@ export namespace interfaces {
|
||||
* 是否忽略已取消的事件
|
||||
*/
|
||||
ignoreCancel?: boolean
|
||||
/**
|
||||
* 依赖插件 没有就不加载
|
||||
*/
|
||||
plugins?: string[]
|
||||
}
|
||||
export interface ConfigMetadata extends plugin.BaseMetadata {
|
||||
/**
|
||||
* 配置文件版本号
|
||||
*/
|
||||
version?: number
|
||||
/**
|
||||
* 默认配置
|
||||
*/
|
||||
default?: any
|
||||
/**
|
||||
* 实体变量名称
|
||||
*/
|
||||
variable?: string
|
||||
/**
|
||||
* 配置文件格式 默认 yml
|
||||
*/
|
||||
format?: string
|
||||
/**
|
||||
* 是否合并默认配置
|
||||
*/
|
||||
migrate?: boolean
|
||||
/**
|
||||
* 自动保存 默认为 false
|
||||
*/
|
||||
autosave?: boolean
|
||||
/**
|
||||
* 配置文件名称
|
||||
*/
|
||||
filename?: string
|
||||
/**
|
||||
* 配置文件全路径
|
||||
*/
|
||||
file?: any
|
||||
}
|
||||
export interface PlayerDataMetadata extends plugin.BaseMetadata {
|
||||
/**
|
||||
* 配置文件版本号
|
||||
*/
|
||||
@@ -92,12 +139,16 @@ export namespace interfaces {
|
||||
*/
|
||||
autosave?: boolean
|
||||
/**
|
||||
* 配置文件名称
|
||||
* 配置文件名称 默认玩家名称
|
||||
*/
|
||||
filename?: string
|
||||
filename?: "username" | "uuid"
|
||||
/**
|
||||
* 配置文件全路径
|
||||
* 配置文件目录 默认 playerdata
|
||||
*/
|
||||
file?: any
|
||||
dir?: string
|
||||
/**
|
||||
* 配置文件子目录 默认为空
|
||||
*/
|
||||
subdir?: string
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,13 +63,13 @@ export class IocLoader implements plugin.PluginLoader {
|
||||
}
|
||||
|
||||
private bindPlugin(metadata: plugin.PluginMetadata) {
|
||||
try {
|
||||
if (this.container.isBoundNamed(plugin.Plugin, metadata.name)) {
|
||||
let pluginInstance = this.container.getNamed<plugin.Plugin>(plugin.Plugin, metadata.name)
|
||||
if (pluginInstance.description.source + '' !== metadata.source + '') {
|
||||
console.i18n('ms.plugin.manager.build.duplicate', { exists: pluginInstance.description.source, source: metadata.source })
|
||||
}
|
||||
this.container.rebind(plugin.Plugin).to(metadata.target).inSingletonScope().whenTargetNamed(metadata.name)
|
||||
} catch {
|
||||
} else {
|
||||
this.container.bind(plugin.Plugin).to(metadata.target).inSingletonScope().whenTargetNamed(metadata.name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,11 @@ import i18n from '@ccms/i18n'
|
||||
import { plugin, server } from '@ccms/api'
|
||||
import { provideSingleton, Container, ContainerInstance, Autowired } from '@ccms/container'
|
||||
|
||||
import './config'
|
||||
import { interfaces } from './interfaces'
|
||||
import { PluginTaskManager } from './task'
|
||||
import { PluginEventManager } from './event'
|
||||
import { PluginCommandManager } from './command'
|
||||
import { PluginConfigManager } from './config'
|
||||
import { PluginCommandManager } from './command'
|
||||
|
||||
const Thread = Java.type('java.lang.Thread')
|
||||
|
||||
@@ -64,8 +63,13 @@ export class PluginManagerImpl implements plugin.PluginManager {
|
||||
initialize() {
|
||||
if (this.pluginInstance === undefined) { throw new Error("Can't found Plugin Instance!") }
|
||||
if (this.initialized !== true) {
|
||||
process.emit('plugin.manager.before.initialize', this)
|
||||
console.i18n('ms.plugin.initialize', { plugin: this.pluginInstance, loader: Thread.currentThread().contextClassLoader })
|
||||
console.i18n('ms.plugin.event.map', { count: this.eventManager.mapEventName(), type: this.serverType })
|
||||
try {
|
||||
console.i18n('ms.plugin.event.map', { count: this.eventManager.mapEventName(), type: this.serverType })
|
||||
} catch (error) {
|
||||
console.i18n('ms.plugin.event.map.error', { type: this.serverType, error })
|
||||
}
|
||||
let pluginScanner = this.container.getAll<plugin.PluginScanner>(plugin.PluginScanner)
|
||||
pluginScanner.forEach((scanner) => {
|
||||
console.debug(`loading plugin sacnner ${scanner.type}...`)
|
||||
@@ -77,37 +81,38 @@ export class PluginManagerImpl implements plugin.PluginManager {
|
||||
this.loaderMap.set(loader.type, loader)
|
||||
})
|
||||
this.initialized = true
|
||||
process.emit('plugin.initialize')
|
||||
process.emit('plugin.manager.after.initialize', this)
|
||||
}
|
||||
}
|
||||
|
||||
scan(folder: string): void {
|
||||
if (!folder) { throw new Error('plugin scan folder can\'t be empty!') }
|
||||
this.initialize()
|
||||
process.emit('plugin.manager.before.scan', folder, this)
|
||||
for (const [, scanner] of this.sacnnerMap) {
|
||||
try {
|
||||
console.i18n('ms.plugin.manager.scan', { scanner: scanner.type, folder })
|
||||
let plugins = scanner.scan(folder)
|
||||
console.i18n('ms.plugin.manager.scan.finish', { scanner: scanner.type, folder, size: plugins.length })
|
||||
plugins.forEach(loadMetadata => {
|
||||
let loadMetadatas = scanner.scan(folder)
|
||||
console.i18n('ms.plugin.manager.scan.finish', { scanner: scanner.type, folder, size: loadMetadatas.length })
|
||||
for (const loadMetadata of loadMetadatas) {
|
||||
try {
|
||||
this.loadAndRequirePlugin(loadMetadata)
|
||||
} catch (error: any) {
|
||||
console.error(`plugin scanner ${scanner.type} load ${loadMetadata.file} occurred error ${error}`)
|
||||
console.console(`§c扫描器 §4${scanner.type} §c文件 §4${loadMetadata.file.toString().replace(root, '')} §c编译失败 请提供下列错误给开发者`)
|
||||
console.ex(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error(`plugin scanner ${scanner.type} occurred error ${error}`)
|
||||
console.ex(error)
|
||||
}
|
||||
}
|
||||
process.emit('plugin.scan', folder)
|
||||
process.emit('plugin.manager.after.scan', folder, this)
|
||||
}
|
||||
|
||||
build(): void {
|
||||
process.emit('plugin.manager.before.build', this)
|
||||
this.buildPlugins()
|
||||
process.emit('plugin.build')
|
||||
process.emit('plugin.manager.after.build', this)
|
||||
}
|
||||
|
||||
private logStage(plugin: plugin.Plugin, stage: string) {
|
||||
@@ -132,6 +137,7 @@ export class PluginManagerImpl implements plugin.PluginManager {
|
||||
private loadPlugin(loadMetadata: plugin.PluginLoadMetadata) {
|
||||
if (!loadMetadata) { throw new Error('loadMetadata can\'t be undefiend when loadPlugin!') }
|
||||
if (loadMetadata.loaded) { throw new Error(`Plugin file ${loadMetadata.file} is already loaded by ${loadMetadata.loader?.type}!`) }
|
||||
process.emit(`plugin.before.require`, loadMetadata)
|
||||
try {
|
||||
for (const [, loader] of this.loaderMap) {
|
||||
if (this.loaderRequirePlugin(loadMetadata, loader)?.loaded) return loadMetadata.metadata
|
||||
@@ -140,7 +146,6 @@ export class PluginManagerImpl implements plugin.PluginManager {
|
||||
console.i18n("ms.plugin.manager.initialize.error", { name: loadMetadata.file, ex: error })
|
||||
console.ex(error)
|
||||
}
|
||||
console.console(`§6scanner: §b${loadMetadata.scanner.type} §ccan\'t load §6file §b${loadMetadata.file}. §eskip!`)
|
||||
}
|
||||
|
||||
private loaderRequirePlugin(loadMetadata: plugin.PluginLoadMetadata, loader: plugin.PluginLoader) {
|
||||
@@ -154,6 +159,7 @@ export class PluginManagerImpl implements plugin.PluginManager {
|
||||
}
|
||||
this.metadataMap.set(metadata.name, metadata)
|
||||
metadata.loadMetadata = loadMetadata
|
||||
process.emit(`plugin.after.require`, loadMetadata)
|
||||
}
|
||||
return loadMetadata
|
||||
} catch (error: any) {
|
||||
@@ -169,6 +175,7 @@ export class PluginManagerImpl implements plugin.PluginManager {
|
||||
private loadAndRequirePlugin(loadMetadata: plugin.PluginLoadMetadata) {
|
||||
let startTime = Date.now()
|
||||
let metadata = this.loadPlugin(loadMetadata.scanner.load(loadMetadata))
|
||||
if (!metadata) { throw new Error('load plugin metadata failed.') }
|
||||
console.i18n('ms.plugin.manager.build', {
|
||||
name: loadMetadata.metadata.name,
|
||||
version: loadMetadata.metadata.version,
|
||||
@@ -184,11 +191,14 @@ export class PluginManagerImpl implements plugin.PluginManager {
|
||||
* 从文件加载插件
|
||||
* @param file java.io.File
|
||||
*/
|
||||
loadFromFile(file: string, scanner = this.sacnnerMap.get('file')): plugin.Plugin {
|
||||
if (!file) { throw new Error('plugin file can\'t be undefiend!') }
|
||||
if (!scanner) { throw new Error('plugin scanner can\'t be undefiend!') }
|
||||
loadFromFile(file: string, ext: any = 'js'): plugin.Plugin {
|
||||
if (!file) { throw new Error('plugin file can\'t be undefiend.') }
|
||||
let scanner = this.sacnnerMap.get(ext)
|
||||
if (!scanner) { throw new Error(`plugin scanner ${ext} can't found in sacnnerMap.`) }
|
||||
let metadata = this.loadAndRequirePlugin(scanner.read(file))
|
||||
let plugin = this.buildPlugin(metadata)
|
||||
this.buildPlugin(metadata)
|
||||
let plugin = metadata.target
|
||||
if (!plugin) { throw new Error(`plugin scanner ${ext} can't found in sacnnerMap.`) }
|
||||
this.load(plugin)
|
||||
this.enable(plugin)
|
||||
return plugin
|
||||
@@ -213,12 +223,20 @@ export class PluginManagerImpl implements plugin.PluginManager {
|
||||
reload(...args: any[]): void {
|
||||
this.checkAndGet(args[0]).forEach((pl: plugin.Plugin) => {
|
||||
this.disable(pl)
|
||||
this.loadFromFile(pl.description.loadMetadata.file, pl.description.loadMetadata.scanner)
|
||||
this.loadFromFile(pl.description.loadMetadata.file, pl.description.loadMetadata.scanner.type)
|
||||
})
|
||||
}
|
||||
|
||||
has(name: string) {
|
||||
return this.instanceMap.has(name)
|
||||
}
|
||||
|
||||
get(name: string) {
|
||||
return this.instanceMap.get(name) || null
|
||||
}
|
||||
|
||||
getPlugin(name: string) {
|
||||
return this.instanceMap.get(name)
|
||||
return this.instanceMap.get(name) || null
|
||||
}
|
||||
|
||||
getPlugins() {
|
||||
@@ -235,12 +253,12 @@ export class PluginManagerImpl implements plugin.PluginManager {
|
||||
}
|
||||
|
||||
private checkAndGet(name: string | plugin.Plugin | undefined | any): Map<string, plugin.Plugin> | plugin.Plugin[] {
|
||||
if (name === undefined) throw new Error(`checkAndGet Plugin can't be undefiend!`)
|
||||
if (name === undefined) throw new Error(`checkAndGet Plugin can't be undefiend.`)
|
||||
if (name == this.instanceMap) { return this.instanceMap }
|
||||
if (typeof name == 'string' && this.instanceMap.has(name)) { return [this.instanceMap.get(name)] }
|
||||
if (name instanceof interfaces.Plugin) { return [name as plugin.Plugin] }
|
||||
if (name.description?.name) { return [name as plugin.Plugin] }
|
||||
throw new Error(`Plugin ${JSON.stringify(name)} not exist!`)
|
||||
throw new Error(`Plugin ${JSON.stringify(name)} not exist.`)
|
||||
}
|
||||
|
||||
private buildPlugins() {
|
||||
@@ -248,10 +266,10 @@ export class PluginManagerImpl implements plugin.PluginManager {
|
||||
if (metadata?.depends?.length) {
|
||||
this.lazyMetadataMap.set(key, metadata)
|
||||
} else {
|
||||
this.buildPlugin(metadata)
|
||||
this.tryBuildPlugin(metadata)
|
||||
}
|
||||
})
|
||||
this.lazyMetadataMap.forEach((metadata, key) => this.buildPlugin(metadata))
|
||||
this.lazyMetadataMap.forEach((metadata, key) => this.tryBuildPlugin(metadata))
|
||||
}
|
||||
|
||||
private checkDepends(depends: string | string[]) {
|
||||
@@ -266,22 +284,29 @@ export class PluginManagerImpl implements plugin.PluginManager {
|
||||
for (const depend of depends) { if (!this.nativePluginManager.has(depend)) loseDepends.push(depend) }
|
||||
return loseDepends
|
||||
}
|
||||
private buildPlugin(metadata: plugin.PluginMetadata) {
|
||||
|
||||
private tryBuildPlugin(metadata: plugin.PluginMetadata) {
|
||||
try {
|
||||
if (this.instanceMap.has(metadata.name)) { throw new Error(`Plugin ${metadata.name} is already load from ${metadata.source}...`) }
|
||||
if (!this.loaderMap.has(metadata.type)) { throw new Error(`§4无法加载插件 §b${metadata.name} §4请检查 §c${metadata.type} §4加载器是否正常启用!`) }
|
||||
if (!this.serverChecker.check(metadata.servers)) { throw new Error(`§6插件 §b${metadata.name} §c服务器类型不兼容(${metadata.servers.join(',')}) §6忽略加载...`) }
|
||||
let loseDepends = this.checkDepends(metadata.depends) || []
|
||||
if (loseDepends.length) { throw new Error(`§4无法加载插件 §b${metadata.name} §4请检查脚本依赖 §3[${loseDepends.join(',')}] §4是否安装完整!`) }
|
||||
let loseNativeDepends = this.checkNativeDepends(metadata.nativeDepends) || []
|
||||
if (loseNativeDepends.length) { throw new Error(`§4无法加载插件 §b${metadata.name} §4请检查插件依赖 §3[${loseNativeDepends.join(',')}] §4是否安装完整!`) }
|
||||
let pluginInstance = this.loaderMap.get(metadata.type).build(metadata)
|
||||
if (!pluginInstance) { throw new Error(`§4加载器 §c${metadata.type} §4加载插件 §c${metadata.name} §4失败!`) }
|
||||
this.instanceMap.set(metadata.name, pluginInstance)
|
||||
return pluginInstance
|
||||
return this.buildPlugin(metadata)
|
||||
} catch (error: any) {
|
||||
console.console(`§4无法加载插件 §b${metadata.name} §4构建插件失败!`)
|
||||
console.ex(error)
|
||||
}
|
||||
}
|
||||
|
||||
private buildPlugin(metadata: plugin.PluginMetadata) {
|
||||
process.emit(`plugin.before.build`, metadata)
|
||||
if (this.instanceMap.has(metadata.name)) { throw new Error(`Plugin ${metadata.name} is already load from ${metadata.source}...`) }
|
||||
if (!this.loaderMap.has(metadata.type)) { throw new Error(`§4无法加载插件 §b${metadata.name} §4请检查 §c${metadata.type} §4加载器是否正常启用!`) }
|
||||
if (!this.serverChecker.check(metadata.servers)) { throw new Error(`§6插件 §b${metadata.name} §c服务器类型不兼容(${metadata.servers.join(',')}) §6忽略加载...`) }
|
||||
let loseDepends = this.checkDepends(metadata.depends) || []
|
||||
if (loseDepends.length) { throw new Error(`§4无法加载插件 §b${metadata.name} §4请检查脚本依赖 §3[${loseDepends.join(',')}] §4是否安装完整!`) }
|
||||
let loseNativeDepends = this.checkNativeDepends(metadata.nativeDepends) || []
|
||||
if (loseNativeDepends.length) { throw new Error(`§4无法加载插件 §b${metadata.name} §4请检查插件依赖 §3[${loseNativeDepends.join(',')}] §4是否安装完整!`) }
|
||||
let pluginInstance = this.loaderMap.get(metadata.type).build(metadata)
|
||||
if (!pluginInstance) { throw new Error(`§4加载器 §c${metadata.type} §4加载插件 §c${metadata.name} §4失败!`) }
|
||||
metadata.target = pluginInstance
|
||||
this.instanceMap.set(metadata.name, pluginInstance)
|
||||
process.emit(`plugin.after.build`, metadata, pluginInstance)
|
||||
return pluginInstance
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { plugin } from "@ccms/api"
|
||||
import * as fs from '@ccms/common/dist/fs'
|
||||
import { provideSingletonNamed } from "@ccms/container"
|
||||
|
||||
const SCANNER_TYPE_NAME = 'file'
|
||||
const SCANNER_TYPE_NAME = 'js'
|
||||
|
||||
@provideSingletonNamed(plugin.PluginScanner, SCANNER_TYPE_NAME)
|
||||
export class JSFileScanner implements plugin.PluginScanner {
|
||||
@@ -67,7 +67,13 @@ function getPluginConfigMetadata(target: any) {
|
||||
) || new Map<string, interfaces.ConfigMetadata>()
|
||||
return configMetadata
|
||||
}
|
||||
|
||||
function getPluginPlayerDataMetadata(target: any) {
|
||||
let playerdataMetadata: Map<string, interfaces.ConfigMetadata> = Reflect.getMetadata(
|
||||
METADATA_KEY.playerdata,
|
||||
target.constructor
|
||||
) || new Map<string, interfaces.ConfigMetadata>()
|
||||
return playerdataMetadata
|
||||
}
|
||||
function getPluginStageMetadata(target: any, stage: string) {
|
||||
let stageMetadata: interfaces.ExecMetadata[] = Reflect.getMetadata(
|
||||
METADATA_KEY.stage[stage],
|
||||
@@ -86,5 +92,6 @@ export {
|
||||
getPluginTabCompleterMetadata,
|
||||
getPluginListenerMetadata,
|
||||
getPluginConfigMetadata,
|
||||
getPluginPlayerDataMetadata,
|
||||
getPluginStageMetadata
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ccms/polyfill",
|
||||
"version": "0.18.0",
|
||||
"version": "0.28.0-beta.2",
|
||||
"description": "MiaoScript polyfill package",
|
||||
"author": "MiaoWoo <admin@yumc.pw>",
|
||||
"homepage": "https://github.com/circlecloud/ms.git",
|
||||
@@ -14,14 +14,14 @@
|
||||
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ccms/i18n": "^0.18.0",
|
||||
"@ccms/nodejs": "^0.18.0",
|
||||
"core-js": "^3.21.0"
|
||||
"@ccms/i18n": "^0.28.0-beta.2",
|
||||
"@ccms/nodejs": "^0.28.0-beta.2",
|
||||
"core-js": "^3.27.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ccms/nashorn": "^0.18.0",
|
||||
"@ccms/nashorn": "^0.28.0-beta.2",
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.5.5"
|
||||
"rimraf": "^4.1.2",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
}
|
||||
|
||||
2134
packages/polyfill/src/buffer.ts
Normal file
2134
packages/polyfill/src/buffer.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -12,5 +12,7 @@ import 'core-js'
|
||||
process.on('exit', () => require.disable())
|
||||
global.setGlobal('Proxy', require('./proxy').Proxy)
|
||||
global.setGlobal('XMLHttpRequest', require('./xml-http-request').XMLHttpRequest)
|
||||
global.setGlobal('Buffer', require('./buffer').Buffer)
|
||||
global.setGlobal('Blob', require('blob-polyfill').Blob)
|
||||
console.i18n("ms.polyfill.completed", { time: (new Date().getTime() - polyfillStartTime) / 1000 })
|
||||
export default true
|
||||
|
||||
@@ -2,6 +2,7 @@ import { EventEmitter } from 'events'
|
||||
|
||||
const System = Java.type('java.lang.System')
|
||||
const Thread = Java.type('java.lang.Thread')
|
||||
const ManagementFactory = Java.type('java.lang.management.ManagementFactory')
|
||||
const InterruptedException = Java.type('java.lang.InterruptedException')
|
||||
const ThreadGroup = Java.type("java.lang.ThreadGroup")
|
||||
const AtomicInteger = Java.type("java.util.concurrent.atomic.AtomicInteger")
|
||||
@@ -15,19 +16,35 @@ const DelayQueue = Java.type('java.util.concurrent.DelayQueue')
|
||||
const JavaScriptTask = Java.type(base.getJavaScriptTaskClass().name)
|
||||
|
||||
const threadCount = new AtomicInteger(0)
|
||||
const threadGroup = new ThreadGroup("@ccms/ployfill-micro-task")
|
||||
const threadGroup = new ThreadGroup("@ccms/micro-task")
|
||||
const microTaskPool = new ThreadPoolExecutor(
|
||||
100, 200, 60, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue(300),
|
||||
new LinkedBlockingQueue(1024),
|
||||
new ThreadFactory((run: any) => new Thread(threadGroup, run, "@ccms/micro-task-" + threadCount.incrementAndGet()))
|
||||
)
|
||||
class Process extends EventEmitter {
|
||||
readonly version = base.version
|
||||
readonly versions = []
|
||||
readonly config = {}
|
||||
readonly pid: number = parseInt(ManagementFactory.getRuntimeMXBean().getName().split('@')[0])
|
||||
readonly ppid: number
|
||||
title: string
|
||||
readonly arch: string = System.getProperty("os.arch")
|
||||
readonly platform = System.getProperty("os.name")
|
||||
|
||||
env = {
|
||||
__noSuchProperty__: (prop) => {
|
||||
return System.getenv(prop)
|
||||
}
|
||||
}
|
||||
platform = System.getProperty("os.name")
|
||||
|
||||
stdout = System.out
|
||||
stderr = System.err
|
||||
stdin = System.in
|
||||
|
||||
execArgv = ''
|
||||
execPath = ''
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
this.on('exit', () => {
|
||||
@@ -49,10 +66,10 @@ class Process extends EventEmitter {
|
||||
}
|
||||
})
|
||||
}
|
||||
nextTick(func: Function, ...args: any[]) {
|
||||
nextTick(callback: Function, ...args: any[]): void {
|
||||
microTaskPool.execute(() => {
|
||||
try {
|
||||
func(args)
|
||||
callback(args)
|
||||
} catch (origin: any) {
|
||||
try {
|
||||
super.emit('error', origin)
|
||||
@@ -65,27 +82,63 @@ class Process extends EventEmitter {
|
||||
}
|
||||
exit(code: number) {
|
||||
console.log(`process exit by code ${code}!`)
|
||||
this.emit('exit', code)
|
||||
this.emit('exit', this.exitCode = code)
|
||||
}
|
||||
exitCode = 0
|
||||
openStdin() {
|
||||
throw new Error('MiaoScript unsupport openStdin.')
|
||||
}
|
||||
chdir(directory: string): void {
|
||||
console.error('MiaoScript unsupport chdir. lock at ' + root)
|
||||
}
|
||||
cwd() {
|
||||
return root
|
||||
}
|
||||
getgid(): number {
|
||||
throw new Error('MiaoScript unsupport getgid.')
|
||||
}
|
||||
setgid(id: number | string) {
|
||||
throw new Error('MiaoScript unsupport setgid.')
|
||||
}
|
||||
getuid(): number {
|
||||
throw new Error('MiaoScript unsupport getuid.')
|
||||
}
|
||||
setuid(id: number | string) {
|
||||
throw new Error('MiaoScript unsupport setuid.')
|
||||
}
|
||||
setUncaughtExceptionCaptureCallback(cb: ((err: Error) => void) | null) {
|
||||
if (cb == null) {
|
||||
this.removeAllListeners('error')
|
||||
} else {
|
||||
this.on('error', cb)
|
||||
}
|
||||
}
|
||||
hasUncaughtExceptionCaptureCallback() {
|
||||
return this.listenerCount('error') > 0
|
||||
}
|
||||
kill(pid: number, signal?: string | number): true {
|
||||
throw new Error('MiaoScript unsupport kill.')
|
||||
return true
|
||||
}
|
||||
|
||||
toString() {
|
||||
return "[object process]"
|
||||
}
|
||||
}
|
||||
|
||||
class EventLoop {
|
||||
private threadCount = new AtomicInteger(0)
|
||||
private eventLoopMainThread = undefined
|
||||
private eventLoopTaskQueue = new DelayQueue()
|
||||
private taskExecTimeout = 3
|
||||
private taskExecuteTimeout = 3000
|
||||
private fixedThreadPool = undefined
|
||||
|
||||
constructor() {
|
||||
this.taskExecTimeout = parseInt(process.env.MS_NODE_EVENT_LOOP_TIMEOUT) || 3
|
||||
this.taskExecuteTimeout = parseInt(process.env.MS_TASK_EXECUTE_TIMEOUT) || 3000
|
||||
this.fixedThreadPool = new ThreadPoolExecutor(
|
||||
1, 1, 0, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue(300),
|
||||
8, 16, 0, TimeUnit.SECONDS,
|
||||
new LinkedBlockingQueue(1024),
|
||||
new ThreadFactory((run: any) => {
|
||||
let thread = new Thread(run, "@ccms/node-shim/event-loop-exec")
|
||||
let thread = new Thread(run, "@ccms/event-loop-" + this.threadCount.incrementAndGet())
|
||||
thread.setDaemon(true)
|
||||
return thread
|
||||
}))
|
||||
@@ -115,7 +168,7 @@ class EventLoop {
|
||||
this.intervalTasks = undefined
|
||||
this.eventLoopMainThread = undefined
|
||||
}
|
||||
}, "@ccms/node-shim/event-loop")
|
||||
}, "@ccms/event-loop")
|
||||
this.eventLoopMainThread.setDaemon(true)
|
||||
process.on('exit', () => {
|
||||
this.eventLoopMainThread.interrupt()
|
||||
@@ -137,14 +190,16 @@ class EventLoop {
|
||||
if (!callback) {
|
||||
throw new Error(`task ${name} callback function can't be null!`)
|
||||
}
|
||||
if (this.fixedThreadPool.isShutdown()) { return console.warn(`FixedThreadPool isTerminated! ignore Task ${name}!`) }
|
||||
if (this.fixedThreadPool.isShutdown()) {
|
||||
return console.warn(`FixedThreadPool isTerminated! ignore Task ${name}!`)
|
||||
}
|
||||
try {
|
||||
this.fixedThreadPool.submit(new Callable({
|
||||
call: () => {
|
||||
try {
|
||||
callback.apply(undefined, args)
|
||||
} catch (cause: any) {
|
||||
cause = cause.getCause && cause.getCause() || cause
|
||||
cause = cause.getCause ? cause.getCause() : cause
|
||||
try {
|
||||
process.emit('error', cause)
|
||||
} catch (error: any) {
|
||||
@@ -153,13 +208,13 @@ class EventLoop {
|
||||
}
|
||||
}
|
||||
}
|
||||
})).get(this.taskExecTimeout, TimeUnit.SECONDS)
|
||||
})).get(this.taskExecuteTimeout, TimeUnit.MILLISECONDS)
|
||||
} catch (error: any) {
|
||||
if (error instanceof InterruptedException) {
|
||||
return console.warn(`FixedThreadPool isInterrupted exit! Task ${name} exec exit!`)
|
||||
}
|
||||
if (error instanceof TimeoutException) {
|
||||
return console.warn(`Task ${name} => ${callback} exec time greater than ${this.taskExecTimeout}s!`)
|
||||
return console.warn(`Task ${name} => ${callback} exec time greater than ${this.taskExecuteTimeout}ms!`)
|
||||
}
|
||||
throw error.getCause && error.getCause() || error
|
||||
}
|
||||
|
||||
@@ -68,13 +68,14 @@ type EventType =
|
||||
| 'timeout'
|
||||
| 'loadend'
|
||||
| 'loadstart'
|
||||
type HttpHeader = { [key: string]: string }
|
||||
|
||||
type RequestHttpHeader = { [key: string]: string }
|
||||
type HttpHeader = { [key: string]: string[] }
|
||||
|
||||
const executor = Executors.newCachedThreadPool()
|
||||
|
||||
export class XMLHttpRequest {
|
||||
private _timeout: number = 120000;
|
||||
private _connectTimeout: number = 5000;
|
||||
private _readTimeout: number = 120000;
|
||||
private _responseType: ResponseType = 'text';
|
||||
private _withCredentials: boolean
|
||||
|
||||
@@ -84,7 +85,7 @@ export class XMLHttpRequest {
|
||||
private _url: string
|
||||
private _async: boolean
|
||||
private _mimeType: string
|
||||
private _requestHeaders: HttpHeader = {};
|
||||
private _requestHeaders: RequestHttpHeader = {};
|
||||
|
||||
private _status: number = 0;
|
||||
private _statusText: string = null;
|
||||
@@ -96,10 +97,22 @@ export class XMLHttpRequest {
|
||||
private _connection = null;
|
||||
|
||||
get timeout() {
|
||||
return this._timeout
|
||||
return this._readTimeout
|
||||
}
|
||||
set timeout(timeout: number) {
|
||||
this._timeout = timeout
|
||||
this._readTimeout = timeout
|
||||
}
|
||||
get connectTimeout() {
|
||||
return this._connectTimeout
|
||||
}
|
||||
set connectTimeout(timeout: number) {
|
||||
this._connectTimeout = timeout
|
||||
}
|
||||
get readTimeout() {
|
||||
return this._readTimeout
|
||||
}
|
||||
set readTimeout(timeout: number) {
|
||||
this._readTimeout = timeout
|
||||
}
|
||||
get readyState() {
|
||||
return this._readyState
|
||||
@@ -143,7 +156,7 @@ export class XMLHttpRequest {
|
||||
this._requestHeaders[key] = val
|
||||
}
|
||||
getResponseHeader(key: string): string {
|
||||
return this._responseHeaders[key]
|
||||
return this._responseHeaders[key]?.[0]
|
||||
}
|
||||
getAllResponseHeaders(): any {
|
||||
return this._responseHeaders
|
||||
@@ -169,8 +182,8 @@ export class XMLHttpRequest {
|
||||
this._connection.setRequestMethod(this._method)
|
||||
this._connection.setDoOutput(true)
|
||||
this._connection.setDoInput(true)
|
||||
this._connection.setConnectTimeout(this._timeout)
|
||||
this._connection.setReadTimeout(this._timeout)
|
||||
this._connection.setConnectTimeout(this._connectTimeout)
|
||||
this._connection.setReadTimeout(this._readTimeout)
|
||||
|
||||
this.setRequestHeader('X-Requested-With', 'XMLHttpRequest')
|
||||
this.setReadyState(ReadyState.OPENED)
|
||||
@@ -181,7 +194,7 @@ export class XMLHttpRequest {
|
||||
}
|
||||
if (this._readyState !== ReadyState.OPENED) { throw new Error(`Error Status ${this._readyState}!`) }
|
||||
let future = executor.submit(new Callable({ call: () => this._send(body) }))
|
||||
if (!this._async) { future.get(this._timeout, TimeUnit.MILLISECONDS) }
|
||||
if (!this._async) { future.get(this._connectTimeout + this._readTimeout + 100, TimeUnit.MILLISECONDS) }
|
||||
return future
|
||||
}
|
||||
get() {
|
||||
@@ -199,22 +212,23 @@ export class XMLHttpRequest {
|
||||
}
|
||||
abort() {
|
||||
this._connection.disconnect()
|
||||
this.onabort && this.onabort()
|
||||
this.onabort?.()
|
||||
}
|
||||
|
||||
private _send(body?: string | object) {
|
||||
try {
|
||||
this._connection.connect()
|
||||
this.onloadstart && this.onloadstart()
|
||||
this.onloadstart?.()
|
||||
if (body) {
|
||||
let bodyType = Object.prototype.toString.call(body)
|
||||
if (typeof body !== "string") { throw new Error(`body(${bodyType}) must be string!`) }
|
||||
if (typeof body !== "string") { throw new Error(`body(${bodyType}) must be string.`) }
|
||||
var out = this._connection.getOutputStream()
|
||||
out.write(new JavaString(body).getBytes(UTF_8))
|
||||
out.flush()
|
||||
out.close()
|
||||
}
|
||||
this.setReadyState(ReadyState.LOADING)
|
||||
this.onload?.()
|
||||
this._status = this._connection.getResponseCode()
|
||||
this._statusText = this._connection.getResponseMessage()
|
||||
if (this._status >= 0 && this._status < 300) {
|
||||
@@ -224,8 +238,8 @@ export class XMLHttpRequest {
|
||||
} else {
|
||||
this._responseText = this.readOutput(this._connection.getErrorStream())
|
||||
}
|
||||
this.setResponseHeaders(this._connection.getHeaderFields())
|
||||
this.onloadend && this.onloadend()
|
||||
this.setResponseHeaders()
|
||||
this.onloadend?.()
|
||||
} catch (ex: any) {
|
||||
if (ex instanceof SocketTimeoutException && this.ontimeout) {
|
||||
return this.ontimeout(ex)
|
||||
@@ -239,15 +253,15 @@ export class XMLHttpRequest {
|
||||
}
|
||||
}
|
||||
|
||||
private setResponseHeaders(header: any) {
|
||||
header.forEach((key: string | number, value: string | any[]) => {
|
||||
this._responseHeaders[key + ''] = value[value.length - 1] + ''
|
||||
private setResponseHeaders() {
|
||||
this._connection.getHeaderFields().forEach((key: string | number, value: any[]) => {
|
||||
this._responseHeaders[key + ''] = Java.from(value)
|
||||
})
|
||||
}
|
||||
|
||||
private setReadyState(state: ReadyState) {
|
||||
this._readyState = state
|
||||
this.onreadystatechange && this.onreadystatechange()
|
||||
this.onreadystatechange?.()
|
||||
}
|
||||
|
||||
private readOutput(input: any) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ccms/protocol",
|
||||
"version": "0.18.0",
|
||||
"version": "0.28.0-beta.2",
|
||||
"description": "MiaoScript protocol package",
|
||||
"keywords": [
|
||||
"miaoscript",
|
||||
@@ -21,7 +21,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.5.5"
|
||||
"rimraf": "^4.1.2",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
}
|
||||
|
||||
26
packages/qrcode/package.json
Normal file
26
packages/qrcode/package.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "@ccms/qrcode",
|
||||
"version": "0.28.0-beta.2",
|
||||
"description": "MiaoScript qrcode package",
|
||||
"keywords": [
|
||||
"miaoscript",
|
||||
"minecraft",
|
||||
"bukkit",
|
||||
"sponge"
|
||||
],
|
||||
"author": "MiaoWoo <admin@yumc.pw>",
|
||||
"homepage": "https://github.com/circlecloud/ms.git",
|
||||
"license": "ISC",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"clean": "rimraf dist",
|
||||
"watch": "tsc --watch",
|
||||
"build": "yarn clean && tsc",
|
||||
"test": "echo \"Error: run tests from root\" && exit 1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"reflect-metadata": "^0.1.13",
|
||||
"rimraf": "^4.1.2",
|
||||
"typescript": "^4.9.5"
|
||||
}
|
||||
}
|
||||
1243
packages/qrcode/src/index.ts
Normal file
1243
packages/qrcode/src/index.ts
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user