feat: 新增Native插件管理
Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
parent
a3cbe455a1
commit
ad85c3bc9b
@ -27,7 +27,8 @@ export class MiaoScriptConsole implements Console {
|
|||||||
private _level: LogLevel = LogLevel.INFO
|
private _level: LogLevel = LogLevel.INFO
|
||||||
|
|
||||||
protected logger: any
|
protected logger: any
|
||||||
protected prefix: string = '§6[§bMiaoScript§6]§r '
|
|
||||||
|
public prefix: string = '§6[§bMiaoScript§6]§r '
|
||||||
|
|
||||||
constructor(name?: string) {
|
constructor(name?: string) {
|
||||||
this.name = name
|
this.name = name
|
||||||
@ -47,10 +48,10 @@ export class MiaoScriptConsole implements Console {
|
|||||||
set name(name: string) {
|
set name(name: string) {
|
||||||
if (name) {
|
if (name) {
|
||||||
this._name = `[${name}] `
|
this._name = `[${name}] `
|
||||||
// noinspection JSUnusedGlobalSymbols
|
|
||||||
this.prefix = `§6[§cMS§6][§b${name}§6]§r `
|
this.prefix = `§6[§cMS§6][§b${name}§6]§r `
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log(...args: any[]): void {
|
log(...args: any[]): void {
|
||||||
this.logger.info(this.name + args.join(' '))
|
this.logger.info(this.name + args.join(' '))
|
||||||
}
|
}
|
||||||
|
@ -12,4 +12,5 @@ export * from './console'
|
|||||||
export * from './channel'
|
export * from './channel'
|
||||||
export * from './command'
|
export * from './command'
|
||||||
export * from './database'
|
export * from './database'
|
||||||
|
export * from './particle'
|
||||||
export * from './constants'
|
export * from './constants'
|
||||||
|
@ -18,9 +18,15 @@ export namespace server {
|
|||||||
export const ServerInstance = Symbol("ServerInstance")
|
export const ServerInstance = Symbol("ServerInstance")
|
||||||
@injectable()
|
@injectable()
|
||||||
export abstract class NativePluginManager {
|
export abstract class NativePluginManager {
|
||||||
|
list(): any[] {
|
||||||
|
throw new Error("Method not implemented.")
|
||||||
|
}
|
||||||
has(name: string): boolean {
|
has(name: string): boolean {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
get(name: string): any {
|
||||||
|
throw new Error("Method not implemented.")
|
||||||
|
}
|
||||||
load(name: string): boolean {
|
load(name: string): boolean {
|
||||||
throw new Error("Method not implemented.")
|
throw new Error("Method not implemented.")
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ export namespace task {
|
|||||||
* 提交任务
|
* 提交任务
|
||||||
* @param args 任务参数
|
* @param args 任务参数
|
||||||
*/
|
*/
|
||||||
submit(...args: any[]): Cancelable {
|
submit(...args: any[]): task.Task {
|
||||||
this.innerTask = this.submit0(...args)
|
this.innerTask = this.submit0(...args)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,12 @@ import './chat'
|
|||||||
import './task'
|
import './task'
|
||||||
import './event'
|
import './event'
|
||||||
import './server'
|
import './server'
|
||||||
|
import { BukkitNativePluginManager } from './plugin'
|
||||||
import './command'
|
import './command'
|
||||||
import './channel'
|
import './channel'
|
||||||
|
import './particle'
|
||||||
|
|
||||||
export default function BukkitImpl(container: Container) {
|
export default function BukkitImpl(container: Container) {
|
||||||
container.bind(server.Console).toConstantValue(BukkitConsole)
|
container.bind(server.Console).toConstantValue(BukkitConsole)
|
||||||
|
container.rebind(server.NativePluginManager).toConstantValue(new BukkitNativePluginManager())
|
||||||
}
|
}
|
||||||
|
12
packages/bukkit/src/plugin.ts
Normal file
12
packages/bukkit/src/plugin.ts
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -3,13 +3,15 @@
|
|||||||
import { server } from '@ccms/api'
|
import { server } from '@ccms/api'
|
||||||
import { Container } from '@ccms/container'
|
import { Container } from '@ccms/container'
|
||||||
|
|
||||||
import { BungeeConsole } from './console';
|
import { BungeeConsole } from './console'
|
||||||
import './event';
|
import './task'
|
||||||
import './server';
|
import './event'
|
||||||
import './command';
|
import './server'
|
||||||
import './channel';
|
import { BungeeNativePluginManager } from './plugin'
|
||||||
import './task';
|
import './command'
|
||||||
|
import './channel'
|
||||||
|
|
||||||
export default function BungeeImpl(container: Container) {
|
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())
|
||||||
}
|
}
|
||||||
|
12
packages/bungee/src/plugin.ts
Normal file
12
packages/bungee/src/plugin.ts
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -1,13 +1,13 @@
|
|||||||
/// <reference types="@ccms/nashorn" />
|
/// <reference types="@ccms/nashorn" />
|
||||||
import * as yaml from 'js-yaml'
|
import * as yaml from 'js-yaml'
|
||||||
|
|
||||||
const File = Java.type("java.io.File");
|
const File = Java.type("java.io.File")
|
||||||
const separatorChar = File.separatorChar;
|
const separatorChar = File.separatorChar
|
||||||
type TranslateParam = { [key: string]: any }
|
type TranslateParam = { [key: string]: any }
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Console {
|
interface Console {
|
||||||
i18n(name: string, param?: TranslateParam);
|
i18n(name: string, param?: TranslateParam)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,20 +23,20 @@ export class Translate {
|
|||||||
|
|
||||||
constructor(root: string | TranslateContent) {
|
constructor(root: string | TranslateContent) {
|
||||||
if (typeof root == 'string') {
|
if (typeof root == 'string') {
|
||||||
this.root = root;
|
this.root = root
|
||||||
} else {
|
} else {
|
||||||
this.langMap = root.langMap;
|
this.langMap = root.langMap
|
||||||
this.fallbackMap = root.fallbackMap || {};
|
this.fallbackMap = root.fallbackMap || {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
translate(name: string, param?: TranslateParam) {
|
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 }
|
if (!langText) { return '[WARN] @ccms/i18n miss lang translate: ' + name }
|
||||||
for (const key in param) {
|
for (const key in param) {
|
||||||
langText = langText.replace(new RegExp("{" + key + "}", 'gm'), param[key])
|
langText = langText.replace(new RegExp("{" + key + "}", 'gm'), param[key])
|
||||||
}
|
}
|
||||||
return langText;
|
return langText
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize(lang: string = 'zh_cn', fallback: string = 'zh_cn') {
|
initialize(lang: string = 'zh_cn', fallback: string = 'zh_cn') {
|
||||||
@ -49,7 +49,7 @@ export class Translate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
readYamlFile(dir: string, name: string) {
|
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))
|
return this.exists(langFile) && yaml.safeLoad(base.read(langFile))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +74,7 @@ declare global {
|
|||||||
delete(path: string): void
|
delete(path: string): void
|
||||||
}
|
}
|
||||||
interface Console {
|
interface Console {
|
||||||
|
prefix: string
|
||||||
ex(err: Error): void
|
ex(err: Error): void
|
||||||
stack(err: Error, color?: boolean): string[]
|
stack(err: Error, color?: boolean): string[]
|
||||||
sender(sender: any, ...args: any): void
|
sender(sender: any, ...args: any): void
|
||||||
|
@ -3,12 +3,14 @@
|
|||||||
import { server } from '@ccms/api'
|
import { server } from '@ccms/api'
|
||||||
import { Container } from '@ccms/container'
|
import { Container } from '@ccms/container'
|
||||||
|
|
||||||
import { NukkitConsole } from './console';
|
import { NukkitConsole } from './console'
|
||||||
import './event';
|
import './task'
|
||||||
import './server';
|
import './event'
|
||||||
import './command';
|
import './server'
|
||||||
import './task';
|
import { NukkitNativePluginManager } from './plugin'
|
||||||
|
import './command'
|
||||||
|
|
||||||
export default function NukkitImpl(container: Container) {
|
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())
|
||||||
}
|
}
|
||||||
|
12
packages/nukkit/src/plugin.ts
Normal file
12
packages/nukkit/src/plugin.ts
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -42,9 +42,8 @@ class Process extends EventEmitter {
|
|||||||
}
|
}
|
||||||
exit(code: number) {
|
exit(code: number) {
|
||||||
process.emit('exit', code)
|
process.emit('exit', code)
|
||||||
microTaskPool.shutdown()
|
console.log(`process exit await microTaskPool termination! queueTask: ${microTaskPool.shutdownNow().size()} remainTask: ${threadGroup.activeCount()}`)
|
||||||
console.log('process exit await microTaskPool termination...')
|
microTaskPool.awaitTermination(3000, TimeUnit.MILLISECONDS)
|
||||||
microTaskPool.awaitTermination(5000, TimeUnit.MILLISECONDS)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { command, plugin, server } from '@ccms/api'
|
import { command, plugin, server } from '@ccms/api'
|
||||||
import { provideSingleton, Autowired } from '@ccms/container'
|
import { provideSingleton, Autowired } from '@ccms/container'
|
||||||
|
import { interfaces } from './interfaces'
|
||||||
import { getPluginCommandMetadata, getPluginTabCompleterMetadata } from './utils'
|
import { getPluginCommandMetadata, getPluginTabCompleterMetadata } from './utils'
|
||||||
|
|
||||||
@provideSingleton(PluginCommandManager)
|
@provideSingleton(PluginCommandManager)
|
||||||
@ -23,11 +24,10 @@ export class PluginCommandManager {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for (let command of [cmd.name, ...cmd.alias]) {
|
for (let command of [cmd.name, ...cmd.alias]) {
|
||||||
|
let [cmdExecutor, cmdCompleter] = this.generateAutoMainCommand(pluginInstance, cmd, tabs.get(command))
|
||||||
this.CommandManager.on(pluginInstance, command, {
|
this.CommandManager.on(pluginInstance, command, {
|
||||||
cmd: pluginInstance[cmd.executor].bind(pluginInstance),
|
cmd: cmdExecutor.bind(pluginInstance),
|
||||||
tab: tabs.has(command) ?
|
tab: cmdCompleter?.bind(pluginInstance)
|
||||||
pluginInstance[tabs.get(command).executor].bind(pluginInstance) :
|
|
||||||
console.debug(`[${pluginInstance.description.name}] command ${cmd.name} is not registry tabCompleter`)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -37,4 +37,29 @@ export class PluginCommandManager {
|
|||||||
let cmds = getPluginCommandMetadata(pluginInstance)
|
let cmds = getPluginCommandMetadata(pluginInstance)
|
||||||
cmds.forEach(cmd => this.CommandManager.off(pluginInstance, cmd.name))
|
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]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,10 @@ export namespace interfaces {
|
|||||||
* 参数列表
|
* 参数列表
|
||||||
*/
|
*/
|
||||||
paramtypes?: string[]
|
paramtypes?: string[]
|
||||||
|
/**
|
||||||
|
* 自动化主命令
|
||||||
|
*/
|
||||||
|
autoMain?: boolean
|
||||||
}
|
}
|
||||||
export interface ListenerMetadata extends ExecMetadata {
|
export interface ListenerMetadata extends ExecMetadata {
|
||||||
/**
|
/**
|
||||||
|
@ -233,21 +233,25 @@ export class PluginManagerImpl implements plugin.PluginManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private checkDepends(depends: string | string[]) {
|
private checkDepends(depends: string | string[]) {
|
||||||
if (!depends) return true
|
if (!depends) return []
|
||||||
for (const depend of depends) { if (!this.metadataMap.has(depend)) return false }
|
let loseDepends = []
|
||||||
return true
|
for (const depend of depends) { if (!this.metadataMap.has(depend)) loseDepends.push(depend) }
|
||||||
|
return loseDepends
|
||||||
}
|
}
|
||||||
private checkNativeDepends(depends: string | string[]) {
|
private checkNativeDepends(depends: string | string[]) {
|
||||||
if (!depends) return true
|
if (!depends) return []
|
||||||
for (const depend of depends) { if (!this.nativePluginManager.has(depend)) return false }
|
let loseDepends = []
|
||||||
return true
|
for (const depend of depends) { if (!this.nativePluginManager.has(depend)) loseDepends.push(depend) }
|
||||||
|
return loseDepends
|
||||||
}
|
}
|
||||||
private buildPlugin(metadata: plugin.PluginMetadata) {
|
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.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.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.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是否安装完整!`) }
|
let loseDepends = this.checkDepends(metadata.depends) || []
|
||||||
if (!this.checkNativeDepends(metadata.nativeDepends)) { throw new Error(`§4无法加载插件 §b${metadata.name} §4请检查插件依赖 §3${metadata.nativeDepends.join(',')} §4是否安装完整!`) }
|
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)
|
let pluginInstance = this.loaderMap.get(metadata.type).build(metadata)
|
||||||
if (!pluginInstance) { throw new Error(`§4加载器 §c${metadata.type} §4加载插件 §c${metadata.name} §4失败!`) }
|
if (!pluginInstance) { throw new Error(`§4加载器 §c${metadata.type} §4加载插件 §c${metadata.name} §4失败!`) }
|
||||||
this.instanceMap.set(metadata.name, pluginInstance)
|
this.instanceMap.set(metadata.name, pluginInstance)
|
||||||
|
@ -8,9 +8,12 @@ import './chat'
|
|||||||
import './task'
|
import './task'
|
||||||
import './event'
|
import './event'
|
||||||
import './server'
|
import './server'
|
||||||
|
import { SpongeNativePluginManager } from './plugin'
|
||||||
import './command'
|
import './command'
|
||||||
import './channel'
|
import './channel'
|
||||||
|
import './particle'
|
||||||
|
|
||||||
export default function SpongeImpl(container: Container) {
|
export default function SpongeImpl(container: Container) {
|
||||||
container.bind(server.Console).toConstantValue(SpongeConsole)
|
container.bind(server.Console).toConstantValue(SpongeConsole)
|
||||||
|
container.rebind(server.NativePluginManager).toConstantValue(new SpongeNativePluginManager())
|
||||||
}
|
}
|
||||||
|
12
packages/sponge/src/plugin.ts
Normal file
12
packages/sponge/src/plugin.ts
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user