Merge remote-tracking branch 'origin/master'

This commit is contained in:
Him188 2020-02-14 13:34:17 +08:00
commit cf5deb7826
13 changed files with 507 additions and 232 deletions

View File

@ -11,20 +11,22 @@ buildscript {
// Do try to waste your time.
classpath 'com.android.tools.build:gradle:3.5.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath("com.github.jengelman.gradle.plugins:shadow:5.2.0")
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlinVersion"
classpath "org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicFuVersion"
}
}
def keyProps = new Properties()
def keyFile = file("local.properties")
if (keyFile.exists()) keyFile.withInputStream { keyProps.load(it) }
if (!keyProps.getProperty("sdk.dir", "").isEmpty()) {
project.ext.set("isAndroidSDKAvailable", true)
} else {
project.ext.set("isAndroidSDKAvailable", false)
}
try {
def keyProps = new Properties()
def keyFile = file("local.properties")
if (keyFile.exists()) keyFile.withInputStream { keyProps.load(it) }
if (!keyProps.getProperty("sdk.dir", "").isEmpty()) {
project.ext.set("isAndroidSDKAvailable", true)
} else {
project.ext.set("isAndroidSDKAvailable", false)
}
}catch(Exception e){}
allprojects {
group = "net.mamoe"
version = getProperty("mirai_version")

View File

@ -1,5 +1,5 @@
#Thu Feb 06 14:10:33 CST 2020
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStorePath=wrapper/dists

View File

@ -1,10 +1,20 @@
plugins {
id("com.github.johnrengelman.shadow") version "5.2.0"
id("kotlinx-serialization")
id("kotlin")
id("java")
}
apply(plugin = "com.github.johnrengelman.shadow")
apply(plugin = "java-library")
tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>() {
manifest {
attributes["Main-Class"] = "net.mamoe.mirai.MiraiConsoleLoader"
}
}
val kotlinVersion: String by rootProject.ext
val atomicFuVersion: String by rootProject.ext
val coroutinesVersion: String by rootProject.ext

View File

@ -1,68 +0,0 @@
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
import net.mamoe.mirai.plugin.PluginManager
object CommandManager {
private val registeredCommand: MutableMap<String, Command> = mutableMapOf()
fun register(command: Command) {
val allNames = mutableListOf<String>(command.name).also { it.addAll(command.alias) }
allNames.forEach {
if (registeredCommand.containsKey(it)) {
error("Command Name(or Alias) $it is already registered, consider if same function plugin was installed")
}
}
allNames.forEach {
registeredCommand[it] = command
}
}
fun unregister(command: Command) {
val allNames = mutableListOf<String>(command.name).also { it.addAll(command.alias) }
allNames.forEach {
registeredCommand.remove(it)
}
}
fun runCommand(fullCommand: String): Boolean {
val blocks = fullCommand.split(" ")
val commandHead = blocks[0].replace("/", "")
if (!registeredCommand.containsKey(commandHead)) {
return false
}
val args = blocks.subList(1, blocks.size)
registeredCommand[commandHead]?.run {
if (onCommand(
blocks.subList(1, blocks.size)
)
) {
PluginManager.onCommand(this, args)
}
}
return true
}
}
abstract class Command(
val name: String,
val alias: List<String> = listOf(),
val description: String = ""
) {
/**
* 最高优先级监听器
* 如果return [false] 这次指令不会被[PluginBase]的全局onCommand监听器监听
* */
open fun onCommand(args: List<String>): Boolean {
return true
}
}

View File

@ -1,138 +0,0 @@
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.UnstableDefault
import net.mamoe.mirai.Bot
import net.mamoe.mirai.alsoLogin
import net.mamoe.mirai.api.http.generateSessionKey
import net.mamoe.mirai.plugin.*
import java.io.File
import kotlin.concurrent.thread
object MiraiConsole {
val bots
get() = Bot.instances
val pluginManager: PluginManager
get() = PluginManager
var logger: MiraiConsoleLogger = DefaultLogger
var path: String = System.getProperty("user.dir")
val version = "0.13"
val build = "Beta"
fun start() {
logger("Mirai-console v${version} $build is still in testing stage, majority feature is available")
logger("Mirai-console v${version} $build 还处于测试阶段, 大部分功能可用")
logger()
logger("Mirai-console now running under " + System.getProperty("user.dir"))
logger("Mirai-console 正在 " + System.getProperty("user.dir") + "下运行")
logger()
logger("Get news in github: https://github.com/mamoe/mirai")
logger("在Github中获取项目最新进展: https://github.com/mamoe/mirai")
logger("Mirai为开源项目请自觉遵守开源项目协议")
logger("Powered by Mamoe Technology")
logger()
CommandManager.register(DefaultCommands.DefaultLoginCommand())
pluginManager.loadPlugins()
CommandListener.start()
println(MiraiProperties.HTTP_API_ENABLE)
logger("\"/login qqnumber qqpassword \" to login a bot")
logger("\"/login qq号 qq密码 \" 来登陆一个BOT")
}
fun stop() {
PluginManager.disableAllPlugins()
}
/**
* Defaults Commands are recommend to be replaced by plugin provided commands
*/
object DefaultCommands {
class DefaultLoginCommand : Command(
"login"
) {
override fun onCommand(args: List<String>): Boolean {
if (args.size < 2) {
println("\"/login qqnumber qqpassword \" to login a bot")
println("\"/login qq号 qq密码 \" 来登录一个BOT")
return false
}
val qqNumber = args[0].toLong()
val qqPassword = args[1]
println("login...")
try {
runBlocking {
Bot(qqNumber, qqPassword).alsoLogin()
}
} catch (e: Exception) {
println("$qqNumber login failed")
}
return true
}
}
}
object CommandListener {
fun start() {
thread {
processNextCommandLine()
}
}
tailrec fun processNextCommandLine() {
val fullCommand = readLine()
if (fullCommand != null && fullCommand.startsWith("/")) {
if (!CommandManager.runCommand(fullCommand)) {
logger("unknown command $fullCommand")
logger("未知指令 $fullCommand")
}
}
processNextCommandLine();
}
}
interface MiraiConsoleLogger {
operator fun invoke(any: Any? = null)
}
object DefaultLogger : MiraiConsoleLogger {
override fun invoke(any: Any?) {
if (any != null) {
println("[Mirai${version} $build]: " + any.toString())
}
}
}
object MiraiProperties {
var config = File("$path/mirai.json").loadAsConfig()
var HTTP_API_ENABLE: Boolean by config.withDefaultWrite { true }
var HTTP_API_PORT: Int by config.withDefaultWrite { 8080 }
var HTTP_API_AUTH_KEY: String by config.withDefaultWriteSave {
"InitKey".also {
logger("Mirai HTTPAPI auth key 已随机生成 请注意修改")
} + generateSessionKey()
}
}
}
fun main() {
MiraiConsole.start()
Runtime.getRuntime().addShutdownHook(thread(start = false) {
MiraiConsole.stop()
})
}

View File

@ -0,0 +1,130 @@
package net.mamoe.mirai
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
import net.mamoe.mirai.plugins.PluginManager
object CommandManager {
private val registeredCommand: MutableMap<String, ICommand> = mutableMapOf()
fun getCommands(): Collection<ICommand> {
return registeredCommand.values
}
fun register(command: ICommand) {
val allNames = mutableListOf(command.name).also { it.addAll(command.alias) }
allNames.forEach {
if (registeredCommand.containsKey(it)) {
error("net.mamoe.mirai.Command Name(or Alias) $it is already registered, consider if same function plugin was installed")
}
}
allNames.forEach {
registeredCommand[it] = command
}
}
fun unregister(command: ICommand) {
val allNames = mutableListOf<String>(command.name).also { it.addAll(command.alias) }
allNames.forEach {
registeredCommand.remove(it)
}
}
fun unregister(commandName: String) {
registeredCommand.remove(commandName)
}
fun runCommand(fullCommand: String): Boolean {
val blocks = fullCommand.split(" ")
val commandHead = blocks[0].replace("/", "")
if (!registeredCommand.containsKey(commandHead)) {
return false
}
val args = blocks.subList(1, blocks.size)
registeredCommand[commandHead]?.run {
if (onCommand(
blocks.subList(1, blocks.size)
)
) {
PluginManager.onCommand(this, args)
}
}
return true
}
}
interface ICommand {
val name: String
val alias: List<String>
val description: String
fun onCommand(args: List<String>): Boolean
fun register()
}
abstract class Command(
override val name: String,
override val alias: List<String> = listOf(),
override val description: String = ""
) : ICommand {
/**
* 最高优先级监听器
* 如果return [false] 这次指令不会被[PluginBase]的全局onCommand监听器监听
* */
open override fun onCommand(args: List<String>): Boolean {
return true
}
override fun register() {
CommandManager.register(this)
}
}
class AnonymousCommand internal constructor(
override val name: String,
override val alias: List<String>,
override val description: String,
val onCommand: ICommand.(args: List<String>) -> Boolean
) : ICommand {
override fun onCommand(args: List<String>): Boolean {
return onCommand.invoke(this, args)
}
override fun register() {
CommandManager.register(this)
}
}
class CommandBuilder internal constructor() {
var name: String? = null
var alias: List<String>? = null
var description: String = ""
var onCommand: (ICommand.(args: List<String>) -> Boolean)? = null
fun onCommand(commandProcess: ICommand.(args: List<String>) -> Boolean) {
onCommand = commandProcess
}
fun register(): ICommand {
if (name == null || onCommand == null) {
error("net.mamoe.mirai.CommandBuilder not complete")
}
if (alias == null) {
alias = listOf()
}
return AnonymousCommand(name!!, alias!!, description, onCommand!!).also { it.register() }
}
}
fun buildCommand(builder: CommandBuilder.() -> Unit): ICommand {
return CommandBuilder().apply(builder).register()
}

View File

@ -0,0 +1,295 @@
package net.mamoe.mirai
/*
* Copyright 2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
import kotlinx.coroutines.runBlocking
import net.mamoe.mirai.plugins.PluginManager
import net.mamoe.mirai.plugins.loadAsConfig
import net.mamoe.mirai.plugins.withDefaultWrite
import net.mamoe.mirai.plugins.withDefaultWriteSave
import net.mamoe.mirai.api.http.MiraiHttpAPIServer
import net.mamoe.mirai.api.http.generateSessionKey
import net.mamoe.mirai.contact.sendMessage
import java.io.File
import kotlin.concurrent.thread
object MiraiConsole {
val bots
get() = Bot.instances
fun getBotByUIN(uin: Long): Bot? {
bots.forEach {
if (it.get()?.uin == uin) {
return it.get()
}
}
return null
}
val pluginManager: PluginManager
get() = PluginManager
var logger: MiraiConsoleLogger =
DefaultLogger
var path: String = System.getProperty("user.dir")
val version = "0.01"
var coreVersion = "0.13"
val build = "Beta"
fun start() {
logger("Mirai-console v$version $build | core version v$coreVersion is still in testing stage, majority feature is available")
logger("Mirai-console v$version $build | 核心版本 v${coreVersion}还处于测试阶段, 大部分功能可用")
logger()
logger("Mirai-console now running under " + System.getProperty("user.dir"))
logger("Mirai-console 正在 " + System.getProperty("user.dir") + "下运行")
logger()
logger("Get news in github: https://github.com/mamoe/mirai")
logger("在Github中获取项目最新进展: https://github.com/mamoe/mirai")
logger("Mirai为开源项目请自觉遵守开源项目协议")
logger("Powered by Mamoe Technologies and contributors")
logger()
runBlocking {
DefaultCommands()
HTTPAPIAdaptar()
pluginManager.loadPlugins()
CommandListener.start()
}
logger("Mirai-console 启动完成")
logger("\"/login qqnumber qqpassword \" to login a bot")
logger("\"/login qq号 qq密码 \" 来登陆一个BOT")
}
fun stop() {
PluginManager.disableAllPlugins()
}
object HTTPAPIAdaptar {
operator fun invoke() {
if (MiraiProperties.HTTP_API_ENABLE) {
if (MiraiProperties.HTTP_API_AUTH_KEY.startsWith("InitKey")) {
logger("请尽快更改初始生成的HTTP API AUTHKEY")
}
logger("正在启动HTTPAPI; 端口=" + MiraiProperties.HTTP_API_PORT)
MiraiHttpAPIServer.start(
MiraiProperties.HTTP_API_PORT,
MiraiProperties.HTTP_API_AUTH_KEY
)
logger("HTTPAPI启动完成; 端口=" + MiraiProperties.HTTP_API_PORT)
}
}
}
/**
* Defaults Commands are recommend to be replaced by plugin provided commands
*/
object DefaultCommands {
operator fun invoke() {
buildCommand {
name = "login"
description = "Mirai-Console default bot login command"
onCommand {
if (it.size < 2) {
logger("\"/login qqnumber qqpassword \" to login a bot")
logger("\"/login qq号 qq密码 \" 来登录一个BOT")
return@onCommand false
}
val qqNumber = it[0].toLong()
val qqPassword = it[1]
logger("login...")
try {
runBlocking {
Bot(qqNumber, qqPassword).alsoLogin()
println("$qqNumber login successes")
}
} catch (e: Exception) {
println("$qqNumber login failed")
}
true
}
}
buildCommand {
name = "status"
description = "Mirai-Console default status command"
onCommand {
when (it.size) {
0 -> {
logger("当前有" + bots.size + "个BOT在线")
}
1 -> {
val bot = it[0]
var find = false
bots.forEach {
if (it.get()?.uin.toString().contains(bot)) {
find = true
logger("" + it.get()?.uin + ": 在线中; 好友数量:" + it.get()?.qqs?.size + "; 群组数量:" + it.get()?.groups?.size)
}
}
if (!find) {
logger("没有找到BOT$bot")
}
}
}
true
}
}
buildCommand {
name = "say"
description = "Mirai-Console default say command"
onCommand {
if (it.size < 2) {
logger("say [好友qq号或者群号] [文本消息] //将默认使用第一个BOT")
logger("say [bot号] [好友qq号或者群号] [文本消息]")
return@onCommand false
}
val bot: Bot? = if (it.size == 2) {
if (bots.size == 0) {
logger("还没有BOT登陆")
return@onCommand false
}
bots[0].get()
} else {
getBotByUIN(it[0].toLong())
}
if (bot == null) {
logger("没有找到BOT")
return@onCommand false
}
val target = it[it.size - 2].toLong()
val message = it[it.size - 1]
try {
val contact = bot[target]
runBlocking {
contact.sendMessage(message)
logger("消息已推送")
}
} catch (e: NoSuchElementException) {
logger("没有找到群或好友 号码为${target}")
return@onCommand false
}
true
}
}
buildCommand {
name = "plugins"
alias = listOf("plugin")
description = "show all plugins"
onCommand {
PluginManager.getAllPluginDescriptions().let {
println("loaded " + it.size + " plugins")
it.forEach {
logger("\t" + it.name + " v" + it.version + " by" + it.author + " " + it.info)
}
true
}
}
}
buildCommand {
name = "command"
alias = listOf("commands", "help", "helps")
description = "show all commands"
onCommand {
CommandManager.getCommands().let {
println("currently have " + it.size + " commands")
it.toSet().forEach {
logger("\t" + it.name + " :" + it.description)
}
}
true
}
}
buildCommand {
name = "about"
description = "About Mirai-Console"
onCommand {
logger("v$version $build is still in testing stage, majority feature is available")
logger("now running under " + System.getProperty("user.dir"))
logger("在Github中获取项目最新进展: https://github.com/mamoe/mirai")
logger("Mirai为开源项目请自觉遵守开源项目协议")
logger("Powered by Mamoe Technologies and contributors")
true
}
}
}
}
object CommandListener {
fun start() {
thread {
processNextCommandLine()
}
}
tailrec fun processNextCommandLine() {
var fullCommand = readLine()
if (fullCommand != null) {
if (!fullCommand.startsWith("/")) {
fullCommand = "/$fullCommand"
}
if (!CommandManager.runCommand(fullCommand)) {
logger("未知指令 $fullCommand")
}
}
processNextCommandLine();
}
}
interface MiraiConsoleLogger {
operator fun invoke(any: Any? = null)
}
object DefaultLogger : MiraiConsoleLogger {
override fun invoke(any: Any?) {
if (any != null) {
println("[Mirai$version $build]: " + any.toString())
}
}
}
object MiraiProperties {
var config = File("$path/mirai.json").loadAsConfig()
var HTTP_API_ENABLE: Boolean by config.withDefaultWrite { true }
var HTTP_API_PORT: Int by config.withDefaultWrite { 8080 }
var HTTP_API_AUTH_KEY: String by config.withDefaultWriteSave {
"InitKey" + generateSessionKey()
}
}
}
class MiraiConsoleLoader {
companion object {
@JvmStatic
fun main(args: Array<String>) {
MiraiConsole.start()
Runtime.getRuntime().addShutdownHook(thread(start = false) {
MiraiConsole.stop()
})
}
}
}

View File

@ -7,7 +7,7 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.plugin
package net.mamoe.mirai.plugins
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONObject
@ -16,7 +16,6 @@ import com.alibaba.fastjson.parser.Feature
import kotlinx.serialization.*
import java.io.File
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentSkipListMap
import kotlin.properties.ReadWriteProperty
import kotlin.reflect.KClass
import kotlin.reflect.KProperty
@ -61,6 +60,14 @@ interface Config {
}
return when (file.extension.toLowerCase()) {
"json" -> JsonConfig(file)
"yml" -> YamlConfig(file)
"yaml" -> YamlConfig(file)
"mirai" -> YamlConfig(file)
"ini" -> IniConfig(file)
"toml" -> IniConfig(file)
"properties" -> IniConfig(file)
"property" -> IniConfig(file)
"data" -> IniConfig(file)
else -> error("Unsupported file config type ${file.extension.toLowerCase()}")
}
}
@ -328,4 +335,26 @@ class JsonConfig internal constructor(file: File) : FileConfigImpl(file) {
override fun serialize(config: ConfigSection): String {
return JSONObject.toJSONString(config)
}
}
}
class YamlConfig internal constructor(file: File) : FileConfigImpl(file) {
override fun deserialize(content: String): ConfigSection {
TODO("崔崔还没有写") //To change body of created functions use File | Settings | File Templates.
}
override fun serialize(config: ConfigSection): String {
TODO("崔崔还没有写") //To change body of created functions use File | Settings | File Templates.
}
}
class IniConfig internal constructor(file: File) : FileConfigImpl(file) {
override fun deserialize(content: String): ConfigSection {
TODO("崔崔还没有写") //To change body of created functions use File | Settings | File Templates.
}
override fun serialize(config: ConfigSection): String {
TODO("崔崔还没有写") //To change body of created functions use File | Settings | File Templates.
}
}

View File

@ -7,12 +7,10 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.plugin
package net.mamoe.mirai.plugins
import Command
import net.mamoe.mirai.ICommand
import kotlinx.coroutines.*
import kotlinx.serialization.UnstableDefault
import kotlinx.serialization.json.Json
import net.mamoe.mirai.utils.DefaultLogger
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.io.encodeToString
@ -58,7 +56,7 @@ abstract class PluginBase(coroutineContext: CoroutineContext) : CoroutineScope {
/**
* 当任意指令被使用
*/
open fun onCommand(command: Command, args: List<String>) {
open fun onCommand(command: ICommand, args: List<String>) {
}
@ -162,13 +160,18 @@ object PluginManager {
//已完成加载的
private val nameToPluginBaseMap: MutableMap<String, PluginBase> = mutableMapOf()
private val pluginDescriptions: MutableMap<String, PluginDescription> = mutableMapOf()
fun onCommand(command: Command, args: List<String>) {
this.nameToPluginBaseMap.values.forEach {
fun onCommand(command: ICommand, args: List<String>) {
nameToPluginBaseMap.values.forEach {
it.onCommand(command, args)
}
}
fun getAllPluginDescriptions(): Collection<PluginDescription> {
return pluginDescriptions.values
}
/**
* 尝试加载全部插件
*/
@ -176,6 +179,8 @@ object PluginManager {
val pluginsFound: MutableMap<String, PluginDescription> = mutableMapOf()
val pluginsLocation: MutableMap<String, File> = mutableMapOf()
logger.info("""开始加载${pluginsPath}下的插件""")
File(pluginsPath).listFiles()?.forEach { file ->
if (file != null && file.extension == "jar") {
val jar = JarFile(file)
@ -254,11 +259,17 @@ object PluginManager {
try {
val pluginClass = try {
PluginClassLoader((pluginsLocation[description.name]!!), this.javaClass.classLoader)
PluginClassLoader(
(pluginsLocation[description.name]!!),
this.javaClass.classLoader
)
.loadClass(description.basePath)
} catch (e: ClassNotFoundException) {
logger.info("failed to find Main: " + description.basePath + " checking if it's kotlin's path")
PluginClassLoader((pluginsLocation[description.name]!!), this.javaClass.classLoader)
PluginClassLoader(
(pluginsLocation[description.name]!!),
this.javaClass.classLoader
)
.loadClass("${description.basePath}Kt")
}
return try {
@ -269,6 +280,7 @@ object PluginManager {
logger.info(description.info)
nameToPluginBaseMap[description.name] = plugin
pluginDescriptions[description.name] = description
plugin.init(description)
true
} catch (e: ClassCastException) {
@ -289,6 +301,9 @@ object PluginManager {
nameToPluginBaseMap.values.forEach {
it.enable()
}
logger.info("""加载了${nameToPluginBaseMap.size}个插件""")
}

View File

@ -1,7 +1,7 @@
plugins {
kotlin("jvm")
java
id("com.github.johnrengelman.shadow") version "5.2.0"
id("com.github.johnrengelman.shadow")
}
version = "1.0.0"

View File

@ -14,7 +14,7 @@ import kotlinx.coroutines.GlobalScope
import net.mamoe.mirai.event.events.BotOnlineEvent
import net.mamoe.mirai.event.subscribeAlways
import net.mamoe.mirai.event.subscribeMessages
import net.mamoe.mirai.plugin.PluginBase
import net.mamoe.mirai.plugins.PluginBase
import net.mamoe.mirai.utils.MiraiExperimentalAPI
class ImageSenderMain : PluginBase() {

Binary file not shown.

View File

@ -59,7 +59,7 @@ if (versionPos==-1){
def javaVersionNum = javaVersion.substring(0, versionPos).toInteger()
if (javaVersionNum >= 11) {
println("jdk版本为 "+ javaVersionNum)
include(':mirai-debug')
//include(':mirai-debug')
} else {
println("当前使用的 JDK 版本为 ${System.getProperty("java.version")}, 最低需要 JDK 11 才能引入模块 `:mirai-debug`")
}