release: v0.23.0
1. add item api 2. support rollup source map 3. fix database drvice error 4. support loliserver 5. support 1.19 bukkit chat 6. config add migrate options 7. Signed-off-by: MiaoWoo <admin@yumc.pw>
This commit is contained in:
		@@ -9,5 +9,8 @@
 | 
			
		||||
        "run": {
 | 
			
		||||
            "stream": true
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    "publishConfig": {
 | 
			
		||||
        "access": "public"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@
 | 
			
		||||
        "np": "./script/push.sh",
 | 
			
		||||
        "lsp": "npm login --registry=https://registry.npmjs.org --scope=@ccms",
 | 
			
		||||
        "lp": "lerna publish --registry https://registry.npmjs.org",
 | 
			
		||||
        "lpb": "lerna publish --registry https://registry.npmjs.org --canary --pre-dist-tag beta"
 | 
			
		||||
        "lpb": "lerna publish --registry https://registry.npmjs.org --canary --preid beta --pre-dist-tag beta"
 | 
			
		||||
    },
 | 
			
		||||
    "workspaces": [
 | 
			
		||||
        "packages/*"
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
                            } else if (global.debug) {
 | 
			
		||||
                                console.debug('readSourceMap can\'t found', fileName, 'source map file', sourceMappingURL)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        if (sourceContent) {
 | 
			
		||||
                            sourceMaps[fileName] = new SourceMapBuilder(JSON.parse(sourceContent))
 | 
			
		||||
                            sourceFileMaps[fileName] = Paths.get(fileName, '..', sourceMaps[fileName].sources[0]).toFile().getCanonicalPath()
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                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} => §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 } = 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 {
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,10 @@ export namespace database {
 | 
			
		||||
     * 数据库配置
 | 
			
		||||
     */
 | 
			
		||||
    export interface DataBaseConfig {
 | 
			
		||||
        /**
 | 
			
		||||
         * 数据库类型
 | 
			
		||||
         */
 | 
			
		||||
        type: 'h2' | 'mysql' | 'mongodb' | 'sqlite' | 'postgres' | 'redis'
 | 
			
		||||
        /**
 | 
			
		||||
         * 数据库连接串
 | 
			
		||||
         */
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -149,7 +149,15 @@ export namespace plugin {
 | 
			
		||||
        /**
 | 
			
		||||
         * 插件名称 不填默认为类名
 | 
			
		||||
         */
 | 
			
		||||
        name?: string
 | 
			
		||||
        name: string
 | 
			
		||||
        /**
 | 
			
		||||
         * 插件中文名称
 | 
			
		||||
         */
 | 
			
		||||
        cname?: string
 | 
			
		||||
        /**
 | 
			
		||||
         * 插件等级 付费插件自动注入
 | 
			
		||||
         */
 | 
			
		||||
        level?: number
 | 
			
		||||
        /**
 | 
			
		||||
         * 前缀
 | 
			
		||||
         */
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ import { event, plugin } from '@ccms/api'
 | 
			
		||||
import { inject, provideSingleton } from '@ccms/container'
 | 
			
		||||
import * as reflect from '@ccms/common/dist/reflect'
 | 
			
		||||
 | 
			
		||||
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")
 | 
			
		||||
@@ -19,7 +20,15 @@ export class BukkitEvent extends event.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
 | 
			
		||||
 
 | 
			
		||||
@@ -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,12 +22,12 @@ 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())
 | 
			
		||||
@@ -42,7 +44,7 @@ abstract class BukkitChatInvoke {
 | 
			
		||||
            }
 | 
			
		||||
            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
 | 
			
		||||
@@ -50,10 +52,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('.'))
 | 
			
		||||
@@ -83,9 +87,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
 | 
			
		||||
@@ -100,6 +104,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 +160,31 @@ class BukkitChatInvoke_1_17_1 extends BukkitChatInvoke_1_16_5 {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class BukkitChatInvoke_1_19 extends BukkitChatInvoke_1_17_1 {
 | 
			
		||||
    getSendPacketMethodName(playerConnectionClass: any) {
 | 
			
		||||
        return playerConnectionClass.getMethod('a', this.getPacketClass()).getName()
 | 
			
		||||
    }
 | 
			
		||||
    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 == 0 ? 1 : type)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
try {
 | 
			
		||||
    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 >= 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)
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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
											
										
									
								
							
							
								
								
									
										126
									
								
								packages/bukkit/src/item.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								packages/bukkit/src/item.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,126 @@
 | 
			
		||||
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 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(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()
 | 
			
		||||
            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')
 | 
			
		||||
            } 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
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
    "extends": "../../tsconfig.json",
 | 
			
		||||
    "compilerOptions": {
 | 
			
		||||
        "baseUrl": "src",
 | 
			
		||||
        "outDir": "dist"
 | 
			
		||||
        "outDir": "dist",
 | 
			
		||||
        "resolveJsonModule": true
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -129,12 +129,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(`切换到超类: ${target.getName()}`)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (field === null) {
 | 
			
		||||
@@ -146,21 +148,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(`切换到超类: ${target.getName()}`)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
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'
 | 
			
		||||
@@ -161,19 +161,13 @@ function initialize() {
 | 
			
		||||
    loadCoreScript('initialize')
 | 
			
		||||
    try {
 | 
			
		||||
        let core = createCore()
 | 
			
		||||
        if (VersionUtils.isGreaterOrEqual(base.version, '0.22.0')) { return core }
 | 
			
		||||
        return core.enable()
 | 
			
		||||
        return VersionUtils.isGreaterOrEqual(base.version, '0.22.0') ? core : core.enable()
 | 
			
		||||
    } catch (error: any) {
 | 
			
		||||
        if (console.console) {
 | 
			
		||||
            console.i18n("core.initialize.error", { error })
 | 
			
		||||
            console.ex(error)
 | 
			
		||||
        } else {
 | 
			
		||||
            error.printStackTrace()
 | 
			
		||||
        }
 | 
			
		||||
        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 {
 | 
			
		||||
            enable: () => console.i18n('ms.core.engine.disable.abnormal')
 | 
			
		||||
        }
 | 
			
		||||
        return VersionUtils.isGreaterOrEqual(base.version, '0.22.0') ? core : core.enable()
 | 
			
		||||
    } finally {
 | 
			
		||||
        process.emit('core.after.initialize')
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
import { database } from '@ccms/api'
 | 
			
		||||
import { JSClass, postConstruct } from '@ccms/container'
 | 
			
		||||
import { JSClass } from '@ccms/container'
 | 
			
		||||
 | 
			
		||||
const Thread = Java.type('java.lang.Thread')
 | 
			
		||||
const JavaString = Java.type('java.lang.String')
 | 
			
		||||
const Properties = Java.type('java.util.Properties')
 | 
			
		||||
 | 
			
		||||
@@ -26,9 +27,21 @@ export class DataBase extends database.DataBase {
 | 
			
		||||
 | 
			
		||||
    private createDataSource(dbConfig: database.DataBaseConfig) {
 | 
			
		||||
        if (typeof dbConfig.url === "string") {
 | 
			
		||||
            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)
 | 
			
		||||
@@ -44,7 +57,9 @@ export class DataBase extends database.DataBase {
 | 
			
		||||
                }
 | 
			
		||||
                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
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +0,0 @@
 | 
			
		||||
import 'reflect-metadata'
 | 
			
		||||
 | 
			
		||||
export function id() {
 | 
			
		||||
    return (target: Object, propertyKey: string | symbol) => void {
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,11 +0,0 @@
 | 
			
		||||
import { DataBase } from "./database"
 | 
			
		||||
 | 
			
		||||
export class Model<T> {
 | 
			
		||||
    constructor(private database: DataBase) {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    queryForList(): Array<T> {
 | 
			
		||||
        
 | 
			
		||||
        return []
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -34,7 +34,7 @@ ms.api.command.tab.completer.slow: "§c注意! §6玩家 §a{player} §6执行 
 | 
			
		||||
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} 个插件 开始编译..."
 | 
			
		||||
 
 | 
			
		||||
@@ -83,7 +83,7 @@ export class PluginConfigManager {
 | 
			
		||||
                        name: metadata.name,
 | 
			
		||||
                        format: metadata.format
 | 
			
		||||
                    })
 | 
			
		||||
                } else {
 | 
			
		||||
                } else if (metadata.migrate) {
 | 
			
		||||
                    configValue = configLoader.load(base.read(metadata.file)) || {}
 | 
			
		||||
                    if (defaultValue && this.setDefaultValue(configValue, defaultValue, !!metadata.default)) {
 | 
			
		||||
                        base.save(metadata.file, configLoader.dump(configValue))
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 
 | 
			
		||||
@@ -91,6 +91,10 @@ export namespace interfaces {
 | 
			
		||||
         * 配置文件格式 默认 yml
 | 
			
		||||
         */
 | 
			
		||||
        format?: string
 | 
			
		||||
        /**
 | 
			
		||||
         * 是否合并默认配置
 | 
			
		||||
         */
 | 
			
		||||
        migrate?: boolean
 | 
			
		||||
        /**
 | 
			
		||||
         * 自动保存 默认为 false
 | 
			
		||||
         */
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,7 @@ export class PluginManagerImpl implements plugin.PluginManager {
 | 
			
		||||
            try {
 | 
			
		||||
                console.i18n('ms.plugin.event.map', { count: this.eventManager.mapEventName(), type: this.serverType })
 | 
			
		||||
            } catch (error) {
 | 
			
		||||
                console.i18n('ms.plugin.event.map.error', { error })
 | 
			
		||||
                console.i18n('ms.plugin.event.map.error', { type: this.serverType, error })
 | 
			
		||||
            }
 | 
			
		||||
            let pluginScanner = this.container.getAll<plugin.PluginScanner>(plugin.PluginScanner)
 | 
			
		||||
            pluginScanner.forEach((scanner) => {
 | 
			
		||||
 
 | 
			
		||||
@@ -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")
 | 
			
		||||
@@ -18,16 +19,32 @@ const threadCount = new AtomicInteger(0)
 | 
			
		||||
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,9 +82,44 @@ 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]"
 | 
			
		||||
    }
 | 
			
		||||
@@ -83,7 +135,7 @@ class EventLoop {
 | 
			
		||||
        this.taskExecuteTimeout = parseInt(process.env.MS_TASK_EXECUTE_TIMEOUT) || 3000
 | 
			
		||||
        this.fixedThreadPool = new ThreadPoolExecutor(
 | 
			
		||||
            1, 1, 0, TimeUnit.SECONDS,
 | 
			
		||||
            new LinkedBlockingQueue(500),
 | 
			
		||||
            new LinkedBlockingQueue(1024),
 | 
			
		||||
            new ThreadFactory((run: any) => {
 | 
			
		||||
                let thread = new Thread(run, "@ccms/event-loop")
 | 
			
		||||
                thread.setDaemon(true)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user