From 64bd63d7a00e43f9db05cbeb368bae2467c69316 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 2 Dec 2020 10:46:06 +0800 Subject: [PATCH] Multiple MessageSource.id and MessageSource.internalId for split sources now, and split messages in the future. Close #618 --- .../src/commonMain/kotlin/IMirai.kt | 6 +- .../commonMain/kotlin/event/events/message.kt | 74 +++++++-- .../commonMain/kotlin/message/MessageEvent.kt | 2 +- .../kotlin/message/MessageReceipt.kt | 19 ++- .../kotlin/message/data/MessageSource.kt | 68 ++++---- .../message/data/MessageSourceBuilder.kt | 50 +++--- .../kotlin/message/data/QuoteReply.kt | 8 +- .../src/commonMain/kotlin/Arrays.kt | 24 +++ .../src/commonMain/kotlin/Numbers.kt | 15 ++ .../src/commonMain/kotlin/StandardUtils.kt | 7 +- mirai-core/src/commonMain/kotlin/MiraiImpl.kt | 42 ++--- .../kotlin/message/incomingSourceImpl.kt | 38 ++--- .../kotlin/message/offlineSourceImpl.kt | 25 ++- .../kotlin/message/outgoingSourceImpl.kt | 64 ++++---- .../kotlin/network/protocol/data/proto/Msg.kt | 3 +- .../network/protocol/data/proto/PbReserve.kt | 3 +- .../protocol/packet/chat/PbMessageSvc.kt | 150 ++++++++++-------- .../chat/receive/MessageSvc.PbSendMsg.kt | 20 +-- .../packet/chat/receive/OnlinePush.ReqPush.kt | 8 +- 19 files changed, 370 insertions(+), 256 deletions(-) create mode 100644 mirai-core-utils/src/commonMain/kotlin/Numbers.kt diff --git a/mirai-core-api/src/commonMain/kotlin/IMirai.kt b/mirai-core-api/src/commonMain/kotlin/IMirai.kt index d679adc27..9e060869f 100644 --- a/mirai-core-api/src/commonMain/kotlin/IMirai.kt +++ b/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 diff --git a/mirai-core-api/src/commonMain/kotlin/event/events/message.kt b/mirai-core-api/src/commonMain/kotlin/event/events/message.kt index 664adb1f7..599739169 100644 --- a/mirai-core-api/src/commonMain/kotlin/event/events/message.kt +++ b/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 diff --git a/mirai-core-api/src/commonMain/kotlin/message/MessageEvent.kt b/mirai-core-api/src/commonMain/kotlin/message/MessageEvent.kt index 1f4f16333..6b99a85ed 100644 --- a/mirai-core-api/src/commonMain/kotlin/message/MessageEvent.kt +++ b/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 diff --git a/mirai-core-api/src/commonMain/kotlin/message/MessageReceipt.kt b/mirai-core-api/src/commonMain/kotlin/message/MessageReceipt.kt index 41e2a3997..253535eed 100644 --- a/mirai-core-api/src/commonMain/kotlin/message/MessageReceipt.kt +++ b/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 @MiraiExperimentalApi("The constructor is subject to change.") constructor( @@ -95,23 +94,23 @@ public suspend inline fun MessageReceipt.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] 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 2d4e9ffe3..869b03382 100644 --- a/mirai-core-api/src/commonMain/kotlin/message/data/MessageSource.kt +++ b/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 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 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 955958318..b0f53694b 100644 --- a/mirai-core-api/src/commonMain/kotlin/message/data/QuoteReply.kt +++ b/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 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() } diff --git a/mirai-core-utils/src/commonMain/kotlin/Arrays.kt b/mirai-core-utils/src/commonMain/kotlin/Arrays.kt index e2ef8bc8c..4c1bb535e 100644 --- a/mirai-core-utils/src/commonMain/kotlin/Arrays.kt +++ b/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 Array.mapToArray(block: (element: A) -> B): Array { + val result = arrayOfNulls(size) + this.forEachIndexed { index, element -> + result[index] = block(element) + } + return result.cast() +} + +public inline fun Collection.mapToArray(block: (element: A) -> B): Array { + val result = arrayOfNulls(size) + this.forEachIndexed { index, element -> + result[index] = block(element) + } + return result.cast() +} + +public inline fun Collection.mapToIntArray(block: (element: A) -> Int): IntArray { + val result = IntArray(size) + this.forEachIndexed { index, element -> + result[index] = block(element) + } + return result.cast() +} \ No newline at end of file diff --git a/mirai-core-utils/src/commonMain/kotlin/Numbers.kt b/mirai-core-utils/src/commonMain/kotlin/Numbers.kt new file mode 100644 index 000000000..e0ecaf564 --- /dev/null +++ b/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) \ No newline at end of file diff --git a/mirai-core-utils/src/commonMain/kotlin/StandardUtils.kt b/mirai-core-utils/src/commonMain/kotlin/StandardUtils.kt index ef821d254..b77df67e8 100644 --- a/mirai-core-utils/src/commonMain/kotlin/StandardUtils.kt +++ b/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 Any?.cast(): T = this as T +public inline fun Any?.cast(): T = this as T -inline fun Any?.safeCast(): T? = this as? T +public inline fun Any?.safeCast(): T? = this as? T -inline fun Any?.castOrNull(): T? = this as? T +public inline fun Any?.castOrNull(): T? = this as? T diff --git a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt index e4353e1d8..40dcb694d 100644 --- a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt +++ b/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() } } @@ -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() } @@ -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() } @@ -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() } @@ -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() } @@ -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() } } @@ -370,7 +370,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor { // 1001: No message meets the requirements (实际上是没权限, 管理员在尝试撤回群主的消息) // 154: timeout // 3: - 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, diff --git a/mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt b/mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt index f8c6ac436..73e790b6d 100644 --- a/mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt +++ b/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, diff --git a/mirai-core/src/commonMain/kotlin/message/offlineSourceImpl.kt b/mirai-core/src/commonMain/kotlin/message/offlineSourceImpl.kt index 9b2d3b41c..23688e653 100644 --- a/mirai-core/src/commonMain/kotlin/message/offlineSourceImpl.kt +++ b/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 diff --git a/mirai-core/src/commonMain/kotlin/message/outgoingSourceImpl.kt b/mirai-core/src/commonMain/kotlin/message/outgoingSourceImpl.kt index bf539ed78..2fe4e7870 100644 --- a/mirai-core/src/commonMain/kotlin/message/outgoingSourceImpl.kt +++ b/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.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.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( timeoutMillis = 3000 ) { - if (it.messageRandom == this@MessageSourceToGroupImpl.internalId) { + if (it.messageRandom in this@MessageSourceToGroupImpl.internalIds) { 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 ), diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/Msg.kt b/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/Msg.kt index 671e7187b..2e2c19df5 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/Msg.kt +++ b/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 = 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, diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/PbReserve.kt b/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/PbReserve.kt index 5ad724cc4..bdb62d5fb 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/data/proto/PbReserve.kt +++ b/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? = null ) : ProtoBuf } diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/PbMessageSvc.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/PbMessageSvc.kt index c5f0f4b5b..84ffad91a 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/PbMessageSvc.kt +++ b/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 { diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PbSendMsg.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PbSendMsg.kt index 9b9eb450c..e31bcb9a9 100644 --- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PbSendMsg.kt +++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/MessageSvc.PbSendMsg.kt @@ -78,8 +78,8 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory 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 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 )