diff --git a/packages/api/package.json b/packages/api/package.json index d99d0d4a..25cf6550 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -24,9 +24,11 @@ "dependencies": { "@ms/container": "^0.4.0", "@ms/ployfill": "^0.4.2", + "base64-js": "^1.3.1", "source-map-builder": "^0.0.7" }, "devDependencies": { + "@types/base64-js": "^1.2.5", "reflect-metadata": "^0.1.13", "rimraf": "^3.0.2", "typescript": "^3.8.3" diff --git a/packages/api/src/console.ts b/packages/api/src/console.ts index 3e1e8648..31c85a7c 100644 --- a/packages/api/src/console.ts +++ b/packages/api/src/console.ts @@ -1,10 +1,9 @@ import i18m from '@ms/i18n' import { SourceMapBuilder } from 'source-map-builder' +import * as base64 from 'base64-js' const Arrays = Java.type('java.util.Arrays'); const Level = Java.type('java.util.logging.Level'); -const JavaString = Java.type('java.lang.String'); -const Files = Java.type('java.nio.file.Files'); const Paths = Java.type('java.nio.file.Paths'); const ignoreLogPrefix = ['java.', 'net.minecraft.', 'org.bukkit.', 'jdk.nashorn.', 'io.netty.', 'org.spongepowered.']; @@ -23,6 +22,7 @@ export class MiaoScriptConsole implements Console { Console: NodeJS.ConsoleConstructor; private sourceMaps: { [key: string]: SourceMapBuilder } = {}; + private sourceFileMaps: { [key: string]: string } = {}; private _name: string = ''; private _level: LogLevel = LogLevel.INFO; @@ -83,7 +83,7 @@ export class MiaoScriptConsole implements Console { this.console(i18m.translate(name, param)) } object(obj) { - for (var i in obj) { + for (const i in obj) { this.info(i, '=>', obj[i]) } } @@ -93,23 +93,31 @@ export class MiaoScriptConsole implements Console { readSourceMap(fileName: string, lineNumber: number) { try { if (fileName.endsWith('js')) { - var file = Paths.get(fileName + '.map'); if (this.sourceMaps[fileName] === undefined) { - if (file.toFile().exists()) { - var sourceMapObj = JSON.parse(new JavaString(Files.readAllBytes(file), "UTF-8")) - this.sourceMaps[fileName] = new SourceMapBuilder(sourceMapObj) - } else { - this.sourceMaps[fileName] = null; + this.sourceMaps[fileName] = null + let sourceLine = base.read(fileName).split('\n'); + let lastLine = sourceLine[sourceLine.length - 1] + 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')) { + // TODO + } else { + let file = Paths.get(Paths.get(fileName, '..', sourceMappingURL).toFile().getCanonicalPath()).toFile(); + if (file.exists()) { sourceContent = base.read(file) } + } + if (sourceContent) { + this.sourceMaps[fileName] = new SourceMapBuilder(JSON.parse(sourceContent)) + this.sourceFileMaps[fileName] = Paths.get(fileName, '..', this.sourceMaps[fileName].sources[0]).toFile().getCanonicalPath(); + } } } if (this.sourceMaps[fileName]) { - var sourceMapping = this.sourceMaps[fileName].getSource(lineNumber, 25, true); - if (sourceMapping) { - if (lineNumber != sourceMapping.mapping.sourceLine) { - fileName = fileName.replace(".js", ".ts"); - lineNumber = sourceMapping.mapping.sourceLine; - } - } + let sourceMapping = this.sourceMaps[fileName].getSource(lineNumber, 25, true, true); + fileName = this.sourceFileMaps[fileName] + if (sourceMapping && lineNumber != sourceMapping.mapping.sourceLine) { lineNumber = sourceMapping.mapping.sourceLine; } } } } catch (error) { @@ -121,26 +129,26 @@ export class MiaoScriptConsole implements Console { } } stack(ex: Error): string[] { - var stack = ex.getStackTrace(); - var cache = ['§c' + ex]; + let stack = ex.getStackTrace(); + let cache = ['§c' + ex]; //@ts-ignore if (stack.class) { stack = Arrays.asList(stack) } stack.forEach(trace => { if (trace.className.startsWith('<')) { - var { fileName, lineNumber } = this.readSourceMap(trace.fileName, trace.lineNumber) + let { fileName, lineNumber } = this.readSourceMap(trace.fileName, trace.lineNumber) if (fileName.startsWith(root)) { fileName = fileName.split(root)[1] } cache.push(` §e->§c ${fileName} => §4${trace.methodName}:${lineNumber}`) } else { - var className = trace.className; + let className = trace.className; var fileName = trace.fileName as string; if (className.startsWith('jdk.nashorn.internal.scripts')) { className = className.substr(className.lastIndexOf('$') + 1) var { fileName, lineNumber } = this.readSourceMap(trace.fileName, trace.lineNumber) if (fileName.startsWith(root)) { fileName = fileName.split(root)[1] } } else { - for (var prefix in ignoreLogPrefix) { + for (let prefix in ignoreLogPrefix) { if (className.startsWith(ignoreLogPrefix[prefix])) { return; } diff --git a/packages/api/src/constants.ts b/packages/api/src/constants.ts new file mode 100644 index 00000000..b4bc54a0 --- /dev/null +++ b/packages/api/src/constants.ts @@ -0,0 +1,16 @@ +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'] + } + 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'] + } + } + export enum ServerType { + Bukkit = 'bukkit', + Sponge = 'sponge', + Nukkit = 'nukkit', + Bungee = 'bungee' + } +} diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index b0104af1..4ca3b648 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -4,4 +4,5 @@ export * from './event' export * from './console' export * from './channel' export * from './command' +export * from './constants' export * from './interfaces' diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 876481b2..8a772221 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,6 +1,6 @@ let containerStartTime = Date.now(); console.i18n("ms.core.ioc.initialize"); -import { plugin, server, task } from '@ms/api' +import { plugin, server, task, constants } from '@ms/api' import { DefaultContainer as container, inject, provideSingleton, ContainerInstance, buildProviderModule } from '@ms/container' console.i18n("ms.core.ioc.completed", { time: (Date.now() - containerStartTime) / 1000 }) @@ -24,15 +24,13 @@ class MiaoScriptCore { } loadServerConsole() { - // @ts-ignore - console = new this.Console(); + //@ts-ignore + global.setGlobal('console', new this.Console()) } loadTaskFunction() { - //@ts-ignore - global.setTimeout = (func: Function, tick: number, async: boolean = false) => this.taskManager.create(func).later(tick).async(async).submit() - //@ts-ignore - global.setInterval = (func: Function, tick: number, async: boolean = false) => this.taskManager.create(func).timer(tick).async(async).submit() + global.setGlobal('setTimeout', (func: Function, tick: number, async: boolean = false) => this.taskManager.create(func).later(tick).async(async).submit()) + global.setGlobal('setInterval', (func: Function, tick: number, async: boolean = false) => this.taskManager.create(func).timer(tick).async(async).submit()) } loadPlugins() { @@ -49,49 +47,57 @@ class MiaoScriptCore { console.i18n("ms.core.engine.disable") this.pluginManager.disable(); this.taskManager.disable(); + //@ts-ignore + require.disable() } } -function detectServer() { +function detectServer(): constants.ServerType { try { Java.type("org.bukkit.Bukkit"); - return 'bukkit' + return constants.ServerType.Bukkit } catch (ex) { } try { Java.type("org.spongepowered.api.Sponge"); - return 'sponge' + return constants.ServerType.Sponge } catch (ex) { } try { Java.type("cn.nukkit.Nukkit"); - return 'nukkit' + return constants.ServerType.Nukkit } catch (ex) { } try { Java.type("net.md_5.bungee.api.ProxyServer"); - return 'bungee' + return constants.ServerType.Bungee } catch (ex) { } throw Error('Unknow Server Type...') } function initialize() { - 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", { type }); - container.bind(server.ServerType).toConstantValue(type); - console.i18n("ms.core.package.initialize", { type }); - require(`@ms/${type}`).default(container); - require('@ms/plugin') - container.load(buildProviderModule()); - console.i18n("ms.core.package.completed", { type, time: (Date.now() - corePackageStartTime) / 1000 }); - let disable = container.get(MiaoScriptCore).enable() - console.i18n("ms.core.engine.completed", { time: (Date.now() - global.NashornEngineStartTime) / 1000 }); - return disable; + 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", { type }); + container.bind(server.ServerType).toConstantValue(type); + console.i18n("ms.core.package.initialize", { type }); + require(`@ms/${type}`).default(container); + require('@ms/plugin') + container.load(buildProviderModule()); + console.i18n("ms.core.package.completed", { type, time: (Date.now() - corePackageStartTime) / 1000 }); + let disable = container.get(MiaoScriptCore).enable() + console.i18n("ms.core.engine.completed", { time: (Date.now() - global.NashornEngineStartTime) / 1000 }); + return disable; + } catch (error) { + console.i18n("ms.core.initialize.error", { error }); + console.ex(error) + return () => console.i18n('ms.core.engine.disable.abnormal') + } } export default initialize(); diff --git a/packages/i18n/languages/en.yml b/packages/i18n/languages/en.yml index 3c38263e..0ae1366b 100644 --- a/packages/i18n/languages/en.yml +++ b/packages/i18n/languages/en.yml @@ -4,12 +4,14 @@ ms.ployfill.completed: "Java Nashorn ployfill loading completed... Cost ({time}s ms.core.ioc.initialize: "Initialization MiaoScript IOC Container @ms/container. Please wait..." ms.core.ioc.completed: "MiaoScript IOC Container @ms/container loading completed({time}s)!" ms.core.initialize.detect: "Detect Compatible Server set ServerType to {type} ..." +ms.core.initialize.error: "MiaoScript Engine Initialization Error: {error} ..." ms.core.package.initialize: "Initialization MiaoScript Package @ms/core @ms/{type} @ms/plugin. Please wait..." ms.core.package.completed: "MiaoScript Package @ms/core @ms/{type} @ms/plugin loading completed({time}s)!" 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.abnormal: "abnormal Initialization MiaoScript Engine. Skip disable step..." ms.api.event.resource.not.found: "Can't Mapping Event Because not found Resources {resource}!" ms.api.event.empty.event.dir: "base event dir is empty, can't map event name !" @@ -26,7 +28,7 @@ ms.api.command.unregister: "[{plugin}] unregister command {name}..." ms.api.command.execute.error: "§6Player {player} §6exec §b{plugin} §6Plugin Command §d{command} {args} §6error §4{ex}" 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} ..." +ms.plugin.initialize: "Initialization MiaoScript Plugin System: Plugin: {plugin} Loader: {loader}..." ms.plugin.event.map: "Total {count} {type} Event Mapping Complate..." ms.plugin.manager.scan: "Scanning Plugins in {folder} ..." ms.plugin.manager.initialize.error: "§6Plugin §b{name} §6initialize error §4{ex}" diff --git a/packages/i18n/languages/zh_cn.yml b/packages/i18n/languages/zh_cn.yml index 2e091d43..95b2299d 100644 --- a/packages/i18n/languages/zh_cn.yml +++ b/packages/i18n/languages/zh_cn.yml @@ -4,12 +4,14 @@ ms.ployfill.completed: "Java Nashorn 补丁 加载完成... 耗时 ({time}s)!" ms.core.ioc.initialize: "初始化 MiaoScript IOC 容器 @ms/container. 请稍候..." ms.core.ioc.completed: "MiaoScript IOC 容器 @ms/container 加载完成 耗时({time}s)" ms.core.initialize.detect: "检测到兼容的服务器类型. 设置 ServerType 值 {type} ..." +ms.core.initialize.error: "§4MiaoScript 系统初始化失败 §c{error} ..." ms.core.package.initialize: "初始化 MiaoScript 扩展 @ms/core @ms/{type} @ms/plugin. 请稍候..." ms.core.package.completed: "MiaoScript 扩展 @ms/core @ms/{type} @ms/plugin 加载完成 耗时({time}s)" ms.core.plugin.initialize: "MiaoScript 开始引导插件系统. 请稍候..." ms.core.plugin.completed: "MiaoScript 插件加载完毕 耗时({time}s)!" ms.core.engine.completed: "MiaoScript 脚本引擎 加载完毕... 耗时({time}s)!" ms.core.engine.disable: "关闭 MiaoScript 引擎..." +ms.core.engine.disable.abnormal: "引擎异常启动或初始化未完成 跳过关闭流程..." ms.api.event.resource.not.found: "无法映射事件 未找到资源文件 {resource}!" ms.api.event.empty.event.dir: "事件基础目录为空, 无法映射事件!" @@ -26,7 +28,7 @@ ms.api.command.unregister: "[{plugin}] 注销命令 {name}..." ms.api.command.execute.error: "§6玩家 §a{player} §6执行 §b{plugin} §6插件 §d{command} {args} §6命令时发生异常 §4{ex}" ms.api.command.tab.completer.error: "§6玩家 §a{player} §6执行 §b{plugin} §6插件 §d{command} {args} §6补全时发生异常 §4{ex}" -ms.plugin.initialize: "初始化 MiaoScript 插件系统: {plugin} ..." +ms.plugin.initialize: "初始化 MiaoScript 插件系统: 实例: {plugin} 加载器: {loader}..." ms.plugin.event.map: "总计 {count} 个 {type} 事件 映射完成..." ms.plugin.manager.scan: "扫描 {folder} 文件夹中插件..." ms.plugin.manager.initialize.error: "§6插件 §b{name} §6初始化错误 §4{ex}"