Add docs, rearrange implementations

This commit is contained in:
Him188 2020-04-24 16:41:21 +08:00
parent 716e3ade48
commit 09524da1e9
14 changed files with 359 additions and 52 deletions

View File

@ -24,10 +24,7 @@ import kotlinx.serialization.UnstableDefault
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import kotlinx.serialization.json.int
import net.mamoe.mirai.Bot
import net.mamoe.mirai.BotImpl
import net.mamoe.mirai.LowLevelAPI
import net.mamoe.mirai.ThisApiMustBeUsedInWithConnectionLockBlock
import net.mamoe.mirai.*
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.data.*
import net.mamoe.mirai.event.broadcast
@ -82,10 +79,18 @@ internal class QQAndroidBot constructor(
@OptIn(LowLevelAPI::class)
override suspend fun acceptNewFriendRequest(event: NewFriendRequestEvent) {
check(event.bot === this) {
"the request $event is from Bot ${event.bot.id} but you are responding with bot ${this.id}"
}
check(event.responded.compareAndSet(false, true)) {
"the request $this has already been responded"
}
check(!friends.contains(event.fromId)) {
"the request $event is outdated: You had already responded it on another device."
}
network.run {
NewContact.SystemMsgNewFriend.Action(
bot.client,
@ -100,8 +105,16 @@ internal class QQAndroidBot constructor(
}
override suspend fun rejectNewFriendRequest(event: NewFriendRequestEvent, blackList: Boolean) {
check(event.bot === this) {
"the request $event is from Bot ${event.bot.id} but you are responding with bot ${this.id}"
}
check(event.responded.compareAndSet(false, true)) {
"the request $this has already been responded"
"the request $event has already been responded"
}
check(!friends.contains(event.fromId)) {
"the request $event is outdated: You had already responded it on another device."
}
network.run {
@ -116,10 +129,16 @@ internal class QQAndroidBot constructor(
@OptIn(LowLevelAPI::class)
override suspend fun acceptMemberJoinRequest(event: MemberJoinRequestEvent) {
@Suppress("DuplicatedCode")
checkGroupPermission(event.bot, event.group) { event::class.simpleName ?: "<anonymous class>" }
check(event.responded.compareAndSet(false, true)) {
"the request $this has already been responded"
}
check(!event.group.members.contains(event.fromId)) {
"the request $this is outdated: Another operator has already responded it."
}
network.run {
NewContact.SystemMsgNewGroup.Action(
bot.client,
@ -137,11 +156,17 @@ internal class QQAndroidBot constructor(
}
}
@Suppress("DuplicatedCode")
@OptIn(LowLevelAPI::class)
override suspend fun rejectMemberJoinRequest(event: MemberJoinRequestEvent, blackList: Boolean) {
checkGroupPermission(event.bot, event.group) { event::class.simpleName ?: "<anonymous class>" }
check(event.responded.compareAndSet(false, true)) {
"the request $this has already been responded"
}
check(!event.group.members.contains(event.fromId)) {
"the request $this is outdated: Another operator has already responded it."
}
network.run {
NewContact.SystemMsgNewGroup.Action(
bot.client,
@ -152,7 +177,22 @@ internal class QQAndroidBot constructor(
}
}
private inline fun checkGroupPermission(eventBot: Bot, eventGroup: Group, eventName: () -> String) {
val group = this.getGroupOrNull(eventGroup.id)
?: kotlin.run {
if (this == eventBot) {
error("A ${eventName()} is outdated. Group ${eventGroup.id} not found for bot ${this.id}. " +
"This is because bot isn't in the group anymore")
} else {
error("A ${eventName()} is from bot ${eventBot.id}, but you are trying to respond it using bot ${this.id} who isn't a member of the group ${eventGroup.id}")
}
}
group.checkBotPermissionOperator()
}
override suspend fun ignoreMemberJoinRequest(event: MemberJoinRequestEvent, blackList: Boolean) {
checkGroupPermission(event.bot, event.group) { event::class.simpleName ?: "<anonymous class>" }
check(event.responded.compareAndSet(false, true)) {
"the request $this has already been responded"
}

View File

@ -44,7 +44,7 @@ import kotlin.jvm.JvmSynthetic
@OptIn(MiraiInternalAPI::class)
open class MessageReceipt<out C : Contact>(
/**
* 指代发送出去的消息
* 指代发送出去的消息.
*/
val source: OnlineMessageSource.Outgoing,
/**

View File

@ -12,11 +12,9 @@
package net.mamoe.mirai.message.data
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.SinceMirai
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic
private const val displayA = "@全体成员"
@ -50,15 +48,6 @@ object AtAll :
}
// 自动为消息补充 " "
@OptIn(MiraiInternalAPI::class)
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
@Suppress("INAPPLICABLE_JVM_NAME", "EXPOSED_FUNCTION_RETURN_TYPE")
@JvmName("followedBy")
@JvmSynthetic
override fun followedBy1(tail: Message): CombinedMessage {
return followedByInternalForBinaryCompatibility(tail)
}
override fun followedBy(tail: Message): MessageChain {
if (tail is PlainText && tail.stringValue.startsWith(' ')) {
return super.followedBy(tail)

View File

@ -8,6 +8,8 @@
*/
@file:Suppress("unused", "NOTHING_TO_INLINE")
@file:JvmMultifileClass
@file:JvmName("MessageUtils") // since 0.39.1
package net.mamoe.mirai.message.data
@ -15,10 +17,7 @@ import net.mamoe.mirai.message.data.PokeMessage.Types
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.SinceMirai
import kotlin.jvm.JvmField
import kotlin.jvm.JvmName
import kotlin.jvm.JvmStatic
import kotlin.jvm.JvmSynthetic
import kotlin.jvm.*
/**
* 一些特殊的消息

View File

@ -19,7 +19,6 @@ import net.mamoe.mirai.Bot
import net.mamoe.mirai.BotImpl
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.utils.ExternalImage
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.PlannedRemoval
import net.mamoe.mirai.utils.SinceMirai
@ -38,7 +37,7 @@ import kotlin.jvm.JvmSynthetic
*
* ### [toString] [contentToString]
* - [toString] 固定返回 `[mirai:image:<ID>]` 格式字符串, 其中 `<ID>` 代表 [imageId].
* - [contentToString] 固定返回 `"[图片]"`
* - [contentToString] 固定返回 ```"[图片]"```
*
* ### 上传和发送图片
* @see Contact.uploadImage 上传 [图片文件][ExternalImage] 并得到 [Image] 消息

View File

@ -8,6 +8,8 @@
*/
@file:Suppress("MemberVisibilityCanBePrivate", "unused", "EXPERIMENTAL_API_USAGE", "NOTHING_TO_INLINE")
@file:JvmMultifileClass
@file:JvmName("MessageUtils")
package net.mamoe.mirai.message.data
@ -17,6 +19,7 @@ import net.mamoe.mirai.message.data.Message.Key
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.PlannedRemoval
import net.mamoe.mirai.utils.SinceMirai
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic
@ -313,6 +316,8 @@ interface SingleMessage : Message, CharSequence, Comparable<String> {
/**
* 消息元数据, 即不含内容的元素.
*
* 所有子类的 [contentToString] 都应该返回空字符串.
*
* @see MessageSource 消息源
* @see QuoteReply 引用回复
* @see CustomMessageMetadata 自定义元数据
@ -328,11 +333,12 @@ interface MessageMetadata : SingleMessage {
/**
* 约束一个 [MessageChain] 中只存在这一种类型的元素. 新元素将会替换旧元素, 保持原顺序.
*
* 实现此接口的元素将会在连接时自动处理替换.
*/
@SinceMirai("0.34.0")
interface ConstrainSingle<out M : Message> : MessageMetadata {
val key: Message.Key<M>
val key: Key<M>
}
/**

View File

@ -142,9 +142,7 @@ inline fun MessageChain.allContent(block: (MessageContent) -> Boolean): Boolean
this.forEach {
if (it !is MessageMetadata) {
check(it is MessageContent) { "internal error: Message must be either MessageMetaData or MessageContent" }
if (!block(it)) {
return false
}
if (!block(it)) return false
}
}
return true
@ -158,9 +156,7 @@ inline fun MessageChain.noneContent(block: (MessageContent) -> Boolean): Boolean
this.forEach {
if (it !is MessageMetadata) {
check(it is MessageContent) { "internal error: Message must be either MessageMetaData or MessageContent" }
if (block(it)) {
return false
}
if (block(it)) return false
}
}
return true

View File

@ -29,6 +29,25 @@ import kotlin.jvm.JvmSynthetic
/**
* 消息源, 它存在于 [MessageChain] , 用于表示这个消息的来源.
*
*
* ### 组成
* MessageSource metadata (元数据), form & target, content 组成
*
* #### metadata
* - [id] 消息 id (序列号)
* - [internalId] 消息内部 id
* - [time] 时间
*
* 官方客户端通过 metadata 这三个数据定位消息, 撤回和引用回复都是如此.
*
* #### form & target
* - [fromId] 消息发送人
* - [targetId] 消息发送目标
*
* #### content
* - [originalMessage] 消息内容
*
*
* 消息源可用于 [引用回复][QuoteReply] [撤回][Bot.recall].
*
* @see Bot.recall 撤回一条消息
@ -52,50 +71,74 @@ sealed class MessageSource : Message, MessageMetadata, ConstrainSingle<MessageSo
abstract val bot: Bot
/**
* 消息 id.
* 此值在同一会话中唯一且有顺序.
* 消息 id (序列号).
**
* #### 值域
* 值的范围约为 [UShort] 的范围.
*
* #### 顺序
* 群消息的 id 由服务器维护. 好友消息的 id mirai 维护.
*
* - 在同一个群的消息中此值随每条消息递增 1.
* - 在好友消息中无法保证每次都递增 1. 也可能会产生大幅跳过的情况.
*/
abstract val id: Int
/**
* 内部 id, 仅用于 [Bot.constructMessageSource]
* 值没有顺序, 也可能为 0, 取决于服务器是否提供.
* 在事件中和在引用中无法保证同一条消息的 [internalId] 相同.
* 内部 id. 仅用于协议模块使用.
*
* 仅用于协议实现.
* 在撤回消息和引用回复时均需使用此 id.
*
* 值没有顺序, 也可能为 0, 取决于服务器是否提供.
*
* 在事件中和在引用中无法保证同一条消息的 [internalId] 相同.
*/
@SinceMirai("0.39.0")
abstract val internalId: Int
/**
* 发送时间时间戳, 单位为秒.
* 撤回好友消息时需要
*
* 时间戳可能来自服务器, 也可能来自 mirai, 且无法保证两者时间同步.
*
* 撤回消息时需要此值.
*/
abstract val time: Int
/**
* 发送人.
* [OnlineMessageSource.Outgoing] 时为 [机器人][Bot.id]
* [OnlineMessageSource.Incoming] 时为发信 [目标好友][QQ.id] [][Group.id]
* [OfflineMessageSource] 时为 [机器人][Bot.id], 发信 [目标好友][QQ.id] [][Group.id] (取决于 [OfflineMessageSource.kind])
*
* - [OnlineMessageSource.Outgoing] 时为 [机器人][Bot.id]
* - [OnlineMessageSource.Incoming] 时为发信 [目标好友][QQ.id] [][Group.id]
* - [OfflineMessageSource] 时为 [机器人][Bot.id], 发信 [目标好友][QQ.id] [][Group.id] (取决于 [OfflineMessageSource.kind])
*/
abstract val fromId: Long
/**
* 发送目标.
* [OnlineMessageSource.Outgoing] 时为发信 [目标好友][QQ.id] [][Group.id] [临时消息][Member.id]
* [OnlineMessageSource.Incoming] 时为 [机器人][Bot.id]
* [OfflineMessageSource] 时为 [机器人][Bot.id], 发信 [目标好友][QQ.id] [][Group.id] [临时消息][Member.id] (取决于 [OfflineMessageSource.kind])
* 消息发送目标.
*
* - [OnlineMessageSource.Outgoing] 时为发信 [目标好友][QQ.id] [][Group.id] [临时消息][Member.id]
* - [OnlineMessageSource.Incoming] 时为 [机器人][Bot.id]
* - [OfflineMessageSource] 时为 [机器人][Bot.id], 发信 [目标好友][QQ.id] [][Group.id] [临时消息][Member.id] (取决于 [OfflineMessageSource.kind])
*/
abstract val targetId: Long // groupCode / friendUin / memberUin
/**
* 原消息内容.
*
* 此属性是 **lazy** : 它只会在第一次调用时初始化, 因为需要反序列化服务器发来的整个包, 相当于接收了一条新消息.
*/
@LazyProperty
abstract val originalMessage: MessageChain
/**
* 返回 `"[mirai:source:$id,$internalId]"`
*/
final override fun toString(): String = "[mirai:source:$id,$internalId]"
/**
* 返回空字符串, [MessageMetadata] 的约束.
*/
final override fun contentToString(): String = ""
}
@ -105,7 +148,8 @@ sealed class MessageSource : Message, MessageMetadata, ConstrainSingle<MessageSo
* 拥有对象化的 [sender], [target], 也可以直接 [recall] [quote]
*
* ### 来源
* **必定是一个发出去的消息或接收到的消息的 [MessageChain] 中的一个元数据 [MessageMetadata].**
* - bot 主动发送消息时, 产生 (由协议模块主动构造) [OnlineMessageSource.Outgoing]
* - bot 接收消息时, 产生 (由协议模块根据服务器的提供的信息构造) [OnlineMessageSource.Incoming]
*
* #### 机器人主动发送消息
* 当机器人 [主动发出消息][Member.sendMessage], 将会得到一个 [消息回执][MessageReceipt].
@ -115,6 +159,8 @@ sealed class MessageSource : Message, MessageMetadata, ConstrainSingle<MessageSo
* 当机器人接收一条消息 [ContactMessage], 这条消息包含一个 [内向消息源][OnlineMessageSource.Incoming], 代表着接收到的这条消息的来源.
*
*
* ### 实现
* 此类的所有子类都有协议模块实现. 不要自行实现它们, 否则将无法发送
*
* @see OnlineMessageSource.toOffline 转为 [OfflineMessageSource]
*/
@ -144,7 +190,7 @@ sealed class OnlineMessageSource : MessageSource() {
abstract val subject: Contact
/**
* [机器人主动发送消息][Contact.sendMessage] 产生的 [MessageSource]
* [机器人主动发送消息][Contact.sendMessage] 产生的 [MessageSource], 可通过 [MessageReceipt] 获得.
*/
sealed class Outgoing : OnlineMessageSource() {
companion object Key : Message.Key<Outgoing> {
@ -266,6 +312,8 @@ sealed class OnlineMessageSource : MessageSource() {
/**
* 由一条消息中的 [QuoteReply] 得到的 [MessageSource].
* 此消息源可能来自一条与机器人无关的消息. 因此无法提供对象化的 `sender` `target` 获取.
*
* @see buildMessageSource 构建一个 [OfflineMessageSource]
*/
@SinceMirai("0.33.0")
abstract class OfflineMessageSource : MessageSource() {
@ -290,6 +338,9 @@ abstract class OfflineMessageSource : MessageSource() {
// final override fun toString(): String = "OfflineMessageSource(sender=$senderId, target=$targetId)"
}
/**
* 判断是否是发送给群, 或从群接收的消息的消息源
*/
// inline for future removal
inline fun MessageSource.isAboutGroup(): Boolean {
return when (this) {
@ -298,6 +349,9 @@ inline fun MessageSource.isAboutGroup(): Boolean {
}
}
/**
* 判断是否是发送给临时会话, 或从临时会话接收的消息的消息源
*/
inline fun MessageSource.isAboutTemp(): Boolean {
return when (this) {
is OnlineMessageSource -> subject is Member
@ -305,6 +359,9 @@ inline fun MessageSource.isAboutTemp(): Boolean {
}
}
/**
* 判断是否是发送给好友, 或从好友接收的消息的消息源
*/
// inline for future removal
inline fun MessageSource.isAboutFriend(): Boolean {
return when (this) {
@ -315,6 +372,7 @@ inline fun MessageSource.isAboutFriend(): Boolean {
/**
* 引用这条消息
* @see QuoteReply
*/
fun MessageSource.quote(): QuoteReply {
@OptIn(MiraiInternalAPI::class)
@ -323,17 +381,37 @@ fun MessageSource.quote(): QuoteReply {
/**
* 引用这条消息
* @see QuoteReply
*/
fun MessageChain.quote(): QuoteReply {
@OptIn(MiraiInternalAPI::class)
return QuoteReply(this.source as? OnlineMessageSource ?: error("only online messages can be quoted"))
}
/**
* 撤回这条消息. 可撤回自己 2 分钟内发出的消息, 和任意时间的群成员的消息.
*
* [Bot] 撤回自己的消息不需要权限.
* [Bot] 撤回群员的消息需要管理员权限.
*
* @throws PermissionDeniedException [Bot] 无权限操作时
* @throws IllegalStateException 当这条消息已经被撤回时 (仅同步主动操作)
*
* @see Bot.recall
*/
@JvmSynthetic
suspend inline fun MessageSource.recall() = bot.recall(this)
/**
* 撤回这条消息
* 在一段时间后撤回这条消息. 可撤回自己 2 分钟内发出的消息, 和任意时间的群成员的消息.
*
* [Bot] 撤回自己的消息不需要权限.
* [Bot] 撤回群员的消息需要管理员权限.
*
* @throws PermissionDeniedException [Bot] 无权限操作时
* @throws IllegalStateException 当这条消息已经被撤回时 (仅同步主动操作)
*
* @see Bot.recall
*/
@JvmSynthetic
inline fun MessageSource.recallIn(
@ -345,7 +423,7 @@ inline fun MessageSource.recallIn(
/**
* 消息 id.
* 仅从服务器接收的消息才可以获取 id
* 仅从服务器接收的消息才可以获取
*
* @see MessageSource.id
*/
@ -353,6 +431,36 @@ inline fun MessageSource.recallIn(
inline val MessageChain.id: Int
get() = this.source.id
/**
* 消息内部 id.
* 仅从服务器接收的消息才可以获取
*
* @see MessageSource.id
*/
@get:JvmSynthetic
inline val MessageChain.internalId: Int
get() = this.source.internalId
/**
* 消息时间.
* 仅从服务器接收的消息才可以获取
*
* @see MessageSource.id
*/
@get:JvmSynthetic
inline val MessageChain.time: Int
get() = this.source.time
/**
* 消息内部 id.
* 仅从服务器接收的消息才可以获取
*
* @see MessageSource.id
*/
@get:JvmSynthetic
inline val MessageChain.bot: Bot
get() = this.source.bot
/**
* 获取这条消息源
* 仅从服务器接收的消息才可以获取消息源
@ -361,9 +469,31 @@ inline val MessageChain.id: Int
inline val MessageChain.source: MessageSource
get() = this[MessageSource]
/**
* 撤回这条消息. 可撤回自己 2 分钟内发出的消息, 和任意时间的群成员的消息.
*
* [Bot] 撤回自己的消息不需要权限.
* [Bot] 撤回群员的消息需要管理员权限.
*
* @throws PermissionDeniedException [Bot] 无权限操作时
* @throws IllegalStateException 当这条消息已经被撤回时 (仅同步主动操作)
*
* @see Bot.recall
*/
@JvmSynthetic
suspend inline fun MessageChain.recall() = this.source.recall()
/**
* 在一段时间后撤回这条消息. 可撤回自己 2 分钟内发出的消息, 和任意时间的群成员的消息.
*
* [Bot] 撤回自己的消息不需要权限.
* [Bot] 撤回群员的消息需要管理员权限.
*
* @throws PermissionDeniedException [Bot] 无权限操作时
* @throws IllegalStateException 当这条消息已经被撤回时 (仅同步主动操作)
*
* @see Bot.recall
*/
@JvmSynthetic
inline fun MessageChain.recallIn(
millis: Long,

View File

@ -25,6 +25,9 @@ import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic
/**
* 将在线消息源转换为离线消息源.
*/
@SinceMirai("0.39.0")
@JvmName("toOfflineMessageSource")
fun OnlineMessageSource.toOffline(): OfflineMessageSource =
@ -60,6 +63,14 @@ interface MessageSourceAmender {
var internalId: Int
var originalMessage: MessageChain
/** 从另一个 [MessageSource] 中复制 [id], [internalId], [time]*/
@SinceMirai("0.39.2")
fun metadataFrom(another: MessageSource) {
this.id = another.id
this.internalId = another.internalId
this.time = another.time
}
}

View File

@ -15,7 +15,6 @@ package net.mamoe.mirai.message.data
import kotlinx.coroutines.Job
import net.mamoe.mirai.Bot
import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.SinceMirai
import kotlin.coroutines.CoroutineContext
@ -29,10 +28,19 @@ import kotlin.jvm.JvmSynthetic
/**
* 引用回复.
*
* 可以引用一条群消息并发送给一个好友, 或是引用好友消息发送给群.
* 可以引用自己发出的消息. 详见 [MessageReceipt.quote]
* 支持引用任何一条消息发送给任何人.
*
* @see MessageSource 获取更多信息
* #### [source] 的类型:
* - 在发送引用回复时, [source] 类型为 [OnlineMessageSource] [OfflineMessageSource]
* - 在接收引用回复时, [source] 类型一定为 [OfflineMessageSource]
*
* #### 原消息内容
* 引用回复的原消息内容完全由 [source] [MessageSource.originalMessage] 控制, 客户端不会自行寻找原消息.
*
* #### 客户端内跳转
* 客户端在跳转原消息时, 会通过 [MessageSource.id] metadata
*
* @see MessageSource 获取有关消息源的更多信息
*/
@OptIn(MiraiExperimentalAPI::class)
@SinceMirai("0.33.0")
@ -50,26 +58,52 @@ class QuoteReply(val source: MessageSource) : Message, MessageMetadata, Constrai
override fun hashCode(): Int = source.hashCode()
}
/**
* @see MessageSource.id
*/
@get:JvmSynthetic
inline val QuoteReply.id: Int
get() = source.id
/**
* @see MessageSource.internalId
*/
@SinceMirai("0.39.2")
@get:JvmSynthetic
inline val QuoteReply.internalId: Int
get() = source.internalId
/**
* @see MessageSource.fromId
*/
@get:JvmSynthetic
inline val QuoteReply.fromId: Long
get() = source.fromId
/**
* @see MessageSource.targetId
*/
@get:JvmSynthetic
inline val QuoteReply.targetId: Long
get() = source.targetId
/**
* @see MessageSource.originalMessage
*/
@get:JvmSynthetic
inline val QuoteReply.originalMessage: MessageChain
get() = source.originalMessage
/**
* @see MessageSource.time
*/
@get:JvmSynthetic
inline val QuoteReply.time: Int
get() = source.time
/**
* @see MessageSource.bot
*/
@get:JvmSynthetic
inline val QuoteReply.bot: Bot
get() = source.bot
@ -78,6 +112,9 @@ inline val QuoteReply.bot: Bot
@JvmSynthetic
suspend inline fun QuoteReply.recall() = this.source.recall()
/**
* 在一段时间后撤回这条消息.
*/
@JvmOverloads
inline fun QuoteReply.recallIn(
millis: Long,

View File

@ -0,0 +1,43 @@
/*
* 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:JvmName("HummerMessageKt")
@file:Suppress("NOTHING_TO_INLINE")
package net.mamoe.mirai.message.data
import net.mamoe.mirai.utils.PlannedRemoval
import net.mamoe.mirai.utils.SinceMirai
import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic
/*
因为文件改名为做的兼容
*/
@PlannedRemoval("1.0.0")
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
@JvmName("flash")
@SinceMirai("0.33.0")
inline fun Image.flash2(): FlashImage = FlashImage(this)
@PlannedRemoval("1.0.0")
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
@JvmName("flash")
@JvmSynthetic
@SinceMirai("0.33.0")
inline fun GroupImage.flash2(): GroupFlashImage = FlashImage(this) as GroupFlashImage
@PlannedRemoval("1.0.0")
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
@JvmName("flash")
@JvmSynthetic
@SinceMirai("0.33.0")
inline fun FriendImage.flash2(): FriendFlashImage = FlashImage(this) as FriendFlashImage

View File

@ -0,0 +1,45 @@
/*
* 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:JvmName("MessageKt")
@file:Suppress("NOTHING_TO_INLINE")
package net.mamoe.mirai.message.data
import net.mamoe.mirai.utils.PlannedRemoval
import kotlin.jvm.JvmName
/*
因为文件改名为做的兼容
*/
@PlannedRemoval("1.0.0")
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
@JvmName("isPlain")
inline fun Message.isPlain2(): Boolean = this is PlainText
@PlannedRemoval("1.0.0")
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
@JvmName("isNotPlain")
inline fun Message.isNotPlain2(): Boolean = this !is PlainText
@PlannedRemoval("1.0.0")
@Deprecated("for binary compatibility", level = DeprecationLevel.HIDDEN)
@JvmName("repeat")
// inline: for future removal
inline fun Message.repeat2(count: Int): MessageChain {
if (this is ConstrainSingle<*>) {
// fast-path
return this.asMessageChain()
}
return buildMessageChain(count) {
add(this@repeat2)
}
}

View File

@ -42,6 +42,8 @@ inline fun buildMessageChain(initialSize: Int, block: MessageChainBuilder.() ->
/**
* [MessageChain] 构建器.
* 多个连续的 [String] 会被连接为单个 [PlainText] 以优化性能.
*
*
* **注意:** 无并发安全性.
*
* @see buildMessageChain 推荐使用
@ -91,6 +93,7 @@ open class MessageChainBuilder private constructor(
return addAll(elements.flatten())
}
@JvmSynthetic
operator fun Message.unaryPlus() {
checkBuilt()
flushCache()
@ -98,22 +101,26 @@ open class MessageChainBuilder private constructor(
}
@JvmSynthetic
operator fun String.unaryPlus() {
checkBuilt()
add(this)
}
@JvmSynthetic // they should use add
operator fun plusAssign(plain: String) {
checkBuilt()
withCache { append(plain) }
}
@JvmSynthetic // they should use add
operator fun plusAssign(message: Message) {
checkBuilt()
flushCache()
this.add(message)
}
@JvmSynthetic // they should use add
operator fun plusAssign(message: SingleMessage) { // avoid resolution ambiguity
checkBuilt()
flushCache()
@ -125,6 +132,7 @@ open class MessageChainBuilder private constructor(
withCache { append(plain) }
}
@JvmSynthetic // they should use add
operator fun plusAssign(charSequence: CharSequence) {
checkBuilt()
withCache { append(charSequence) }

View File

@ -311,9 +311,11 @@ internal class SingleMessageChainImpl constructor(
@SharedImmutable
@get:JvmSynthetic
internal val EMPTY_BYTE_ARRAY = ByteArray(0)
@JvmSynthetic
@Suppress("NOTHING_TO_INLINE") // no stack waste
internal inline fun Char.hexDigitToByte(): Int {
return when (this) {
@ -324,6 +326,7 @@ internal inline fun Char.hexDigitToByte(): Int {
}
}
@JvmSynthetic
internal fun String.skipToSecondHyphen(): Int {
var count = 0
this.forEachIndexed { index, c ->
@ -332,6 +335,7 @@ internal fun String.skipToSecondHyphen(): Int {
error("cannot find two hyphens")
}
@JvmSynthetic
internal fun String.imageIdToMd5(offset: Int): ByteArray {
val result = ByteArray(16)
var cur = 0