diff --git a/build.gradle.kts b/build.gradle.kts index f85ddf656..62dc63a6c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -252,7 +252,9 @@ val experimentalAnnotations = arrayOf( "net.mamoe.mirai.utils.MiraiInternalApi", "net.mamoe.mirai.utils.MiraiExperimentalApi", "net.mamoe.mirai.LowLevelApi", - "net.mamoe.mirai.utils.UnstableExternalImage" + "net.mamoe.mirai.utils.UnstableExternalImage", + + "net.mamoe.mirai.message.data.ExperimentalMessageKey" ) fun Project.configureKotlinExperimentalUsages() { diff --git a/mirai-core-api/src/commonMain/kotlin/IMirai.kt b/mirai-core-api/src/commonMain/kotlin/IMirai.kt index eb7ad1b5e..674efc669 100644 --- a/mirai-core-api/src/commonMain/kotlin/IMirai.kt +++ b/mirai-core-api/src/commonMain/kotlin/IMirai.kt @@ -95,9 +95,18 @@ public interface IMirai : LowLevelApiAccessor { @JvmBlockingBridge public suspend fun recallMessage(bot: Bot, source: MessageSource) + /** + * 发送戳一戳消息 + */ @JvmBlockingBridge public suspend fun sendNudge(bot: Bot, nudge: Nudge, receiver: Contact): Boolean + /** + * 构造 [Image] + * + * @see Image + * @see Image.fromId + */ public fun createImage(imageId: String): Image /** diff --git a/mirai-core-api/src/commonMain/kotlin/message/MessageSerializer.kt b/mirai-core-api/src/commonMain/kotlin/message/MessageSerializer.kt index b48c64902..a3fb2d42d 100644 --- a/mirai-core-api/src/commonMain/kotlin/message/MessageSerializer.kt +++ b/mirai-core-api/src/commonMain/kotlin/message/MessageSerializer.kt @@ -111,8 +111,6 @@ private val builtInSerializersModule = SerializersModule { contextual(PokeMessage::class, PokeMessage.serializer()) contextual(VipFace::class, VipFace.serializer()) contextual(FlashImage::class, FlashImage.serializer()) - contextual(GroupFlashImage::class, GroupFlashImage.serializer()) - contextual(FriendFlashImage::class, FriendFlashImage.serializer()) contextual(VipFace.Kind::class, VipFace.Kind.serializer()) diff --git a/mirai-core-api/src/commonMain/kotlin/message/action/Nudge.kt b/mirai-core-api/src/commonMain/kotlin/message/action/Nudge.kt index 1e55cb4fc..aae97bd87 100644 --- a/mirai-core-api/src/commonMain/kotlin/message/action/Nudge.kt +++ b/mirai-core-api/src/commonMain/kotlin/message/action/Nudge.kt @@ -39,13 +39,12 @@ public sealed class Nudge { * 需要 [使用协议][BotConfiguration.protocol] [MiraiProtocol.ANDROID_PHONE]. * * @param receiver 这条 "戳一戳" 消息的接收对象. (不是 "戳" 动作的对象, 而是接收 "A 戳了 B" 这条消息的对象) + * @return 成功发送时为 `true`. 若对方禁用 "戳一戳" 功能, 返回 `false`. + * @throws UnsupportedOperationException 当未使用 [安卓协议][MiraiProtocol.ANDROID_PHONE] 时抛出 * * @see MemberNudgedEvent 成员被戳事件 * @see BotNudgedEvent [Bot] 被戳事件 - * - * @throws UnsupportedOperationException 当未使用 [安卓协议][MiraiProtocol.ANDROID_PHONE] 时抛出 - * - * @return 成功发送时为 `true`. 若对方禁用 "戳一戳" 功能, 返回 `false`. + * @see Contact.sendNudge */ @JvmBlockingBridge @MiraiExperimentalApi @@ -69,6 +68,7 @@ public sealed class Nudge { */ @MiraiExperimentalApi @JvmBlockingBridge + @JvmStatic public suspend fun Contact.sendNudge(nudge: Nudge): Boolean = nudge.sendTo(this) } } diff --git a/mirai-core-api/src/commonMain/kotlin/message/data/HummerMessage.kt b/mirai-core-api/src/commonMain/kotlin/message/data/HummerMessage.kt index 6c09b6134..eb745d75a 100644 --- a/mirai-core-api/src/commonMain/kotlin/message/data/HummerMessage.kt +++ b/mirai-core-api/src/commonMain/kotlin/message/data/HummerMessage.kt @@ -55,31 +55,56 @@ public data class PokeMessage internal constructor( public val type: Int, public val id: Int ) : HummerMessage(), CodableMessage { + @ExperimentalMessageKey override val key: MessageKey get() = Key - @Suppress("DEPRECATION_ERROR", "DEPRECATION", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") public companion object Key : AbstractPolymorphicMessageKey(HummerMessage, { it.castOrNull() }) { /** 戳一戳 */ @JvmField - public val Poke: PokeMessage = PokeMessage("戳一戳", 1, -1) + public val ChuoYiChuo: PokeMessage = PokeMessage("戳一戳", 1, -1) + + /** 戳一戳 */ + @JvmField + @Deprecated("Use ChuoYiChuo", replaceWith = ReplaceWith("ChuoYiChuo")) + public val Poke: PokeMessage = ChuoYiChuo /** 比心 */ @JvmField - public val ShowLove: PokeMessage = PokeMessage("比心", 2, -1) + public val BiXin: PokeMessage = PokeMessage("比心", 2, -1) + + /** 比心 */ + @JvmField + @Deprecated("Use BiXin", replaceWith = ReplaceWith("BiXin")) + public val ShowLove: PokeMessage = BiXin /** 点赞 */ @JvmField - public val Like: PokeMessage = PokeMessage("点赞", 3, -1) + public val DianZan: PokeMessage = PokeMessage("点赞", 3, -1) + + /** 点赞 */ + @JvmField + @Deprecated("Use DianZan", replaceWith = ReplaceWith("DianZan")) + public val Like: PokeMessage = DianZan /** 心碎 */ @JvmField - public val Heartbroken: PokeMessage = PokeMessage("心碎", 4, -1) + public val XinSui: PokeMessage = PokeMessage("心碎", 4, -1) + + /** 心碎 */ + @JvmField + @Deprecated("Use XinSui", replaceWith = ReplaceWith("XinSui")) + public val Heartbroken: PokeMessage = XinSui /** 666 */ @JvmField - public val SixSixSix: PokeMessage = PokeMessage("666", 5, -1) + public val LiuLiuLiu: PokeMessage = PokeMessage("666", 5, -1) + + /** 666 */ + @JvmField + @Deprecated("Use LiuLiuLiu", replaceWith = ReplaceWith("LiuLiuLiu")) + public val SixSixSix: PokeMessage = LiuLiuLiu /** 放大招 */ @JvmField @@ -129,9 +154,9 @@ public data class PokeMessage internal constructor( /** * 所有类型数组 */ - @JvmStatic + @JvmField public val values: Array = arrayOf( - Poke, ShowLove, Like, Heartbroken, SixSixSix, + ChuoYiChuo, BiXin, DianZan, XinSui, LiuLiuLiu, FangDaZhao, BaoBeiQiu, Rose, ZhaoHuanShu, RangNiPi, JieYin, ShouLei, GouYin, ZhuaYiXia, SuiPing ) @@ -160,7 +185,7 @@ public data class PokeMessage internal constructor( * ## mirai 码支持 * 格式: [mirai:vipface:*[Kind.id]*,*[Kind.name]*,*[count]*] * - * @see Types 使用伴生对象中的常量 + * @see VipFace.Key 使用伴生对象中的常量 */ @Serializable public data class VipFace internal constructor( @@ -180,49 +205,50 @@ public data class VipFace internal constructor( } } + @ExperimentalMessageKey override val key: MessageKey get() = Key @Suppress("DEPRECATION_ERROR", "DEPRECATION", "INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") public companion object Key : AbstractPolymorphicMessageKey(HummerMessage, { it.safeCast() }) { - @JvmStatic + @JvmField public val LiuLian: Kind = 9 to "榴莲" - @JvmStatic + @JvmField public val PingDiGuo: Kind = 1 to "平底锅" - @JvmStatic + @JvmField public val ChaoPiao: Kind = 12 to "钞票" - @JvmStatic + @JvmField public val LueLueLue: Kind = 10 to "略略略" - @JvmStatic + @JvmField public val ZhuTou: Kind = 4 to "猪头" - @JvmStatic + @JvmField public val BianBian: Kind = 6 to "便便" - @JvmStatic + @JvmField public val ZhaDan: Kind = 5 to "炸弹" - @JvmStatic + @JvmField public val AiXin: Kind = 2 to "爱心" - @JvmStatic + @JvmField public val HaHa: Kind = 3 to "哈哈" - @JvmStatic + @JvmField public val DianZan: Kind = 1 to "点赞" - @JvmStatic + @JvmField public val QinQin: Kind = 7 to "亲亲" - @JvmStatic + @JvmField public val YaoWan: Kind = 8 to "药丸" - @JvmStatic + @JvmField public val values: Array = arrayOf( LiuLian, PingDiGuo, ChaoPiao, LueLueLue, ZhuTou, BianBian, ZhaDan, AiXin, HaHa, DianZan, QinQin, YaoWan @@ -255,24 +281,19 @@ public data class VipFace internal constructor( * @see Image 查看图片相关信息 */ @Serializable -public sealed class FlashImage : MessageContent, HummerMessage(), CodableMessage, ConstrainSingle { - override val key: MessageKey get() = Key +public data class FlashImage( + /** + * 闪照的内容图片, 即一个普通图片. + */ + @Contextual + public val image: Image +) : MessageContent, HummerMessage(), CodableMessage, ConstrainSingle { + @ExperimentalMessageKey + override val key: MessageKey + get() = Key public companion object Key : AbstractPolymorphicMessageKey(HummerMessage, { it.safeCast() }) { - /** - * 将普通图片转换为闪照. - */ - @JvmStatic - @JvmName("from") - public operator fun invoke(image: Image): FlashImage { - - return when (image) { - is GroupImage -> GroupFlashImage(image) - is FriendImage -> FriendFlashImage(image) - else -> throw IllegalArgumentException("不支持的图片类型(Please use GroupImage or FriendImage)") - } - } /** * 将普通图片转换为闪照. @@ -280,51 +301,35 @@ public sealed class FlashImage : MessageContent, HummerMessage(), CodableMessage * @param imageId 图片 id, 详见 [Image.imageId] */ @JvmStatic - @JvmName("from") - public operator fun invoke(imageId: String): FlashImage { - return invoke(Image(imageId)) - } + public fun from(imageId: String): FlashImage = FlashImage(Image(imageId)) } - /** - * 闪照的内容图片, 即一个普通图片. - */ - public abstract val image: Image + private val stringValue: String by lazy(LazyThreadSafetyMode.NONE) { "[mirai:flash:${image.imageId}]" } - private var stringValue: String? = null - get() { - return field ?: kotlin.run { - field = "[mirai:flash:${image.imageId}]" - field - } - } - - public final override fun toString(): String = stringValue!! + public override fun toString(): String = stringValue public override fun contentToString(): String = "[闪照]" } +/** + * 将普通图片转换为闪照. + */ +@JvmSynthetic +public inline fun FlashImage(imageId: String): FlashImage = FlashImage.from(imageId) + +/** + * 将普通图片转换为闪照. + */ +@JvmSynthetic public inline fun Image.flash(): FlashImage = FlashImage(this) +/** + * 将普通图片转换为闪照. + */ @JvmSynthetic -public inline fun GroupImage.flash(): GroupFlashImage = FlashImage(this) as GroupFlashImage - -@JvmSynthetic -public inline fun FriendImage.flash(): FriendFlashImage = FlashImage(this) as FriendFlashImage +public inline fun GroupImage.flash(): FlashImage = FlashImage(this) /** - * @see FlashImage.invoke + * 将普通图片转换为闪照. */ -@Serializable -public data class GroupFlashImage(@Contextual override val image: GroupImage) : FlashImage() { - public companion object Key : - AbstractPolymorphicMessageKey(FlashImage, { it.safeCast() }) -} - -/** - * @see FlashImage.invoke - */ -@Serializable -public data class FriendFlashImage(@Contextual override val image: FriendImage) : FlashImage() { - public companion object Key : - AbstractPolymorphicMessageKey(FlashImage, { it.safeCast() }) -} +@JvmSynthetic +public inline fun FriendImage.flash(): FlashImage = FlashImage(this) \ No newline at end of file diff --git a/mirai-core-api/src/commonMain/kotlin/message/data/Image.kt b/mirai-core-api/src/commonMain/kotlin/message/data/Image.kt index fab33ccc1..b9a7c03fc 100644 --- a/mirai-core-api/src/commonMain/kotlin/message/data/Image.kt +++ b/mirai-core-api/src/commonMain/kotlin/message/data/Image.kt @@ -22,7 +22,8 @@ package net.mamoe.mirai.message.data -import kotlinx.io.core.Input +import event.sendAsImageTo +import event.uploadAsImage import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable import kotlinx.serialization.builtins.serializer @@ -31,17 +32,18 @@ import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import net.mamoe.kjbb.JvmBlockingBridge import net.mamoe.mirai.Bot +import net.mamoe.mirai.IMirai import net.mamoe.mirai.Mirai import net.mamoe.mirai.contact.Contact import net.mamoe.mirai.message.code.CodableMessage +import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_1 +import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_2 +import net.mamoe.mirai.message.data.Image.Key.GROUP_IMAGE_ID_REGEX import net.mamoe.mirai.message.data.Image.Key.queryUrl -import net.mamoe.mirai.utils.ExternalImage -import net.mamoe.mirai.utils.MiraiInternalApi -import net.mamoe.mirai.utils.safeCast -import net.mamoe.mirai.utils.sendImage +import net.mamoe.mirai.utils.* import java.io.File import java.io.InputStream -import java.net.URL +import kotlin.LazyThreadSafetyMode.NONE /** * 自定义表情 (收藏的表情) 和普通图片. @@ -50,27 +52,23 @@ import java.net.URL * 最推荐的存储方式是存储图片原文件, 每次发送图片时都使用文件上传. * 在上传时服务器会根据其缓存情况回复已有的图片 ID 或要求客户端上传. 详见 [Contact.uploadImage] * + * ### 根据 ID 构造图片 + * - [Image.fromId]. 在 Kotlin, 更推荐使用顶层函数 `val image = Image("id")` * * ### 上传和发送图片 - * @see Contact.uploadImage 上传 [图片文件][ExternalImage] 并得到 [Image] 消息 - * @see Contact.sendImage 上传 [图片文件][ExternalImage] 并发送返回的 [Image] 作为一条消息 - * @see Image.sendTo 上传 [图片文件][ExternalImage] 并得到 [Image] 消息 + * - [Contact.uploadImage] 上传 [图片文件][ExternalImage] 并得到 [Image] 消息 + * - [Contact.sendImage] 上传 [图片文件][ExternalImage] 并发送返回的 [Image] 作为一条消息 + * - [Image.sendTo] 上传 [图片文件][ExternalImage] 并得到 [Image] 消息 * - * @see File.uploadAsImage - * @see InputStream.uploadAsImage - * @see Input.uploadAsImage - * @see URL.uploadAsImage + * - [File.uploadAsImage] + * - [InputStream.uploadAsImage] * - * @see File.sendAsImageTo - * @see InputStream.sendAsImageTo - * @see Input.sendAsImageTo - * @see URL.sendAsImageTo + * - [File.sendAsImageTo] + * - [InputStream.sendAsImageTo] * * ### 下载图片 - * @see Image.queryUrl 扩展函数. 查询图片下载链接 - * @see Bot.queryImageUrl 查询图片下载链接 (Java 使用) - * - * 查看平台 `actual` 定义以获取上传方式扩展. + * - [Image.queryUrl] 扩展函数. 查询图片下载链接 + * - [IMirai.queryImageUrl] 查询图片下载链接 (Java 使用) * * ## mirai 码支持 * 格式: [mirai:image:*[Image.imageId]*] @@ -88,7 +86,7 @@ public interface Image : Message, MessageContent, CodableMessage { * * ### 格式 * 群图片: - * - [GROUP_IMAGE_ID_REGEX], 示例: `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.mirai` (后缀一定为 ".mirai") + * - [GROUP_IMAGE_ID_REGEX], 示例: `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.ext` (ext 为文件后缀, 如 png) * * 好友图片: * - [FRIEND_IMAGE_ID_REGEX_1], 示例: `/f8f1ab55-bf8e-4236-b55e-955848d7069f` @@ -139,9 +137,55 @@ public interface Image : Message, MessageContent, CodableMessage { val bot = Bot._instances.peekFirst()?.get() ?: error("No Bot available to query image url") return Mirai.queryImageUrl(bot, this) } + + + /** + * 好友图片 ID 正则表达式 + * + * `/f8f1ab55-bf8e-4236-b55e-955848d7069f` + * @see FRIEND_IMAGE_ID_REGEX_2 + */ + // Java: MessageUtils.FRIEND_IMAGE_ID_REGEX_1 + @JvmStatic + @MiraiExperimentalApi + @get:JvmName("getFriendImageIdRegex1") + public val FRIEND_IMAGE_ID_REGEX_1: Regex = Regex("""/[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}""") + + /** + * 好友图片 ID 正则表达式 2 + * + * `/000000000-3814297509-BFB7027B9354B8F899A062061D74E206` + * @see FRIEND_IMAGE_ID_REGEX_1 + */ + // Java: MessageUtils.FRIEND_IMAGE_ID_REGEX_2 + @JvmStatic + @MiraiExperimentalApi + @get:JvmName("getFriendImageIdRegex2") + public val FRIEND_IMAGE_ID_REGEX_2: Regex = Regex("""/[0-9]*-[0-9]*-[0-9a-fA-F]{32}""") + + /** + * 群图片 ID 正则表达式 + * + * `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.ext` + */ + @Suppress("RegExpRedundantEscape") // This is required on Android + // Java: MessageUtils.GROUP_IMAGE_ID_REGEX + @JvmStatic + @MiraiExperimentalApi + @get:JvmName("getGroupImageIdRegex") + public val GROUP_IMAGE_ID_REGEX: Regex = + Regex("""\{[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\}\..{3,5}""") } } +@MiraiExperimentalApi +public val Image.isGroupImage: Boolean + get() = GROUP_IMAGE_ID_REGEX matches imageId + +@MiraiExperimentalApi +public val Image.isFriendImage: Boolean + get() = FRIEND_IMAGE_ID_REGEX_1 matches imageId || FRIEND_IMAGE_ID_REGEX_2 matches imageId + /** * 通过 [Image.imageId] 构造一个 [Image] 以便发送. * 这个图片必须是服务器已经存在的图片. @@ -151,35 +195,35 @@ public interface Image : Message, MessageContent, CodableMessage { * * @see Image 获取更多说明 * @see Image.imageId 获取更多说明 + * + * @see IMirai.createImage */ @JvmSynthetic public inline fun Image(imageId: String): Image = Image.fromId(imageId) -/** - * 所有 [Image] 实现的基类. - */ -@MiraiInternalApi -public sealed class AbstractImage : Image { // make sealed in 1.3.0 ? - private var _stringValue: String? = null - get() = field ?: kotlin.run { - field = "[mirai:image:$imageId]" - field - } - - final override fun toString(): String = _stringValue!! - final override fun contentToString(): String = "[图片]" -} - /** * 计算图片的 md5 校验值. * * 在 Java 使用: `MessageUtils.calculateImageMd5(image)` */ +@MiraiInternalApi @get:JvmName("calculateImageMd5") public val Image.md5: ByteArray get() = calculateImageMd5ByImageId(imageId) +/** + * 所有 [Image] 实现的基类. + */ +@MiraiInternalApi +public sealed class AbstractImage : Image { + private val _stringValue: String? by lazy(NONE) { "[mirai:image:$imageId]" } + + final override fun toString(): String = _stringValue!! + final override fun contentToString(): String = "[图片]" +} + + /** * 好友图片 * @@ -203,32 +247,4 @@ public abstract class FriendImage @MiraiInternalApi public constructor() : public abstract class GroupImage @MiraiInternalApi public constructor() : AbstractImage() { // change to sealed in the future. public companion object -} - -/** - * 好友图片 ID 正则表达式 - * - * `/f8f1ab55-bf8e-4236-b55e-955848d7069f` - * @see FRIEND_IMAGE_ID_REGEX_2 - */ -// Java: MessageUtils.FRIEND_IMAGE_ID_REGEX_1 -public val FRIEND_IMAGE_ID_REGEX_1: Regex = Regex("""/[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}""") - -/** - * 好友图片 ID 正则表达式 2 - * - * `/000000000-3814297509-BFB7027B9354B8F899A062061D74E206` - * @see FRIEND_IMAGE_ID_REGEX_1 - */ -// Java: MessageUtils.FRIEND_IMAGE_ID_REGEX_2 -public val FRIEND_IMAGE_ID_REGEX_2: Regex = Regex("""/[0-9]*-[0-9]*-[0-9a-fA-F]{32}""") - -/** - * 群图片 ID 正则表达式 - * - * `{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.ext` - */ -@Suppress("RegExpRedundantEscape") -// This is required on Android -// Java: MessageUtils.GROUP_IMAGE_ID_REGEX -public val GROUP_IMAGE_ID_REGEX: Regex = Regex("""\{[0-9a-fA-F]{8}-([0-9a-fA-F]{4}-){3}[0-9a-fA-F]{12}\}\..{3,5}""") \ No newline at end of file +} \ No newline at end of file diff --git a/mirai-core-api/src/commonMain/kotlin/message/data/Message.kt b/mirai-core-api/src/commonMain/kotlin/message/data/Message.kt index e08c37d9b..2fb810661 100644 --- a/mirai-core-api/src/commonMain/kotlin/message/data/Message.kt +++ b/mirai-core-api/src/commonMain/kotlin/message/data/Message.kt @@ -28,6 +28,7 @@ import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.MessageSerializer import net.mamoe.mirai.message.MessageSerializerImpl import net.mamoe.mirai.utils.MiraiExperimentalApi +import net.mamoe.mirai.utils.PlannedRemoval import net.mamoe.mirai.utils.safeCast import kotlin.contracts.contract @@ -187,6 +188,12 @@ public interface Message { // must be interface. Don't consider any changes. KSerializer by PolymorphicSerializer(Message::class) } +/** + * 标注一个实验性的 [MessageKey] API. + * + * 在 `1.0-M2` 时将会推进 [MessageKey] 到稳定状态并删除此注解. + */ +@PlannedRemoval("1.0-M2") @MiraiExperimentalApi @RequiresOptIn(level = RequiresOptIn.Level.WARNING) public annotation class ExperimentalMessageKey @@ -297,8 +304,8 @@ public interface MessageMetadata : SingleMessage { @ExperimentalMessageKey public interface ConstrainSingle : SingleMessage { /** - * 用于判断是否为同一种元素的 [Key] - * @see Key 查看更多信息 + * 用于判断是否为同一种元素的 [MessageKey] + * @see MessageKey 查看更多信息 */ @ExperimentalMessageKey public val key: MessageKey<*> diff --git a/mirai-core-api/src/commonMain/kotlin/message/data/MessageSource.kt b/mirai-core-api/src/commonMain/kotlin/message/data/MessageSource.kt index 11f66eb04..d620cb508 100644 --- a/mirai-core-api/src/commonMain/kotlin/message/data/MessageSource.kt +++ b/mirai-core-api/src/commonMain/kotlin/message/data/MessageSource.kt @@ -67,6 +67,7 @@ import net.mamoe.mirai.utils.safeCast */ @Serializable(MessageSourceSerializer::class) public sealed class MessageSource : Message, MessageMetadata, ConstrainSingle { + @ExperimentalMessageKey public final override val key: MessageKey get() = Key /** @@ -222,6 +223,7 @@ public sealed class MessageSource : Message, MessageMetadata, ConstrainSingle { * 引用这条消息. 仅从服务器接收的消息 (即来自 [MessageEvent]) 才可以通过这个方式被引用. * @see QuoteReply */ + @JvmStatic public fun MessageChain.quote(): QuoteReply = QuoteReply(this.source) } } @@ -347,7 +349,8 @@ public sealed class OnlineMessageSource : MessageSource() { } public abstract class FromTemp : Incoming() { - public companion object Key : AbstractPolymorphicMessageKey(Incoming, { it.safeCast() }) + public companion object Key : + AbstractPolymorphicMessageKey(Incoming, { it.safeCast() }) public abstract override val sender: Member public inline val group: Group get() = sender.group diff --git a/mirai-core-api/src/commonMain/kotlin/message/data/QuoteReply.kt b/mirai-core-api/src/commonMain/kotlin/message/data/QuoteReply.kt index c2090958b..de43ad26b 100644 --- a/mirai-core-api/src/commonMain/kotlin/message/data/QuoteReply.kt +++ b/mirai-core-api/src/commonMain/kotlin/message/data/QuoteReply.kt @@ -43,6 +43,7 @@ import net.mamoe.mirai.utils.safeCast public data class QuoteReply(public val source: MessageSource) : Message, MessageMetadata, ConstrainSingle { public companion object Key : AbstractMessageKey({ it.safeCast() }) + @ExperimentalMessageKey public override val key: MessageKey get() = Key // TODO: 2020/12/2 QuoteReply.toString diff --git a/mirai-core-api/src/commonMain/kotlin/message/data/impl.kt b/mirai-core-api/src/commonMain/kotlin/message/data/impl.kt index 749981e9b..985d1257e 100644 --- a/mirai-core-api/src/commonMain/kotlin/message/data/impl.kt +++ b/mirai-core-api/src/commonMain/kotlin/message/data/impl.kt @@ -13,6 +13,9 @@ package net.mamoe.mirai.message.data +import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_1 +import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_2 +import net.mamoe.mirai.message.data.Image.Key.GROUP_IMAGE_ID_REGEX import net.mamoe.mirai.utils.MiraiExperimentalApi import kotlin.native.concurrent.SharedImmutable diff --git a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt index 9a4f4463c..19394c619 100644 --- a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt +++ b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt @@ -41,6 +41,9 @@ import net.mamoe.mirai.internal.utils.io.serialization.toByteArray import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.action.Nudge import net.mamoe.mirai.message.data.* +import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_1 +import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_2 +import net.mamoe.mirai.message.data.Image.Key.GROUP_IMAGE_ID_REGEX import net.mamoe.mirai.utils.BotConfiguration import net.mamoe.mirai.utils.MiraiExperimentalApi import net.mamoe.mirai.utils.currentTimeSeconds diff --git a/mirai-core/src/commonMain/kotlin/message/FlashImageImpl.kt b/mirai-core/src/commonMain/kotlin/message/FlashImageImpl.kt index 70dc689db..6e0bbcbff 100644 --- a/mirai-core/src/commonMain/kotlin/message/FlashImageImpl.kt +++ b/mirai-core/src/commonMain/kotlin/message/FlashImageImpl.kt @@ -14,37 +14,44 @@ package net.mamoe.mirai.internal.message import net.mamoe.mirai.internal.network.protocol.data.proto.HummerCommelem import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody import net.mamoe.mirai.internal.utils.io.serialization.toByteArray -import net.mamoe.mirai.message.data.FriendFlashImage -import net.mamoe.mirai.message.data.GroupFlashImage +import net.mamoe.mirai.message.data.FlashImage +import net.mamoe.mirai.message.data.isFriendImage +import net.mamoe.mirai.message.data.isGroupImage import net.mamoe.mirai.message.data.md5 -internal fun GroupFlashImage.toJceData() = ImMsgBody.Elem( - commonElem = ImMsgBody.CommonElem( - serviceType = 3, - businessType = 0, - pbElem = HummerCommelem.MsgElemInfoServtype3( - flashTroopPic = ImMsgBody.CustomFace( - filePath = image.imageId, - md5 = image.md5, - pbReserve = byteArrayOf(0x78, 0x06) +internal fun FlashImage.toJceData(): ImMsgBody.Elem { + return when { + image.isFriendImage -> ImMsgBody.Elem( + commonElem = ImMsgBody.CommonElem( + serviceType = 3, + businessType = 0, + pbElem = HummerCommelem.MsgElemInfoServtype3( + flashC2cPic = ImMsgBody.NotOnlineImage( + filePath = image.imageId, + resId = image.imageId, + picMd5 = image.md5, + oldPicMd5 = false, + pbReserve = byteArrayOf(0x78, 0x06) + ) + ).toByteArray(HummerCommelem.MsgElemInfoServtype3.serializer()) ) - ).toByteArray(HummerCommelem.MsgElemInfoServtype3.serializer()) - ) -) + ) -internal fun FriendFlashImage.toJceData() = ImMsgBody.Elem( - commonElem = ImMsgBody.CommonElem( - serviceType = 3, - businessType = 0, - pbElem = HummerCommelem.MsgElemInfoServtype3( - flashC2cPic = ImMsgBody.NotOnlineImage( - filePath = image.imageId, - resId = image.imageId, - picMd5 = image.md5, - oldPicMd5 = false, - pbReserve = byteArrayOf(0x78, 0x06) + image.isGroupImage -> ImMsgBody.Elem( + commonElem = ImMsgBody.CommonElem( + serviceType = 3, + businessType = 0, + pbElem = HummerCommelem.MsgElemInfoServtype3( + flashTroopPic = ImMsgBody.CustomFace( + filePath = image.imageId, + md5 = image.md5, + pbReserve = byteArrayOf(0x78, 0x06) + ) + ).toByteArray(HummerCommelem.MsgElemInfoServtype3.serializer()) ) - ).toByteArray(HummerCommelem.MsgElemInfoServtype3.serializer()) - ) -) \ No newline at end of file + ) + + else -> error("Internal error: an image is neither group image nor friend image.") + } +} \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/message/conversions.kt b/mirai-core/src/commonMain/kotlin/message/conversions.kt index f371f88ff..99add52cd 100644 --- a/mirai-core/src/commonMain/kotlin/message/conversions.kt +++ b/mirai-core/src/commonMain/kotlin/message/conversions.kt @@ -134,18 +134,11 @@ internal fun MessageChain.toRichTextElems(forGroup: Boolean, withGeneralFlags: B ) transformOneMessage(UNSUPPORTED_POKE_MESSAGE_PLAIN) } - is @Suppress("DEPRECATION") - OfflineGroupImage - -> elements.add(ImMsgBody.Elem(customFace = it.toJceData())) + is OfflineGroupImage -> elements.add(ImMsgBody.Elem(customFace = it.toJceData())) is OnlineGroupImageImpl -> elements.add(ImMsgBody.Elem(customFace = it.delegate)) is OnlineFriendImageImpl -> elements.add(ImMsgBody.Elem(notOnlineImage = it.delegate)) - is @Suppress("DEPRECATION") - OfflineFriendImage - -> elements.add(ImMsgBody.Elem(notOnlineImage = it.toJceData())) - is GroupFlashImage -> elements.add(it.toJceData()) - .also { transformOneMessage(UNSUPPORTED_FLASH_MESSAGE_PLAIN) } - is FriendFlashImage -> elements.add(it.toJceData()) - .also { transformOneMessage(UNSUPPORTED_FLASH_MESSAGE_PLAIN) } + is OfflineFriendImage -> elements.add(ImMsgBody.Elem(notOnlineImage = it.toJceData())) + is FlashImage -> elements.add(it.toJceData()).also { transformOneMessage(UNSUPPORTED_FLASH_MESSAGE_PLAIN) } is AtAll -> elements.add(atAllData) is Face -> elements.add(ImMsgBody.Elem(face = it.toJceData())) is QuoteReply -> { @@ -160,9 +153,7 @@ internal fun MessageChain.toRichTextElems(forGroup: Boolean, withGeneralFlags: B } } } - is VipFace -> { - transformOneMessage(PlainText(it.contentToString())) - } + is VipFace -> transformOneMessage(PlainText(it.contentToString())) is PttMessage -> { elements.add( ImMsgBody.Elem( @@ -480,10 +471,10 @@ internal fun List.joinToMessageChain(groupIdOrZero: Long, botId: 3 -> { val proto = element.commonElem.pbElem.loadAs(HummerCommelem.MsgElemInfoServtype3.serializer()) if (proto.flashTroopPic != null) { - list.add(GroupFlashImage(OnlineGroupImageImpl(proto.flashTroopPic))) + list.add(FlashImage(OnlineGroupImageImpl(proto.flashTroopPic))) } if (proto.flashC2cPic != null) { - list.add(FriendFlashImage(OnlineFriendImageImpl(proto.flashC2cPic))) + list.add(FlashImage(OnlineFriendImageImpl(proto.flashC2cPic))) } } } diff --git a/mirai-core/src/commonMain/kotlin/message/imagesImpl.kt b/mirai-core/src/commonMain/kotlin/message/imagesImpl.kt index f6e31f9cb..8f5ae165f 100644 --- a/mirai-core/src/commonMain/kotlin/message/imagesImpl.kt +++ b/mirai-core/src/commonMain/kotlin/message/imagesImpl.kt @@ -18,7 +18,13 @@ import net.mamoe.mirai.contact.Contact import net.mamoe.mirai.contact.Group import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody import net.mamoe.mirai.internal.utils.hexToBytes -import net.mamoe.mirai.message.data.* +import net.mamoe.mirai.message.data.FriendImage +import net.mamoe.mirai.message.data.GroupImage +import net.mamoe.mirai.message.data.Image +import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_1 +import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_2 +import net.mamoe.mirai.message.data.Image.Key.GROUP_IMAGE_ID_REGEX +import net.mamoe.mirai.message.data.md5 import net.mamoe.mirai.utils.ExternalImage import net.mamoe.mirai.utils.MiraiExperimentalApi