mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-07 16:40:43 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
9e9399a463
16
README.md
16
README.md
@ -1,3 +1,19 @@
|
||||
<div align="center">
|
||||
<img width="160" src="http://img.mamoe.net/2020/02/16/a759783b42f72.png" alt="logo"></br>
|
||||
|
||||
|
||||
<img width="95" src="http://img.mamoe.net/2020/02/16/c4aece361224d.png" alt="title">
|
||||
|
||||
----
|
||||
Mirai 是一个在全平台下运行,提供 QQ Android 和 TIM PC 协议支持的高效率机器人库
|
||||
|
||||
这个项目的名字来源于
|
||||
<p><a href = "http://www.kyotoanimation.co.jp/">京都动画</a>作品<a href = "https://zh.moegirl.org/zh-hans/%E5%A2%83%E7%95%8C%E7%9A%84%E5%BD%BC%E6%96%B9">《境界的彼方》</a>的<a href = "https://zh.moegirl.org/zh-hans/%E6%A0%97%E5%B1%B1%E6%9C%AA%E6%9D%A5">栗山未来(Kuriyama <b>Mirai</b>)</a></p>
|
||||
<p><a href = "https://www.crypton.co.jp/">CRYPTON</a>以<a href = "https://www.crypton.co.jp/miku_eng">初音未来</a>为代表的创作与活动<a href = "https://magicalmirai.com/2019/index_en.html">(Magical <b>Mirai</b>)</a></p>
|
||||
图标以及形象由画师<a href = "">DazeCake</a>绘制
|
||||
</div>
|
||||
|
||||
|
||||
# mirai-console
|
||||
高效率插件支持 QQ 机器人框架, 机器人核心来自 [mirai](https://github.com/mamoe/mirai)
|
||||
|
||||
|
@ -21,6 +21,9 @@ kotlin {
|
||||
languageSettings.useExperimentalAnnotation("kotlin.OptIn")
|
||||
languageSettings.progressiveMode = true
|
||||
languageSettings.useExperimentalAnnotation("net.mamoe.mirai.utils.MiraiInternalAPI")
|
||||
languageSettings.useExperimentalAnnotation("kotlin.ExperimentalUnsignedTypes")
|
||||
languageSettings.useExperimentalAnnotation("kotlin.experimental.ExperimentalTypeInference")
|
||||
languageSettings.useExperimentalAnnotation("kotlin.contracts.ExperimentalContracts")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,100 +0,0 @@
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package net.mamoe.mirai.console.utils
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.console.command.CommandSender
|
||||
import net.mamoe.mirai.console.command.GroupContactCommandSender
|
||||
import net.mamoe.mirai.contact.Group
|
||||
|
||||
/**
|
||||
* this output type of that arg
|
||||
* input is always String
|
||||
*/
|
||||
abstract class CommandArgParser<T : Any> {
|
||||
abstract fun parse(s: String, sender: CommandSender): T
|
||||
protected inline fun parseError(message: String, cause: Throwable? = null): Nothing {
|
||||
throw ParserException(message, cause)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("FunctionName")
|
||||
inline fun <T : Any> CommandArgParser(
|
||||
crossinline parser: CommandArgParser<T>.(s: String, sender: CommandSender) -> T
|
||||
): CommandArgParser<T> {
|
||||
return object : CommandArgParser<T>() {
|
||||
override fun parse(s: String, sender: CommandSender): T = parser(s, sender)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在解析参数时遇到的 _正常_ 错误. 如参数不符合规范.
|
||||
*/
|
||||
class ParserException(message: String, cause: Throwable? = null) : RuntimeException(message, cause)
|
||||
|
||||
inline fun Int.Companion.parser(): CommandArgParser<Int> = IntArgParser
|
||||
inline fun Long.Companion.parser(): CommandArgParser<Long> = LongArgParser
|
||||
inline fun Byte.Companion.parser(): CommandArgParser<Byte> = ByteArgParser
|
||||
inline fun Short.Companion.parser(): CommandArgParser<Short> = ShortArgParser
|
||||
inline fun Float.Companion.parser(): CommandArgParser<Float> = FloatArgParser
|
||||
inline fun Double.Companion.parser(): CommandArgParser<Double> = DoubleArgParser
|
||||
|
||||
|
||||
object IntArgParser : CommandArgParser<Int>() {
|
||||
override fun parse(s: String, sender: CommandSender): Int = s.toIntOrNull() ?: parseError("无法解析 $s 为整数")
|
||||
}
|
||||
|
||||
object LongArgParser : CommandArgParser<Long>() {
|
||||
override fun parse(s: String, sender: CommandSender): Long = s.toLongOrNull() ?: parseError("无法解析 $s 为长整数")
|
||||
}
|
||||
|
||||
object ShortArgParser : CommandArgParser<Short>() {
|
||||
override fun parse(s: String, sender: CommandSender): Short = s.toShortOrNull() ?: parseError("无法解析 $s 为短整数")
|
||||
}
|
||||
|
||||
object ByteArgParser : CommandArgParser<Byte>() {
|
||||
override fun parse(s: String, sender: CommandSender): Byte = s.toByteOrNull() ?: parseError("无法解析 $s 为字节")
|
||||
}
|
||||
|
||||
object DoubleArgParser : CommandArgParser<Double>() {
|
||||
override fun parse(s: String, sender: CommandSender): Double =
|
||||
s.toDoubleOrNull() ?: parseError("无法解析 $s 为小数")
|
||||
}
|
||||
|
||||
object FloatArgParser : CommandArgParser<Float>() {
|
||||
override fun parse(s: String, sender: CommandSender): Float =
|
||||
s.toFloatOrNull() ?: parseError("无法解析 $s 为小数")
|
||||
}
|
||||
|
||||
object StringArgParser : CommandArgParser<String>() {
|
||||
override fun parse(s: String, sender: CommandSender): String = s
|
||||
}
|
||||
|
||||
/**
|
||||
* require a bot that already login in console
|
||||
* input: Bot UIN
|
||||
* output: Bot
|
||||
* errors: String->Int convert, Bot Not Exist
|
||||
*/
|
||||
object ExistBotArgParser : CommandArgParser<Bot>() {
|
||||
override fun parse(s: String, sender: CommandSender): Bot {
|
||||
val uin = s.toLongOrNull() ?: parseError("无法识别机器人账号 $s")
|
||||
return try {
|
||||
Bot.getInstance(uin)
|
||||
} catch (e: NoSuchElementException) {
|
||||
error("无法找到 Bot $uin")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
object ExistGroupArgParser : CommandArgParser<Group>() {
|
||||
override fun parse(s: String, sender: CommandSender): Group {
|
||||
if ((s == "" || s == "~") && sender is GroupContactCommandSender) {
|
||||
return sender.contact as Group
|
||||
}
|
||||
|
||||
val code = s.toLongOrNull() ?: parseError("无法识别群号码 $s")
|
||||
TODO()
|
||||
}
|
||||
}
|
@ -1,272 +0,0 @@
|
||||
package net.mamoe.mirai.console.command
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.console.utils.fuzzySearchMember
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.message.data.At
|
||||
import net.mamoe.mirai.message.data.SingleMessage
|
||||
import net.mamoe.mirai.message.data.content
|
||||
import java.lang.NumberFormatException
|
||||
|
||||
/**
|
||||
* this output type of that arg
|
||||
* input is always String
|
||||
*/
|
||||
interface CommandArg<T:Any>{
|
||||
operator fun invoke(s:String, commandSender: CommandSender):T = parse(s,commandSender)
|
||||
|
||||
operator fun invoke(s:SingleMessage, commandSender: CommandSender):T = parse(s,commandSender)
|
||||
|
||||
fun parse(s:String, commandSender: CommandSender):T
|
||||
|
||||
fun parse(s:SingleMessage, commandSender: CommandSender):T
|
||||
}
|
||||
|
||||
|
||||
abstract class CommandArgImpl<T:Any>(): CommandArg<T> {
|
||||
override fun parse(s: SingleMessage, commandSender: CommandSender): T = parse(s.content,commandSender)
|
||||
}
|
||||
|
||||
class IntArg: CommandArgImpl<Int>(){
|
||||
override fun parse(s: String, commandSender: CommandSender): Int {
|
||||
return try{
|
||||
s.toInt()
|
||||
}catch (e:Exception){
|
||||
error("无法识别整数$s")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LongArg: CommandArgImpl<Long>(){
|
||||
override fun parse(s: String, commandSender: CommandSender): Long {
|
||||
return try{
|
||||
s.toLong()
|
||||
}catch (e:Exception){
|
||||
error("无法识别长整数$s")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DoubleArg: CommandArgImpl<Double>(){
|
||||
override fun parse(s: String, commandSender: CommandSender): Double {
|
||||
return try{
|
||||
s.toDouble()
|
||||
}catch (e:Exception){
|
||||
error("无法识别小数$s")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class FloatArg: CommandArgImpl<Float>(){
|
||||
override fun parse(s: String, commandSender: CommandSender): Float{
|
||||
return try{
|
||||
s.toFloat()
|
||||
}catch (e:Exception){
|
||||
error("无法识别小数$s")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BooleanArg: CommandArgImpl<Boolean>(){
|
||||
override fun parse(s: String, commandSender: CommandSender): Boolean {
|
||||
return s.equals("true",true) || s.equals("yes",true)
|
||||
}
|
||||
}
|
||||
|
||||
class StringArg: CommandArgImpl<String>(){
|
||||
override fun parse(s: String, commandSender: CommandSender): String {
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* require a bot that already login in console
|
||||
* input: Bot UIN
|
||||
* output: Bot
|
||||
* errors: String->Int convert, Bot Not Exist
|
||||
*/
|
||||
class ExistBotArg : CommandArgImpl<Bot>() {
|
||||
override fun parse(s: String, commandSender: CommandSender): Bot {
|
||||
val uin = try {
|
||||
s.toLong()
|
||||
} catch (e: Exception) {
|
||||
error("无法识别QQ UIN$s")
|
||||
}
|
||||
return try {
|
||||
Bot.getInstance(uin)
|
||||
} catch (e: NoSuchElementException) {
|
||||
error("无法找到Bot $uin")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ExistFriendArg: CommandArgImpl<Friend>(){
|
||||
//Bot.friend
|
||||
//friend
|
||||
//~ = self
|
||||
override fun parse(s: String, commandSender: CommandSender): Friend {
|
||||
if(s == "~"){
|
||||
if(commandSender !is BotAware){
|
||||
error("无法解析~作为默认")
|
||||
}
|
||||
val targetID = when (commandSender) {
|
||||
is GroupContactCommandSender -> commandSender.realSender.id
|
||||
is ContactCommandSender -> commandSender.contact.id
|
||||
else -> error("无法解析~作为默认")
|
||||
}
|
||||
return try{
|
||||
commandSender.bot.friends[targetID]
|
||||
}catch (e:NoSuchElementException){
|
||||
error("无法解析~作为默认")
|
||||
}
|
||||
}
|
||||
if(commandSender is BotAware){
|
||||
return try{
|
||||
commandSender.bot.friends[s.toLong()]
|
||||
}catch (e:NoSuchElementException){
|
||||
error("无法找到" + s + "这个好友")
|
||||
}catch (e:NumberFormatException){
|
||||
error("无法解析$s")
|
||||
}
|
||||
}else{
|
||||
with(s.split(".")){
|
||||
if(this.size != 2){
|
||||
error("无法解析$s, 格式应为Bot.Friend")
|
||||
}
|
||||
return try{
|
||||
Bot.getInstance(this[0].toLong()).friends[this[1].toLong()]
|
||||
}catch (e:NoSuchElementException){
|
||||
error("无法找到好友或Bot")
|
||||
}catch (e:NumberFormatException){
|
||||
error("无法解析$s")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun parse(s: SingleMessage, commandSender: CommandSender): Friend {
|
||||
return if(s is At){
|
||||
assert(commandSender is GroupContactCommandSender)
|
||||
return try {
|
||||
(commandSender as BotAware).bot.friends[s.target]
|
||||
}catch (e:NoSuchElementException){
|
||||
error("At的对象非Bot好友")
|
||||
}
|
||||
}else{
|
||||
error("无法识别Member" + s.content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ExistGroupArg: CommandArgImpl<Group>(){
|
||||
override fun parse(s: String, commandSender: CommandSender): Group {
|
||||
//by default
|
||||
if ((s == "" || s == "~") && commandSender is GroupContactCommandSender) {
|
||||
return commandSender.contact as Group
|
||||
}
|
||||
//from bot to group
|
||||
if (commandSender is BotAware) {
|
||||
val code = try {
|
||||
s.toLong()
|
||||
} catch (e: NoSuchElementException) {
|
||||
error("无法识别Group Code$s")
|
||||
}
|
||||
return try {
|
||||
commandSender.bot.getGroup(code)
|
||||
} catch (e: NoSuchElementException) {
|
||||
error("无法找到Group " + code + " from Bot " + commandSender.bot.id)
|
||||
}
|
||||
}
|
||||
//from console/other
|
||||
return with(s.split(".")) {
|
||||
if (this.size != 2) {
|
||||
error("请使用BotQQ号.群号 来表示Bot的一个群")
|
||||
}
|
||||
try {
|
||||
Bot.getInstance(this[0].toLong()).getGroup(this[1].toLong())
|
||||
}catch (e:NoSuchElementException){
|
||||
error("无法找到" + this[0] + "的" + this[1] + "群")
|
||||
}catch (e:NumberFormatException){
|
||||
error("无法识别群号或机器人UIN")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ExistMemberArg: CommandArgImpl<Member>(){
|
||||
//后台: Bot.Group.Member[QQ/名片]
|
||||
//私聊: Group.Member[QQ/名片]
|
||||
//群内: Q号
|
||||
//群内: 名片
|
||||
override fun parse(s: String, commandSender: CommandSender): Member {
|
||||
if(commandSender !is BotAware){
|
||||
with(s.split(".")){
|
||||
if(this.size < 3){
|
||||
error("无法识别Member, 请使用Bot.Group.Member[QQ/名片]的格式")
|
||||
}
|
||||
val bot = try {
|
||||
Bot.getInstance(this[0].toLong())
|
||||
}catch (e:NoSuchElementException){
|
||||
error("无法找到Bot")
|
||||
}catch (e:NumberFormatException){
|
||||
error("无法识别Bot")
|
||||
}
|
||||
val group = try{
|
||||
bot.getGroup(this[1].toLong())
|
||||
}catch (e:NoSuchElementException){
|
||||
error("无法找到Group")
|
||||
}catch (e:NumberFormatException){
|
||||
error("无法识别Group")
|
||||
}
|
||||
|
||||
val memberIndex = this.subList(2,this.size).joinToString(".")
|
||||
return try{
|
||||
group.members[memberIndex.toLong()]
|
||||
}catch (ignored:Exception){
|
||||
group.fuzzySearchMember(memberIndex)?: error("无法找到成员$memberIndex")
|
||||
}
|
||||
}
|
||||
}else {
|
||||
val bot = commandSender.bot
|
||||
if(commandSender is GroupContactCommandSender){
|
||||
val group = commandSender.contact as Group
|
||||
return try {
|
||||
group.members[s.toLong()]
|
||||
} catch (ignored: Exception) {
|
||||
group.fuzzySearchMember(s) ?: error("无法找到成员$s")
|
||||
}
|
||||
}else {
|
||||
with(s.split(".")) {
|
||||
if (this.size < 2) {
|
||||
error("无法识别Member, 请使用Group.Member[QQ/名片]的格式")
|
||||
}
|
||||
val group = try {
|
||||
bot.getGroup(this[0].toLong())
|
||||
} catch (e: NoSuchElementException) {
|
||||
error("无法找到Group")
|
||||
} catch (e: NumberFormatException) {
|
||||
error("无法识别Group")
|
||||
}
|
||||
|
||||
val memberIndex = this.subList(1, this.size).joinToString(".")
|
||||
return try {
|
||||
group.members[memberIndex.toLong()]
|
||||
} catch (ignored: Exception) {
|
||||
group.fuzzySearchMember(memberIndex) ?: error("无法找到成员$memberIndex")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun parse(s: SingleMessage, commandSender: CommandSender): Member {
|
||||
return if(s is At){
|
||||
assert(commandSender is GroupContactCommandSender)
|
||||
((commandSender as GroupContactCommandSender).contact as Group).members[s.target]
|
||||
}else{
|
||||
error("无法识别Member" + s.content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,286 @@
|
||||
@file:Suppress("NOTHING_TO_INLINE")
|
||||
|
||||
package net.mamoe.mirai.console.command
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.console.utils.fuzzySearchMember
|
||||
import net.mamoe.mirai.contact.Friend
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.Member
|
||||
import net.mamoe.mirai.message.data.At
|
||||
import net.mamoe.mirai.message.data.SingleMessage
|
||||
import net.mamoe.mirai.message.data.content
|
||||
import kotlin.contracts.contract
|
||||
|
||||
/**
|
||||
* this output type of that arg
|
||||
* input is always String
|
||||
*/
|
||||
abstract class CommandArgParser<out T : Any> {
|
||||
abstract fun parse(s: String, sender: CommandSender): T
|
||||
open fun parse(s: SingleMessage, sender: CommandSender): T = parse(s.content, sender)
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
@JvmSynthetic
|
||||
inline fun CommandArgParser<*>.illegalArgument(message: String, cause: Throwable? = null): Nothing {
|
||||
throw ParserException(message, cause)
|
||||
}
|
||||
|
||||
@JvmSynthetic
|
||||
inline fun CommandArgParser<*>.checkArgument(
|
||||
condition: Boolean,
|
||||
crossinline message: () -> String = { "Check failed." }
|
||||
) {
|
||||
contract {
|
||||
returns() implies condition
|
||||
}
|
||||
if (!condition) illegalArgument(message())
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建匿名 [CommandArgParser]
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
@JvmSynthetic
|
||||
inline fun <T : Any> CommandArgParser(
|
||||
crossinline parser: CommandArgParser<T>.(s: String, sender: CommandSender) -> T
|
||||
): CommandArgParser<T> = object : CommandArgParser<T>() {
|
||||
override fun parse(s: String, sender: CommandSender): T = parser(s, sender)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 在解析参数时遇到的 _正常_ 错误. 如参数不符合规范.
|
||||
*/
|
||||
class ParserException(message: String, cause: Throwable? = null) : RuntimeException(message, cause)
|
||||
|
||||
|
||||
object IntArgParser : CommandArgParser<Int>() {
|
||||
override fun parse(s: String, sender: CommandSender): Int =
|
||||
s.toIntOrNull() ?: illegalArgument("无法解析 $s 为整数")
|
||||
}
|
||||
|
||||
object LongArgParser : CommandArgParser<Long>() {
|
||||
override fun parse(s: String, sender: CommandSender): Long =
|
||||
s.toLongOrNull() ?: illegalArgument("无法解析 $s 为长整数")
|
||||
}
|
||||
|
||||
object ShortArgParser : CommandArgParser<Short>() {
|
||||
override fun parse(s: String, sender: CommandSender): Short =
|
||||
s.toShortOrNull() ?: illegalArgument("无法解析 $s 为短整数")
|
||||
}
|
||||
|
||||
object ByteArgParser : CommandArgParser<Byte>() {
|
||||
override fun parse(s: String, sender: CommandSender): Byte =
|
||||
s.toByteOrNull() ?: illegalArgument("无法解析 $s 为字节")
|
||||
}
|
||||
|
||||
object DoubleArgParser : CommandArgParser<Double>() {
|
||||
override fun parse(s: String, sender: CommandSender): Double =
|
||||
s.toDoubleOrNull() ?: illegalArgument("无法解析 $s 为小数")
|
||||
}
|
||||
|
||||
object FloatArgParser : CommandArgParser<Float>() {
|
||||
override fun parse(s: String, sender: CommandSender): Float =
|
||||
s.toFloatOrNull() ?: illegalArgument("无法解析 $s 为小数")
|
||||
}
|
||||
|
||||
object StringArgParser : CommandArgParser<String>() {
|
||||
override fun parse(s: String, sender: CommandSender): String = s
|
||||
}
|
||||
|
||||
object BooleanArgParser : CommandArgParser<Boolean>() {
|
||||
override fun parse(s: String, sender: CommandSender): Boolean = s.trim().let { str ->
|
||||
str.equals("true", ignoreCase = true)
|
||||
|| str.equals("yes", ignoreCase = true)
|
||||
|| str.equals("enabled", ignoreCase = true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* require a bot that already login in console
|
||||
* input: Bot UIN
|
||||
* output: Bot
|
||||
* errors: String->Int convert, Bot Not Exist
|
||||
*/
|
||||
object ExistBotArgParser : CommandArgParser<Bot>() {
|
||||
override fun parse(s: String, sender: CommandSender): Bot {
|
||||
val uin = try {
|
||||
s.toLong()
|
||||
} catch (e: Exception) {
|
||||
error("无法识别QQ UIN$s")
|
||||
}
|
||||
return try {
|
||||
Bot.getInstance(uin)
|
||||
} catch (e: NoSuchElementException) {
|
||||
error("无法找到Bot $uin")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object ExistFriendArgParser : CommandArgParser<Friend>() {
|
||||
//Bot.friend
|
||||
//friend
|
||||
//~ = self
|
||||
override fun parse(s: String, sender: CommandSender): Friend {
|
||||
if (s == "~") {
|
||||
if (sender !is BotAware) {
|
||||
illegalArgument("无法解析~作为默认")
|
||||
}
|
||||
val targetID = when (sender) {
|
||||
is GroupContactCommandSender -> sender.realSender.id
|
||||
is ContactCommandSender -> sender.contact.id
|
||||
else -> illegalArgument("无法解析~作为默认")
|
||||
}
|
||||
return try {
|
||||
sender.bot.friends[targetID]
|
||||
} catch (e: NoSuchElementException) {
|
||||
illegalArgument("无法解析~作为默认")
|
||||
}
|
||||
}
|
||||
if (sender is BotAware) {
|
||||
return try {
|
||||
sender.bot.friends[s.toLong()]
|
||||
} catch (e: NoSuchElementException) {
|
||||
error("无法找到" + s + "这个好友")
|
||||
} catch (e: NumberFormatException) {
|
||||
error("无法解析$s")
|
||||
}
|
||||
} else {
|
||||
s.split(".").let { args ->
|
||||
if (args.size != 2) {
|
||||
illegalArgument("无法解析 $s, 格式应为 机器人账号.好友账号")
|
||||
}
|
||||
return try {
|
||||
Bot.getInstance(args[0].toLong()).friends.getOrNull(
|
||||
args[1].toLongOrNull() ?: illegalArgument("无法解析 $s 为好友")
|
||||
) ?: illegalArgument("无法找到好友 ${args[1]}")
|
||||
} catch (e: NoSuchElementException) {
|
||||
illegalArgument("无法找到机器人账号 ${args[0]}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun parse(s: SingleMessage, sender: CommandSender): Friend {
|
||||
if (s is At) {
|
||||
assert(sender is GroupContactCommandSender)
|
||||
return (sender as BotAware).bot.friends.getOrNull(s.target) ?: illegalArgument("At的对象非Bot好友")
|
||||
} else {
|
||||
error("无法解析 $s 为好友")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object ExistGroupArgParser : CommandArgParser<Group>() {
|
||||
override fun parse(s: String, sender: CommandSender): Group {
|
||||
//by default
|
||||
if ((s == "" || s == "~") && sender is GroupContactCommandSender) {
|
||||
return sender.contact as Group
|
||||
}
|
||||
//from bot to group
|
||||
if (sender is BotAware) {
|
||||
val code = try {
|
||||
s.toLong()
|
||||
} catch (e: NoSuchElementException) {
|
||||
error("无法识别Group Code$s")
|
||||
}
|
||||
return try {
|
||||
sender.bot.getGroup(code)
|
||||
} catch (e: NoSuchElementException) {
|
||||
error("无法找到Group " + code + " from Bot " + sender.bot.id)
|
||||
}
|
||||
}
|
||||
//from console/other
|
||||
return with(s.split(".")) {
|
||||
if (this.size != 2) {
|
||||
error("请使用BotQQ号.群号 来表示Bot的一个群")
|
||||
}
|
||||
try {
|
||||
Bot.getInstance(this[0].toLong()).getGroup(this[1].toLong())
|
||||
} catch (e: NoSuchElementException) {
|
||||
error("无法找到" + this[0] + "的" + this[1] + "群")
|
||||
} catch (e: NumberFormatException) {
|
||||
error("无法识别群号或机器人UIN")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object ExistMemberArgParser : CommandArgParser<Member>() {
|
||||
//后台: Bot.Group.Member[QQ/名片]
|
||||
//私聊: Group.Member[QQ/名片]
|
||||
//群内: Q号
|
||||
//群内: 名片
|
||||
override fun parse(s: String, sender: CommandSender): Member {
|
||||
if (sender !is BotAware) {
|
||||
with(s.split(".")) {
|
||||
checkArgument(this.size >= 3) {
|
||||
"无法识别Member, 请使用Bot.Group.Member[QQ/名片]的格式"
|
||||
}
|
||||
|
||||
val bot = try {
|
||||
Bot.getInstance(this[0].toLong())
|
||||
} catch (e: NoSuchElementException) {
|
||||
illegalArgument("无法找到Bot")
|
||||
} catch (e: NumberFormatException) {
|
||||
illegalArgument("无法识别Bot")
|
||||
}
|
||||
|
||||
val group = try {
|
||||
bot.getGroup(this[1].toLong())
|
||||
} catch (e: NoSuchElementException) {
|
||||
illegalArgument("无法找到Group")
|
||||
} catch (e: NumberFormatException) {
|
||||
illegalArgument("无法识别Group")
|
||||
}
|
||||
|
||||
val memberIndex = this.subList(2, this.size).joinToString(".")
|
||||
return group.members.getOrNull(memberIndex.toLong())
|
||||
?: group.fuzzySearchMember(memberIndex)
|
||||
?: error("无法找到成员$memberIndex")
|
||||
}
|
||||
} else {
|
||||
val bot = sender.bot
|
||||
if (sender is GroupContactCommandSender) {
|
||||
val group = sender.contact as Group
|
||||
return try {
|
||||
group.members[s.toLong()]
|
||||
} catch (ignored: Exception) {
|
||||
group.fuzzySearchMember(s) ?: illegalArgument("无法找到成员$s")
|
||||
}
|
||||
} else {
|
||||
with(s.split(".")) {
|
||||
if (this.size < 2) {
|
||||
illegalArgument("无法识别Member, 请使用Group.Member[QQ/名片]的格式")
|
||||
}
|
||||
val group = try {
|
||||
bot.getGroup(this[0].toLong())
|
||||
} catch (e: NoSuchElementException) {
|
||||
illegalArgument("无法找到Group")
|
||||
} catch (e: NumberFormatException) {
|
||||
illegalArgument("无法识别Group")
|
||||
}
|
||||
|
||||
val memberIndex = this.subList(1, this.size).joinToString(".")
|
||||
return try {
|
||||
group.members[memberIndex.toLong()]
|
||||
} catch (ignored: Exception) {
|
||||
group.fuzzySearchMember(memberIndex) ?: illegalArgument("无法找到成员$memberIndex")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun parse(s: SingleMessage, sender: CommandSender): Member {
|
||||
return if (s is At) {
|
||||
checkArgument(sender is GroupContactCommandSender)
|
||||
(sender.contact as Group).members[s.target]
|
||||
} else {
|
||||
illegalArgument("无法识别Member" + s.content)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,139 @@
|
||||
@file:Suppress("NOTHING_TO_INLINE", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "unused", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package net.mamoe.mirai.console.command
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* 指令描述. 包含名称, 权限要求, 参数解析器环境, 参数列表.
|
||||
*/
|
||||
class CommandDescriptor(
|
||||
/**
|
||||
* 包含子命令的全名. 如 "`group kick`", 其中 `kick` 为 `group` 的子命令
|
||||
*/
|
||||
val fullName: String,
|
||||
/**
|
||||
* 指令参数解析器环境.
|
||||
*/
|
||||
val context: CommandParserContext,
|
||||
/**
|
||||
* 指令参数列表, 有顺序.
|
||||
*/
|
||||
val params: List<CommandParam<*>>,
|
||||
/**
|
||||
* 指令权限
|
||||
*
|
||||
* @see CommandPermission.or 要求其中一个权限
|
||||
* @see CommandPermission.and 同时要求两个权限
|
||||
*/
|
||||
val permission: CommandPermission = CommandPermission.Default
|
||||
)
|
||||
|
||||
/**
|
||||
* 构建一个 [CommandDescriptor]
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
inline fun CommandDescriptor(
|
||||
fullName: String,
|
||||
block: CommandDescriptorBuilder.() -> Unit
|
||||
): CommandDescriptor = CommandDescriptorBuilder(fullName).apply(block).build()
|
||||
|
||||
class CommandDescriptorBuilder(
|
||||
val fullName: String
|
||||
) {
|
||||
@PublishedApi
|
||||
internal var context: CommandParserContext = CommandParserContext.Builtins
|
||||
|
||||
@PublishedApi
|
||||
internal var permission: CommandPermission = CommandPermission.Default
|
||||
|
||||
@PublishedApi
|
||||
internal var params: MutableList<CommandParam<*>> = mutableListOf()
|
||||
|
||||
/** 增加指令参数解析器列表 */
|
||||
@JvmSynthetic
|
||||
inline fun context(block: CommandParserContextBuilder.() -> Unit) {
|
||||
this.context += CommandParserContext(block)
|
||||
}
|
||||
|
||||
/** 增加指令参数解析器列表 */
|
||||
@JvmSynthetic
|
||||
inline fun context(context: CommandParserContext): CommandDescriptorBuilder = apply {
|
||||
this.context += context
|
||||
}
|
||||
|
||||
/** 设置权限要求 */
|
||||
fun permission(permission: CommandPermission): CommandDescriptorBuilder = apply {
|
||||
this.permission = permission
|
||||
}
|
||||
|
||||
/** 设置权限要求 */
|
||||
@JvmSynthetic
|
||||
inline fun permission(crossinline block: CommandSender.() -> Boolean) {
|
||||
this.permission = AnonymousCommandPermission(block)
|
||||
}
|
||||
|
||||
fun param(vararg params: CommandParam<*>): CommandDescriptorBuilder = apply {
|
||||
this.params.addAll(params)
|
||||
}
|
||||
|
||||
@JvmSynthetic
|
||||
fun <T : Any> param(
|
||||
name: String?,
|
||||
type: KClass<T>,
|
||||
overrideParser: CommandArgParser<T>? = null
|
||||
): CommandDescriptorBuilder = apply {
|
||||
this.params.add(CommandParam(name, type).apply { this.parser = overrideParser })
|
||||
}
|
||||
|
||||
fun <T : Any> param(
|
||||
name: String?,
|
||||
type: Class<T>,
|
||||
overrideParser: CommandArgParser<T>? = null
|
||||
): CommandDescriptorBuilder =
|
||||
param(name, type, overrideParser)
|
||||
|
||||
inline fun <reified T : Any> param(
|
||||
name: String? = null,
|
||||
overrideParser: CommandArgParser<T>? = null
|
||||
): CommandDescriptorBuilder =
|
||||
param(name, T::class, overrideParser)
|
||||
|
||||
@JvmSynthetic
|
||||
fun param(vararg pairs: Pair<String?, KClass<*>>): CommandDescriptorBuilder = apply {
|
||||
for (pair in pairs) {
|
||||
this.params.add(CommandParam(pair.first, pair.second))
|
||||
}
|
||||
}
|
||||
|
||||
@JvmSynthetic
|
||||
fun params(block: ParamBlock.() -> Unit): CommandDescriptorBuilder = apply {
|
||||
ParamBlock(params).apply(block)
|
||||
}
|
||||
|
||||
@JvmSynthetic
|
||||
fun param(type: KClass<*>): CommandDescriptorBuilder = apply {
|
||||
this.params.add(CommandParam(null, type))
|
||||
}
|
||||
|
||||
fun param(type: Class<*>): CommandDescriptorBuilder = apply {
|
||||
this.params.add(CommandParam(null, type.kotlin))
|
||||
}
|
||||
|
||||
fun build(): CommandDescriptor = CommandDescriptor(fullName, context, params, permission)
|
||||
}
|
||||
|
||||
@Suppress("NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS")
|
||||
inline class ParamBlock internal constructor(@PublishedApi internal val list: MutableList<CommandParam<*>>) {
|
||||
/** 添加一个名称为 [this], 类型为 [klass] 的参数. 返回添加成功的对象 */
|
||||
infix fun <T : Any> String.typed(klass: KClass<T>): CommandParam<T> =
|
||||
CommandParam(this, klass).also { list.add(it) }
|
||||
|
||||
/** 指定 [CommandParam.overrideParser] */
|
||||
infix fun <T : Any> CommandParam<T>.using(parser: CommandArgParser<T>): CommandParam<T> =
|
||||
this.apply { this.parser = parser }
|
||||
|
||||
/** 覆盖 [CommandArgParser] */
|
||||
inline infix fun <reified T : Any> String.using(parser: CommandArgParser<T>): CommandParam<T> =
|
||||
this typed T::class using parser
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package net.mamoe.mirai.console.command
|
||||
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* 指令形式参数.
|
||||
*/
|
||||
data class CommandParam<T : Any>(
|
||||
/**
|
||||
* 参数名, 为 `null` 时即为匿名参数.
|
||||
* 参数名允许重复 (尽管并不建议这样做).
|
||||
* 参数名仅提供给 [CommandArgParser] 以发送更好的错误信息.
|
||||
*/
|
||||
val name: String?,
|
||||
/**
|
||||
* 参数类型. 将从 [CommandDescriptor.context] 中寻找 [CommandArgParser] 解析.
|
||||
*/
|
||||
val type: KClass<T> // exact type
|
||||
) {
|
||||
constructor(name: String?, type: KClass<T>, parser: CommandArgParser<T>) : this(name, type) {
|
||||
this.parser = parser
|
||||
}
|
||||
|
||||
@JvmField
|
||||
internal var parser: CommandArgParser<T>? = null
|
||||
|
||||
|
||||
/**
|
||||
* 覆盖的 [CommandArgParser].
|
||||
*
|
||||
* 如果非 `null`, 将不会从 [CommandParserContext] 寻找 [CommandArgParser]
|
||||
*/
|
||||
val overrideParser: CommandArgParser<T>? get() = parser
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
@file:Suppress("NOTHING_TO_INLINE", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE", "unused", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package net.mamoe.mirai.console.command
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.console.command.AbstractCommandParserContext.Node
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.Member
|
||||
import kotlin.internal.LowPriorityInOverloadResolution
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
/**
|
||||
* [KClass] 到 [CommandArgParser] 的匹配
|
||||
*/
|
||||
interface CommandParserContext {
|
||||
operator fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>?
|
||||
|
||||
/**
|
||||
* 内建的默认 [CommandArgParser]
|
||||
*/
|
||||
object Builtins : CommandParserContext by (CommandParserContext {
|
||||
Int::class with IntArgParser
|
||||
Byte::class with ByteArgParser
|
||||
Short::class with ShortArgParser
|
||||
Boolean::class with BooleanArgParser
|
||||
String::class with StringArgParser
|
||||
Long::class with LongArgParser
|
||||
Double::class with DoubleArgParser
|
||||
Float::class with FloatArgParser
|
||||
|
||||
Member::class with ExistMemberArgParser
|
||||
Group::class with ExistGroupArgParser
|
||||
Bot::class with ExistBotArgParser
|
||||
})
|
||||
}
|
||||
|
||||
fun <T : Any> CommandParserContext.parserFor(param: CommandParam<T>): CommandArgParser<T>? = this[param.type]
|
||||
|
||||
/**
|
||||
* 合并两个 [CommandParserContext], [replacer] 将会替换 [this] 中重复的 parser.
|
||||
*/
|
||||
operator fun CommandParserContext.plus(replacer: CommandParserContext): CommandParserContext {
|
||||
return object : CommandParserContext {
|
||||
override fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>? = replacer[klass] ?: this@plus[klass]
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
open class AbstractCommandParserContext(val list: List<Node<*>>) : CommandParserContext {
|
||||
class Node<T : Any>(
|
||||
val klass: KClass<T>,
|
||||
val parser: CommandArgParser<T>
|
||||
)
|
||||
|
||||
override fun <T : Any> get(klass: KClass<T>): CommandArgParser<T>? =
|
||||
this.list.firstOrNull { it.klass == klass }?.parser as CommandArgParser<T>?
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建一个 [CommandParserContext].
|
||||
*
|
||||
* ```
|
||||
* CommandParserContext {
|
||||
* Int::class with IntArgParser
|
||||
* Member::class with ExistMemberArgParser
|
||||
* Group::class with { s: String, sender: CommandSender ->
|
||||
* Bot.getInstance(s.toLong()).getGroup(s.toLong())
|
||||
* }
|
||||
* Bot::class with { s: String ->
|
||||
* Bot.getInstance(s.toLong())
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
@JvmSynthetic
|
||||
inline fun CommandParserContext(block: CommandParserContextBuilder.() -> Unit): CommandParserContext {
|
||||
return AbstractCommandParserContext(
|
||||
CommandParserContextBuilder().apply(block).distinctByReversed { it.klass })
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CommandParserContext
|
||||
*/
|
||||
class CommandParserContextBuilder : MutableList<Node<*>> by mutableListOf() {
|
||||
@JvmName("add")
|
||||
inline infix fun <T : Any> KClass<T>.with(parser: CommandArgParser<T>): Node<*> =
|
||||
Node(this, parser)
|
||||
|
||||
/**
|
||||
* 添加一个指令解析器
|
||||
*/
|
||||
@JvmSynthetic
|
||||
@LowPriorityInOverloadResolution
|
||||
inline infix fun <T : Any> KClass<T>.with(
|
||||
crossinline parser: CommandArgParser<T>.(s: String, sender: CommandSender) -> T
|
||||
): Node<*> = Node(this, CommandArgParser(parser))
|
||||
|
||||
/**
|
||||
* 添加一个指令解析器
|
||||
*/
|
||||
@JvmSynthetic
|
||||
inline infix fun <T : Any> KClass<T>.with(
|
||||
crossinline parser: CommandArgParser<T>.(s: String) -> T
|
||||
): Node<*> = Node(this, CommandArgParser { s: String, _: CommandSender -> parser(s) })
|
||||
}
|
||||
|
||||
|
||||
@PublishedApi
|
||||
internal inline fun <T, K> Iterable<T>.distinctByReversed(selector: (T) -> K): List<T> {
|
||||
val set = HashSet<K>()
|
||||
val list = ArrayList<T>()
|
||||
for (i in list.indices.reversed()) {
|
||||
val element = list[i]
|
||||
if (set.add(element.let(selector))) {
|
||||
list.add(element)
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
@file:Suppress("unused", "NOTHING_TO_INLINE", "MemberVisibilityCanBePrivate")
|
||||
|
||||
package net.mamoe.mirai.console.command
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.console.utils.isManager
|
||||
import net.mamoe.mirai.contact.isAdministrator
|
||||
import net.mamoe.mirai.contact.isOperator
|
||||
import net.mamoe.mirai.contact.isOwner
|
||||
|
||||
/**
|
||||
* 指令权限
|
||||
*
|
||||
* @see AnonymousCommandPermission
|
||||
*/
|
||||
abstract class CommandPermission {
|
||||
/**
|
||||
* 判断 [this] 是否拥有这个指令的权限
|
||||
*/
|
||||
abstract fun CommandSender.hasPermission(): Boolean
|
||||
|
||||
|
||||
/**
|
||||
* 满足两个权限其中一个即可使用指令
|
||||
*/ // no extension for Java
|
||||
infix fun or(another: CommandPermission): CommandPermission = OrCommandPermission(this, another)
|
||||
|
||||
/**
|
||||
* 同时拥有两个权限才能使用指令
|
||||
*/ // no extension for Java
|
||||
infix fun and(another: CommandPermission): CommandPermission = AndCommandPermission(this, another)
|
||||
|
||||
|
||||
/**
|
||||
* 任何人都可以使用这个指令
|
||||
*/
|
||||
object Any : CommandPermission() {
|
||||
override fun CommandSender.hasPermission(): Boolean = true
|
||||
}
|
||||
|
||||
/**
|
||||
* 任何人都不能使用这个指令. 指令只能通过代码在 [CommandManager] 使用
|
||||
*/
|
||||
object None : CommandPermission() {
|
||||
override fun CommandSender.hasPermission(): Boolean = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理员或群主可以使用这个指令
|
||||
*/
|
||||
class Operator(
|
||||
/**
|
||||
* 指定只有来自某个 [Bot] 的管理员或群主才可以使用这个指令
|
||||
*/
|
||||
vararg val fromBot: Long
|
||||
) : CommandPermission() {
|
||||
constructor(vararg fromBot: Bot) : this(*fromBot.map { it.id }.toLongArray())
|
||||
|
||||
override fun CommandSender.hasPermission(): Boolean {
|
||||
return this is GroupContactCommandSender && this.bot.id in fromBot && this.realSender.isOperator()
|
||||
}
|
||||
|
||||
/**
|
||||
* 来自任何 [Bot] 的任何一个管理员或群主都可以使用这个指令
|
||||
*/
|
||||
companion object Any : CommandPermission() {
|
||||
override fun CommandSender.hasPermission(): Boolean {
|
||||
return this is GroupContactCommandSender && this.realSender.isOperator()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 群主可以使用这个指令
|
||||
*/
|
||||
class GroupOwner(
|
||||
/**
|
||||
* 指定只有来自某个 [Bot] 的群主才可以使用这个指令
|
||||
*/
|
||||
vararg val fromBot: Long
|
||||
) : CommandPermission() {
|
||||
constructor(vararg fromBot: Bot) : this(*fromBot.map { it.id }.toLongArray())
|
||||
|
||||
override fun CommandSender.hasPermission(): Boolean {
|
||||
return this is GroupContactCommandSender && this.bot.id in fromBot && this.realSender.isOwner()
|
||||
}
|
||||
|
||||
/**
|
||||
* 来自任何 [Bot] 的任何一个群主都可以使用这个指令
|
||||
*/
|
||||
companion object Any : CommandPermission() {
|
||||
override fun CommandSender.hasPermission(): Boolean {
|
||||
return this is GroupContactCommandSender && this.realSender.isOwner()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 管理员 (不包含群主) 可以使用这个指令
|
||||
*/
|
||||
class Administrator(
|
||||
/**
|
||||
* 指定只有来自某个 [Bot] 的管理员 (不包含群主) 才可以使用这个指令
|
||||
*/
|
||||
vararg val fromBot: Long
|
||||
) : CommandPermission() {
|
||||
constructor(vararg fromBot: Bot) : this(*fromBot.map { it.id }.toLongArray())
|
||||
|
||||
override fun CommandSender.hasPermission(): Boolean {
|
||||
return this is GroupContactCommandSender && this.bot.id in fromBot && this.realSender.isAdministrator()
|
||||
}
|
||||
|
||||
/**
|
||||
* 来自任何 [Bot] 的任何一个管理员 (不包含群主) 都可以使用这个指令
|
||||
*/
|
||||
companion object Any : CommandPermission() {
|
||||
override fun CommandSender.hasPermission(): Boolean {
|
||||
return this is GroupContactCommandSender && this.realSender.isAdministrator()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* console 管理员可以使用这个指令
|
||||
*/
|
||||
class Manager(
|
||||
/**
|
||||
* 指定只有来自某个 [Bot] 的管理员或群主才可以使用这个指令
|
||||
*/
|
||||
vararg val fromBot: Long
|
||||
) : CommandPermission() {
|
||||
constructor(vararg fromBot: Bot) : this(*fromBot.map { it.id }.toLongArray())
|
||||
|
||||
override fun CommandSender.hasPermission(): Boolean {
|
||||
return this is GroupContactCommandSender && this.bot.id in fromBot && this.realSender.isManager
|
||||
}
|
||||
|
||||
/**
|
||||
* 任何 [Bot] 的 manager 都可以使用这个指令
|
||||
*/
|
||||
companion object Any : CommandPermission() {
|
||||
override fun CommandSender.hasPermission(): Boolean {
|
||||
return this is GroupContactCommandSender && this.realSender.isManager
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 仅控制台能使用和这个指令
|
||||
*/
|
||||
object Console : CommandPermission() {
|
||||
override fun CommandSender.hasPermission(): Boolean = false
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
val Default: CommandPermission = Manager or Console
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用 [lambda][block] 快速构造 [CommandPermission]
|
||||
*/
|
||||
@JvmSynthetic
|
||||
@Suppress("FunctionName")
|
||||
inline fun AnonymousCommandPermission(crossinline block: CommandSender.() -> Boolean): CommandPermission {
|
||||
return object : CommandPermission() {
|
||||
override fun CommandSender.hasPermission(): Boolean = block()
|
||||
}
|
||||
}
|
||||
|
||||
inline fun CommandSender.hasPermission(permission: CommandPermission): Boolean =
|
||||
permission.run { this@hasPermission.hasPermission() }
|
||||
|
||||
|
||||
inline fun CommandPermission.hasPermission(sender: CommandSender): Boolean = this.run { sender.hasPermission() }
|
||||
|
||||
|
||||
internal class OrCommandPermission(
|
||||
private val first: CommandPermission,
|
||||
private val second: CommandPermission
|
||||
) : CommandPermission() {
|
||||
override fun CommandSender.hasPermission(): Boolean {
|
||||
return this.hasPermission(first) || this.hasPermission(second)
|
||||
}
|
||||
}
|
||||
|
||||
internal class AndCommandPermission(
|
||||
private val first: CommandPermission,
|
||||
private val second: CommandPermission
|
||||
) : CommandPermission() {
|
||||
override fun CommandSender.hasPermission(): Boolean {
|
||||
return this.hasPermission(first) || this.hasPermission(second)
|
||||
}
|
||||
}
|
@ -13,8 +13,16 @@ import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import net.mamoe.mirai.console.plugins.*
|
||||
import net.mamoe.mirai.console.utils.BotManagers.BOT_MANAGERS
|
||||
import net.mamoe.mirai.contact.User
|
||||
import java.io.File
|
||||
|
||||
|
||||
/**
|
||||
* 判断此用户是否为 console 管理员
|
||||
*/
|
||||
val User.isManager: Boolean
|
||||
get() = this.bot.managers.contains(this.id)
|
||||
|
||||
@OptIn(ToBeRemoved::class)
|
||||
internal object BotManagers {
|
||||
val config = File("${MiraiConsole.path}/bot.yml").loadAsConfig()
|
||||
|
@ -69,16 +69,16 @@ internal fun Throwable.addSuppressedMirai(e: Throwable) {
|
||||
* XXXXXYYYYY.fuzzyCompare(XXXXXYYYZZ) = 0.8
|
||||
*/
|
||||
|
||||
fun String.fuzzyCompare(target:String):Double{
|
||||
internal fun String.fuzzyCompare(target: String): Double {
|
||||
var step = 0
|
||||
if(this == target){
|
||||
if (this == target) {
|
||||
return 1.0
|
||||
}
|
||||
if(target.length > this.length){
|
||||
if (target.length > this.length) {
|
||||
return 0.0
|
||||
}
|
||||
for(i in this.indices){
|
||||
if(target.length == i){
|
||||
for (i in this.indices) {
|
||||
if (target.length == i) {
|
||||
step--
|
||||
}else {
|
||||
if (this[i] != target[i]) {
|
||||
@ -97,14 +97,14 @@ fun String.fuzzyCompare(target:String):Double{
|
||||
/**
|
||||
* 模糊搜索一个List中index最接近target的东西
|
||||
*/
|
||||
inline fun <T:Any> Collection<T>.fuzzySearch(
|
||||
internal inline fun <T : Any> Collection<T>.fuzzySearch(
|
||||
target: String,
|
||||
index: (T) -> String
|
||||
):T?{
|
||||
if(this.isEmpty()){
|
||||
): T? {
|
||||
if (this.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
var potential:T? = null
|
||||
var potential: T? = null
|
||||
var rate = 0.0
|
||||
this.forEach {
|
||||
val thisIndex = index(it)
|
||||
@ -126,14 +126,14 @@ inline fun <T:Any> Collection<T>.fuzzySearch(
|
||||
* 并且确保target是唯一的
|
||||
* 如搜索index为XXXXYY list中同时存在XXXXYYY XXXXYYYY 将返回null
|
||||
*/
|
||||
inline fun <T:Any> Collection<T>.fuzzySearchOnly(
|
||||
internal inline fun <T : Any> Collection<T>.fuzzySearchOnly(
|
||||
target: String,
|
||||
index: (T) -> String
|
||||
):T?{
|
||||
if(this.isEmpty()){
|
||||
): T? {
|
||||
if (this.isEmpty()) {
|
||||
return null
|
||||
}
|
||||
var potential:T? = null
|
||||
var potential: T? = null
|
||||
var rate = 0.0
|
||||
var collide = 0
|
||||
this.forEach {
|
||||
@ -154,8 +154,8 @@ inline fun <T:Any> Collection<T>.fuzzySearchOnly(
|
||||
}
|
||||
|
||||
|
||||
fun Group.fuzzySearchMember(nameCardTarget:String):Member?{
|
||||
return this.members.fuzzySearchOnly(nameCardTarget){
|
||||
internal fun Group.fuzzySearchMember(nameCardTarget: String): Member? {
|
||||
return this.members.fuzzySearchOnly(nameCardTarget) {
|
||||
it.nameCard
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user