mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-27 00:30:17 +08:00
Command registering, matching, executing
This commit is contained in:
parent
41112affa8
commit
ee8be9799f
@ -40,6 +40,8 @@ dependencies {
|
|||||||
|
|
||||||
testApi("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}")
|
testApi("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}")
|
||||||
testApi(kotlin("stdlib"))
|
testApi(kotlin("stdlib"))
|
||||||
|
testApi(kotlin("test"))
|
||||||
|
testApi(kotlin("test-junit5"))
|
||||||
}
|
}
|
||||||
|
|
||||||
version = Versions.Mirai.console
|
version = Versions.Mirai.console
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
package net.mamoe.mirai.console.command;
|
|
||||||
|
|
||||||
// import jdk.jfr.Description;
|
|
||||||
|
|
||||||
public class JCommandManager {
|
|
||||||
|
|
||||||
private JCommandManager() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CommandManager getInstance() {
|
|
||||||
return CommandManager.INSTANCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
package net.mamoe.mirai.console.utils;
|
package net.mamoe.mirai.console.utils;
|
||||||
|
|
||||||
import net.mamoe.mirai.Bot;
|
import net.mamoe.mirai.Bot;
|
||||||
import net.mamoe.mirai.console.MiraiConsole;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -12,7 +11,7 @@ import java.util.List;
|
|||||||
public class BotManager {
|
public class BotManager {
|
||||||
|
|
||||||
public static List<Long> getManagers(long botAccount) {
|
public static List<Long> getManagers(long botAccount) {
|
||||||
Bot bot = MiraiConsole.INSTANCE.getBotOrThrow(botAccount);
|
Bot bot = Bot.getInstance(botAccount);
|
||||||
return getManagers(bot);
|
return getManagers(bot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,9 +13,10 @@ import kotlinx.coroutines.CoroutineScope
|
|||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.io.charsets.Charset
|
import kotlinx.io.charsets.Charset
|
||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.console.command.CommandManager
|
import net.mamoe.mirai.console.command.CommandOwner
|
||||||
import net.mamoe.mirai.console.plugins.PluginManager
|
|
||||||
import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd
|
import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd
|
||||||
|
import net.mamoe.mirai.utils.DefaultLogger
|
||||||
|
import net.mamoe.mirai.utils.MiraiExperimentalAPI
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.PrintStream
|
import java.io.PrintStream
|
||||||
@ -42,7 +43,7 @@ interface IMiraiConsole : CoroutineScope {
|
|||||||
val mainLogger: MiraiLogger
|
val mainLogger: MiraiLogger
|
||||||
}
|
}
|
||||||
|
|
||||||
object MiraiConsole : CoroutineScope, IMiraiConsole {
|
object MiraiConsole : CoroutineScope, IMiraiConsole, CommandOwner {
|
||||||
private lateinit var instance: IMiraiConsole
|
private lateinit var instance: IMiraiConsole
|
||||||
|
|
||||||
/** 由前端调用 */
|
/** 由前端调用 */
|
||||||
@ -58,18 +59,20 @@ object MiraiConsole : CoroutineScope, IMiraiConsole {
|
|||||||
override val coroutineContext: CoroutineContext get() = instance.coroutineContext
|
override val coroutineContext: CoroutineContext get() = instance.coroutineContext
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
DefaultLogger = {
|
||||||
|
this.newLogger(it)
|
||||||
|
}
|
||||||
this.coroutineContext[Job]!!.invokeOnCompletion {
|
this.coroutineContext[Job]!!.invokeOnCompletion {
|
||||||
PluginManager.disablePlugins()
|
|
||||||
CommandManager.cancel()
|
|
||||||
Bot.botInstances.forEach {
|
Bot.botInstances.forEach {
|
||||||
it.close()
|
it.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@MiraiExperimentalAPI
|
||||||
|
fun newLogger(identity: String?): MiraiLogger = frontEnd.loggerFor(identity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal val Throwable.stacktraceString: String
|
internal val Throwable.stacktraceString: String
|
||||||
get() =
|
get() =
|
||||||
ByteArrayOutputStream().apply {
|
ByteArrayOutputStream().apply {
|
||||||
|
@ -7,15 +7,8 @@ import io.ktor.client.HttpClient
|
|||||||
import io.ktor.client.engine.cio.CIO
|
import io.ktor.client.engine.cio.CIO
|
||||||
import io.ktor.client.request.get
|
import io.ktor.client.request.get
|
||||||
import io.ktor.util.KtorExperimentalAPI
|
import io.ktor.util.KtorExperimentalAPI
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import net.mamoe.mirai.console.plugins.PluginManager
|
|
||||||
import net.mamoe.mirai.console.utils.retryCatching
|
import net.mamoe.mirai.console.utils.retryCatching
|
||||||
import net.mamoe.mirai.console.utils.tryNTimes
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
|
||||||
import java.net.HttpURLConnection
|
|
||||||
import java.net.URL
|
|
||||||
|
|
||||||
internal object CuiPluginCenter : PluginCenter {
|
internal object CuiPluginCenter : PluginCenter {
|
||||||
|
|
||||||
@ -96,6 +89,8 @@ internal object CuiPluginCenter : PluginCenter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun <T : Any> T.downloadPlugin(name: String, progressListener: T.(Float) -> Unit): File {
|
override suspend fun <T : Any> T.downloadPlugin(name: String, progressListener: T.(Float) -> Unit): File {
|
||||||
|
TODO()
|
||||||
|
/*
|
||||||
val info = findPlugin(name) ?: error("Plugin Not Found")
|
val info = findPlugin(name) ?: error("Plugin Not Found")
|
||||||
val targetFile = File(PluginManager.pluginsPath, "$name-" + info.version + ".jar")
|
val targetFile = File(PluginManager.pluginsPath, "$name-" + info.version + ".jar")
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
@ -116,6 +111,7 @@ internal object CuiPluginCenter : PluginCenter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return targetFile
|
return targetFile
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
override val name: String
|
override val name: String
|
||||||
|
@ -13,129 +13,134 @@ package net.mamoe.mirai.console.command
|
|||||||
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import net.mamoe.mirai.console.MiraiConsole
|
||||||
import net.mamoe.mirai.console.plugins.PluginBase
|
import net.mamoe.mirai.console.plugins.PluginBase
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
internal const val FOR_BINARY_COMPATIBILITY = "for binary compatibility"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 指令
|
* 指令
|
||||||
*
|
*
|
||||||
* @see register 注册这个指令
|
* @see register 注册这个指令
|
||||||
* @see registerCommand 注册指令 DSL
|
|
||||||
*/
|
*/
|
||||||
interface Command {
|
interface Command {
|
||||||
/**
|
val owner: CommandOwner
|
||||||
* 指令主名称
|
val descriptor: CommandDescriptor
|
||||||
*/
|
|
||||||
val name: String
|
/*
|
||||||
|
@Deprecated(FOR_BINARY_COMPATIBILITY, level = DeprecationLevel.HIDDEN)
|
||||||
|
suspend fun onCommand(sender: CommandSender, args: List<String>): Boolean {
|
||||||
|
return true
|
||||||
|
}*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 别名
|
* 执行这个指令.
|
||||||
*/
|
*/
|
||||||
val alias: List<String>
|
suspend fun onCommand(sender: CommandSender, args: CommandArgs): Boolean
|
||||||
|
|
||||||
/**
|
|
||||||
* 描述, 将会显示在 "/help" 指令中
|
|
||||||
*/
|
|
||||||
val description: String
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用法说明
|
|
||||||
*/
|
|
||||||
val usage: String
|
|
||||||
|
|
||||||
suspend fun onCommand(sender: CommandSender, args: List<String>): Boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class AbstractCommand(
|
|
||||||
override val name: String,
|
|
||||||
override val alias: List<String>,
|
|
||||||
override val description: String,
|
|
||||||
override val usage: String
|
|
||||||
) : Command
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 注册这个指令
|
|
||||||
*/
|
|
||||||
inline fun Command.register(commandOwner: CommandOwner) = CommandManager.register(commandOwner, this)
|
|
||||||
|
|
||||||
internal inline fun registerConsoleCommands(builder: CommandBuilder.() -> Unit): Command {
|
|
||||||
return CommandBuilder().apply(builder).register(ConsoleCommandOwner)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构造并注册一个指令
|
* 指令实际参数列表. 参数顺序与 [Command.descriptor] 的 [CommandDescriptor.params] 相同.
|
||||||
*/
|
*/
|
||||||
inline fun PluginBase.registerCommand(builder: CommandBuilder.() -> Unit): Command {
|
class CommandArgs private constructor(
|
||||||
return CommandBuilder().apply(builder).register(this.asCommandOwner())
|
@JvmField
|
||||||
}
|
internal val values: List<Any>,
|
||||||
|
private val fromCommand: Command
|
||||||
|
) : List<Any> by values {
|
||||||
// for java
|
|
||||||
@Suppress("unused")
|
|
||||||
abstract class BlockingCommand(
|
|
||||||
override val name: String,
|
|
||||||
override val alias: List<String> = listOf(),
|
|
||||||
override val description: String = "",
|
|
||||||
override val usage: String = ""
|
|
||||||
) : Command {
|
|
||||||
/**
|
/**
|
||||||
* 最高优先级监听器.
|
* 获取第一个类型为 [R] 的参数
|
||||||
|
*/
|
||||||
|
@JvmSynthetic
|
||||||
|
inline fun <reified R> getReified(): R {
|
||||||
|
for (value in this) {
|
||||||
|
if (value is R) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error("Cannot find argument typed ${R::class.qualifiedName}")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取名称为 [name] 的参数.
|
||||||
*
|
*
|
||||||
* 指令调用将优先触发 [Command.onCommand], 若该函数返回 `false`, 则不会调用 [PluginBase.onCommand]
|
* 若 [name] 为 `null` 则获取第一个匿名参数
|
||||||
* */
|
* @throws NoSuchElementException 找不到这个名称的参数时抛出
|
||||||
final override suspend fun onCommand(sender: CommandSender, args: List<String>): Boolean {
|
*/
|
||||||
return withContext(Dispatchers.IO) {
|
operator fun get(name: String?): Any {
|
||||||
onCommandBlocking(sender, args)
|
val index = fromCommand.descriptor.params.indexOfFirst { it.name == name }
|
||||||
|
if (index == -1) {
|
||||||
|
throw NoSuchElementException("Cannot find argument named $name")
|
||||||
|
}
|
||||||
|
return values[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取名称为 [name] 的参数. 并强转为 [R].
|
||||||
|
*
|
||||||
|
* 若 [name] 为 `null` 则获取第一个匿名参数
|
||||||
|
* @throws IllegalStateException 无法强转时抛出
|
||||||
|
*/
|
||||||
|
fun <R> getAs(name: String?): R {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
return this[name] as? R ?: error("Argument $name has a type $")
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 获取第一个类型为 [R] 的参数并提供委托 */
|
||||||
|
inline operator fun <reified R : Any> getValue(thisRef: Any?, property: KProperty<*>): R = getReified()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun parseFrom(command: Command, sender: CommandSender, rawArgs: List<Any>): CommandArgs {
|
||||||
|
val params = command.descriptor.params
|
||||||
|
|
||||||
|
require(rawArgs.size >= params.size) { "No enough rawArgs: required ${params.size}, found only ${rawArgs.size}" }
|
||||||
|
|
||||||
|
command.descriptor.params.asSequence().zip(rawArgs.asSequence()).map { (commandParam, any) ->
|
||||||
|
command.parserFor(commandParam)?.parse(any, sender)
|
||||||
|
?: error("ICould not find a parser for param named ${commandParam.name}")
|
||||||
|
}.toList().let { bakedArgs ->
|
||||||
|
return CommandArgs(bakedArgs, command)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun onCommandBlocking(sender: CommandSender, args: List<String>): Boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline val Command.fullName get() = descriptor.fullName
|
||||||
|
inline val Command.usage get() = descriptor.usage
|
||||||
|
inline val Command.params get() = descriptor.params
|
||||||
|
inline val Command.description get() = descriptor.description
|
||||||
|
inline val Command.context get() = descriptor.context
|
||||||
|
inline val Command.aliases get() = descriptor.aliases
|
||||||
|
inline val Command.permission get() = descriptor.permission
|
||||||
|
inline val Command.allNames get() = descriptor.allNames
|
||||||
|
|
||||||
|
abstract class PluginCommand(
|
||||||
|
final override val owner: PluginBase,
|
||||||
|
descriptor: CommandDescriptor
|
||||||
|
) : AbstractCommand(descriptor)
|
||||||
|
|
||||||
|
internal abstract class ConsoleCommand(
|
||||||
|
descriptor: CommandDescriptor
|
||||||
|
) : AbstractCommand(descriptor) {
|
||||||
|
final override val owner: MiraiConsole get() = MiraiConsole
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class AbstractCommand(
|
||||||
|
final override val descriptor: CommandDescriptor
|
||||||
|
) : Command
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see registerCommand
|
* For Java
|
||||||
*/
|
*/
|
||||||
class CommandBuilder @PublishedApi internal constructor() {
|
@Suppress("unused")
|
||||||
var name: String? = null
|
abstract class BlockingCommand(
|
||||||
var alias: List<String>? = null
|
owner: PluginBase,
|
||||||
var description: String = ""
|
descriptor: CommandDescriptor
|
||||||
var usage: String = "use /help for help"
|
) : PluginCommand(owner, descriptor) {
|
||||||
|
final override suspend fun onCommand(sender: CommandSender, args: CommandArgs): Boolean {
|
||||||
internal var onCommand: (suspend CommandSender.(args: List<String>) -> Boolean)? = null
|
return withContext(Dispatchers.IO) { onCommandBlocking(sender, args) }
|
||||||
|
|
||||||
fun onCommand(commandProcess: suspend CommandSender.(args: List<String>) -> Boolean) {
|
|
||||||
onCommand = commandProcess
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
abstract fun onCommandBlocking(sender: CommandSender, args: CommandArgs): Boolean
|
||||||
// internal
|
|
||||||
|
|
||||||
|
|
||||||
internal class AnonymousCommand internal constructor(
|
|
||||||
override val name: String,
|
|
||||||
override val alias: List<String>,
|
|
||||||
override val description: String,
|
|
||||||
override val usage: String = "",
|
|
||||||
val onCommand: suspend CommandSender.(args: List<String>) -> Boolean
|
|
||||||
) : Command {
|
|
||||||
override suspend fun onCommand(sender: CommandSender, args: List<String>): Boolean {
|
|
||||||
return onCommand.invoke(sender, args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@PublishedApi
|
|
||||||
internal fun CommandBuilder.register(commandOwner: CommandOwner): AnonymousCommand {
|
|
||||||
if (name == null || onCommand == null) {
|
|
||||||
error("CommandBuilder not complete")
|
|
||||||
}
|
|
||||||
if (alias == null) {
|
|
||||||
alias = listOf()
|
|
||||||
}
|
|
||||||
return AnonymousCommand(
|
|
||||||
name!!,
|
|
||||||
alias!!,
|
|
||||||
description,
|
|
||||||
usage,
|
|
||||||
onCommand!!
|
|
||||||
).also { it.register(commandOwner) }
|
|
||||||
}
|
}
|
@ -17,8 +17,20 @@ import kotlin.contracts.contract
|
|||||||
* input is always String
|
* input is always String
|
||||||
*/
|
*/
|
||||||
abstract class CommandArgParser<out T : Any> {
|
abstract class CommandArgParser<out T : Any> {
|
||||||
abstract fun parse(s: String, sender: CommandSender): T
|
abstract fun parse(raw: String, sender: CommandSender): T
|
||||||
open fun parse(s: SingleMessage, sender: CommandSender): T = parse(s.content, sender)
|
open fun parse(raw: SingleMessage, sender: CommandSender): T = parse(raw.content, sender)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : Any> CommandArgParser<T>.parse(raw: Any, sender: CommandSender): T {
|
||||||
|
contract {
|
||||||
|
returns() implies (raw is String || raw is SingleMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
return when (raw) {
|
||||||
|
is String -> parse(raw, sender)
|
||||||
|
is SingleMessage -> parse(raw, sender)
|
||||||
|
else -> throw IllegalArgumentException("Illegal raw argument type: ${raw::class.qualifiedName}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
@ -46,7 +58,7 @@ inline fun CommandArgParser<*>.checkArgument(
|
|||||||
inline fun <T : Any> CommandArgParser(
|
inline fun <T : Any> CommandArgParser(
|
||||||
crossinline parser: CommandArgParser<T>.(s: String, sender: CommandSender) -> T
|
crossinline parser: CommandArgParser<T>.(s: String, sender: CommandSender) -> T
|
||||||
): CommandArgParser<T> = object : CommandArgParser<T>() {
|
): CommandArgParser<T> = object : CommandArgParser<T>() {
|
||||||
override fun parse(s: String, sender: CommandSender): T = parser(s, sender)
|
override fun parse(raw: String, sender: CommandSender): T = parser(raw, sender)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -57,41 +69,41 @@ class ParserException(message: String, cause: Throwable? = null) : RuntimeExcept
|
|||||||
|
|
||||||
|
|
||||||
object IntArgParser : CommandArgParser<Int>() {
|
object IntArgParser : CommandArgParser<Int>() {
|
||||||
override fun parse(s: String, sender: CommandSender): Int =
|
override fun parse(raw: String, sender: CommandSender): Int =
|
||||||
s.toIntOrNull() ?: illegalArgument("无法解析 $s 为整数")
|
raw.toIntOrNull() ?: illegalArgument("无法解析 $raw 为整数")
|
||||||
}
|
}
|
||||||
|
|
||||||
object LongArgParser : CommandArgParser<Long>() {
|
object LongArgParser : CommandArgParser<Long>() {
|
||||||
override fun parse(s: String, sender: CommandSender): Long =
|
override fun parse(raw: String, sender: CommandSender): Long =
|
||||||
s.toLongOrNull() ?: illegalArgument("无法解析 $s 为长整数")
|
raw.toLongOrNull() ?: illegalArgument("无法解析 $raw 为长整数")
|
||||||
}
|
}
|
||||||
|
|
||||||
object ShortArgParser : CommandArgParser<Short>() {
|
object ShortArgParser : CommandArgParser<Short>() {
|
||||||
override fun parse(s: String, sender: CommandSender): Short =
|
override fun parse(raw: String, sender: CommandSender): Short =
|
||||||
s.toShortOrNull() ?: illegalArgument("无法解析 $s 为短整数")
|
raw.toShortOrNull() ?: illegalArgument("无法解析 $raw 为短整数")
|
||||||
}
|
}
|
||||||
|
|
||||||
object ByteArgParser : CommandArgParser<Byte>() {
|
object ByteArgParser : CommandArgParser<Byte>() {
|
||||||
override fun parse(s: String, sender: CommandSender): Byte =
|
override fun parse(raw: String, sender: CommandSender): Byte =
|
||||||
s.toByteOrNull() ?: illegalArgument("无法解析 $s 为字节")
|
raw.toByteOrNull() ?: illegalArgument("无法解析 $raw 为字节")
|
||||||
}
|
}
|
||||||
|
|
||||||
object DoubleArgParser : CommandArgParser<Double>() {
|
object DoubleArgParser : CommandArgParser<Double>() {
|
||||||
override fun parse(s: String, sender: CommandSender): Double =
|
override fun parse(raw: String, sender: CommandSender): Double =
|
||||||
s.toDoubleOrNull() ?: illegalArgument("无法解析 $s 为小数")
|
raw.toDoubleOrNull() ?: illegalArgument("无法解析 $raw 为小数")
|
||||||
}
|
}
|
||||||
|
|
||||||
object FloatArgParser : CommandArgParser<Float>() {
|
object FloatArgParser : CommandArgParser<Float>() {
|
||||||
override fun parse(s: String, sender: CommandSender): Float =
|
override fun parse(raw: String, sender: CommandSender): Float =
|
||||||
s.toFloatOrNull() ?: illegalArgument("无法解析 $s 为小数")
|
raw.toFloatOrNull() ?: illegalArgument("无法解析 $raw 为小数")
|
||||||
}
|
}
|
||||||
|
|
||||||
object StringArgParser : CommandArgParser<String>() {
|
object StringArgParser : CommandArgParser<String>() {
|
||||||
override fun parse(s: String, sender: CommandSender): String = s
|
override fun parse(raw: String, sender: CommandSender): String = raw
|
||||||
}
|
}
|
||||||
|
|
||||||
object BooleanArgParser : CommandArgParser<Boolean>() {
|
object BooleanArgParser : CommandArgParser<Boolean>() {
|
||||||
override fun parse(s: String, sender: CommandSender): Boolean = s.trim().let { str ->
|
override fun parse(raw: String, sender: CommandSender): Boolean = raw.trim().let { str ->
|
||||||
str.equals("true", ignoreCase = true)
|
str.equals("true", ignoreCase = true)
|
||||||
|| str.equals("yes", ignoreCase = true)
|
|| str.equals("yes", ignoreCase = true)
|
||||||
|| str.equals("enabled", ignoreCase = true)
|
|| str.equals("enabled", ignoreCase = true)
|
||||||
@ -105,11 +117,11 @@ object BooleanArgParser : CommandArgParser<Boolean>() {
|
|||||||
* errors: String->Int convert, Bot Not Exist
|
* errors: String->Int convert, Bot Not Exist
|
||||||
*/
|
*/
|
||||||
object ExistBotArgParser : CommandArgParser<Bot>() {
|
object ExistBotArgParser : CommandArgParser<Bot>() {
|
||||||
override fun parse(s: String, sender: CommandSender): Bot {
|
override fun parse(raw: String, sender: CommandSender): Bot {
|
||||||
val uin = try {
|
val uin = try {
|
||||||
s.toLong()
|
raw.toLong()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
error("无法识别QQ UIN$s")
|
error("无法识别QQ UIN$raw")
|
||||||
}
|
}
|
||||||
return try {
|
return try {
|
||||||
Bot.getInstance(uin)
|
Bot.getInstance(uin)
|
||||||
@ -123,8 +135,8 @@ object ExistFriendArgParser : CommandArgParser<Friend>() {
|
|||||||
//Bot.friend
|
//Bot.friend
|
||||||
//friend
|
//friend
|
||||||
//~ = self
|
//~ = self
|
||||||
override fun parse(s: String, sender: CommandSender): Friend {
|
override fun parse(raw: String, sender: CommandSender): Friend {
|
||||||
if (s == "~") {
|
if (raw == "~") {
|
||||||
if (sender !is BotAware) {
|
if (sender !is BotAware) {
|
||||||
illegalArgument("无法解析~作为默认")
|
illegalArgument("无法解析~作为默认")
|
||||||
}
|
}
|
||||||
@ -141,20 +153,20 @@ object ExistFriendArgParser : CommandArgParser<Friend>() {
|
|||||||
}
|
}
|
||||||
if (sender is BotAware) {
|
if (sender is BotAware) {
|
||||||
return try {
|
return try {
|
||||||
sender.bot.friends[s.toLong()]
|
sender.bot.friends[raw.toLong()]
|
||||||
} catch (e: NoSuchElementException) {
|
} catch (e: NoSuchElementException) {
|
||||||
error("无法找到" + s + "这个好友")
|
error("无法找到" + raw + "这个好友")
|
||||||
} catch (e: NumberFormatException) {
|
} catch (e: NumberFormatException) {
|
||||||
error("无法解析$s")
|
error("无法解析$raw")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s.split(".").let { args ->
|
raw.split(".").let { args ->
|
||||||
if (args.size != 2) {
|
if (args.size != 2) {
|
||||||
illegalArgument("无法解析 $s, 格式应为 机器人账号.好友账号")
|
illegalArgument("无法解析 $raw, 格式应为 机器人账号.好友账号")
|
||||||
}
|
}
|
||||||
return try {
|
return try {
|
||||||
Bot.getInstance(args[0].toLong()).friends.getOrNull(
|
Bot.getInstance(args[0].toLong()).friends.getOrNull(
|
||||||
args[1].toLongOrNull() ?: illegalArgument("无法解析 $s 为好友")
|
args[1].toLongOrNull() ?: illegalArgument("无法解析 $raw 为好友")
|
||||||
) ?: illegalArgument("无法找到好友 ${args[1]}")
|
) ?: illegalArgument("无法找到好友 ${args[1]}")
|
||||||
} catch (e: NoSuchElementException) {
|
} catch (e: NoSuchElementException) {
|
||||||
illegalArgument("无法找到机器人账号 ${args[0]}")
|
illegalArgument("无法找到机器人账号 ${args[0]}")
|
||||||
@ -163,28 +175,28 @@ object ExistFriendArgParser : CommandArgParser<Friend>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun parse(s: SingleMessage, sender: CommandSender): Friend {
|
override fun parse(raw: SingleMessage, sender: CommandSender): Friend {
|
||||||
if (s is At) {
|
if (raw is At) {
|
||||||
assert(sender is GroupContactCommandSender)
|
assert(sender is GroupContactCommandSender)
|
||||||
return (sender as BotAware).bot.friends.getOrNull(s.target) ?: illegalArgument("At的对象非Bot好友")
|
return (sender as BotAware).bot.friends.getOrNull(raw.target) ?: illegalArgument("At的对象非Bot好友")
|
||||||
} else {
|
} else {
|
||||||
error("无法解析 $s 为好友")
|
error("无法解析 $raw 为好友")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object ExistGroupArgParser : CommandArgParser<Group>() {
|
object ExistGroupArgParser : CommandArgParser<Group>() {
|
||||||
override fun parse(s: String, sender: CommandSender): Group {
|
override fun parse(raw: String, sender: CommandSender): Group {
|
||||||
//by default
|
//by default
|
||||||
if ((s == "" || s == "~") && sender is GroupContactCommandSender) {
|
if ((raw == "" || raw == "~") && sender is GroupContactCommandSender) {
|
||||||
return sender.contact as Group
|
return sender.contact as Group
|
||||||
}
|
}
|
||||||
//from bot to group
|
//from bot to group
|
||||||
if (sender is BotAware) {
|
if (sender is BotAware) {
|
||||||
val code = try {
|
val code = try {
|
||||||
s.toLong()
|
raw.toLong()
|
||||||
} catch (e: NoSuchElementException) {
|
} catch (e: NoSuchElementException) {
|
||||||
error("无法识别Group Code$s")
|
error("无法识别Group Code$raw")
|
||||||
}
|
}
|
||||||
return try {
|
return try {
|
||||||
sender.bot.getGroup(code)
|
sender.bot.getGroup(code)
|
||||||
@ -193,7 +205,7 @@ object ExistGroupArgParser : CommandArgParser<Group>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//from console/other
|
//from console/other
|
||||||
return with(s.split(".")) {
|
return with(raw.split(".")) {
|
||||||
if (this.size != 2) {
|
if (this.size != 2) {
|
||||||
error("请使用BotQQ号.群号 来表示Bot的一个群")
|
error("请使用BotQQ号.群号 来表示Bot的一个群")
|
||||||
}
|
}
|
||||||
@ -213,9 +225,9 @@ object ExistMemberArgParser : CommandArgParser<Member>() {
|
|||||||
//私聊: Group.Member[QQ/名片]
|
//私聊: Group.Member[QQ/名片]
|
||||||
//群内: Q号
|
//群内: Q号
|
||||||
//群内: 名片
|
//群内: 名片
|
||||||
override fun parse(s: String, sender: CommandSender): Member {
|
override fun parse(raw: String, sender: CommandSender): Member {
|
||||||
if (sender !is BotAware) {
|
if (sender !is BotAware) {
|
||||||
with(s.split(".")) {
|
with(raw.split(".")) {
|
||||||
checkArgument(this.size >= 3) {
|
checkArgument(this.size >= 3) {
|
||||||
"无法识别Member, 请使用Bot.Group.Member[QQ/名片]的格式"
|
"无法识别Member, 请使用Bot.Group.Member[QQ/名片]的格式"
|
||||||
}
|
}
|
||||||
@ -246,12 +258,12 @@ object ExistMemberArgParser : CommandArgParser<Member>() {
|
|||||||
if (sender is GroupContactCommandSender) {
|
if (sender is GroupContactCommandSender) {
|
||||||
val group = sender.contact as Group
|
val group = sender.contact as Group
|
||||||
return try {
|
return try {
|
||||||
group.members[s.toLong()]
|
group.members[raw.toLong()]
|
||||||
} catch (ignored: Exception) {
|
} catch (ignored: Exception) {
|
||||||
group.fuzzySearchMember(s) ?: illegalArgument("无法找到成员$s")
|
group.fuzzySearchMember(raw) ?: illegalArgument("无法找到成员$raw")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
with(s.split(".")) {
|
with(raw.split(".")) {
|
||||||
if (this.size < 2) {
|
if (this.size < 2) {
|
||||||
illegalArgument("无法识别Member, 请使用Group.Member[QQ/名片]的格式")
|
illegalArgument("无法识别Member, 请使用Group.Member[QQ/名片]的格式")
|
||||||
}
|
}
|
||||||
@ -274,12 +286,12 @@ object ExistMemberArgParser : CommandArgParser<Member>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun parse(s: SingleMessage, sender: CommandSender): Member {
|
override fun parse(raw: SingleMessage, sender: CommandSender): Member {
|
||||||
return if (s is At) {
|
return if (raw is At) {
|
||||||
checkArgument(sender is GroupContactCommandSender)
|
checkArgument(sender is GroupContactCommandSender)
|
||||||
(sender.contact as Group).members[s.target]
|
(sender.contact as Group).members[raw.target]
|
||||||
} else {
|
} else {
|
||||||
illegalArgument("无法识别Member" + s.content)
|
illegalArgument("无法识别Member" + raw.content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console.command
|
package net.mamoe.mirai.console.command
|
||||||
|
|
||||||
|
import net.mamoe.mirai.message.data.Message
|
||||||
|
import net.mamoe.mirai.message.data.MessageChain
|
||||||
|
import net.mamoe.mirai.message.data.PlainText
|
||||||
|
import net.mamoe.mirai.message.data.SingleMessage
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -11,15 +15,19 @@ class CommandDescriptor(
|
|||||||
/**
|
/**
|
||||||
* 包含子命令的全名. 如 "`group kick`", 其中 `kick` 为 `group` 的子命令
|
* 包含子命令的全名. 如 "`group kick`", 其中 `kick` 为 `group` 的子命令
|
||||||
*/
|
*/
|
||||||
val fullName: String,
|
fullName: CommandFullName,
|
||||||
/**
|
/**
|
||||||
* 用法说明
|
* 用法说明
|
||||||
*/
|
*/
|
||||||
val usage: String,
|
usage: String,
|
||||||
/**
|
/**
|
||||||
* 指令参数列表, 有顺序.
|
* 指令参数列表, 有顺序.
|
||||||
*/
|
*/
|
||||||
val params: List<CommandParam<*>>,
|
val params: List<CommandParam<*>>,
|
||||||
|
/**
|
||||||
|
* 指令说明
|
||||||
|
*/
|
||||||
|
description: String = "",
|
||||||
/**
|
/**
|
||||||
* 指令参数解析器环境.
|
* 指令参数解析器环境.
|
||||||
*/
|
*/
|
||||||
@ -27,7 +35,7 @@ class CommandDescriptor(
|
|||||||
/**
|
/**
|
||||||
* 指令别名
|
* 指令别名
|
||||||
*/
|
*/
|
||||||
val aliases: Array<String> = arrayOf(),
|
aliases: Array<CommandFullName> = arrayOf(),
|
||||||
/**
|
/**
|
||||||
* 指令权限
|
* 指令权限
|
||||||
*
|
*
|
||||||
@ -35,19 +43,101 @@ class CommandDescriptor(
|
|||||||
* @see CommandPermission.and 同时要求两个权限
|
* @see CommandPermission.and 同时要求两个权限
|
||||||
*/
|
*/
|
||||||
val permission: CommandPermission = CommandPermission.Default
|
val permission: CommandPermission = CommandPermission.Default
|
||||||
)
|
) {
|
||||||
|
/**
|
||||||
|
* 指令别名
|
||||||
|
*/
|
||||||
|
val aliases: Array<CommandFullName> = aliases.map { it.checkFullName("alias") }.toTypedArray()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指令说明
|
||||||
|
*/
|
||||||
|
val description: String = description.trim()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用法说明
|
||||||
|
*/
|
||||||
|
val usage: String = usage.trim()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 包含子命令的全名. 如 "`group kick`", 其中 `kick` 为 `group` 的子命令
|
||||||
|
* 元素类型可以为 [Message] 或 [String]
|
||||||
|
*/
|
||||||
|
val fullName: CommandFullName = fullName.checkFullName("fullName")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `fullName + aliases`
|
||||||
|
*/
|
||||||
|
val allNames = arrayOf(fullName, *aliases)
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as CommandDescriptor
|
||||||
|
|
||||||
|
if (!fullName.contentEquals(other.fullName)) return false
|
||||||
|
if (usage != other.usage) return false
|
||||||
|
if (params != other.params) return false
|
||||||
|
if (description != other.description) return false
|
||||||
|
if (context != other.context) return false
|
||||||
|
if (!aliases.contentEquals(other.aliases)) return false
|
||||||
|
if (permission != other.permission) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = fullName.hashCode()
|
||||||
|
result = 31 * result + usage.hashCode()
|
||||||
|
result = 31 * result + params.hashCode()
|
||||||
|
result = 31 * result + description.hashCode()
|
||||||
|
result = 31 * result + context.hashCode()
|
||||||
|
result = 31 * result + aliases.contentHashCode()
|
||||||
|
result = 31 * result + permission.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun Command.checkArgs(args: CommandArgs) = this.descriptor.checkArgs(args)
|
||||||
|
fun CommandDescriptor.checkArgs(args: CommandArgs) {
|
||||||
|
require(args.size >= this.params.size) { "No enough args. Required ${params.size}, but given ${args.size}" }
|
||||||
|
params.forEachIndexed { index, commandParam ->
|
||||||
|
require(commandParam.type.isInstance(args[index])) {
|
||||||
|
"Illegal arg #$index, required ${commandParam.type.qualifiedName}, but given ${args[index]::class.qualifiedName}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Any.flattenCommandComponents(): Sequence<Any> = when (this) {
|
||||||
|
is Array<*> -> this.asSequence().flatMap {
|
||||||
|
it?.flattenCommandComponents() ?: throw java.lang.IllegalArgumentException("unexpected null value")
|
||||||
|
}
|
||||||
|
is String -> splitToSequence(' ').filterNot { it.isBlank() }
|
||||||
|
is PlainText -> content.flattenCommandComponents()
|
||||||
|
is SingleMessage -> sequenceOf(this)
|
||||||
|
is MessageChain -> this.asSequence().map { it.flattenCommandComponents() }
|
||||||
|
else -> throw IllegalArgumentException("Illegal component: $this")
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun CommandFullName.checkFullName(errorHint: String): CommandFullName {
|
||||||
|
return flattenCommandComponents().toList().also {
|
||||||
|
require(it.isNotEmpty()) { "$errorHint must not be empty" }
|
||||||
|
}.toTypedArray()
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 构建一个 [CommandDescriptor]
|
* 构建一个 [CommandDescriptor]
|
||||||
*/
|
*/
|
||||||
@Suppress("FunctionName")
|
@Suppress("FunctionName")
|
||||||
inline fun CommandDescriptor(
|
inline fun CommandDescriptor(
|
||||||
fullName: String,
|
vararg fullName: Any,
|
||||||
block: CommandDescriptorBuilder.() -> Unit
|
block: CommandDescriptorBuilder.() -> Unit = {}
|
||||||
): CommandDescriptor = CommandDescriptorBuilder(fullName).apply(block).build()
|
): CommandDescriptor = CommandDescriptorBuilder(fullName).apply(block).build()
|
||||||
|
|
||||||
class CommandDescriptorBuilder(
|
class CommandDescriptorBuilder(
|
||||||
val fullName: String
|
vararg val fullName: Any
|
||||||
) {
|
) {
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
internal var context: CommandParserContext = CommandParserContext.Builtins
|
internal var context: CommandParserContext = CommandParserContext.Builtins
|
||||||
@ -62,7 +152,10 @@ class CommandDescriptorBuilder(
|
|||||||
internal var usage: String = "<no usage>"
|
internal var usage: String = "<no usage>"
|
||||||
|
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
internal var aliases: MutableList<String> = mutableListOf()
|
internal var aliases: MutableList<CommandFullName> = mutableListOf()
|
||||||
|
|
||||||
|
@PublishedApi
|
||||||
|
internal var description: String = ""
|
||||||
|
|
||||||
/** 增加指令参数解析器列表 */
|
/** 增加指令参数解析器列表 */
|
||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
@ -91,8 +184,15 @@ class CommandDescriptorBuilder(
|
|||||||
usage = message
|
usage = message
|
||||||
}
|
}
|
||||||
|
|
||||||
fun alias(vararg name: String): CommandDescriptorBuilder = apply {
|
fun description(description: String): CommandDescriptorBuilder = apply {
|
||||||
this.aliases.addAll(name)
|
this.description = description
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加一个别名
|
||||||
|
*/
|
||||||
|
fun alias(vararg fullName: Any): CommandDescriptorBuilder = apply {
|
||||||
|
this.aliases.add(fullName)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun param(vararg params: CommandParam<*>): CommandDescriptorBuilder = apply {
|
fun param(vararg params: CommandParam<*>): CommandDescriptorBuilder = apply {
|
||||||
@ -105,7 +205,7 @@ class CommandDescriptorBuilder(
|
|||||||
type: KClass<T>,
|
type: KClass<T>,
|
||||||
overrideParser: CommandArgParser<T>? = null
|
overrideParser: CommandArgParser<T>? = null
|
||||||
): CommandDescriptorBuilder = apply {
|
): CommandDescriptorBuilder = apply {
|
||||||
this.params.add(CommandParam(name, type).apply { this.parser = overrideParser })
|
this.params.add(CommandParam(name, type).apply { this._overrideParser = overrideParser })
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> param(
|
fun <T : Any> param(
|
||||||
@ -143,7 +243,7 @@ class CommandDescriptorBuilder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun build(): CommandDescriptor =
|
fun build(): CommandDescriptor =
|
||||||
CommandDescriptor(fullName, context, params, usage, aliases.toTypedArray(), permission)
|
CommandDescriptor(fullName, usage, params, description, context, aliases.toTypedArray(), permission)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS")
|
@Suppress("NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS")
|
||||||
@ -154,7 +254,7 @@ inline class ParamBlock internal constructor(@PublishedApi internal val list: Mu
|
|||||||
|
|
||||||
/** 指定 [CommandParam.overrideParser] */
|
/** 指定 [CommandParam.overrideParser] */
|
||||||
infix fun <T : Any> CommandParam<T>.using(parser: CommandArgParser<T>): CommandParam<T> =
|
infix fun <T : Any> CommandParam<T>.using(parser: CommandArgParser<T>): CommandParam<T> =
|
||||||
this.apply { this.parser = parser }
|
this.apply { this._overrideParser = parser }
|
||||||
|
|
||||||
/** 覆盖 [CommandArgParser] */
|
/** 覆盖 [CommandArgParser] */
|
||||||
inline infix fun <reified T : Any> String.using(parser: CommandArgParser<T>): CommandParam<T> =
|
inline infix fun <reified T : Any> String.using(parser: CommandArgParser<T>): CommandParam<T> =
|
||||||
|
@ -1,3 +1,121 @@
|
|||||||
|
@file:Suppress("NOTHING_TO_INLINE")
|
||||||
|
@file:JvmName("CommandManager")
|
||||||
|
|
||||||
package net.mamoe.mirai.console.command
|
package net.mamoe.mirai.console.command
|
||||||
|
|
||||||
object CommandManager
|
import kotlinx.atomicfu.locks.withLock
|
||||||
|
import net.mamoe.mirai.message.data.Message
|
||||||
|
import net.mamoe.mirai.message.data.MessageChain
|
||||||
|
import java.util.*
|
||||||
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
|
|
||||||
|
typealias CommandFullName = Array<out Any>
|
||||||
|
|
||||||
|
interface CommandOwner
|
||||||
|
|
||||||
|
val CommandOwner.registeredCommands: List<Command> get() = InternalCommandManager.registeredCommands.filter { it.owner == this }
|
||||||
|
|
||||||
|
fun CommandOwner.unregisterAllCommands() {
|
||||||
|
for (registeredCommand in registeredCommands) {
|
||||||
|
registeredCommand.unregister()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册一个指令. 若此指令已经注册或有已经注册的指令与 [allNames] 重名, 返回 `false`
|
||||||
|
*/
|
||||||
|
fun Command.register(): Boolean = InternalCommandManager.modifyLock.withLock {
|
||||||
|
with(descriptor) {
|
||||||
|
if (findDuplicate() != null) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
InternalCommandManager.registeredCommands.add(this@register)
|
||||||
|
for (name in this.allNames) {
|
||||||
|
InternalCommandManager.nameToCommandMap[name] = this@register
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找是否有重名的指令. 返回重名的指令.
|
||||||
|
*/
|
||||||
|
fun Command.findDuplicate(): Command? {
|
||||||
|
return InternalCommandManager.nameToCommandMap.entries.firstOrNull { (names, _) ->
|
||||||
|
this.allNames.any { it.contentEquals(names) }
|
||||||
|
}?.value
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消注册这个指令. 若指令未注册, 返回 `false`
|
||||||
|
*/
|
||||||
|
fun Command.unregister(): Boolean = InternalCommandManager.modifyLock.withLock {
|
||||||
|
if (!InternalCommandManager.registeredCommands.contains(this)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
InternalCommandManager.registeredCommands.remove(this)
|
||||||
|
for (name in this.allNames) {
|
||||||
|
InternalCommandManager.nameToCommandMap.entries.removeIf {
|
||||||
|
it.key.contentEquals(this.fullName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析并执行一个指令
|
||||||
|
* @param args 接受 [String] 或 [Message]
|
||||||
|
* @return 是否成功解析到指令. 返回 `false` 代表无任何指令匹配
|
||||||
|
*/
|
||||||
|
suspend fun CommandSender.executeCommand(vararg args: Any): Boolean {
|
||||||
|
return args.flattenCommandComponents().toList().executeCommand(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析并执行一个指令
|
||||||
|
* @return 是否成功解析到指令. 返回 `false` 代表无任何指令匹配
|
||||||
|
*/
|
||||||
|
suspend fun MessageChain.executeAsCommand(sender: CommandSender): Boolean {
|
||||||
|
return this.flattenCommandComponents().toList().executeCommand(sender)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun CommandSender.execute(command: Command, args: CommandArgs): Boolean = with(command) {
|
||||||
|
checkArgs(args)
|
||||||
|
return onCommand(this@execute, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun Command.execute(sender: CommandSender, args: CommandArgs): Boolean = sender.execute(this, args)
|
||||||
|
suspend fun Command.execute(sender: CommandSender, vararg args: Any): Boolean = sender.execute(this, args)
|
||||||
|
suspend fun CommandSender.execute(command: Command, vararg args: Any): Boolean = command.execute(this, args)
|
||||||
|
|
||||||
|
|
||||||
|
internal suspend fun List<Any>.executeCommand(sender: CommandSender): Boolean {
|
||||||
|
val command = InternalCommandManager.matchCommand(this) ?: return false
|
||||||
|
return command.onCommand(sender, CommandArgs.parseFrom(command, sender, this.drop(command.fullName.size)))
|
||||||
|
}
|
||||||
|
|
||||||
|
internal infix fun CommandFullName.matchesBeginning(list: List<Any>): Boolean {
|
||||||
|
this.forEachIndexed { index, any ->
|
||||||
|
if (list[index] != any) return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
internal object InternalCommandManager {
|
||||||
|
@JvmField
|
||||||
|
internal val registeredCommands: MutableList<Command> = mutableListOf()
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
internal val nameToCommandMap: TreeMap<CommandFullName, Command> = TreeMap(Comparator.comparingInt { it.size })
|
||||||
|
|
||||||
|
@JvmField
|
||||||
|
internal val modifyLock = ReentrantLock()
|
||||||
|
|
||||||
|
|
||||||
|
internal fun matchCommand(splitted: List<Any>): Command? {
|
||||||
|
nameToCommandMap.entries.forEach {
|
||||||
|
if (it.key matchesBeginning splitted) return it.value
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
@ -20,17 +20,27 @@ data class CommandParam<T : Any>(
|
|||||||
val type: KClass<T> // exact type
|
val type: KClass<T> // exact type
|
||||||
) {
|
) {
|
||||||
constructor(name: String?, type: KClass<T>, parser: CommandArgParser<T>) : this(name, type) {
|
constructor(name: String?, type: KClass<T>, parser: CommandArgParser<T>) : this(name, type) {
|
||||||
this.parser = parser
|
this._overrideParser = parser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("PropertyName")
|
||||||
@JvmField
|
@JvmField
|
||||||
internal var parser: CommandArgParser<T>? = null
|
internal var _overrideParser: CommandArgParser<T>? = null
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 覆盖的 [CommandArgParser].
|
* 覆盖的 [CommandArgParser].
|
||||||
*
|
*
|
||||||
* 如果非 `null`, 将不会从 [CommandParserContext] 寻找 [CommandArgParser]
|
* 如果非 `null`, 将不会从 [CommandParserContext] 寻找 [CommandArgParser]
|
||||||
|
*
|
||||||
|
* @see Command.parserFor
|
||||||
*/
|
*/
|
||||||
val overrideParser: CommandArgParser<T>? get() = parser
|
val overrideParser: CommandArgParser<T>? get() = _overrideParser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T : Any> CommandParam<T>.parserFrom(command: Command): CommandArgParser<T>? = command.parserFor(this)
|
||||||
|
|
||||||
|
fun <T : Any> CommandParam<T>.parserFrom(descriptor: CommandDescriptor): CommandArgParser<T>? =
|
||||||
|
descriptor.parserFor(this)
|
||||||
|
|
||||||
|
fun <T : Any> CommandParam<T>.parserFrom(context: CommandParserContext): CommandArgParser<T>? = context.parserFor(this)
|
@ -12,7 +12,7 @@
|
|||||||
package net.mamoe.mirai.console.command
|
package net.mamoe.mirai.console.command
|
||||||
|
|
||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.console.command.AbstractCommandParserContext.Node
|
import net.mamoe.mirai.console.command.AbstractCommandParserContext.ParserPair
|
||||||
import net.mamoe.mirai.contact.Group
|
import net.mamoe.mirai.contact.Group
|
||||||
import net.mamoe.mirai.contact.Member
|
import net.mamoe.mirai.contact.Member
|
||||||
import kotlin.internal.LowPriorityInOverloadResolution
|
import kotlin.internal.LowPriorityInOverloadResolution
|
||||||
@ -21,6 +21,7 @@ import kotlin.reflect.KClass
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* [KClass] 到 [CommandArgParser] 的匹配
|
* [KClass] 到 [CommandArgParser] 的匹配
|
||||||
|
* @see AbstractCommandParserContext
|
||||||
*/
|
*/
|
||||||
interface CommandParserContext {
|
interface CommandParserContext {
|
||||||
operator fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>?
|
operator fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>?
|
||||||
@ -44,7 +45,14 @@ interface CommandParserContext {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Any> CommandParserContext.parserFor(param: CommandParam<T>): CommandArgParser<T>? = this[param.type]
|
fun <T : Any> CommandParserContext.parserFor(param: CommandParam<T>): CommandArgParser<T>? =
|
||||||
|
param.overrideParser ?: this[param.type]
|
||||||
|
|
||||||
|
fun <T : Any> CommandDescriptor.parserFor(param: CommandParam<T>): CommandArgParser<T>? =
|
||||||
|
param.overrideParser ?: this.context.parserFor(param)
|
||||||
|
|
||||||
|
fun <T : Any> Command.parserFor(param: CommandParam<T>): CommandArgParser<T>? =
|
||||||
|
param.overrideParser ?: this.descriptor.parserFor(param)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 合并两个 [CommandParserContext], [replacer] 将会替换 [this] 中重复的 parser.
|
* 合并两个 [CommandParserContext], [replacer] 将会替换 [this] 中重复的 parser.
|
||||||
@ -56,8 +64,8 @@ operator fun CommandParserContext.plus(replacer: CommandParserContext): CommandP
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
open class AbstractCommandParserContext(val list: List<Node<*>>) : CommandParserContext {
|
open class AbstractCommandParserContext(val list: List<ParserPair<*>>) : CommandParserContext {
|
||||||
class Node<T : Any>(
|
class ParserPair<T : Any>(
|
||||||
val klass: KClass<T>,
|
val klass: KClass<T>,
|
||||||
val parser: CommandArgParser<T>
|
val parser: CommandArgParser<T>
|
||||||
)
|
)
|
||||||
@ -92,10 +100,10 @@ inline fun CommandParserContext(block: CommandParserContextBuilder.() -> Unit):
|
|||||||
/**
|
/**
|
||||||
* @see CommandParserContext
|
* @see CommandParserContext
|
||||||
*/
|
*/
|
||||||
class CommandParserContextBuilder : MutableList<Node<*>> by mutableListOf() {
|
class CommandParserContextBuilder : MutableList<ParserPair<*>> by mutableListOf() {
|
||||||
@JvmName("add")
|
@JvmName("add")
|
||||||
inline infix fun <T : Any> KClass<T>.with(parser: CommandArgParser<T>): Node<*> =
|
inline infix fun <T : Any> KClass<T>.with(parser: CommandArgParser<T>): ParserPair<*> =
|
||||||
Node(this, parser)
|
ParserPair(this, parser)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加一个指令解析器
|
* 添加一个指令解析器
|
||||||
@ -104,7 +112,7 @@ class CommandParserContextBuilder : MutableList<Node<*>> by mutableListOf() {
|
|||||||
@LowPriorityInOverloadResolution
|
@LowPriorityInOverloadResolution
|
||||||
inline infix fun <T : Any> KClass<T>.with(
|
inline infix fun <T : Any> KClass<T>.with(
|
||||||
crossinline parser: CommandArgParser<T>.(s: String, sender: CommandSender) -> T
|
crossinline parser: CommandArgParser<T>.(s: String, sender: CommandSender) -> T
|
||||||
): Node<*> = Node(this, CommandArgParser(parser))
|
): ParserPair<*> = ParserPair(this, CommandArgParser(parser))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加一个指令解析器
|
* 添加一个指令解析器
|
||||||
@ -112,7 +120,7 @@ class CommandParserContextBuilder : MutableList<Node<*>> by mutableListOf() {
|
|||||||
@JvmSynthetic
|
@JvmSynthetic
|
||||||
inline infix fun <T : Any> KClass<T>.with(
|
inline infix fun <T : Any> KClass<T>.with(
|
||||||
crossinline parser: CommandArgParser<T>.(s: String) -> T
|
crossinline parser: CommandArgParser<T>.(s: String) -> T
|
||||||
): Node<*> = Node(this, CommandArgParser { s: String, _: CommandSender -> parser(s) })
|
): ParserPair<*> = ParserPair(this, CommandArgParser { s: String, _: CommandSender -> parser(s) })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ package net.mamoe.mirai.console.command
|
|||||||
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
|
||||||
import net.mamoe.mirai.contact.Contact
|
import net.mamoe.mirai.contact.Contact
|
||||||
import net.mamoe.mirai.contact.Member
|
import net.mamoe.mirai.contact.Member
|
||||||
import net.mamoe.mirai.message.data.Message
|
import net.mamoe.mirai.message.data.Message
|
||||||
@ -58,11 +57,13 @@ abstract class AbstractCommandSender : CommandSender {
|
|||||||
*/
|
*/
|
||||||
object ConsoleCommandSender : AbstractCommandSender() {
|
object ConsoleCommandSender : AbstractCommandSender() {
|
||||||
override suspend fun sendMessage(messageChain: Message) {
|
override suspend fun sendMessage(messageChain: Message) {
|
||||||
MiraiConsole.logger("[Command]", 0, messageChain.toString())
|
TODO()
|
||||||
|
// MiraiConsole.logger("[Command]", 0, messageChain.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun sendMessage(message: String) {
|
override suspend fun sendMessage(message: String) {
|
||||||
MiraiConsole.logger("[Command]", 0, message)
|
TODO()
|
||||||
|
// MiraiConsole.logger("[Command]", 0, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun flushMessage() {
|
override suspend fun flushMessage() {
|
||||||
|
@ -9,22 +9,26 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console.command
|
package net.mamoe.mirai.console.command
|
||||||
|
|
||||||
import kotlinx.coroutines.GlobalScope
|
suspend fun main() {
|
||||||
import kotlinx.coroutines.launch
|
ConsoleCommandSender.execute(DefaultCommands.Test, "test")
|
||||||
import net.mamoe.mirai.Bot
|
}
|
||||||
import net.mamoe.mirai.Bot.Companion.botInstances
|
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
|
||||||
import net.mamoe.mirai.console.plugins.PluginManager
|
|
||||||
import net.mamoe.mirai.console.utils.addManager
|
|
||||||
import net.mamoe.mirai.console.utils.checkManager
|
|
||||||
import net.mamoe.mirai.console.utils.managers
|
|
||||||
import net.mamoe.mirai.console.utils.removeManager
|
|
||||||
import net.mamoe.mirai.event.subscribeMessages
|
|
||||||
import net.mamoe.mirai.getFriendOrNull
|
|
||||||
import net.mamoe.mirai.message.GroupMessageEvent
|
|
||||||
import net.mamoe.mirai.utils.SimpleLogger
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
|
internal object DefaultCommands {
|
||||||
|
|
||||||
|
object Test : ConsoleCommand(
|
||||||
|
CommandDescriptor("test") {
|
||||||
|
param<String>()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
override suspend fun onCommand(sender: CommandSender, args: CommandArgs): Boolean {
|
||||||
|
val s = args.getReified<String>()
|
||||||
|
sender.sendMessage(s)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some defaults commands are recommend to be replaced by plugin provided commands
|
* Some defaults commands are recommend to be replaced by plugin provided commands
|
||||||
@ -369,3 +373,5 @@ internal object DefaultCommands {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*/
|
@ -12,13 +12,12 @@
|
|||||||
package net.mamoe.mirai.console.plugins
|
package net.mamoe.mirai.console.plugins
|
||||||
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
|
||||||
import net.mamoe.mirai.console.command.Command
|
import net.mamoe.mirai.console.command.Command
|
||||||
|
import net.mamoe.mirai.console.command.CommandOwner
|
||||||
import net.mamoe.mirai.console.command.CommandSender
|
import net.mamoe.mirai.console.command.CommandSender
|
||||||
import net.mamoe.mirai.console.events.EventListener
|
import net.mamoe.mirai.console.events.EventListener
|
||||||
import net.mamoe.mirai.console.scheduler.PluginScheduler
|
import net.mamoe.mirai.console.scheduler.PluginScheduler
|
||||||
import net.mamoe.mirai.utils.MiraiLogger
|
import net.mamoe.mirai.utils.MiraiLogger
|
||||||
import net.mamoe.mirai.utils.SimpleLogger
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
@ -28,15 +27,17 @@ import kotlin.coroutines.EmptyCoroutineContext
|
|||||||
* 所有插件的基类
|
* 所有插件的基类
|
||||||
*/
|
*/
|
||||||
abstract class PluginBase
|
abstract class PluginBase
|
||||||
@JvmOverloads constructor(coroutineContext: CoroutineContext = EmptyCoroutineContext) : CoroutineScope {
|
@JvmOverloads constructor(coroutineContext: CoroutineContext = EmptyCoroutineContext) : CoroutineScope, CommandOwner {
|
||||||
final override val coroutineContext: CoroutineContext = coroutineContext + SupervisorJob()
|
final override val coroutineContext: CoroutineContext = coroutineContext + SupervisorJob()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 插件被分配的数据目录。数据目录会与插件名称同名。
|
* 插件被分配的数据目录。数据目录会与插件名称同名。
|
||||||
*/
|
*/
|
||||||
val dataFolder: File by lazy {
|
val dataFolder: File by lazy {
|
||||||
|
TODO()
|
||||||
|
/*
|
||||||
File(PluginManager.pluginsPath + "/" + PluginManager.lastPluginName)
|
File(PluginManager.pluginsPath + "/" + PluginManager.lastPluginName)
|
||||||
.also { it.mkdir() }
|
.also { it.mkdir() }*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -82,13 +83,15 @@ abstract class PluginBase
|
|||||||
* 插件的日志
|
* 插件的日志
|
||||||
*/
|
*/
|
||||||
val logger: MiraiLogger by lazy {
|
val logger: MiraiLogger by lazy {
|
||||||
|
TODO()
|
||||||
|
/*
|
||||||
SimpleLogger("Plugin $pluginName") { priority, message, e ->
|
SimpleLogger("Plugin $pluginName") { priority, message, e ->
|
||||||
val identityString = "[${pluginName}]"
|
val identityString = "[${pluginName}]"
|
||||||
MiraiConsole.logger(priority, identityString, 0, message)
|
MiraiConsole.logger(priority, identityString, 0, message)
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
MiraiConsole.logger(priority, identityString, 0, e)
|
MiraiConsole.logger(priority, identityString, 0, e)
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -98,10 +101,13 @@ abstract class PluginBase
|
|||||||
return try {
|
return try {
|
||||||
this.javaClass.classLoader.getResourceAsStream(fileName)
|
this.javaClass.classLoader.getResourceAsStream(fileName)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
TODO()
|
||||||
|
|
||||||
|
/*
|
||||||
PluginManager.getFileInJarByName(
|
PluginManager.getFileInJarByName(
|
||||||
this.pluginName,
|
this.pluginName,
|
||||||
fileName
|
fileName
|
||||||
)
|
)*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,18 +14,18 @@ package net.mamoe.mirai.console.plugins
|
|||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
import net.mamoe.mirai.console.MiraiConsole
|
||||||
import net.mamoe.mirai.console.command.Command
|
import net.mamoe.mirai.console.command.Command
|
||||||
import net.mamoe.mirai.console.command.CommandManager
|
|
||||||
import net.mamoe.mirai.console.command.CommandSender
|
import net.mamoe.mirai.console.command.CommandSender
|
||||||
|
import net.mamoe.mirai.console.command.description
|
||||||
|
import net.mamoe.mirai.console.command.unregisterAllCommands
|
||||||
import net.mamoe.mirai.console.encodeToString
|
import net.mamoe.mirai.console.encodeToString
|
||||||
import net.mamoe.mirai.utils.LockFreeLinkedList
|
import net.mamoe.mirai.utils.LockFreeLinkedList
|
||||||
import net.mamoe.mirai.utils.SimpleLogger
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.net.JarURLConnection
|
import java.net.JarURLConnection
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.util.jar.JarFile
|
import java.util.jar.JarFile
|
||||||
|
|
||||||
val PluginBase.description: PluginDescription get() = PluginManager.getPluginDescription(this)
|
val PluginBase.description: PluginDescription get() = TODO()
|
||||||
|
|
||||||
object PluginManagerOld {
|
object PluginManagerOld {
|
||||||
/**
|
/**
|
||||||
@ -53,9 +53,9 @@ object PluginManagerOld {
|
|||||||
*/
|
*/
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun disablePlugins(throwable: CancellationException? = null) {
|
fun disablePlugins(throwable: CancellationException? = null) {
|
||||||
CommandManager.clearPluginsCommands()
|
pluginsSequence.forEach { plugin ->
|
||||||
pluginsSequence.forEach {
|
plugin.unregisterAllCommands()
|
||||||
it.disable(throwable)
|
plugin.disable(throwable)
|
||||||
}
|
}
|
||||||
nameToPluginBaseMap.clear()
|
nameToPluginBaseMap.clear()
|
||||||
pluginDescriptions.clear()
|
pluginDescriptions.clear()
|
||||||
@ -87,10 +87,7 @@ object PluginManagerOld {
|
|||||||
File(it).mkdirs()
|
File(it).mkdirs()
|
||||||
}
|
}
|
||||||
|
|
||||||
private val logger = SimpleLogger("Plugin Manager") { p, message, e ->
|
private val logger = MiraiConsole.newLogger("Plugin Manager")
|
||||||
MiraiConsole.logger(p, "[Plugin Manager]", 0, message)
|
|
||||||
MiraiConsole.logger(p, "[Plugin Manager]", 0, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载成功的插件, 名字->插件
|
* 加载成功的插件, 名字->插件
|
||||||
@ -351,7 +348,7 @@ object PluginManagerOld {
|
|||||||
plugin: PluginBase,
|
plugin: PluginBase,
|
||||||
exception: CancellationException? = null
|
exception: CancellationException? = null
|
||||||
) {
|
) {
|
||||||
CommandManager.clearPluginCommands(plugin)
|
plugin.unregisterAllCommands()
|
||||||
plugin.disable(exception)
|
plugin.disable(exception)
|
||||||
nameToPluginBaseMap.remove(plugin.pluginName)
|
nameToPluginBaseMap.remove(plugin.pluginName)
|
||||||
pluginDescriptions.remove(plugin.pluginName)
|
pluginDescriptions.remove(plugin.pluginName)
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
package net.mamoe.mirai.console.plugins
|
package net.mamoe.mirai.console.plugins
|
||||||
|
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
import net.mamoe.mirai.console.MiraiConsole
|
||||||
import net.mamoe.mirai.utils.SimpleLogger
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.URLClassLoader
|
import java.net.URLClassLoader
|
||||||
|
|
||||||
@ -18,10 +17,7 @@ internal class PluginsLoader(private val parentClassLoader: ClassLoader) {
|
|||||||
private val loggerName = "PluginsLoader"
|
private val loggerName = "PluginsLoader"
|
||||||
private val pluginLoaders = linkedMapOf<String, PluginClassLoader>()
|
private val pluginLoaders = linkedMapOf<String, PluginClassLoader>()
|
||||||
private val classesCache = mutableMapOf<String, Class<*>>()
|
private val classesCache = mutableMapOf<String, Class<*>>()
|
||||||
private val logger = SimpleLogger(loggerName) { p, message, e ->
|
private val logger = MiraiConsole.newLogger(loggerName)
|
||||||
MiraiConsole.logger(p, "[${loggerName}]", 0, message)
|
|
||||||
MiraiConsole.logger(p, "[${loggerName}]", 0, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清除所有插件加载器
|
* 清除所有插件加载器
|
||||||
|
@ -27,7 +27,7 @@ interface MiraiConsoleFrontEnd {
|
|||||||
*/
|
*/
|
||||||
val pluginCenter: PluginCenter get() = CuiPluginCenter
|
val pluginCenter: PluginCenter get() = CuiPluginCenter
|
||||||
|
|
||||||
fun loggerFor(identity: Long): MiraiLogger
|
fun loggerFor(identity: String?): MiraiLogger
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 让 UI 层准备接受新增的一个BOT
|
* 让 UI 层准备接受新增的一个BOT
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
package net.mamoe.mirai.console.graphical
|
package net.mamoe.mirai.console.graphical
|
||||||
|
|
||||||
|
import kotlinx.coroutines.cancel
|
||||||
import net.mamoe.mirai.console.MiraiConsole
|
import net.mamoe.mirai.console.MiraiConsole
|
||||||
import tornadofx.launch
|
import tornadofx.launch
|
||||||
import kotlin.concurrent.thread
|
import kotlin.concurrent.thread
|
||||||
@ -24,7 +25,7 @@ class MiraiConsoleGraphicalLoader {
|
|||||||
this.coreVersion = coreVersion
|
this.coreVersion = coreVersion
|
||||||
this.consoleVersion = consoleVersion
|
this.consoleVersion = consoleVersion
|
||||||
Runtime.getRuntime().addShutdownHook(thread(start = false) {
|
Runtime.getRuntime().addShutdownHook(thread(start = false) {
|
||||||
MiraiConsole.stop()
|
MiraiConsole.cancel()
|
||||||
})
|
})
|
||||||
launch<MiraiGraphicalUI>()
|
launch<MiraiGraphicalUI>()
|
||||||
}
|
}
|
||||||
|
@ -23,41 +23,46 @@ pluginManagement {
|
|||||||
|
|
||||||
rootProject.name = 'mirai-console'
|
rootProject.name = 'mirai-console'
|
||||||
|
|
||||||
|
def onlyBackEnd = true
|
||||||
|
|
||||||
include(':mirai-console')
|
include(':mirai-console')
|
||||||
project(':mirai-console').dir = file("backend/mirai-console")
|
project(':mirai-console').dir = file("backend/mirai-console")
|
||||||
|
|
||||||
|
|
||||||
include(':mirai-console-pure')
|
if (!onlyBackEnd) {
|
||||||
project(':mirai-console-pure').dir = file("frontend/mirai-console-pure")
|
|
||||||
|
|
||||||
include(':mirai-console-terminal')
|
include(':mirai-console-pure')
|
||||||
project(':mirai-console-terminal').dir = file("frontend/mirai-console-terminal")
|
project(':mirai-console-pure').dir = file("frontend/mirai-console-pure")
|
||||||
|
|
||||||
try{
|
include(':mirai-console-terminal')
|
||||||
def javaVersion = System.getProperty("java.version")
|
project(':mirai-console-terminal').dir = file("frontend/mirai-console-terminal")
|
||||||
def versionPos = javaVersion.indexOf(".")
|
|
||||||
def javaVersionNum = javaVersion.substring(0, 1).toInteger()
|
|
||||||
|
|
||||||
if (javaVersion.startsWith("1.")) {
|
try {
|
||||||
javaVersionNum = javaVersion.substring(2, 3).toInteger()
|
def javaVersion = System.getProperty("java.version")
|
||||||
} else {
|
def versionPos = javaVersion.indexOf(".")
|
||||||
if (versionPos==-1) versionPos = javaVersion.indexOf("-")
|
def javaVersionNum = javaVersion.substring(0, 1).toInteger()
|
||||||
if (versionPos==-1){
|
|
||||||
println("jdk version unknown")
|
if (javaVersion.startsWith("1.")) {
|
||||||
}else{
|
javaVersionNum = javaVersion.substring(2, 3).toInteger()
|
||||||
javaVersionNum = javaVersion.substring(0, versionPos).toInteger()
|
} else {
|
||||||
|
if (versionPos == -1) versionPos = javaVersion.indexOf("-")
|
||||||
|
if (versionPos == -1) {
|
||||||
|
println("jdk version unknown")
|
||||||
|
} else {
|
||||||
|
javaVersionNum = javaVersion.substring(0, versionPos).toInteger()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (javaVersionNum >= 9) {
|
||||||
|
include(':mirai-console-graphical')
|
||||||
|
project(':mirai-console-graphical').dir = file("frontend/mirai-console-graphical")
|
||||||
|
} else {
|
||||||
|
println("jdk版本为 " + javaVersionNum)
|
||||||
|
println("当前使用的 JDK 版本为 ${System.getProperty("java.version")}, 请使用JDK 9以上版本引入模块 `:mirai-console-graphical`\n")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (javaVersionNum >= 9) {
|
|
||||||
include(':mirai-console-graphical')
|
|
||||||
project(':mirai-console-graphical').dir = file("frontend/mirai-console-graphical")
|
|
||||||
} else {
|
|
||||||
println("jdk版本为 "+ javaVersionNum)
|
|
||||||
println("当前使用的 JDK 版本为 ${System.getProperty("java.version")}, 请使用JDK 9以上版本引入模块 `:mirai-console-graphical`\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
}catch(Exception ignored){
|
} catch (Exception ignored) {
|
||||||
println("无法确定 JDK 版本, 将不会引入 `:mirai-console-graphical`")
|
println("无法确定 JDK 版本, 将不会引入 `:mirai-console-graphical`")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user