diff --git a/packages/api/src/console.ts b/packages/api/src/console.ts index e071c5ed..d0467144 100644 --- a/packages/api/src/console.ts +++ b/packages/api/src/console.ts @@ -27,7 +27,8 @@ export class MiaoScriptConsole implements Console { private _level: LogLevel = LogLevel.INFO protected logger: any - protected prefix: string = '§6[§bMiaoScript§6]§r ' + + public prefix: string = '§6[§bMiaoScript§6]§r ' constructor(name?: string) { this.name = name @@ -47,10 +48,10 @@ export class MiaoScriptConsole implements Console { set name(name: string) { if (name) { this._name = `[${name}] ` - // noinspection JSUnusedGlobalSymbols this.prefix = `§6[§cMS§6][§b${name}§6]§r ` } } + log(...args: any[]): void { this.logger.info(this.name + args.join(' ')) } diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index 4a0b3035..d5e087ff 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -12,4 +12,5 @@ export * from './console' export * from './channel' export * from './command' export * from './database' +export * from './particle' export * from './constants' diff --git a/packages/api/src/server.ts b/packages/api/src/server.ts index c721b7cb..fb302b8e 100644 --- a/packages/api/src/server.ts +++ b/packages/api/src/server.ts @@ -18,9 +18,15 @@ export namespace server { export const ServerInstance = Symbol("ServerInstance") @injectable() export abstract class NativePluginManager { + list(): any[] { + throw new Error("Method not implemented.") + } has(name: string): boolean { return true } + get(name: string): any { + throw new Error("Method not implemented.") + } load(name: string): boolean { throw new Error("Method not implemented.") } diff --git a/packages/api/src/task.ts b/packages/api/src/task.ts index da4d2dca..bae11bee 100644 --- a/packages/api/src/task.ts +++ b/packages/api/src/task.ts @@ -152,7 +152,7 @@ export namespace task { * 提交任务 * @param args 任务参数 */ - submit(...args: any[]): Cancelable { + submit(...args: any[]): task.Task { this.innerTask = this.submit0(...args) return this } diff --git a/packages/bukkit/src/index.ts b/packages/bukkit/src/index.ts index d0e331e1..1cddaca8 100644 --- a/packages/bukkit/src/index.ts +++ b/packages/bukkit/src/index.ts @@ -8,9 +8,12 @@ import './chat' import './task' import './event' import './server' +import { BukkitNativePluginManager } from './plugin' import './command' import './channel' +import './particle' export default function BukkitImpl(container: Container) { container.bind(server.Console).toConstantValue(BukkitConsole) + container.rebind(server.NativePluginManager).toConstantValue(new BukkitNativePluginManager()) } diff --git a/packages/bukkit/src/plugin.ts b/packages/bukkit/src/plugin.ts new file mode 100644 index 00000000..2a638928 --- /dev/null +++ b/packages/bukkit/src/plugin.ts @@ -0,0 +1,12 @@ +import { server } from '@ccms/api' + +const Bukkit = org.bukkit.Bukkit + +export class BukkitNativePluginManager extends server.NativePluginManager { + has(name: string) { + return !!this.get(name) + } + get(name: string) { + return Bukkit.getPluginManager().getPlugin(name) + } +} diff --git a/packages/bungee/src/index.ts b/packages/bungee/src/index.ts index c59e0955..3abbfdef 100644 --- a/packages/bungee/src/index.ts +++ b/packages/bungee/src/index.ts @@ -3,13 +3,15 @@ import { server } from '@ccms/api' import { Container } from '@ccms/container' -import { BungeeConsole } from './console'; -import './event'; -import './server'; -import './command'; -import './channel'; -import './task'; +import { BungeeConsole } from './console' +import './task' +import './event' +import './server' +import { BungeeNativePluginManager } from './plugin' +import './command' +import './channel' export default function BungeeImpl(container: Container) { - container.bind(server.Console).toConstantValue(BungeeConsole); + container.bind(server.Console).toConstantValue(BungeeConsole) + container.rebind(server.NativePluginManager).toConstantValue(new BungeeNativePluginManager()) } diff --git a/packages/bungee/src/plugin.ts b/packages/bungee/src/plugin.ts new file mode 100644 index 00000000..19fda2d5 --- /dev/null +++ b/packages/bungee/src/plugin.ts @@ -0,0 +1,12 @@ +import { server } from '@ccms/api' + +let Bungee: net.md_5.bungee.api.ProxyServer = base.getInstance().getProxy() + +export class BungeeNativePluginManager extends server.NativePluginManager { + has(name: string) { + return !!this.get(name) + } + get(name: string) { + return Bungee.getPluginManager().getPlugin(name) + } +} diff --git a/packages/i18n/src/index.ts b/packages/i18n/src/index.ts index 39501652..d5a8b652 100644 --- a/packages/i18n/src/index.ts +++ b/packages/i18n/src/index.ts @@ -1,13 +1,13 @@ /// import * as yaml from 'js-yaml' -const File = Java.type("java.io.File"); -const separatorChar = File.separatorChar; +const File = Java.type("java.io.File") +const separatorChar = File.separatorChar type TranslateParam = { [key: string]: any } declare global { interface Console { - i18n(name: string, param?: TranslateParam); + i18n(name: string, param?: TranslateParam) } } @@ -23,20 +23,20 @@ export class Translate { constructor(root: string | TranslateContent) { if (typeof root == 'string') { - this.root = root; + this.root = root } else { - this.langMap = root.langMap; - this.fallbackMap = root.fallbackMap || {}; + this.langMap = root.langMap + this.fallbackMap = root.fallbackMap || {} } } translate(name: string, param?: TranslateParam) { - let langText: string = this.langMap[name] || this.fallbackMap[name]; + let langText: string = this.langMap[name] || this.fallbackMap[name] if (!langText) { return '[WARN] @ccms/i18n miss lang translate: ' + name } for (const key in param) { langText = langText.replace(new RegExp("{" + key + "}", 'gm'), param[key]) } - return langText; + return langText } initialize(lang: string = 'zh_cn', fallback: string = 'zh_cn') { @@ -49,7 +49,7 @@ export class Translate { } readYamlFile(dir: string, name: string) { - let langFile = this.concat(dir, 'languages', name + '.yml'); + let langFile = this.concat(dir, 'languages', name + '.yml') return this.exists(langFile) && yaml.safeLoad(base.read(langFile)) } diff --git a/packages/nashorn/src/index.ts b/packages/nashorn/src/index.ts index e62ac3f7..0f9db70d 100644 --- a/packages/nashorn/src/index.ts +++ b/packages/nashorn/src/index.ts @@ -74,6 +74,7 @@ declare global { delete(path: string): void } interface Console { + prefix: string ex(err: Error): void stack(err: Error, color?: boolean): string[] sender(sender: any, ...args: any): void diff --git a/packages/nukkit/src/index.ts b/packages/nukkit/src/index.ts index 855dc4f9..23fadf3e 100644 --- a/packages/nukkit/src/index.ts +++ b/packages/nukkit/src/index.ts @@ -3,12 +3,14 @@ import { server } from '@ccms/api' import { Container } from '@ccms/container' -import { NukkitConsole } from './console'; -import './event'; -import './server'; -import './command'; -import './task'; +import { NukkitConsole } from './console' +import './task' +import './event' +import './server' +import { NukkitNativePluginManager } from './plugin' +import './command' export default function NukkitImpl(container: Container) { - container.bind(server.Console).toConstantValue(NukkitConsole); + container.bind(server.Console).toConstantValue(NukkitConsole) + container.bind(server.NativePluginManager).toConstantValue(new NukkitNativePluginManager()) } diff --git a/packages/nukkit/src/plugin.ts b/packages/nukkit/src/plugin.ts new file mode 100644 index 00000000..b13c58cc --- /dev/null +++ b/packages/nukkit/src/plugin.ts @@ -0,0 +1,12 @@ +import { server } from '@ccms/api' + +let Nukkit: cn.nukkit.Server = base.getInstance().getServer() + +export class NukkitNativePluginManager extends server.NativePluginManager { + has(name: string) { + return !!this.get(name) + } + get(name: string) { + return Nukkit.getPluginManager().getPlugin(name) + } +} diff --git a/packages/ployfill/src/node-shim.ts b/packages/ployfill/src/node-shim.ts index 5ccbfc25..a9efdd41 100644 --- a/packages/ployfill/src/node-shim.ts +++ b/packages/ployfill/src/node-shim.ts @@ -42,9 +42,8 @@ class Process extends EventEmitter { } exit(code: number) { process.emit('exit', code) - microTaskPool.shutdown() - console.log('process exit await microTaskPool termination...') - microTaskPool.awaitTermination(5000, TimeUnit.MILLISECONDS) + console.log(`process exit await microTaskPool termination! queueTask: ${microTaskPool.shutdownNow().size()} remainTask: ${threadGroup.activeCount()}`) + microTaskPool.awaitTermination(3000, TimeUnit.MILLISECONDS) } } diff --git a/packages/plugin/src/command.ts b/packages/plugin/src/command.ts index f10a4905..1d96f75d 100644 --- a/packages/plugin/src/command.ts +++ b/packages/plugin/src/command.ts @@ -1,5 +1,6 @@ import { command, plugin, server } from '@ccms/api' import { provideSingleton, Autowired } from '@ccms/container' +import { interfaces } from './interfaces' import { getPluginCommandMetadata, getPluginTabCompleterMetadata } from './utils' @provideSingleton(PluginCommandManager) @@ -23,11 +24,10 @@ export class PluginCommandManager { continue } for (let command of [cmd.name, ...cmd.alias]) { + let [cmdExecutor, cmdCompleter] = this.generateAutoMainCommand(pluginInstance, cmd, tabs.get(command)) this.CommandManager.on(pluginInstance, command, { - cmd: pluginInstance[cmd.executor].bind(pluginInstance), - tab: tabs.has(command) ? - pluginInstance[tabs.get(command).executor].bind(pluginInstance) : - console.debug(`[${pluginInstance.description.name}] command ${cmd.name} is not registry tabCompleter`) + cmd: cmdExecutor.bind(pluginInstance), + tab: cmdCompleter?.bind(pluginInstance) }) } } @@ -37,4 +37,29 @@ export class PluginCommandManager { let cmds = getPluginCommandMetadata(pluginInstance) cmds.forEach(cmd => this.CommandManager.off(pluginInstance, cmd.name)) } + + 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)) + if (cmd.autoMain) { + cmdExecutor = (sender: any, command: string, args: string[]) => { + let subcommand = args[0] || 'help' + let cmdKey = 'cmd' + subcommand + if (!pluginInstance[cmdKey]) { + console.sender(sender, '§4未知的子命令: §c' + subcommand) + pluginInstance['cmdhelp'] && console.sender(sender, `§6请执行 §b/${command} §ahelp §6查看帮助!`) + return + } + args.shift() + return pluginInstance[cmdKey].apply(pluginInstance, [sender, ...args]) + } + let originCompleter = cmdCompleter + cmdCompleter = (sender: any, command: string, args: string[]) => { + return (args.length == 1 ? cmdSubCache : []).concat(originCompleter?.apply(pluginInstance, [sender, command, args]) || []) + } + } + if (!cmdCompleter) { console.warn(`[${pluginInstance.description.name}] command ${cmd.name} is not registry tabCompleter`) } + return [cmdExecutor, cmdCompleter] + } } diff --git a/packages/plugin/src/interfaces.ts b/packages/plugin/src/interfaces.ts index 308894e0..1e27b1c3 100644 --- a/packages/plugin/src/interfaces.ts +++ b/packages/plugin/src/interfaces.ts @@ -47,6 +47,10 @@ export namespace interfaces { * 参数列表 */ paramtypes?: string[] + /** + * 自动化主命令 + */ + autoMain?: boolean } export interface ListenerMetadata extends ExecMetadata { /** diff --git a/packages/plugin/src/manager.ts b/packages/plugin/src/manager.ts index 000409bf..34bce018 100644 --- a/packages/plugin/src/manager.ts +++ b/packages/plugin/src/manager.ts @@ -233,21 +233,25 @@ export class PluginManagerImpl implements plugin.PluginManager { } private checkDepends(depends: string | string[]) { - if (!depends) return true - for (const depend of depends) { if (!this.metadataMap.has(depend)) return false } - return true + if (!depends) return [] + let loseDepends = [] + for (const depend of depends) { if (!this.metadataMap.has(depend)) loseDepends.push(depend) } + return loseDepends } private checkNativeDepends(depends: string | string[]) { - if (!depends) return true - for (const depend of depends) { if (!this.nativePluginManager.has(depend)) return false } - return true + if (!depends) return [] + let loseDepends = [] + for (const depend of depends) { if (!this.nativePluginManager.has(depend)) loseDepends.push(depend) } + return loseDepends } private buildPlugin(metadata: plugin.PluginMetadata) { 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忽略加载...`) } - if (!this.checkDepends(metadata.depends)) { throw new Error(`§4无法加载插件 §b${metadata.name} §4请检查依赖 §3${metadata.depends.join(',')} §4是否安装完整!`) } - if (!this.checkNativeDepends(metadata.nativeDepends)) { throw new Error(`§4无法加载插件 §b${metadata.name} §4请检查插件依赖 §3${metadata.nativeDepends.join(',')} §4是否安装完整!`) } + 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) diff --git a/packages/sponge/src/index.ts b/packages/sponge/src/index.ts index 06ed8b0f..953a5b11 100644 --- a/packages/sponge/src/index.ts +++ b/packages/sponge/src/index.ts @@ -8,9 +8,12 @@ import './chat' import './task' import './event' import './server' +import { SpongeNativePluginManager } from './plugin' import './command' import './channel' +import './particle' export default function SpongeImpl(container: Container) { container.bind(server.Console).toConstantValue(SpongeConsole) + container.rebind(server.NativePluginManager).toConstantValue(new SpongeNativePluginManager()) } diff --git a/packages/sponge/src/plugin.ts b/packages/sponge/src/plugin.ts new file mode 100644 index 00000000..7dff50e0 --- /dev/null +++ b/packages/sponge/src/plugin.ts @@ -0,0 +1,12 @@ +import { server } from '@ccms/api' + +const Sponge = org.spongepowered.api.Sponge + +export class SpongeNativePluginManager extends server.NativePluginManager { + has(name: string) { + return !!this.get(name) + } + get(name: string) { + return Sponge.getPluginManager().getPlugin(name).orElse(null) + } +}