feat: support base64 source map
Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
parent
13a3611ebd
commit
d53287fc51
@ -24,9 +24,11 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ms/container": "^0.4.0",
|
"@ms/container": "^0.4.0",
|
||||||
"@ms/ployfill": "^0.4.2",
|
"@ms/ployfill": "^0.4.2",
|
||||||
|
"base64-js": "^1.3.1",
|
||||||
"source-map-builder": "^0.0.7"
|
"source-map-builder": "^0.0.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/base64-js": "^1.2.5",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.8.3"
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import i18m from '@ms/i18n'
|
import i18m from '@ms/i18n'
|
||||||
import { SourceMapBuilder } from 'source-map-builder'
|
import { SourceMapBuilder } from 'source-map-builder'
|
||||||
|
import * as base64 from 'base64-js'
|
||||||
|
|
||||||
const Arrays = Java.type('java.util.Arrays');
|
const Arrays = Java.type('java.util.Arrays');
|
||||||
const Level = Java.type('java.util.logging.Level');
|
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 Paths = Java.type('java.nio.file.Paths');
|
||||||
const ignoreLogPrefix = ['java.', 'net.minecraft.', 'org.bukkit.', 'jdk.nashorn.', 'io.netty.', 'org.spongepowered.'];
|
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;
|
Console: NodeJS.ConsoleConstructor;
|
||||||
|
|
||||||
private sourceMaps: { [key: string]: SourceMapBuilder } = {};
|
private sourceMaps: { [key: string]: SourceMapBuilder } = {};
|
||||||
|
private sourceFileMaps: { [key: string]: string } = {};
|
||||||
private _name: string = '';
|
private _name: string = '';
|
||||||
private _level: LogLevel = LogLevel.INFO;
|
private _level: LogLevel = LogLevel.INFO;
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ export class MiaoScriptConsole implements Console {
|
|||||||
this.console(i18m.translate(name, param))
|
this.console(i18m.translate(name, param))
|
||||||
}
|
}
|
||||||
object(obj) {
|
object(obj) {
|
||||||
for (var i in obj) {
|
for (const i in obj) {
|
||||||
this.info(i, '=>', obj[i])
|
this.info(i, '=>', obj[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -93,23 +93,31 @@ export class MiaoScriptConsole implements Console {
|
|||||||
readSourceMap(fileName: string, lineNumber: number) {
|
readSourceMap(fileName: string, lineNumber: number) {
|
||||||
try {
|
try {
|
||||||
if (fileName.endsWith('js')) {
|
if (fileName.endsWith('js')) {
|
||||||
var file = Paths.get(fileName + '.map');
|
|
||||||
if (this.sourceMaps[fileName] === undefined) {
|
if (this.sourceMaps[fileName] === undefined) {
|
||||||
if (file.toFile().exists()) {
|
this.sourceMaps[fileName] = null
|
||||||
var sourceMapObj = JSON.parse(new JavaString(Files.readAllBytes(file), "UTF-8"))
|
let sourceLine = base.read(fileName).split('\n');
|
||||||
this.sourceMaps[fileName] = new SourceMapBuilder(sourceMapObj)
|
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 {
|
} else {
|
||||||
this.sourceMaps[fileName] = null;
|
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]) {
|
if (this.sourceMaps[fileName]) {
|
||||||
var sourceMapping = this.sourceMaps[fileName].getSource(lineNumber, 25, true);
|
let sourceMapping = this.sourceMaps[fileName].getSource(lineNumber, 25, true, true);
|
||||||
if (sourceMapping) {
|
fileName = this.sourceFileMaps[fileName]
|
||||||
if (lineNumber != sourceMapping.mapping.sourceLine) {
|
if (sourceMapping && lineNumber != sourceMapping.mapping.sourceLine) { lineNumber = sourceMapping.mapping.sourceLine; }
|
||||||
fileName = fileName.replace(".js", ".ts");
|
|
||||||
lineNumber = sourceMapping.mapping.sourceLine;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -121,26 +129,26 @@ export class MiaoScriptConsole implements Console {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
stack(ex: Error): string[] {
|
stack(ex: Error): string[] {
|
||||||
var stack = ex.getStackTrace();
|
let stack = ex.getStackTrace();
|
||||||
var cache = ['§c' + ex];
|
let cache = ['§c' + ex];
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
if (stack.class) {
|
if (stack.class) {
|
||||||
stack = Arrays.asList(stack)
|
stack = Arrays.asList(stack)
|
||||||
}
|
}
|
||||||
stack.forEach(trace => {
|
stack.forEach(trace => {
|
||||||
if (trace.className.startsWith('<')) {
|
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] }
|
if (fileName.startsWith(root)) { fileName = fileName.split(root)[1] }
|
||||||
cache.push(` §e->§c ${fileName} => §4${trace.methodName}:${lineNumber}`)
|
cache.push(` §e->§c ${fileName} => §4${trace.methodName}:${lineNumber}`)
|
||||||
} else {
|
} else {
|
||||||
var className = trace.className;
|
let className = trace.className;
|
||||||
var fileName = trace.fileName as string;
|
var fileName = trace.fileName as string;
|
||||||
if (className.startsWith('jdk.nashorn.internal.scripts')) {
|
if (className.startsWith('jdk.nashorn.internal.scripts')) {
|
||||||
className = className.substr(className.lastIndexOf('$') + 1)
|
className = className.substr(className.lastIndexOf('$') + 1)
|
||||||
var { fileName, lineNumber } = this.readSourceMap(trace.fileName, trace.lineNumber)
|
var { fileName, lineNumber } = this.readSourceMap(trace.fileName, trace.lineNumber)
|
||||||
if (fileName.startsWith(root)) { fileName = fileName.split(root)[1] }
|
if (fileName.startsWith(root)) { fileName = fileName.split(root)[1] }
|
||||||
} else {
|
} else {
|
||||||
for (var prefix in ignoreLogPrefix) {
|
for (let prefix in ignoreLogPrefix) {
|
||||||
if (className.startsWith(ignoreLogPrefix[prefix])) {
|
if (className.startsWith(ignoreLogPrefix[prefix])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
16
packages/api/src/constants.ts
Normal file
16
packages/api/src/constants.ts
Normal file
@ -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'
|
||||||
|
}
|
||||||
|
}
|
@ -4,4 +4,5 @@ export * from './event'
|
|||||||
export * from './console'
|
export * from './console'
|
||||||
export * from './channel'
|
export * from './channel'
|
||||||
export * from './command'
|
export * from './command'
|
||||||
|
export * from './constants'
|
||||||
export * from './interfaces'
|
export * from './interfaces'
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
let containerStartTime = Date.now();
|
let containerStartTime = Date.now();
|
||||||
console.i18n("ms.core.ioc.initialize");
|
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'
|
import { DefaultContainer as container, inject, provideSingleton, ContainerInstance, buildProviderModule } from '@ms/container'
|
||||||
console.i18n("ms.core.ioc.completed", { time: (Date.now() - containerStartTime) / 1000 })
|
console.i18n("ms.core.ioc.completed", { time: (Date.now() - containerStartTime) / 1000 })
|
||||||
|
|
||||||
@ -25,14 +25,12 @@ class MiaoScriptCore {
|
|||||||
|
|
||||||
loadServerConsole() {
|
loadServerConsole() {
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
console = new this.Console();
|
global.setGlobal('console', new this.Console())
|
||||||
}
|
}
|
||||||
|
|
||||||
loadTaskFunction() {
|
loadTaskFunction() {
|
||||||
//@ts-ignore
|
global.setGlobal('setTimeout', (func: Function, tick: number, async: boolean = false) => this.taskManager.create(func).later(tick).async(async).submit())
|
||||||
global.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())
|
||||||
//@ts-ignore
|
|
||||||
global.setInterval = (func: Function, tick: number, async: boolean = false) => this.taskManager.create(func).timer(tick).async(async).submit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadPlugins() {
|
loadPlugins() {
|
||||||
@ -49,34 +47,37 @@ class MiaoScriptCore {
|
|||||||
console.i18n("ms.core.engine.disable")
|
console.i18n("ms.core.engine.disable")
|
||||||
this.pluginManager.disable();
|
this.pluginManager.disable();
|
||||||
this.taskManager.disable();
|
this.taskManager.disable();
|
||||||
|
//@ts-ignore
|
||||||
|
require.disable()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function detectServer() {
|
function detectServer(): constants.ServerType {
|
||||||
try {
|
try {
|
||||||
Java.type("org.bukkit.Bukkit");
|
Java.type("org.bukkit.Bukkit");
|
||||||
return 'bukkit'
|
return constants.ServerType.Bukkit
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Java.type("org.spongepowered.api.Sponge");
|
Java.type("org.spongepowered.api.Sponge");
|
||||||
return 'sponge'
|
return constants.ServerType.Sponge
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Java.type("cn.nukkit.Nukkit");
|
Java.type("cn.nukkit.Nukkit");
|
||||||
return 'nukkit'
|
return constants.ServerType.Nukkit
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Java.type("net.md_5.bungee.api.ProxyServer");
|
Java.type("net.md_5.bungee.api.ProxyServer");
|
||||||
return 'bungee'
|
return constants.ServerType.Bungee
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
}
|
}
|
||||||
throw Error('Unknow Server Type...')
|
throw Error('Unknow Server Type...')
|
||||||
}
|
}
|
||||||
|
|
||||||
function initialize() {
|
function initialize() {
|
||||||
|
try {
|
||||||
let corePackageStartTime = new Date().getTime()
|
let corePackageStartTime = new Date().getTime()
|
||||||
container.bind(ContainerInstance).toConstantValue(container);
|
container.bind(ContainerInstance).toConstantValue(container);
|
||||||
container.bind(plugin.PluginInstance).toConstantValue(base.getInstance());
|
container.bind(plugin.PluginInstance).toConstantValue(base.getInstance());
|
||||||
@ -92,6 +93,11 @@ function initialize() {
|
|||||||
let disable = container.get<MiaoScriptCore>(MiaoScriptCore).enable()
|
let disable = container.get<MiaoScriptCore>(MiaoScriptCore).enable()
|
||||||
console.i18n("ms.core.engine.completed", { time: (Date.now() - global.NashornEngineStartTime) / 1000 });
|
console.i18n("ms.core.engine.completed", { time: (Date.now() - global.NashornEngineStartTime) / 1000 });
|
||||||
return disable;
|
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();
|
export default initialize();
|
||||||
|
@ -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.initialize: "Initialization MiaoScript IOC Container @ms/container. Please wait..."
|
||||||
ms.core.ioc.completed: "MiaoScript IOC Container @ms/container loading completed({time}s)!"
|
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.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.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.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.initialize: "Initialization MiaoScript Plugin System. Please wait..."
|
||||||
ms.core.plugin.completed: "MiaoScript Plugin System loading completed({time}s)!"
|
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.completed: "MiaoScript ScriptEngine loading completed... Done({time}s)!"
|
||||||
ms.core.engine.disable: "Disable MiaoScript Engine..."
|
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.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 !"
|
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.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.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.event.map: "Total {count} {type} Event Mapping Complate..."
|
||||||
ms.plugin.manager.scan: "Scanning Plugins in {folder} ..."
|
ms.plugin.manager.scan: "Scanning Plugins in {folder} ..."
|
||||||
ms.plugin.manager.initialize.error: "§6Plugin §b{name} §6initialize error §4{ex}"
|
ms.plugin.manager.initialize.error: "§6Plugin §b{name} §6initialize error §4{ex}"
|
||||||
|
@ -4,12 +4,14 @@ ms.ployfill.completed: "Java Nashorn 补丁 加载完成... 耗时 ({time}s)!"
|
|||||||
ms.core.ioc.initialize: "初始化 MiaoScript IOC 容器 @ms/container. 请稍候..."
|
ms.core.ioc.initialize: "初始化 MiaoScript IOC 容器 @ms/container. 请稍候..."
|
||||||
ms.core.ioc.completed: "MiaoScript IOC 容器 @ms/container 加载完成 耗时({time}s)"
|
ms.core.ioc.completed: "MiaoScript IOC 容器 @ms/container 加载完成 耗时({time}s)"
|
||||||
ms.core.initialize.detect: "检测到兼容的服务器类型. 设置 ServerType 值 {type} ..."
|
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.initialize: "初始化 MiaoScript 扩展 @ms/core @ms/{type} @ms/plugin. 请稍候..."
|
||||||
ms.core.package.completed: "MiaoScript 扩展 @ms/core @ms/{type} @ms/plugin 加载完成 耗时({time}s)"
|
ms.core.package.completed: "MiaoScript 扩展 @ms/core @ms/{type} @ms/plugin 加载完成 耗时({time}s)"
|
||||||
ms.core.plugin.initialize: "MiaoScript 开始引导插件系统. 请稍候..."
|
ms.core.plugin.initialize: "MiaoScript 开始引导插件系统. 请稍候..."
|
||||||
ms.core.plugin.completed: "MiaoScript 插件加载完毕 耗时({time}s)!"
|
ms.core.plugin.completed: "MiaoScript 插件加载完毕 耗时({time}s)!"
|
||||||
ms.core.engine.completed: "MiaoScript 脚本引擎 加载完毕... 耗时({time}s)!"
|
ms.core.engine.completed: "MiaoScript 脚本引擎 加载完毕... 耗时({time}s)!"
|
||||||
ms.core.engine.disable: "关闭 MiaoScript 引擎..."
|
ms.core.engine.disable: "关闭 MiaoScript 引擎..."
|
||||||
|
ms.core.engine.disable.abnormal: "引擎异常启动或初始化未完成 跳过关闭流程..."
|
||||||
|
|
||||||
ms.api.event.resource.not.found: "无法映射事件 未找到资源文件 {resource}!"
|
ms.api.event.resource.not.found: "无法映射事件 未找到资源文件 {resource}!"
|
||||||
ms.api.event.empty.event.dir: "事件基础目录为空, 无法映射事件!"
|
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.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.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.event.map: "总计 {count} 个 {type} 事件 映射完成..."
|
||||||
ms.plugin.manager.scan: "扫描 {folder} 文件夹中插件..."
|
ms.plugin.manager.scan: "扫描 {folder} 文件夹中插件..."
|
||||||
ms.plugin.manager.initialize.error: "§6插件 §b{name} §6初始化错误 §4{ex}"
|
ms.plugin.manager.initialize.error: "§6插件 §b{name} §6初始化错误 §4{ex}"
|
||||||
|
Loading…
Reference in New Issue
Block a user