Sfoglia il codice sorgente

Multiple MessageSource.id and MessageSource.internalId for split sources now, and split messages in the future. Close #618

Him188 5 anni fa
parent
commit
64bd63d7a0

+ 3 - 3
mirai-core-api/src/commonMain/kotlin/IMirai.kt

@@ -107,8 +107,8 @@ public interface IMirai : LowLevelApiAccessor {
     /**
      * 构造一个 [OfflineMessageSource]
      *
-     * @param id 即 [MessageSource.id]
-     * @param internalId 即 [MessageSource.internalId]
+     * @param ids 即 [MessageSource.ids]
+     * @param internalIds 即 [MessageSource.internalIds]
      *
      * @param fromUin 为用户时为 [Friend.id], 为群时需使用 [Group.calculateGroupUinByGroupCode] 计算
      * @param targetUin 为用户时为 [Friend.id], 为群时需使用 [Group.calculateGroupUinByGroupCode] 计算
@@ -118,7 +118,7 @@ public interface IMirai : LowLevelApiAccessor {
         bot: Bot,
         kind: OfflineMessageSource.Kind,
         fromUin: Long, targetUin: Long,
-        id: Int, time: Int, internalId: Int,
+        ids: IntArray, time: Int, internalIds: IntArray,
         originalMessage: MessageChain
     ): OfflineMessageSource
 

+ 63 - 11
mirai-core-api/src/commonMain/kotlin/event/events/message.kt

@@ -259,16 +259,16 @@ public sealed class MessageRecallEvent : BotEvent, AbstractEvent() {
     public abstract val authorId: Long
 
     /**
-     * 消息 id.
-     * @see MessageSource.id
+     * 消息 ids.
+     * @see MessageSource.ids
      */
-    public abstract val messageId: Int
+    public abstract val messageIds: IntArray
 
     /**
-     * 消息内部 id.
-     * @see MessageSource.id
+     * 消息内部 ids.
+     * @see MessageSource.ids
      */
-    public abstract val messageInternalId: Int
+    public abstract val messageInternalIds: IntArray
 
     /**
      * 原发送时间
@@ -280,8 +280,8 @@ public sealed class MessageRecallEvent : BotEvent, AbstractEvent() {
      */
     public data class FriendRecall internal constructor(
         public override val bot: Bot,
-        public override val messageId: Int,
-        public override val messageInternalId: Int,
+        public override val messageIds: IntArray,
+        public override val messageInternalIds: IntArray,
         public override val messageTime: Int,
         /**
          * 撤回操作人, 好友的 [User.id]
@@ -290,6 +290,30 @@ public sealed class MessageRecallEvent : BotEvent, AbstractEvent() {
     ) : MessageRecallEvent(), Packet {
         public override val authorId: Long
             get() = bot.id
+
+        override fun equals(other: Any?): Boolean {
+            if (this === other) return true
+            if (javaClass != other?.javaClass) return false
+
+            other as FriendRecall
+
+            if (bot != other.bot) return false
+            if (!messageIds.contentEquals(other.messageIds)) return false
+            if (!messageInternalIds.contentEquals(other.messageInternalIds)) return false
+            if (messageTime != other.messageTime) return false
+            if (operator != other.operator) return false
+
+            return true
+        }
+
+        override fun hashCode(): Int {
+            var result = bot.hashCode()
+            result = 31 * result + messageIds.contentHashCode()
+            result = 31 * result + messageInternalIds.contentHashCode()
+            result = 31 * result + messageTime
+            result = 31 * result + operator.hashCode()
+            return result
+        }
     }
 
     /**
@@ -298,15 +322,43 @@ public sealed class MessageRecallEvent : BotEvent, AbstractEvent() {
     public data class GroupRecall @PublishedApi internal constructor(
         public override val bot: Bot,
         public override val authorId: Long,
-        public override val messageId: Int,
-        public override val messageInternalId: Int,
+        public override val messageIds: IntArray,
+        public override val messageInternalIds: IntArray,
         public override val messageTime: Int,
         /**
          * 操作人. 为 null 时则为 [Bot] 操作.
          */
         public override val operator: Member?,
         public override val group: Group
-    ) : MessageRecallEvent(), GroupOperableEvent, Packet
+    ) : MessageRecallEvent(), GroupOperableEvent, Packet {
+        override fun equals(other: Any?): Boolean {
+            if (this === other) return true
+            if (javaClass != other?.javaClass) return false
+
+            other as GroupRecall
+
+            if (bot != other.bot) return false
+            if (authorId != other.authorId) return false
+            if (!messageIds.contentEquals(other.messageIds)) return false
+            if (!messageInternalIds.contentEquals(other.messageInternalIds)) return false
+            if (messageTime != other.messageTime) return false
+            if (operator != other.operator) return false
+            if (group != other.group) return false
+
+            return true
+        }
+
+        override fun hashCode(): Int {
+            var result = bot.hashCode()
+            result = 31 * result + authorId.hashCode()
+            result = 31 * result + messageIds.contentHashCode()
+            result = 31 * result + messageInternalIds.contentHashCode()
+            result = 31 * result + messageTime
+            result = 31 * result + (operator?.hashCode() ?: 0)
+            result = 31 * result + group.hashCode()
+            return result
+        }
+    }
 }
 
 public val MessageRecallEvent.GroupRecall.author: Member

+ 1 - 1
mirai-core-api/src/commonMain/kotlin/message/MessageEvent.kt

@@ -78,7 +78,7 @@ public abstract class MessageEvent : ContactMessage(),
     /**
      * 消息内容.
      *
-     * 第一个元素一定为 [MessageSource], 存储此消息的发送人, 发送时间, 收信人, 消息 id 等数据.
+     * 第一个元素一定为 [MessageSource], 存储此消息的发送人, 发送时间, 收信人, 消息 ids 等数据.
      * 随后的元素为拥有顺序的真实消息内容.
      */
     public abstract override val message: MessageChain

+ 9 - 10
mirai-core-api/src/commonMain/kotlin/message/MessageReceipt.kt

@@ -16,7 +16,6 @@ import net.mamoe.mirai.Mirai
 import net.mamoe.mirai.contact.*
 import net.mamoe.mirai.message.data.*
 import net.mamoe.mirai.utils.MiraiExperimentalApi
-import kotlin.jvm.JvmSynthetic
 
 /**
  * 发送消息后得到的回执. 可用于撤回, 引用回复等.
@@ -32,7 +31,7 @@ import kotlin.jvm.JvmSynthetic
  * @see User.sendMessage 发送群消息, 返回回执(此对象)
  * @see Member.sendMessage 发送临时消息, 返回回执(此对象)
  *
- * @see MessageReceipt.sourceId 源 id
+ * @see MessageReceipt.sourceIds 源 ids
  * @see MessageReceipt.sourceTime 源时间
  */
 public open class MessageReceipt<out C : Contact> @MiraiExperimentalApi("The constructor is subject to change.") constructor(
@@ -95,23 +94,23 @@ public suspend inline fun <C : Contact> MessageReceipt<C>.quoteReply(message: St
 
 
 /**
- * 获取源消息 [MessageSource.id]
+ * 获取源消息 [MessageSource.ids]
  *
- * @see MessageSource.id
+ * @see MessageSource.ids
  */
 @get:JvmSynthetic
-public inline val MessageReceipt<*>.sourceId: Int
-    get() = this.source.id
+public inline val MessageReceipt<*>.sourceIds: IntArray
+    get() = this.source.ids
 
 
 /**
- * 获取源消息 [MessageSource.internalId]
+ * 获取源消息 [MessageSource.internalIds]
  *
- * @see MessageSource.id
+ * @see MessageSource.ids
  */
 @get:JvmSynthetic
-public inline val MessageReceipt<*>.sourceInternalId: Int
-    get() = this.source.internalId
+public inline val MessageReceipt<*>.sourceInternalIds: IntArray
+    get() = this.source.internalIds
 
 /**
  * 获取源消息 [MessageSource.time]

+ 39 - 29
mirai-core-api/src/commonMain/kotlin/message/data/MessageSource.kt

@@ -22,9 +22,6 @@ import net.mamoe.mirai.message.MessageReceipt
 import net.mamoe.mirai.message.quote
 import net.mamoe.mirai.message.recall
 import net.mamoe.mirai.utils.LazyProperty
-import kotlin.jvm.JvmMultifileClass
-import kotlin.jvm.JvmName
-import kotlin.jvm.JvmSynthetic
 
 /**
  * 消息源. 消息源存在于 [MessageChain] 中, 用于表示这个消息的来源, 也可以用来分辨 [MessageChain].
@@ -36,8 +33,8 @@ import kotlin.jvm.JvmSynthetic
  * [MessageSource] 由 metadata (元数据), form & target, content 组成
  *
  * #### metadata
- * - [id] 消息 id (序列号)
- * - [internalId] 消息内部 id
+ * - [ids] 消息 ids (序列号)
+ * - [internalIds] 消息内部 ids
  * - [time] 时间
  *
  * 官方客户端通过 metadata 这三个数据定位消息, 撤回和引用回复都是如此.
@@ -51,9 +48,9 @@ import kotlin.jvm.JvmSynthetic
  *
  * ### 使用
  *
- * 消息源可用于 [引用回复][QuoteReply] 或 [撤回][Bot.recall].
+ * 消息源可用于 [引用回复][QuoteReply] 或 [撤回][IMirai.recall].
  *
- * @see Bot.recall 撤回一条消息
+ * @see IMirai.recall 撤回一条消息
  * @see MessageSource.quote 引用这条消息, 创建 [MessageChain]
  *
  * @see OnlineMessageSource 在线消息的 [MessageSource]
@@ -74,28 +71,28 @@ public sealed class MessageSource : Message, MessageMetadata, ConstrainSingle<Me
     public abstract val bot: Bot
 
     /**
-     * 消息 id (序列号). 在获取失败时 (概率很低) 为 `-1`.
+     * 消息 ids (序列号). 在获取失败时 (概率很低) 为 `-1`.
      **
      * #### 值域
      * 值的范围约为 [UShort] 的范围.
      *
      * #### 顺序
-     * 群消息的 id 由服务器维护. 好友消息的 id 由 mirai 维护.
-     * 此 id 不一定从 0 开始.
+     * 群消息的 ids 由服务器维护. 好友消息的 ids 由 mirai 维护.
+     * 此 ids 不一定从 0 开始.
      *
      * - 在同一个群的消息中此值随每条消息递增 1, 但此行为由服务器决定, mirai 不保证自增顺序.
      * - 在好友消息中无法保证每次都递增 1. 也可能会产生大幅跳过的情况.
      */
-    public abstract val id: Int
+    public abstract val ids: IntArray
 
     /**
-     * 内部 id. **仅用于协议模块使用**
+     * 内部 ids. **仅用于协议模块使用**
      *
      * 值没有顺序, 也可能为 0, 取决于服务器是否提供.
      *
-     * 在事件中和在引用中无法保证同一条消息的 [internalId] 相同.
+     * 在事件中和在引用中无法保证同一条消息的 [internalIds] 相同.
      */
-    public abstract val internalId: Int
+    public abstract val internalIds: IntArray
 
     /**
      * 发送时间时间戳, 单位为秒.
@@ -131,9 +128,9 @@ public sealed class MessageSource : Message, MessageMetadata, ConstrainSingle<Me
     public abstract val originalMessage: MessageChain
 
     /**
-     * 返回 `"[mirai:source:$id,$internalId]"`
+     * 返回 `"[mirai:source:$ids,$internalIds]"`
      */
-    public final override fun toString(): String = "[mirai:source:$id,$internalId]"
+    public final override fun toString(): String = "[mirai:source:$ids,$internalIds]"
 }
 
 
@@ -206,7 +203,7 @@ public sealed class OnlineMessageSource : MessageSource() {
 
             public abstract override val target: Friend
             public final override val subject: Friend get() = target
-            //  final override fun toString(): String = "OnlineMessageSource.ToFriend(target=${target.id})"
+            //  final override fun toString(): String = "OnlineMessageSource.ToFriend(target=${target.ids})"
         }
 
         public abstract class ToTemp : Outgoing() {
@@ -250,7 +247,7 @@ public sealed class OnlineMessageSource : MessageSource() {
             public abstract override val sender: Friend
             public final override val subject: Friend get() = sender
             public final override val target: Bot get() = sender.bot
-            // final override fun toString(): String = "OnlineMessageSource.FromFriend(from=${sender.id})"
+            // final override fun toString(): String = "OnlineMessageSource.FromFriend(from=${sender.ids})"
         }
 
         public abstract class FromTemp : Incoming() {
@@ -367,44 +364,44 @@ public suspend inline fun MessageSource.recall(): Unit = Mirai.recall(bot, this)
 // For MessageChain
 
 /**
- * 消息 id.
+ * 消息 ids.
  *
  * 仅从服务器接收的消息 (即来自 [MessageEvent.message]), 或手动添加了 [MessageSource] 元素的 [MessageChain] 才可以获取消息源.
  *
- * @see MessageSource.id
+ * @see MessageSource.ids
  */
 @get:JvmSynthetic
-public val MessageChain.id: Int
-    get() = this.source.id
+public val MessageChain.ids: IntArray
+    get() = this.source.ids
 
 /**
- * 消息内部 id.
+ * 消息内部 ids.
  *
  * 仅从服务器接收的消息 (即来自 [MessageEvent.message]), 或手动添加了 [MessageSource] 元素的 [MessageChain] 才可以获取消息源.
  *
- * @see MessageSource.id
+ * @see MessageSource.ids
  */
 @get:JvmSynthetic
-public val MessageChain.internalId: Int
-    get() = this.source.internalId
+public val MessageChain.internalId: IntArray
+    get() = this.source.internalIds
 
 /**
  * 消息时间.
  *
  * 仅从服务器接收的消息 (即来自 [MessageEvent.message]), 或手动添加了 [MessageSource] 元素的 [MessageChain] 才可以获取消息源.
  *
- * @see MessageSource.id
+ * @see MessageSource.ids
  */
 @get:JvmSynthetic
 public val MessageChain.time: Int
     get() = this.source.time
 
 /**
- * 消息内部 id.
+ * 消息内部 ids.
  *
  * 仅从服务器接收的消息 (即来自 [MessageEvent.message]), 或手动添加了 [MessageSource] 元素的 [MessageChain] 才可以获取. 否则将抛出异常 [NoSuchElementException]
  *
- * @see MessageSource.id
+ * @see MessageSource.ids
  */
 @get:JvmSynthetic
 public val MessageChain.bot: Bot
@@ -414,11 +411,24 @@ public val MessageChain.bot: Bot
  * 获取这条消息的 [消息源][MessageSource].
  *
  * 仅从服务器接收的消息 (即来自 [MessageEvent.message]), 或手动添加了 [MessageSource] 元素的 [MessageChain] 才可以获取消息源, 否则将抛出异常 [NoSuchElementException]
+ *
+ * @see sourceOrNull
  */
 @get:JvmSynthetic
 public val MessageChain.source: MessageSource
     get() = this.getOrFail(MessageSource)
 
+/**
+ * 获取这条消息的 [消息源][MessageSource].
+ *
+ * 仅从服务器接收的消息 (即来自 [MessageEvent.message]), 或手动添加了 [MessageSource] 元素的 [MessageChain] 才可以获取消息源, 否则返回 `null`
+ *
+ * @see source
+ */
+@get:JvmSynthetic
+public val MessageChain.sourceOrNull: MessageSource?
+    get() = this[MessageSource]
+
 /**
  * 撤回这条消息. 可撤回自己 2 分钟内发出的消息, 和任意时间的群成员的消息.
  *

+ 25 - 25
mirai-core-api/src/commonMain/kotlin/message/data/MessageSourceBuilder.kt

@@ -52,16 +52,16 @@ public interface MessageSourceAmender {
     public var kind: OfflineMessageSource.Kind
     public var fromUin: Long
     public var targetUin: Long
-    public var id: Int
+    public var ids: IntArray
     public var time: Int
-    public var internalId: Int
+    public var internalIds: IntArray
 
     public var originalMessage: MessageChain
 
-    /** 从另一个 [MessageSource] 中复制 [id], [internalId], [time]*/
+    /** 从另一个 [MessageSource] 中复制 [ids], [internalIds], [time]*/
     public fun metadataFrom(another: MessageSource) {
-        this.id = another.id
-        this.internalId = another.internalId
+        this.ids = another.ids
+        this.internalIds = another.internalIds
         this.time = another.time
     }
 }
@@ -78,9 +78,9 @@ public interface MessageSourceAmender {
  * ### 参数
  * 一个 [OfflineMessageSource] 须要以下参数:
  * - 发送人和发送目标: 通过 [MessageSourceBuilder.sendTo] 设置
- * - 消息元数据 (即 [MessageSource.id], [MessageSource.internalId], [MessageSource.time])
+ * - 消息元数据 (即 [MessageSource.ids], [MessageSource.internalIds], [MessageSource.time])
  *   元数据用于 [撤回][MessageSource.recall], [引用回复][MessageSource.quote], 和官方客户端定位原消息.
- *   可通过 [MessageSourceBuilder.id], [MessageSourceBuilder.time], [MessageSourceBuilder.internalId] 设置
+ *   可通过 [MessageSourceBuilder.ids], [MessageSourceBuilder.time], [MessageSourceBuilder.internalIds] 设置
  *   可通过 [MessageSourceBuilder.metadata] 从另一个 [MessageSource] 复制
  * - 消息内容: 通过 [MessageSourceBuilder.messages] 设置
  *
@@ -92,7 +92,7 @@ public interface MessageSourceAmender {
  * ```
  * bot.buildMessageSource {
  *     bot sendTo target // 指定发送人和发送目标
- *     metadata(source) // 从另一个消息源复制 id, internalId, time
+ *     metadata(source) // 从另一个消息源复制 ids, internalIds, time
  *
  *     messages { // 指定消息内容
  *         +"hi"
@@ -109,9 +109,9 @@ public fun Bot.buildMessageSource(block: MessageSourceBuilder.() -> Unit): Messa
         builder.kind ?: error("You must call `Contact.sendTo(Contact)` when `buildMessageSource`"),
         builder.fromUin,
         builder.targetUin,
-        builder.id,
+        builder.ids,
         builder.time,
-        builder.internalId,
+        builder.internalIds,
         builder.originalMessages.build()
     )
 }
@@ -124,9 +124,9 @@ public abstract class MessageSourceBuilder {
     internal abstract var fromUin: Long
     internal abstract var targetUin: Long
 
-    internal abstract var id: Int
+    internal abstract var ids: IntArray
     internal abstract var time: Int
-    internal abstract var internalId: Int
+    internal abstract var internalIds: IntArray
 
     @PublishedApi
     internal val originalMessages: MessageChainBuilder = MessageChainBuilder()
@@ -135,15 +135,15 @@ public abstract class MessageSourceBuilder {
     public val now: Int get() = currentTimeSeconds.toInt()
     public fun time(value: Int): MessageSourceBuilder = apply { this.time = value }
 
-    public fun internalId(from: MessageSource): MessageSourceBuilder = apply { this.internalId = from.internalId }
-    public fun internalId(value: Int): MessageSourceBuilder = apply { this.internalId = value }
+    public fun internalId(from: MessageSource): MessageSourceBuilder = apply { this.internalIds = from.internalIds }
+    public fun internalId(vararg value: Int): MessageSourceBuilder = apply { this.internalIds = value }
 
-    public fun id(from: MessageSource): MessageSourceBuilder = apply { this.id = from.id }
-    public fun id(value: Int): MessageSourceBuilder = apply { this.id = value }
+    public fun id(from: MessageSource): MessageSourceBuilder = apply { this.ids = from.ids }
+    public fun id(vararg value: Int): MessageSourceBuilder = apply { this.ids = value }
 
 
     /**
-     * 从另一个 [MessageSource] 复制 [id], [time], [internalId].
+     * 从另一个 [MessageSource] 复制 [ids], [time], [internalIds].
      * 这三个数据决定官方客户端能 "定位" 到的原消息
      */
     public fun metadata(from: MessageSource): MessageSourceBuilder = apply {
@@ -157,11 +157,11 @@ public abstract class MessageSourceBuilder {
      */
     public fun allFrom(source: MessageSource): MessageSourceBuilder {
         this.kind = determineKind(source)
-        this.id = source.id
+        this.ids = source.ids
         this.time = source.time
         this.fromUin = source.fromId
         this.targetUin = source.targetId
-        this.internalId = source.internalId
+        this.internalIds = source.internalIds
         this.originalMessages.addAll(source.originalMessage)
         return this
     }
@@ -212,9 +212,9 @@ internal class MessageSourceBuilderImpl : MessageSourceBuilder() {
     override var fromUin: Long = 0
     override var targetUin: Long = 0
 
-    override var id: Int = 0
+    override var ids: IntArray = intArrayOf()
     override var time: Int = currentTimeSeconds.toInt()
-    override var internalId: Int = 0
+    override var internalIds: IntArray = intArrayOf()
 
     @JvmSynthetic
     override fun ContactOrBot.sendTo(target: ContactOrBot): MessageSourceBuilder {
@@ -259,8 +259,8 @@ internal class MutableOfflineMessageSourceByOnline(
             targetId = value
         }
     override var bot: Bot = origin.bot
-    override var id: Int = origin.id
-    override var internalId: Int = origin.internalId
+    override var ids: IntArray = origin.ids
+    override var internalIds: IntArray = origin.internalIds
     override var time: Int = origin.time
     override var fromId: Long = origin.fromId
     override var targetId: Long = origin.targetId
@@ -287,8 +287,8 @@ internal class OfflineMessageSourceByOnline(
             else -> error("stub")
         }
     override val bot: Bot get() = onlineMessageSource.bot
-    override val id: Int get() = onlineMessageSource.id
-    override val internalId: Int get() = onlineMessageSource.internalId
+    override val ids: IntArray get() = onlineMessageSource.ids
+    override val internalIds: IntArray get() = onlineMessageSource.internalIds
     override val time: Int get() = onlineMessageSource.time
     override val fromId: Long get() = onlineMessageSource.fromId
     override val targetId: Long get() = onlineMessageSource.targetId

+ 3 - 5
mirai-core-api/src/commonMain/kotlin/message/data/QuoteReply.kt

@@ -14,9 +14,6 @@
 package net.mamoe.mirai.message.data
 
 import net.mamoe.mirai.Bot
-import kotlin.jvm.JvmMultifileClass
-import kotlin.jvm.JvmName
-import kotlin.jvm.JvmSynthetic
 
 
 /**
@@ -35,7 +32,7 @@ import kotlin.jvm.JvmSynthetic
  * 引用回复的原消息内容完全由 [source] 中 [MessageSource.originalMessage] 控制, 客户端不会自行寻找原消息.
  *
  * #### 客户端内跳转
- * 客户端在跳转原消息时, 会通过 [MessageSource.id] 等 metadata
+ * 客户端在跳转原消息时, 会通过 [MessageSource.ids] 等 metadata
  *
  * @see MessageSource 获取有关消息源的更多信息
  */
@@ -47,7 +44,8 @@ public class QuoteReply(public val source: MessageSource) : Message, MessageMeta
 
     public override val key: Message.Key<QuoteReply> get() = Key
 
-    public override fun toString(): String = "[mirai:quote:${source.id},${source.internalId}]"
+    // TODO: 2020/12/2 QuoteReply.toString
+    public override fun toString(): String = "[mirai:quote:${source.ids},${source.internalIds}]"
     public override fun equals(other: Any?): Boolean = other is QuoteReply && other.source == this.source
     public override fun hashCode(): Int = source.hashCode()
 }

+ 24 - 0
mirai-core-utils/src/commonMain/kotlin/Arrays.kt

@@ -7,7 +7,31 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
+@file:JvmMultifileClass
 @file:JvmName("MiraiUtils")
 
 package net.mamoe.mirai.utils
 
+public inline fun <A, reified B> Array<A>.mapToArray(block: (element: A) -> B): Array<B> {
+    val result = arrayOfNulls<B>(size)
+    this.forEachIndexed { index, element ->
+        result[index] = block(element)
+    }
+    return result.cast()
+}
+
+public inline fun <A, reified B> Collection<A>.mapToArray(block: (element: A) -> B): Array<B> {
+    val result = arrayOfNulls<B>(size)
+    this.forEachIndexed { index, element ->
+        result[index] = block(element)
+    }
+    return result.cast()
+}
+
+public inline fun <A> Collection<A>.mapToIntArray(block: (element: A) -> Int): IntArray {
+    val result = IntArray(size)
+    this.forEachIndexed { index, element ->
+        result[index] = block(element)
+    }
+    return result.cast()
+}

+ 15 - 0
mirai-core-utils/src/commonMain/kotlin/Numbers.kt

@@ -0,0 +1,15 @@
+/*
+ * 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:JvmMultifileClass
+@file:JvmName("MiraiUtils")
+
+package net.mamoe.mirai.utils
+
+public fun Int.toLongUnsigned(): Long = this.toLong().and(0xFFFF_FFFF)

+ 4 - 3
mirai-core-utils/src/commonMain/kotlin/StandardUtils.kt

@@ -7,12 +7,13 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
+@file:JvmMultifileClass
 @file:JvmName("MiraiUtils")
 
 package net.mamoe.mirai.utils
 
-inline fun <reified T> Any?.cast(): T = this as T
+public inline fun <reified T> Any?.cast(): T = this as T
 
-inline fun <reified T> Any?.safeCast(): T? = this as? T
+public inline fun <reified T> Any?.safeCast(): T? = this as? T
 
-inline fun <reified T> Any?.castOrNull(): T? = this as? T
+public inline fun <reified T> Any?.castOrNull(): T? = this as? T

+ 21 - 21
mirai-core/src/commonMain/kotlin/MiraiImpl.kt

@@ -280,8 +280,8 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
                 MessageRecallEvent.GroupRecall(
                     bot,
                     source.fromId,
-                    source.id,
-                    source.internalId,
+                    source.ids,
+                    source.internalIds,
                     source.time,
                     null,
                     group
@@ -291,8 +291,8 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
                     PbMessageSvc.PbMsgWithDraw.createForGroupMessage(
                         bot.asQQAndroidBot().client,
                         group.id,
-                        source.sequenceId,
-                        source.internalId
+                        source.sequenceIds,
+                        source.internalIds
                     ).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
                 }
             }
@@ -305,8 +305,8 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
                 PbMessageSvc.PbMsgWithDraw.createForFriendMessage(
                     bot.client,
                     source.targetId,
-                    source.sequenceId,
-                    source.internalId,
+                    source.sequenceIds,
+                    source.internalIds,
                     source.time
                 ).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
             }
@@ -321,8 +321,8 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
                     bot.client,
                     (source.target.group as GroupImpl).uin,
                     source.targetId,
-                    source.sequenceId,
-                    source.internalId,
+                    source.sequenceIds,
+                    source.internalIds,
                     source.time
                 ).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
             }
@@ -335,8 +335,8 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
                         PbMessageSvc.PbMsgWithDraw.createForFriendMessage(
                             bot.client,
                             source.targetId,
-                            source.sequenceId,
-                            source.internalId,
+                            source.sequenceIds,
+                            source.internalIds,
                             source.time
                         ).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
                     }
@@ -348,8 +348,8 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
                             bot.client,
                             source.targetId, // groupUin
                             source.targetId, // memberUin
-                            source.sequenceId,
-                            source.internalId,
+                            source.sequenceIds,
+                            source.internalIds,
                             source.time
                         ).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
                     }
@@ -357,8 +357,8 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
                         PbMessageSvc.PbMsgWithDraw.createForGroupMessage(
                             bot.client,
                             source.targetId,
-                            source.sequenceId,
-                            source.internalId
+                            source.sequenceIds,
+                            source.internalIds
                         ).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
                     }
                 }
@@ -370,7 +370,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
         // 1001: No message meets the requirements (实际上是没权限, 管理员在尝试撤回群主的消息)
         // 154: timeout
         // 3: <no message>
-        check(response is PbMessageSvc.PbMsgWithDraw.Response.Success) { "Failed to recall message #${source.id}: $response" }
+        check(response is PbMessageSvc.PbMsgWithDraw.Response.Success) { "Failed to recall message #${source.ids}: $response" }
     }
 
     @LowLevelApi
@@ -813,28 +813,28 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
         kind: OfflineMessageSource.Kind,
         fromUin: Long,
         targetUin: Long,
-        id: Int,
+        ids: IntArray,
         time: Int,
-        internalId: Int,
+        internalIds: IntArray,
         originalMessage: MessageChain
     ): OfflineMessageSource {
         return object : OfflineMessageSource(), MessageSourceInternal {
             override val kind: Kind get() = kind
-            override val id: Int get() = id
+            override val ids: IntArray get() = ids
             override val bot: Bot get() = bot
             override val time: Int get() = time
             override val fromId: Long get() = fromUin
             override val targetId: Long get() = targetUin
             override val originalMessage: MessageChain get() = originalMessage
-            override val sequenceId: Int = id
-            override val internalId: Int = internalId
+            override val sequenceIds: IntArray = ids
+            override val internalIds: IntArray = internalIds
 
             @Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
             override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
 
             override fun toJceData(): ImMsgBody.SourceMsg {
                 return ImMsgBody.SourceMsg(
-                    origSeqs = listOf(sequenceId),
+                    origSeqs = sequenceIds,
                     senderUin = fromUin,
                     toUin = 0,
                     flag = 1,

+ 19 - 19
mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt

@@ -29,11 +29,11 @@ import net.mamoe.mirai.message.data.OnlineMessageSource
 import java.util.concurrent.atomic.AtomicBoolean
 
 internal interface MessageSourceInternal {
-    val sequenceId: Int
-    val internalId: Int // randomId
+    val sequenceIds: IntArray
+    val internalIds: IntArray // randomId
 
     @Deprecated("don't use this internally. Use sequenceId or random instead.", level = DeprecationLevel.ERROR)
-    val id: Int
+    val ids: IntArray
 
     val isRecalledOrPlanned: AtomicBoolean
 
@@ -66,25 +66,25 @@ internal class MessageSourceFromFriendImpl(
     override val bot: Bot,
     val msg: MsgComm.Msg
 ) : OnlineMessageSource.Incoming.FromFriend(), MessageSourceInternal {
-    override val sequenceId: Int get() = msg.msgHead.msgSeq
+    override val sequenceIds: IntArray get() = intArrayOf(msg.msgHead.msgSeq)
     override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
-    override val id: Int get() = sequenceId// msg.msgBody.richText.attr!!.random
-    override val internalId: Int get() = msg.msgBody.richText.attr!!.random
+    override val ids: IntArray get() = sequenceIds// msg.msgBody.richText.attr!!.random
+    override val internalIds: IntArray get() = intArrayOf(msg.msgBody.richText.attr!!.random)
     override val time: Int get() = msg.msgHead.msgTime
     override val originalMessage: MessageChain by lazy { msg.toMessageChain(bot, 0, false) }
     override val sender: Friend get() = bot.getFriend(msg.msgHead.fromUin)
 
-    private val jceData by lazy { msg.toJceDataFriendOrTemp(internalId) }
+    private val jceData by lazy { msg.toJceDataFriendOrTemp(internalIds) }
 
     override fun toJceData(): ImMsgBody.SourceMsg = jceData
 }
 
-private fun MsgComm.Msg.toJceDataFriendOrTemp(id: Int): ImMsgBody.SourceMsg {
+private fun MsgComm.Msg.toJceDataFriendOrTemp(ids: IntArray): ImMsgBody.SourceMsg {
     val elements = msgBody.richText.elems.toMutableList().also {
         if (it.last().elemFlags2 == null) it.add(ImMsgBody.Elem(elemFlags2 = ImMsgBody.ElemFlags2()))
     }
     return ImMsgBody.SourceMsg(
-        origSeqs = listOf(this.msgHead.msgSeq),
+        origSeqs = intArrayOf(this.msgHead.msgSeq),
         senderUin = this.msgHead.fromUin,
         toUin = this.msgHead.toUin,
         flag = 1,
@@ -92,7 +92,7 @@ private fun MsgComm.Msg.toJceDataFriendOrTemp(id: Int): ImMsgBody.SourceMsg {
         type = 0,
         time = this.msgHead.msgTime,
         pbReserve = SourceMsg.ResvAttr(
-            origUids = id.toLong() and 0xFFFF_FFFF
+            origUids = ids.map { it.toLong() and 0xFFFF_FFFF }
         ).toByteArray(SourceMsg.ResvAttr.serializer()),
         srcMsg = MsgComm.Msg(
             msgHead = MsgComm.MsgHead(
@@ -102,7 +102,7 @@ private fun MsgComm.Msg.toJceDataFriendOrTemp(id: Int): ImMsgBody.SourceMsg {
                 c2cCmd = this.msgHead.c2cCmd,
                 msgSeq = this.msgHead.msgSeq,
                 msgTime = this.msgHead.msgTime,
-                msgUid = id.toLong() and 0xFFFF_FFFF, // ok
+                msgUid = ids.single().toLong() and 0xFFFF_FFFF, // ok
                 // groupInfo = MsgComm.GroupInfo(groupCode = this.msgHead.groupInfo.groupCode),
                 isSrcMsg = true
             ),
@@ -119,15 +119,15 @@ internal class MessageSourceFromTempImpl(
     override val bot: Bot,
     private val msg: MsgComm.Msg
 ) : OnlineMessageSource.Incoming.FromTemp(), MessageSourceInternal {
-    override val sequenceId: Int get() = msg.msgHead.msgSeq
-    override val internalId: Int get() = msg.msgBody.richText.attr!!.random
+    override val sequenceIds: IntArray get() = intArrayOf(msg.msgHead.msgSeq)
+    override val internalIds: IntArray get() = intArrayOf(msg.msgBody.richText.attr!!.random)
     override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
-    override val id: Int get() = sequenceId//
+    override val ids: IntArray get() = sequenceIds//
     override val time: Int get() = msg.msgHead.msgTime
     override val originalMessage: MessageChain by lazy { msg.toMessageChain(bot, 0, false) }
     override val sender: Member get() = with(msg.msgHead) { bot.getGroup(c2cTmpMsgHead!!.groupUin)[fromUin] }
 
-    private val jceData by lazy { msg.toJceDataFriendOrTemp(internalId) }
+    private val jceData by lazy { msg.toJceDataFriendOrTemp(internalIds) }
     override fun toJceData(): ImMsgBody.SourceMsg = jceData
 }
 
@@ -136,9 +136,9 @@ internal data class MessageSourceFromGroupImpl(
     private val msg: MsgComm.Msg
 ) : OnlineMessageSource.Incoming.FromGroup(), MessageSourceInternal {
     override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
-    override val sequenceId: Int get() = msg.msgHead.msgSeq
-    override val internalId: Int get() = msg.msgBody.richText.attr!!.random
-    override val id: Int get() = sequenceId
+    override val sequenceIds: IntArray get() = intArrayOf(msg.msgHead.msgSeq)
+    override val internalIds: IntArray get() = intArrayOf(msg.msgBody.richText.attr!!.random)
+    override val ids: IntArray get() = sequenceIds
     override val time: Int get() = msg.msgHead.msgTime
     override val originalMessage: MessageChain by lazy {
         msg.toMessageChain(bot, groupIdOrZero = group.id, onlineSource = false)
@@ -159,7 +159,7 @@ internal data class MessageSourceFromGroupImpl(
 
     override fun toJceData(): ImMsgBody.SourceMsg {
         return ImMsgBody.SourceMsg(
-            origSeqs = listOf(msg.msgHead.msgSeq),
+            origSeqs = intArrayOf(msg.msgHead.msgSeq),
             senderUin = msg.msgHead.fromUin,
             toUin = 0,
             flag = 1,

+ 12 - 13
mirai-core/src/commonMain/kotlin/message/offlineSourceImpl.kt

@@ -19,6 +19,7 @@ import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY
 import net.mamoe.mirai.internal.utils.io.serialization.loadAs
 import net.mamoe.mirai.message.data.MessageChain
 import net.mamoe.mirai.message.data.OfflineMessageSource
+import net.mamoe.mirai.utils.mapToIntArray
 import java.util.concurrent.atomic.AtomicBoolean
 
 
@@ -28,9 +29,8 @@ internal class OfflineMessageSourceImplByMsg(
     override val bot: Bot
 ) : OfflineMessageSource(), MessageSourceInternal {
     override val kind: Kind = if (delegate.msgHead.groupInfo != null) Kind.GROUP else Kind.FRIEND
-    override val id: Int get() = sequenceId
-    override val internalId: Int
-        get() = delegate.msgHead.msgUid.toInt()
+    override val ids: IntArray get() = sequenceIds
+    override val internalIds: IntArray = intArrayOf(delegate.msgHead.msgUid.toInt())
     override val time: Int
         get() = delegate.msgHead.msgTime
     override val fromId: Long
@@ -38,20 +38,20 @@ internal class OfflineMessageSourceImplByMsg(
     override val targetId: Long
         get() = delegate.msgHead.groupInfo?.groupCode ?: delegate.msgHead.toUin
     override val originalMessage: MessageChain by lazy {
-        delegate.toMessageChain(bot,
+        delegate.toMessageChain(
+            bot,
             groupIdOrZero = delegate.msgHead.groupInfo?.groupCode ?: 0,
             onlineSource = false,
             isTemp = delegate.msgHead.c2cTmpMsgHead != null
         )
     }
-    override val sequenceId: Int
-        get() = delegate.msgHead.msgSeq
+    override val sequenceIds: IntArray = intArrayOf(delegate.msgHead.msgSeq)
 
     override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
 
     override fun toJceData(): ImMsgBody.SourceMsg {
         return ImMsgBody.SourceMsg(
-            origSeqs = listOf(delegate.msgHead.msgSeq),
+            origSeqs = intArrayOf(delegate.msgHead.msgSeq),
             senderUin = delegate.msgHead.fromUin,
             toUin = 0,
             flag = 1,
@@ -73,20 +73,19 @@ internal class OfflineMessageSourceImplBySourceMsg(
     override val kind: Kind get() = if (delegate.srcMsg == null) Kind.GROUP else Kind.FRIEND
 
     override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
-    override val sequenceId: Int
-        get() = delegate.origSeqs.firstOrNull() ?: error("cannot find sequenceId")
-    override val internalId: Int
-        get() = delegate.pbReserve.loadAs(SourceMsg.ResvAttr.serializer()).origUids?.toInt() ?: 0
+    override val sequenceIds: IntArray = delegate.origSeqs
+    override val internalIds: IntArray = delegate.pbReserve.loadAs(SourceMsg.ResvAttr.serializer())
+        .origUids?.mapToIntArray { it.toInt() } ?: intArrayOf()
     override val time: Int get() = delegate.time
     override val originalMessage: MessageChain by lazy { delegate.toMessageChain(bot, groupIdOrZero) }
     /*
-    override val id: Long
+    override val ids: Long
         get() = (delegate.origSeqs?.firstOrNull()
             ?: error("cannot find sequenceId from ImMsgBody.SourceMsg")).toLong().shl(32) or
                 delegate.pbReserve.loadAs(SourceMsg.ResvAttr.serializer()).origUids!!.and(0xFFFFFFFF)
     */
 
-    override val id: Int get() = sequenceId
+    override val ids: IntArray get() = sequenceIds
     // delegate.pbReserve.loadAs(SourceMsg.ResvAttr.serializer()).origUids?.toInt()
     // ?: 0
 

+ 35 - 29
mirai-core/src/commonMain/kotlin/message/outgoingSourceImpl.kt

@@ -24,6 +24,7 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
 import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
 import net.mamoe.mirai.internal.network.protocol.data.proto.SourceMsg
 import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.OnlinePushPbPushGroupMsg.SendGroupMessageReceipt
+import net.mamoe.mirai.internal.network.protocol.packet.chat.toLongUnsigned
 import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
 import net.mamoe.mirai.message.data.MessageChain
 import net.mamoe.mirai.message.data.MessageSource
@@ -35,27 +36,30 @@ private fun <T> T.toJceDataImpl(): ImMsgBody.SourceMsg
         where T : MessageSourceInternal, T : MessageSource {
 
     val elements = originalMessage.toRichTextElems(forGroup = false, withGeneralFlags = true)
-    val messageUid: Long = sequenceId.toLong().shl(32) or internalId.toLong().and(0xffFFffFF)
+
+    val pdReserve = SourceMsg.ResvAttr(
+        origUids = sequenceIds.zip(internalIds)
+            .map { (seq, internal) -> seq.toLong().shl(32) or internal.toLongUnsigned() }
+    )
+
     return ImMsgBody.SourceMsg(
-        origSeqs = listOf(sequenceId),
+        origSeqs = sequenceIds,
         senderUin = fromId,
         toUin = targetId,
         flag = 1,
         elems = elements,
         type = 0,
         time = time,
-        pbReserve = SourceMsg.ResvAttr(
-            origUids = messageUid
-        ).toByteArray(SourceMsg.ResvAttr.serializer()),
+        pbReserve = pdReserve.toByteArray(SourceMsg.ResvAttr.serializer()),
         srcMsg = MsgComm.Msg(
             msgHead = MsgComm.MsgHead(
                 fromUin = fromId, // qq
                 toUin = targetId, // group
                 msgType = 9, // 82?
                 c2cCmd = 11,
-                msgSeq = sequenceId,
+                msgSeq = sequenceIds.single(), // TODO !!
                 msgTime = time,
-                msgUid = messageUid, // ok
+                msgUid = pdReserve.origUids!!.single(), // TODO !!
                 // groupInfo = MsgComm.GroupInfo(groupCode = delegate.msgHead.groupInfo.groupCode),
                 isSrcMsg = true
             ),
@@ -71,8 +75,8 @@ private fun <T> T.toJceDataImpl(): ImMsgBody.SourceMsg
 }
 
 internal class MessageSourceToFriendImpl(
-    override val sequenceId: Int,
-    override val internalId: Int,
+    override val sequenceIds: IntArray,
+    override val internalIds: IntArray,
     override val time: Int,
     override val originalMessage: MessageChain,
     override val sender: Bot,
@@ -80,16 +84,16 @@ internal class MessageSourceToFriendImpl(
 ) : OnlineMessageSource.Outgoing.ToFriend(), MessageSourceInternal {
     override val bot: Bot
         get() = sender
-    override val id: Int
-        get() = sequenceId
+    override val ids: IntArray
+        get() = sequenceIds
     override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
     private val jceData by lazy { toJceDataImpl() }
     override fun toJceData(): ImMsgBody.SourceMsg = jceData
 }
 
 internal class MessageSourceToTempImpl(
-    override val sequenceId: Int,
-    override val internalId: Int,
+    override val sequenceIds: IntArray,
+    override val internalIds: IntArray,
     override val time: Int,
     override val originalMessage: MessageChain,
     override val sender: Bot,
@@ -97,8 +101,8 @@ internal class MessageSourceToTempImpl(
 ) : OnlineMessageSource.Outgoing.ToTemp(), MessageSourceInternal {
     override val bot: Bot
         get() = sender
-    override val id: Int
-        get() = sequenceId
+    override val ids: IntArray
+        get() = sequenceIds
     override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
     private val jceData by lazy { toJceDataImpl() }
     override fun toJceData(): ImMsgBody.SourceMsg = jceData
@@ -106,14 +110,14 @@ internal class MessageSourceToTempImpl(
 
 internal class MessageSourceToGroupImpl(
     coroutineScope: CoroutineScope,
-    override val internalId: Int,
+    override val internalIds: IntArray,
     override val time: Int,
     override val originalMessage: MessageChain,
     override val sender: Bot,
     override val target: Group
 ) : OnlineMessageSource.Outgoing.ToGroup(), MessageSourceInternal {
-    override val id: Int
-        get() = sequenceId
+    override val ids: IntArray
+        get() = sequenceIds
     override val bot: Bot
         get() = sender
     override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
@@ -122,25 +126,27 @@ internal class MessageSourceToGroupImpl(
         coroutineScope.asyncFromEventOrNull<SendGroupMessageReceipt, Int>(
             timeoutMillis = 3000
         ) {
-            if (it.messageRandom == [email protected]) {
+            if (it.messageRandom in [email protected]) {
                 it.sequenceId
             } else null
         }
 
     @OptIn(ExperimentalCoroutinesApi::class)
-    override val sequenceId: Int
-        get() = when {
-            sequenceIdDeferred.isCompleted -> sequenceIdDeferred.getCompleted() ?: -1
-            !sequenceIdDeferred.isActive -> -1
-            else -> error("sequenceId not yet available")
-        }
+    override val sequenceIds: IntArray
+        get() = intArrayOf(
+            when {
+                sequenceIdDeferred.isCompleted -> sequenceIdDeferred.getCompleted() ?: -1
+                !sequenceIdDeferred.isActive -> -1
+                else -> error("sequenceIds not yet available")
+            }
+        )
 
     suspend fun ensureSequenceIdAvailable() = kotlin.run { sequenceIdDeferred.await() }
 
     private val jceData by lazy {
         val elements = originalMessage.toRichTextElems(forGroup = false, withGeneralFlags = true)
         ImMsgBody.SourceMsg(
-            origSeqs = listOf(sequenceId),
+            origSeqs = sequenceIds,
             senderUin = fromId,
             toUin = Mirai.calculateGroupUinByGroupCode(targetId),
             flag = 1,
@@ -148,7 +154,7 @@ internal class MessageSourceToGroupImpl(
             type = 0,
             time = time,
             pbReserve = SourceMsg.ResvAttr(
-                origUids = internalId.toLong() and 0xffFFffFF // id is actually messageRandom
+                origUids = internalIds.map { it.toLongUnsigned() } // ids is actually messageRandom
             ).toByteArray(SourceMsg.ResvAttr.serializer()),
             srcMsg = MsgComm.Msg(
                 msgHead = MsgComm.MsgHead(
@@ -156,9 +162,9 @@ internal class MessageSourceToGroupImpl(
                     toUin = Mirai.calculateGroupUinByGroupCode(targetId), // group
                     msgType = 82, // 82?
                     c2cCmd = 1,
-                    msgSeq = sequenceId,
+                    msgSeq = sequenceIds.single(), // TODO !!
                     msgTime = time,
-                    msgUid = internalId.toLong() and 0xffFFffFF, // ok
+                    msgUid = internalIds.single().toLongUnsigned(), //  TODO !!
                     groupInfo = MsgComm.GroupInfo(groupCode = targetId),
                     isSrcMsg = true
                 ),

+ 1 - 2
mirai-core/src/commonMain/kotlin/network/protocol/data/proto/Msg.kt

@@ -16,7 +16,6 @@ import kotlinx.serialization.protobuf.ProtoType
 import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY
 import net.mamoe.mirai.internal.utils.io.ProtoBuf
 import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
-import kotlin.jvm.JvmField
 
 @Serializable
 internal class ImCommon : ProtoBuf {
@@ -879,7 +878,7 @@ internal class ImMsgBody : ProtoBuf {
 
     @Serializable
     internal class SourceMsg(
-        @ProtoNumber(1) @JvmField val origSeqs: List<Int> = emptyList(),
+        @ProtoNumber(1) @JvmField val origSeqs: IntArray = intArrayOf(),
         @ProtoNumber(2) @JvmField val senderUin: Long = 0L,
         @ProtoNumber(3) @JvmField val time: Int = 0,
         @ProtoNumber(4) @JvmField val flag: Int = 0,

+ 1 - 2
mirai-core/src/commonMain/kotlin/network/protocol/data/proto/PbReserve.kt

@@ -13,7 +13,6 @@ import kotlinx.serialization.Serializable
 import kotlinx.serialization.protobuf.ProtoNumber
 import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY
 import net.mamoe.mirai.internal.utils.io.ProtoBuf
-import kotlin.jvm.JvmField
 
 internal class Generalflags : ProtoBuf {
     @Serializable
@@ -117,7 +116,7 @@ internal class SourceMsg : ProtoBuf {
 internal class ResvAttr(
         @ProtoNumber(1) @JvmField val richMsg2: ByteArray? = null,
         @ProtoNumber(2) @JvmField val oriMsgtype: Int? = null,
-        @ProtoNumber(3) @JvmField val origUids: Long? = null // 原来是 list
+        @ProtoNumber(3) @JvmField val origUids: List<Long>? = null
     ) : ProtoBuf
 }
 

+ 81 - 69
mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/PbMessageSvc.kt

@@ -46,66 +46,74 @@ internal class PbMessageSvc {
         fun createForGroupMessage(
             client: QQAndroidClient,
             groupCode: Long,
-            messageSequenceId: Int, // 56639
-            messageRandom: Int, // 921878719
+            messageSequenceId: IntArray, // 56639
+            messageRandom: IntArray, // 921878719
             messageType: Int = 0
-        ): OutgoingPacket = buildOutgoingUniPacket(client) {
-            writeProtoBuf(
-                MsgSvc.PbMsgWithDrawReq.serializer(),
-                MsgSvc.PbMsgWithDrawReq(
-                    groupWithDraw = listOf(
-                        MsgSvc.PbGroupMsgWithDrawReq(
-                            subCmd = 1,
-                            groupType = 0, // 普通群
-                            groupCode = groupCode,
-                            msgList = listOf(
-                                MsgSvc.PbGroupMsgWithDrawReq.MessageInfo(
-                                    msgSeq = messageSequenceId,
-                                    msgRandom = messageRandom,
-                                    msgType = messageType
-                                )
-                            ),
-                            userdef = MsgRevokeUserDef.MsgInfoUserDef(
-                                longMessageFlag = 0
-                            ).toByteArray(MsgRevokeUserDef.MsgInfoUserDef.serializer())
+        ): OutgoingPacket {
+            require(messageSequenceId.size == messageRandom.size)
+
+            return buildOutgoingUniPacket(client) {
+                writeProtoBuf(
+                    MsgSvc.PbMsgWithDrawReq.serializer(),
+                    MsgSvc.PbMsgWithDrawReq(
+                        groupWithDraw = listOf(
+                            MsgSvc.PbGroupMsgWithDrawReq(
+                                subCmd = 1,
+                                groupType = 0, // 普通群
+                                groupCode = groupCode,
+                                msgList = messageSequenceId.zip(messageRandom).map { (seq, random) ->
+                                    MsgSvc.PbGroupMsgWithDrawReq.MessageInfo(
+                                        msgSeq = seq,
+                                        msgRandom = random,
+                                        msgType = messageType
+                                    )
+                                },
+                                userdef = MsgRevokeUserDef.MsgInfoUserDef(
+                                    longMessageFlag = 0
+                                ).toByteArray(MsgRevokeUserDef.MsgInfoUserDef.serializer())
+                            )
                         )
                     )
                 )
-            )
+            }
         }
 
         fun createForTempMessage(
             client: QQAndroidClient,
             groupUin: Long,
             toUin: Long,
-            messageSequenceId: Int, // 56639
-            messageRandom: Int, // 921878719
+            messageSequenceId: IntArray, // 56639
+            messageRandom: IntArray, // 921878719
             time: Int
-        ): OutgoingPacket = buildOutgoingUniPacket(client) {
-            writeProtoBuf(
-                MsgSvc.PbMsgWithDrawReq.serializer(),
-                MsgSvc.PbMsgWithDrawReq(
-                    c2cWithDraw = listOf(
-                        MsgSvc.PbC2CMsgWithDrawReq(
-                            subCmd = 1,
-                            msgInfo = listOf(
-                                MsgSvc.PbC2CMsgWithDrawReq.MsgInfo(
-                                    fromUin = client.bot.id,
-                                    toUin = toUin,
-                                    msgSeq = messageSequenceId,
-                                    msgRandom = messageRandom,
-                                    msgUid = 0x0100000000000000 or (messageRandom.toLong() and 0xFFFFFFFF),
-                                    msgTime = time.toLong(),
-                                    routingHead = MsgSvc.RoutingHead(
-                                        grpTmp = MsgSvc.GrpTmp(groupUin, toUin)
+        ): OutgoingPacket {
+            require(messageSequenceId.size == messageRandom.size)
+
+            return buildOutgoingUniPacket(client) {
+                writeProtoBuf(
+                    MsgSvc.PbMsgWithDrawReq.serializer(),
+                    MsgSvc.PbMsgWithDrawReq(
+                        c2cWithDraw = listOf(
+                            MsgSvc.PbC2CMsgWithDrawReq(
+                                subCmd = 1,
+                                msgInfo = messageSequenceId.zip(messageRandom).map { (seq, random) ->
+                                    MsgSvc.PbC2CMsgWithDrawReq.MsgInfo(
+                                        fromUin = client.bot.id,
+                                        toUin = toUin,
+                                        msgSeq = seq,
+                                        msgRandom = random,
+                                        msgUid = 0x0100000000000000 or random.toLongUnsigned(),
+                                        msgTime = time.toLong(),
+                                        routingHead = MsgSvc.RoutingHead(
+                                            grpTmp = MsgSvc.GrpTmp(groupUin, toUin)
+                                        )
                                     )
-                                )
-                            ),
-                            reserved = RESERVED_TEMP
+                                },
+                                reserved = RESERVED_TEMP
+                            )
                         )
                     )
                 )
-            )
+            }
         }
 
         private val RESERVED_TEMP = "08 01 10 E3 E9 D6 80 02".hexToBytes()
@@ -113,36 +121,40 @@ internal class PbMessageSvc {
         fun createForFriendMessage(
             client: QQAndroidClient,
             toUin: Long,
-            messageSequenceId: Int, // 56639
-            messageRandom: Int, // 921878719
+            messageSequenceId: IntArray, // 56639
+            messageRandom: IntArray, // 921878719
             time: Int
-        ): OutgoingPacket = buildOutgoingUniPacket(client) {
-            writeProtoBuf(
-                MsgSvc.PbMsgWithDrawReq.serializer(),
-                MsgSvc.PbMsgWithDrawReq(
-                    c2cWithDraw = listOf(
-                        MsgSvc.PbC2CMsgWithDrawReq(
-                            subCmd = 1,
-                            msgInfo = listOf(
-                                MsgSvc.PbC2CMsgWithDrawReq.MsgInfo(
-                                    fromUin = client.bot.id,
-                                    toUin = toUin,
-                                    msgSeq = messageSequenceId,
-                                    msgRandom = messageRandom,
-                                    msgUid = 0x0100000000000000 or (messageRandom.toLong() and 0xFFFFFFFF),
-                                    msgTime = time.toLong(),
-                                    routingHead = MsgSvc.RoutingHead(
-                                        c2c = MsgSvc.C2C(
-                                            toUin = toUin
+        ): OutgoingPacket {
+            require(messageSequenceId.size == messageRandom.size)
+
+            return buildOutgoingUniPacket(client) {
+                writeProtoBuf(
+                    MsgSvc.PbMsgWithDrawReq.serializer(),
+                    MsgSvc.PbMsgWithDrawReq(
+                        c2cWithDraw = listOf(
+                            MsgSvc.PbC2CMsgWithDrawReq(
+                                subCmd = 1,
+                                msgInfo = messageSequenceId.zip(messageRandom).map { (seq, random) ->
+                                    MsgSvc.PbC2CMsgWithDrawReq.MsgInfo(
+                                        fromUin = client.bot.id,
+                                        toUin = toUin,
+                                        msgSeq = seq,
+                                        msgRandom = random,
+                                        msgUid = 0x0100000000000000 or random.toLongUnsigned(),
+                                        msgTime = time.toLong(),
+                                        routingHead = MsgSvc.RoutingHead(
+                                            c2c = MsgSvc.C2C(
+                                                toUin = toUin
+                                            )
                                         )
                                     )
-                                )
-                            ),
-                            reserved = byteArrayOf(0x08, 0x00)
+                                },
+                                reserved = byteArrayOf(0x08, 0x00)
+                            )
                         )
                     )
                 )
-            )
+            }
         }
 
         override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {

+ 10 - 10
mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PbSendMsg.kt

@@ -78,8 +78,8 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
                         elems = message.toRichTextElems(forGroup = false, withGeneralFlags = true)
                     )
                 ),
-                msgSeq = source.sequenceId,
-                msgRand = source.internalId,
+                msgSeq = source.sequenceIds.single(),
+                msgRand = source.internalIds.single(),
                 syncCookie = client.syncingController.syncCookie ?: byteArrayOf()
                 // msgVia = 1
             )
@@ -108,8 +108,8 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
                         elems = message.toRichTextElems(forGroup = false, withGeneralFlags = true)
                     )
                 ),
-                msgSeq = source.sequenceId,
-                msgRand = source.internalId,
+                msgSeq = source.sequenceIds.single(),
+                msgRand = source.internalIds.single(),
                 syncCookie = client.syncingController.syncCookie ?: byteArrayOf()
             )
         )
@@ -152,7 +152,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
                     )
                 ),
                 msgSeq = client.atomicNextMessageSequenceId(),
-                msgRand = source.internalId,
+                msgRand = source.internalIds.single(),
                 syncCookie = EMPTY_BYTE_ARRAY,
                 msgVia = 1,
                 msgCtrl = if (isForward) MsgCtrl.MsgCtrl(
@@ -186,11 +186,11 @@ internal inline fun MessageSvcPbSendMsg.createToTemp(
         callsInPlace(sourceCallback, InvocationKind.EXACTLY_ONCE)
     }
     val source = MessageSourceToTempImpl(
-        internalId = Random.nextInt().absoluteValue,
+        internalIds = intArrayOf(Random.nextInt().absoluteValue),
         sender = client.bot,
         target = member,
         time = currentTimeSeconds.toInt(),
-        sequenceId = client.atomicNextMessageSequenceId(),
+        sequenceIds = intArrayOf(client.atomicNextMessageSequenceId()),
         originalMessage = message
     )
     sourceCallback(source)
@@ -214,11 +214,11 @@ internal inline fun MessageSvcPbSendMsg.createToFriend(
     }
     val rand = Random.nextInt().absoluteValue
     val source = MessageSourceToFriendImpl(
-        internalId = rand,
+        internalIds = intArrayOf(rand),
         sender = client.bot,
         target = qq,
         time = currentTimeSeconds.toInt(),
-        sequenceId = client.nextFriendSeq(),
+        sequenceIds = intArrayOf(client.nextFriendSeq()),
         originalMessage = message
     )
     sourceCallback(source)
@@ -242,7 +242,7 @@ internal inline fun MessageSvcPbSendMsg.createToGroup(
     }
     val source = MessageSourceToGroupImpl(
         group,
-        internalId = Random.nextInt().absoluteValue,
+        internalIds = intArrayOf(Random.nextInt().absoluteValue),
         sender = client.bot,
         target = group,
         time = currentTimeSeconds.toInt(),

+ 4 - 4
mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.ReqPush.kt

@@ -367,8 +367,8 @@ private object Transformers732 : Map<Int, Lambda732> by mapOf(
                     MessageRecallEvent.GroupRecall(
                         bot,
                         pkg.authorUin,
-                        pkg.seq,
-                        pkg.msgRandom,
+                        intArrayOf(pkg.seq),
+                        intArrayOf(pkg.msgRandom),
                         pkg.time,
                         operator,
                         group
@@ -440,8 +440,8 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
             .filter { it.botUin == bot.id }.map {
                 MessageRecallEvent.FriendRecall(
                     bot = bot,
-                    messageId = it.srcId,
-                    messageInternalId = it.srcInternalId,
+                    messageIds = intArrayOf(it.srcId),
+                    messageInternalIds = intArrayOf(it.srcInternalId),
                     messageTime = it.time,
                     operator = it.fromUin
                 )