mirror of
https://github.com/mamoe/mirai.git
synced 2024-12-29 10:00:13 +08:00
Add GroupInfo
This commit is contained in:
parent
95f4f9d45a
commit
d171073dc5
@ -1,7 +1,7 @@
|
||||
# style guide
|
||||
kotlin.code.style=official
|
||||
# config
|
||||
mirai_version=0.1.7
|
||||
mirai_version=0.2.0
|
||||
kotlin.incremental.multiplatform=true
|
||||
kotlin.parallel.tasks.in.project=true
|
||||
# kotlin
|
||||
|
@ -59,9 +59,13 @@ inline fun <R> Contact.withSession(block: BotSession.() -> R): R {
|
||||
/**
|
||||
* 只读联系人列表
|
||||
*/
|
||||
class ContactList<C : Contact> internal constructor(private val delegate: MutableContactList<C>) : Map<UInt, C> by delegate
|
||||
class ContactList<C : Contact> internal constructor(private val delegate: MutableContactList<C>) : Map<UInt, C> by delegate {
|
||||
override fun toString(): String = delegate.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* 可修改联系人列表. 只会在内部使用.
|
||||
*/
|
||||
internal class MutableContactList<C : Contact> : MutableMap<UInt, C> by mutableMapOf()
|
||||
internal class MutableContactList<C : Contact> : MutableMap<UInt, C> by mutableMapOf() {
|
||||
override fun toString(): String = asIterable().joinToString(separator = ", ", prefix = "ContactList(", postfix = ")") { it.value.toString() }
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
|
||||
package net.mamoe.mirai.contact
|
||||
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.action.GroupInfo
|
||||
import net.mamoe.mirai.utils.internal.PositiveNumbers
|
||||
import net.mamoe.mirai.utils.internal.coerceAtLeastOrFail
|
||||
|
||||
@ -20,6 +21,11 @@ interface Group : Contact {
|
||||
val member: ContactList<Member>
|
||||
|
||||
suspend fun getMember(id: UInt): Member
|
||||
|
||||
/**
|
||||
* 查询群资料
|
||||
*/
|
||||
suspend fun queryGroupInfo(): GroupInfo
|
||||
}
|
||||
|
||||
/**
|
||||
@ -36,7 +42,8 @@ inline class GroupId(inline val value: UInt)
|
||||
/**
|
||||
* 将 [this] 转为 [GroupId].
|
||||
*/
|
||||
fun UInt.groupId(): GroupId = GroupId(this)
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun UInt.groupId(): GroupId = GroupId(this)
|
||||
|
||||
/**
|
||||
* 将无符号整数格式的 [Long] 转为 [GroupId].
|
||||
|
@ -10,6 +10,11 @@ interface Member : QQ, Contact {
|
||||
* 所在的群
|
||||
*/
|
||||
val group: Group
|
||||
|
||||
/**
|
||||
* 权限
|
||||
*/
|
||||
val permission: MemberPermission
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5,8 +5,7 @@ package net.mamoe.mirai.contact.internal
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import net.mamoe.mirai.*
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.contact.data.Profile
|
||||
import net.mamoe.mirai.message.Message
|
||||
@ -14,8 +13,12 @@ import net.mamoe.mirai.message.MessageChain
|
||||
import net.mamoe.mirai.message.chain
|
||||
import net.mamoe.mirai.message.singleChain
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.action.*
|
||||
import net.mamoe.mirai.network.qqAccount
|
||||
import net.mamoe.mirai.network.sessionKey
|
||||
import net.mamoe.mirai.qqAccount
|
||||
import net.mamoe.mirai.sendPacket
|
||||
import net.mamoe.mirai.utils.SuspendLazy
|
||||
import net.mamoe.mirai.withSession
|
||||
|
||||
internal sealed class ContactImpl : Contact {
|
||||
abstract override suspend fun sendMessage(message: MessageChain)
|
||||
@ -37,14 +40,18 @@ internal data class GroupImpl internal constructor(override val bot: Bot, val gr
|
||||
|
||||
override suspend fun getMember(id: UInt): Member =
|
||||
if (_members.containsKey(id)) _members[id]!!
|
||||
else membersLock.withLock {
|
||||
else throw NoSuchElementException("No such member whose id is $id in group $id") /*membersLock.withLock {
|
||||
_members.getOrPut(id) { MemberImpl(bot.getQQ(id), this) }
|
||||
}
|
||||
}*/
|
||||
|
||||
override suspend fun sendMessage(message: MessageChain) {
|
||||
bot.sendPacket(GroupPacket.Message(bot.qqAccount, internalId, bot.sessionKey, message))
|
||||
}
|
||||
|
||||
override suspend fun queryGroupInfo(): GroupInfo = bot.withSession {
|
||||
GroupPacket.QueryGroupInfo(qqAccount, internalId, sessionKey).sendAndExpect()
|
||||
}
|
||||
|
||||
override fun toString(): String = "Group(${this.id})"
|
||||
}
|
||||
|
||||
@ -74,6 +81,6 @@ internal data class QQImpl internal constructor(override val bot: Bot, override
|
||||
/**
|
||||
* 群成员
|
||||
*/
|
||||
internal data class MemberImpl(private val delegate: QQ, override val group: Group) : QQ by delegate, Member {
|
||||
override fun toString(): String = "Member(${this.id})"
|
||||
internal data class MemberImpl(private val delegate: QQ, override val group: Group, override val permission: MemberPermission) : QQ by delegate, Member {
|
||||
override fun toString(): String = "Member(id=${this.id}, permission=$permission)"
|
||||
}
|
@ -81,6 +81,8 @@ enum class KnownPacketId(override inline val value: UShort, override inline val
|
||||
inline REQUEST_PROFILE_DETAILS(0x003Cu, RequestProfileDetailsPacket),
|
||||
|
||||
inline QUERY_PREVIOUS_NAME(0x01BCu, QueryPreviousNamePacket),
|
||||
|
||||
inline QUERY_FRIEND_REMARK(0x003Eu, QueryFriendRemarkPacket)
|
||||
// 031F 查询 "新朋友" 记录
|
||||
|
||||
|
||||
|
@ -2,38 +2,38 @@
|
||||
|
||||
package net.mamoe.mirai.network.protocol.tim.packet.action
|
||||
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.writeFully
|
||||
import kotlinx.io.core.writeUByte
|
||||
import net.mamoe.mirai.contact.GroupInternalId
|
||||
import kotlinx.io.core.*
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.contact.internal.MemberImpl
|
||||
import net.mamoe.mirai.getQQ
|
||||
import net.mamoe.mirai.message.MessageChain
|
||||
import net.mamoe.mirai.message.internal.toPacket
|
||||
import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.*
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
import net.mamoe.mirai.withSession
|
||||
|
||||
/*
|
||||
// TODO: 2019/11/27 群公告
|
||||
|
||||
群公告请求:
|
||||
72 E2 E0 74 F7 00 00 00 00
|
||||
|
||||
群公告回复(同群消息的id):
|
||||
72 00 E2 E0 74 F7 12 DB 48 77 00 00 00 03 01 01 00 04 01 00 80 01 40 6C 18 F5 DA 02 00 00 27 1B 00 00 00 00 27 1B 01 F4 01 00 00 00 01 00 00 0F 1F 0C 42 69 67 20 63 6F 6E 76 65 6E 65 27 00 00 96 E6 AF 95 E4 B8 9A E4 BA 86 EF BC 8C E5 B8 8C E6 9C 9B E5 A4 A7 E5 AE B6 E8 83 BD E5 A4 9F E5 83 8F E4 BB A5 E5 89 8D E9 82 A3 E6 A0 B7 E5 BC 80 E5 BF 83 EF BC 8C E5 AD A6 E4 B9 A0 E8 BF 9B E6 AD A5 EF BC 8C E5 A4 A9 E5 A4 A9 E5 BF AB E4 B9 90 E3 80 82 E6 AD A4 E7 BE A4 E7 A6 81 E6 AD A2 E9 AA 82 E4 BA BA EF BC 8C E5 88 B7 E5 B1 8F E6 9A B4 E5 8A 9B EF BC 8C E8 BF 9D E8 A7 84 E8 80 85 E7 A6 81 E8 A8 80 EF BC 8C E4 B8 A5 E9 87 8D E8 80 85 E5 B0 B1 76 E8 BF 9B E7 BE A4 E6 97 B6 EF BC 8C E8 AF B7 E4 BF AE E6 94 B9 E6 AD A3 E7 A1 AE E5 A7 93 E5 90 8D E3 80 82 E4 B8 8D E8 83 BD 54 E5 90 8C E5 AD A6 EF BC 8C E5 A4 AA E8 BF 87 E5 88 86 E7 9A 84 54 21 28 E4 BA 92 E8 B5 9E E7 BE A4 EF BC 8C E6 89 8B E6 9C BA E5 9C A8 E7 BA BF E8 81 8A E5 A4 A9 E8 80 85 E5 8F AF E4 BB A5 E4 BA 92 E8 B5 9E E5 AF B9 E6 96 B9 00 38 D9 FD F5 21 A6 1F 8D 61 37 A1 7A 92 91 2A 2C 71 46 A9 B9 1C 45 EB 38 74 4A 74 EA 77 7D 14 DB 12 D0 B0 09 C2 AA 22 16 F1 D0 B9 97 21 F0 5A A0 06 59 A7 3B 2F 32 D2 B8 E3 00 0F 00 00 00 00 06 00 03 00 02 01 01 00 04 00 04 00 00 00 15 00 05 00 04 52 7C C5 7C 00 06 00 04 00 00 00 20 00 07 00 04 00 00 00 00 00 09 00 01 00 C5 15 BE BE 00 1C ED 9F 9B 00 00 26 D0 E1 3A 00 00 2D 5C 53 A6 00 01 2D BD 28 D2 00 00 2E 94 76 3E 00 00 35 F3 BC F2 00 00 37 D6 91 AB 00 00 3A 60 1C 3E 00 80 3A 86 EA A3 00 48 3D 7F E7 70 00 00 3E 03 3F A2 00 09 41 47 0C DD 00 40 41 B6 32 A8 00 80 44 C8 DA 23 00 00 45 3E 1B 6A 00 80 45 C6 59 E9 00 C0 4A BD C6 F9 00 00 4C 67 45 E8 00 00 4E AD C2 C2 00 80 4F A0 F7 EC 00 80 50 CB 11 E8 00 00 58 22 21 90 00 00 59 17 3E 05 00 01 5E 74 48 D9 00 00 5E A2 B5 88 00 00 66 A1 32 9B 00 40 68 07 29 0A 00 00 68 0F EF 4F 00 00 69 8B 14 F3 00 80 6A A5 27 4E 00 00 6C 11 A0 89 00 81 6C 18 F5 DA 00 08 6C 21 F8 E2 00 01 71 F8 F5 18 00 00 72 0B CC B6 00 00 75 53 38 DF 00 00 7A A1 8B 82 00 00 7C 8C 1D 1B 00 00 7C BC D3 C1 00 00 84 2D B8 5F 00 00 88 4C 33 76 00 00 8C C8 0D 43 00 00 90 B8 65 22 00 00 91 54 89 E9 00 00 9C E6 93 A5 00 01 9D 59 6A 36 00 00 9D 63 81 5C 00 00 9E 31 AF AC 00 00 9E 69 86 25 00 80 A1 FD CA 2D 00 00 A5 22 5C 48 00 00 A5 F2 9A B7 00 00 AF 25 74 9E 00 01 B1 50 24 00 00 00 B2 BD 81 A9 00 00 B5 0E B3 DD 00 00 B9 BF 0D BC 00 00 C5 15 BE BE 00 00
|
||||
*/
|
||||
data class GroupInfo(
|
||||
val group: Group,
|
||||
val owner: Member,
|
||||
val name: String,
|
||||
val announcement: String,
|
||||
val members: ContactList<Member>
|
||||
) : GroupPacket.GroupPacketResponse
|
||||
|
||||
@AnnotatedId(KnownPacketId.SEND_GROUP_MESSAGE)
|
||||
@PacketVersion(date = "2019.10.19", timVersion = "2.3.2 (21173)")
|
||||
object GroupPacket : SessionPacketFactory<GroupPacket.Response>() {
|
||||
object GroupPacket : SessionPacketFactory<GroupPacket.GroupPacketResponse>() {
|
||||
@Suppress("FunctionName")
|
||||
@PacketVersion(date = "2019.10.19", timVersion = "2.3.2 (21173)")
|
||||
fun Message(
|
||||
botQQ: UInt,
|
||||
bot: UInt,
|
||||
groupInternalId: GroupInternalId,
|
||||
sessionKey: SessionKey,
|
||||
message: MessageChain
|
||||
): OutgoingPacket = buildSessionPacket(botQQ, sessionKey, name = "GroupMessage") {
|
||||
writeByte(0x2A)
|
||||
): OutgoingPacket = buildSessionPacket(bot, sessionKey, name = "GroupMessage") {
|
||||
writeUByte(0x2Au)
|
||||
writeGroup(groupInternalId)
|
||||
|
||||
writeShortLVPacket {
|
||||
@ -51,25 +51,206 @@ object GroupPacket : SessionPacketFactory<GroupPacket.Response>() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询公告
|
||||
* 查询群信息
|
||||
*/
|
||||
@Suppress("FunctionName")
|
||||
fun QueryBulletin(
|
||||
botQQ: UInt,
|
||||
@PacketVersion(date = "2019.11.27", timVersion = "2.3.2 (21173)")
|
||||
fun QueryGroupInfo(
|
||||
bot: UInt,
|
||||
groupInternalId: GroupInternalId,
|
||||
sessionKey: SessionKey
|
||||
): OutgoingPacket = buildSessionPacket(
|
||||
botQQ, sessionKey, name = "QueryBulletin"
|
||||
) {
|
||||
): OutgoingPacket = buildSessionPacket(bot, sessionKey, name = "QueryBulletin", headerSizeHint = 9) {
|
||||
writeUByte(0x72u)
|
||||
writeGroup(groupInternalId)
|
||||
writeZero(4)
|
||||
}
|
||||
|
||||
interface GroupPacketResponse : Packet
|
||||
|
||||
@NoLog
|
||||
object Response : Packet {
|
||||
override fun toString(): String = "SendGroupMessagePacket.Response"
|
||||
object MessageResponse : Packet, GroupPacketResponse {
|
||||
override fun toString(): String = "GroupPacket.MessageResponse"
|
||||
}
|
||||
|
||||
override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): Response = Response
|
||||
@UseExperimental(ExperimentalStdlibApi::class)
|
||||
override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): GroupPacketResponse = handler.bot.withSession {
|
||||
return when (readUByte().toUInt()) {
|
||||
0x72u -> {
|
||||
discardExact(1) // 00
|
||||
discardExact(4) // group internal id
|
||||
val group = readUInt().group() // group id
|
||||
|
||||
discardExact(13) //00 00 00 03 01 01 00 04 01 00 80 01 40
|
||||
val owner = MemberImpl(readUInt().qq(), group, MemberPermission.OWNER)
|
||||
discardExact(22)
|
||||
val groupName = readUByteLVString()
|
||||
|
||||
discardExact(readUByte()) // 00
|
||||
discardExact(readUByte()) // 00
|
||||
val announcement = readUByteLVString()
|
||||
discardExact(readUByte()) // 00
|
||||
discardExact(readUByte()) // 00
|
||||
discardExact(readUByte()) // 38 ... 未知
|
||||
discardExact(readUByte()) // 00
|
||||
discardExact(readUByte()) // 0A ...
|
||||
|
||||
discardExact(38)
|
||||
|
||||
val stop = readUInt() // 标记读取群成员的结束
|
||||
discardExact(1) // 00
|
||||
val members: MutableContactList<Member> = MutableContactList()
|
||||
members[owner.id] = owner
|
||||
do {
|
||||
val qq = readUInt()
|
||||
val status = readUShort().toInt() // 这个群成员的状态, 最后一 bit 为管理员权限. 这里面还包含其他状态
|
||||
if (qq == owner.id) {
|
||||
continue
|
||||
}
|
||||
|
||||
val permission = when (status.takeLowestOneBit()) {
|
||||
1 -> MemberPermission.OPERATOR
|
||||
else -> MemberPermission.MEMBER
|
||||
}
|
||||
members[qq] = MemberImpl(handler.bot.getQQ(qq), group, permission)
|
||||
} while (qq != stop && remaining != 0L)
|
||||
return GroupInfo(group, owner, groupName, announcement, ContactList(members))
|
||||
/*
|
||||
* 群 Mirai
|
||||
*
|
||||
* 00 00 00 03 01 41 00 04 01 40 23 04 40
|
||||
* B1 89 BE 09 群主
|
||||
*
|
||||
* 02 00 00 00 00 00 00 00 00 00 21 00 C8 01
|
||||
* 00 00 00 01 00 00
|
||||
* 00 2D
|
||||
*
|
||||
* 06 4D 69 72 61 69 20 群名
|
||||
* 00
|
||||
* 00
|
||||
* 00
|
||||
* 00
|
||||
* 00
|
||||
* 38 87 5F D8 E8 D4 E9 79 73 8A A4 21 1C 3E 2C 43 D0 23 55 53 49 D3 1C DB F6 1F 84 59 77 66 DA 9C D7 26 0F E3 BD E1 F2 B9 29 D1 F6 97 1C 42 5E B0 AF 09 51 72 DA 03 37 AB 65
|
||||
* 00
|
||||
* 0A 00 00 00 00 06 00 03 00 02 00
|
||||
* 01 00 04 00 04 00 00 00 01 00 05 00 04 5D 90 A7 25 00 06 00 04 04 08 00 00 00 07 00 04 00 00 05 80 00 09 00 01 01
|
||||
* B1 89 BE 09 00
|
||||
* 3E 03 3F A2 00 01
|
||||
* 48 76 54 DC 00 00
|
||||
* 76 E4 B8 DD 00 00
|
||||
* 89 1A 5E AC 00 00
|
||||
* B1 89 BE 09 00 00
|
||||
*/
|
||||
|
||||
/*
|
||||
* 群 XkWhXi
|
||||
*
|
||||
* 00 00 00 03 01 41 00 04 01 40 21 04 40
|
||||
* 3E 03 3F A2 群主
|
||||
*
|
||||
* 02 00 00 00 01 00 00 00 00 27 1A 00 C8 01
|
||||
* 00 00 00 01 00 00
|
||||
* F3 C8
|
||||
*
|
||||
* 06 58 6B 57 68 58 69
|
||||
* 00
|
||||
* 00
|
||||
* 3B E6 AC A2 E8 BF 8E E5 BC 80 E8 BD A6 EF BC 8C E5 8E BB 74 6D E7 9A 84 E7 BD 91 E8 AD A6 0A E6 AC A2 E8 BF 8E E5 BC 80 E8 BD A6 EF BC 8C E5 8E BB 74 6D E7 9A 84 E7 BD 91 E8 AD A6
|
||||
* 00
|
||||
* 00
|
||||
* 38 EB 3B A5 90 AC E3 70 1F 42 51 B4 72 81 C8 F5 5A D8 80 69 B6 76 AD A4 AA CC 6A 17 4C 79 81 FF 82 04 BA 13 CE 28 DA 6C 3F 41 77 C0 77 40 B5 87 8E EE 29 20 65 FC 2D FF 63
|
||||
* 00
|
||||
* 0A 00 00 00 00 06 00 03 00 02 00
|
||||
* 01 00 04 00 04 00 00 00 05 00 05 00 04 57 94 6F 41 00 06 00 04 04 08 00 10 00 07 00 04 00 00 04 04 00 09 00 01 00
|
||||
* B1 89 BE 09 00 2D 5C 53 A6 00 01 2F 9B 1C F2 00 00 35 49 95 D1 00 01 3B FA 06 9F 00 00 3E 03 3F A2 00 00 42 C4 32 63 00 01 59 17 3E 05 00 01 6A 89 3E 3E 00 00 6D D7 4E CA 00 00 76 E4 B8 DD 00 00 7C BB 60 3C 00 01 7C BC D3 C1 00 01 87 73 86 9D 00 00 90 19 72 65 00 00 97 30 9A 6B 00 00 9C B1 E5 55 00 01 B1 89 BE 09 00 01
|
||||
*/
|
||||
|
||||
/*
|
||||
* 群 20秃顶28火葬30重生异世
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* 群 Big convene' (与上面两个来自不同 bot)
|
||||
*
|
||||
* 00 00 00 03 01 01 00 04 01 00 80 01 40
|
||||
* 6C 18 F5 DA 群主
|
||||
*
|
||||
* 02 00 00 27 1B 00 00 00 00 27 1B 01 F4 01
|
||||
* 00 00 00 01 00 00
|
||||
* 0F 1F
|
||||
*
|
||||
* 0C 42 69 67 20 63 6F 6E 76 65 6E 65 27 00 群名
|
||||
* 00 96 E6 AF 95 E4 B8 9A E4 BA 86 EF BC 8C E5 B8 8C E6 9C 9B E5 A4 A7 E5 AE B6 E8 83 BD E5 A4 9F E5 83 8F E4 BB A5 E5 89 8D E9 82 A3 E6 A0 B7 E5 BC 80 E5 BF 83 EF BC 8C E5 AD A6 E4 B9 A0 E8 BF 9B E6 AD A5 EF BC 8C E5 A4 A9 E5 A4 A9 E5 BF AB E4 B9 90 E3 80 82 E6 AD A4 E7 BE A4 E7 A6 81 E6 AD A2 E9 AA 82 E4 BA BA EF BC 8C E5 88 B7 E5 B1 8F E6 9A B4 E5 8A 9B EF BC 8C E8 BF 9D E8 A7 84 E8 80 85 E7 A6 81 E8 A8 80 EF BC 8C E4 B8 A5 E9 87 8D E8 80 85 E5 B0 B1
|
||||
* 76 E8 BF 9B E7 BE A4 E6 97 B6 EF BC 8C E8 AF B7 E4 BF AE E6 94 B9 E6 AD A3 E7 A1 AE E5 A7 93 E5 90 8D E3 80 82 E4 B8 8D E8 83 BD 54 E5 90 8C E5 AD A6 EF BC 8C E5 A4 AA E8 BF 87 E5 88 86 E7 9A 84 54 21 28 E4 BA 92 E8 B5 9E E7 BE A4 EF BC 8C E6 89 8B E6 9C BA E5 9C A8 E7 BA BF E8 81 8A E5 A4 A9 E8 80 85 E5 8F AF E4 BB A5 E4 BA 92 E8 B5 9E E5 AF B9 E6 96 B9
|
||||
* 00 38 D9 FD F5 21 A6 1F 8D 61 37 A1 7A 92 91 2A 2C 71 46 A9 B9 1C 45 EB 38 74 4A 74 EA 77 7D 14 DB 12 D0 B0 09 C2 AA 22 16 F1 D0 B9 97 21 F0 5A A0 06 59 A7 3B 2F 32 D2 B8 E3
|
||||
* 00 0F 00 00 00 00 06 00 03 00 02 01 01 00 04 00 04 00 00 00 15 00 05 00 04 52 7C C5 7C 00 06 00 04 00 00 00 20 00 07 00 04 00 00 00 00 00 09 00 01 00
|
||||
*
|
||||
* C5 15 BE BE 00 ???为啥这个只有一个呢
|
||||
* 1C ED 9F 9B 00 00
|
||||
* 26 D0 E1 3A 00 00
|
||||
* 2D 5C 53 A6 00 01 自己 管理员
|
||||
* 2D BD 28 D2 00 00
|
||||
* 2E 94 76 3E 00 00
|
||||
* 35 F3 BC F2 00 00
|
||||
* 37 D6 91 AB 00 00
|
||||
* 3A 60 1C 3E 00 80 10000000 群员, 好友
|
||||
* 3A 86 EA A3 00 48 01001000 群员 手机在线
|
||||
* 3D 7F E7 70 00 00
|
||||
* 3E 03 3F A2 00 09 00001001 好友, 特别关心, TIM PC 在线, 管理员
|
||||
* 41 47 0C DD 00 40 01000000 群员, 离线
|
||||
* 41 B6 32 A8 00 80
|
||||
* 44 C8 DA 23 00 00
|
||||
* 45 3E 1B 6A 00 80 10000000 群员 手机在线
|
||||
* 45 C6 59 E9 00 C0 群员
|
||||
* 4A BD C6 F9 00 00
|
||||
* 4C 67 45 E8 00 00
|
||||
* 4E AD C2 C2 00 80
|
||||
* 4F A0 F7 EC 00 80
|
||||
* 50 CB 11 E8 00 00
|
||||
* 58 22 21 90 00 00
|
||||
* 59 17 3E 05 00 01 管理员 好友
|
||||
* 5E 74 48 D9 00 00
|
||||
* 5E A2 B5 88 00 00
|
||||
* 66 A1 32 9B 00 40
|
||||
* 68 07 29 0A 00 00
|
||||
* 68 0F EF 4F 00 00
|
||||
* 69 8B 14 F3 00 80
|
||||
* 6A A5 27 4E 00 00
|
||||
* 6C 11 A0 89 00 81 10000001 管理员
|
||||
* 6C 18 F5 DA 00 08 群主
|
||||
* 6C 21 F8 E2 00 01 管理员
|
||||
* 71 F8 F5 18 00 00
|
||||
* 72 0B CC B6 00 00
|
||||
* 75 53 38 DF 00 00
|
||||
* 7A A1 8B 82 00 00
|
||||
* 7C 8C 1D 1B 00 00
|
||||
* 7C BC D3 C1 00 00
|
||||
* 84 2D B8 5F 00 00
|
||||
* 88 4C 33 76 00 00
|
||||
* 8C C8 0D 43 00 00
|
||||
* 90 B8 65 22 00 00
|
||||
* 91 54 89 E9 00 00
|
||||
* 9C E6 93 A5 00 01 管理员
|
||||
* 9D 59 6A 36 00 00
|
||||
* 9D 63 81 5C 00 00
|
||||
* 9E 31 AF AC 00 00
|
||||
* 9E 69 86 25 00 80
|
||||
* A1 FD CA 2D 00 00
|
||||
* A5 22 5C 48 00 00
|
||||
* A5 F2 9A B7 00 00
|
||||
* AF 25 74 9E 00 01
|
||||
* B1 50 24 00 00 00
|
||||
* B2 BD 81 A9 00 00
|
||||
* B5 0E B3 DD 00 00
|
||||
* B9 BF 0D BC 00 00
|
||||
* C5 15 BE BE 00 00
|
||||
*/
|
||||
}
|
||||
|
||||
0x2Au -> MessageResponse
|
||||
else -> unsupported()
|
||||
}
|
||||
}
|
||||
}
|
@ -18,6 +18,12 @@ data class UnknownEventPacket(
|
||||
override fun toString(): String = "UnknownEventPacket(id=${id.toUHexString()}, identity=$identity)\n = ${body.readBytes().toUHexString()}"
|
||||
}
|
||||
|
||||
/*
|
||||
被好友拉入群 (已经进入)
|
||||
Mirai 21:54:15 : Packet received: UnknownEventPacket(id=00 57, identity=(920503456->1994701021))
|
||||
= 00 00 00 08 00 0A 00 04 01 00 00 00 36 DD C4 A0 01 04 00 00 00 00 3E 03 3F A2 00 00 20 E5 96 01 BC 23 AE 03 C7 B8 9F BE B3 E5 E4 77 A9 0E FD 2B 7C 64 8B C0 5F 29 8B D7 DC 85 7E 44 7B 00 30 33 65 62 61 62 31 31 66 63 63 61 34 63 38 39 31 36 31 33 37 37 65 65 62 36 63 32 39 37 31 33 34 32 35 62 64 30 34 66 62 31 61 31 65 37 31 63 33
|
||||
*/
|
||||
|
||||
//TODO This class should be declared with `inline`, but a CompilationException will be thrown
|
||||
class UnknownEventParserAndHandler(override val id: UShort) : EventParserAndHandler<UnknownEventPacket> {
|
||||
|
||||
|
@ -7,6 +7,19 @@ import kotlinx.io.pool.useInstance
|
||||
import kotlin.jvm.JvmName
|
||||
import kotlin.jvm.JvmSynthetic
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun Input.discardExact(n: Short) = this.discardExact(n.toInt())
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@JvmSynthetic
|
||||
inline fun Input.discardExact(n: UShort) = this.discardExact(n.toInt())
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
@JvmSynthetic
|
||||
inline fun Input.discardExact(n: UByte) = this.discardExact(n.toInt())
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun Input.discardExact(n: Byte) = this.discardExact(n.toInt())
|
||||
|
||||
fun ByteReadPacket.readRemainingBytes(
|
||||
n: Int = remaining.toInt()//not that safe but adequate
|
||||
@ -30,13 +43,17 @@ fun Input.readPacket(length: Int): ByteReadPacket = this.readBytes(length).toRea
|
||||
|
||||
fun Input.readUVarIntLVString(): String = String(this.readUVarIntByteArray())
|
||||
|
||||
fun Input.readUByteLVString(): String = String(this.readUByteLVByteArray())
|
||||
|
||||
fun Input.readUShortLVString(): String = String(this.readUShortLVByteArray())
|
||||
|
||||
fun Input.readUVarIntByteArray(): ByteArray = this.readBytes(this.readUVarInt().toInt())
|
||||
|
||||
fun Input.readUByteLVByteArray(): ByteArray = this.readBytes(this.readUByte().toInt())
|
||||
|
||||
fun Input.readUShortLVByteArray(): ByteArray = this.readBytes(this.readUShort().toInt())
|
||||
|
||||
private inline fun <R> inline(block: () -> R): R = block()
|
||||
internal inline fun <R> inline(block: () -> R): R = block()
|
||||
|
||||
@Suppress("DuplicatedCode")
|
||||
fun Input.readTLVMap(expectingEOF: Boolean = false, tagSize: Int = 1): MutableMap<UInt, ByteArray> {
|
||||
@ -138,6 +155,7 @@ fun Input.readString(length: Long): String = String(this.readBytes(length.toInt(
|
||||
fun Input.readString(length: Short): String = String(this.readBytes(length.toInt()))
|
||||
@JvmSynthetic
|
||||
fun Input.readString(length: UShort): String = String(this.readBytes(length.toInt()))
|
||||
|
||||
fun Input.readString(length: Byte): String = String(this.readBytes(length.toInt()))
|
||||
|
||||
@JvmSynthetic
|
||||
|
@ -16,7 +16,11 @@ import net.mamoe.mirai.utils.internal.coerceAtMostOrFail
|
||||
import kotlin.random.Random
|
||||
import kotlin.random.nextInt
|
||||
|
||||
fun BytePacketBuilder.writeZero(count: Int) = repeat(count) { this.writeByte(0) }
|
||||
fun BytePacketBuilder.writeZero(count: Int) {
|
||||
require(count != 0) { "Trying to write zero with count 0, you made a mistake?" }
|
||||
require(count > 0) { "writeZero: count must > 0" }
|
||||
repeat(count) { this.writeByte(0) }
|
||||
}
|
||||
|
||||
fun BytePacketBuilder.writeRandom(length: Int) = repeat(length) { this.writeByte(Random.Default.nextInt(255).toByte()) }
|
||||
|
||||
|
@ -7,7 +7,9 @@ import javafx.scene.layout.Region
|
||||
import javafx.scene.paint.Color
|
||||
import javafx.scene.text.FontWeight
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.io.core.readUByte
|
||||
import kotlinx.io.core.readUInt
|
||||
import kotlinx.io.core.readUShort
|
||||
import net.mamoe.mirai.utils.io.encodeToString
|
||||
import net.mamoe.mirai.utils.io.hexToBytes
|
||||
import net.mamoe.mirai.utils.io.read
|
||||
@ -77,6 +79,7 @@ class HexDebuggerGui : View("s") {
|
||||
private lateinit var outShort: TextField
|
||||
private lateinit var outUInt: TextField
|
||||
private lateinit var outString: TextArea
|
||||
private lateinit var outBits: TextField
|
||||
|
||||
|
||||
private val clip = Toolkit.getDefaultToolkit().systemClipboard
|
||||
@ -151,6 +154,18 @@ class HexDebuggerGui : View("s") {
|
||||
value.hexToBytes().size.toString()
|
||||
}
|
||||
|
||||
outBits.text = runOrNull {
|
||||
value.hexToBytes().read {
|
||||
when (remaining.toInt()) {
|
||||
0 -> null
|
||||
1 -> readUByte().toString(2)
|
||||
2 -> readUShort().toString(2)
|
||||
4 -> readUInt().toString(2)
|
||||
else -> ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
outString.text = runOrNull {
|
||||
value.hexToBytes().encodeToString()
|
||||
}
|
||||
@ -201,6 +216,7 @@ class HexDebuggerGui : View("s") {
|
||||
label("UVarInt")
|
||||
label("short")
|
||||
label("uint")
|
||||
label("bits")
|
||||
label("string")
|
||||
children.filterIsInstance<Region>().forEach {
|
||||
it.fitToParentWidth()
|
||||
@ -230,6 +246,11 @@ class HexDebuggerGui : View("s") {
|
||||
isEditable = false
|
||||
}
|
||||
|
||||
outBits = textfield {
|
||||
promptText = "Bits"
|
||||
isEditable = false
|
||||
}
|
||||
|
||||
outString = textarea {
|
||||
promptText = "String"
|
||||
isEditable = false
|
||||
|
@ -116,7 +116,7 @@ object PacketDebugger {
|
||||
* 7. 运行完 `mov eax,dword ptr ss:[ebp+10]`
|
||||
* 8. 查看内存, `eax` 到 `eax+10` 的 16 字节就是 `sessionKey`
|
||||
*/
|
||||
val sessionKey: SessionKey = SessionKey("43 EA BD 3C FF 6A 07 8E E4 13 E9 42 7F AD 03 F1".hexToBytes())
|
||||
val sessionKey: SessionKey = SessionKey("10 52 CD 27 0B A5 9C 74 1B A2 15 7E 41 19 0C 7B".hexToBytes())
|
||||
const val qq: UInt = 761025446u
|
||||
|
||||
val IgnoredPacketIdList: List<PacketId> = listOf(
|
||||
|
17
mirai-debug/src/main/kotlin/test/PacketTest.kt
Normal file
17
mirai-debug/src/main/kotlin/test/PacketTest.kt
Normal file
@ -0,0 +1,17 @@
|
||||
@file:Suppress("EXPERIMENTAL_UNSIGNED_LITERALS")
|
||||
|
||||
package test
|
||||
|
||||
import DebugNetworkHandler
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.UnknownPacketId
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.action.GroupPacket.decode
|
||||
import net.mamoe.mirai.utils.io.hexToBytes
|
||||
import net.mamoe.mirai.utils.io.read
|
||||
|
||||
suspend fun main() {
|
||||
|
||||
"00 00 00 03 01 41 00 04 01 00 23 04 40 1A F7 2F 11 02 00 00 00 00 00 00 00 00 00 21 00 C8 01 00 00 00 01 00 00 00 9E 1E 32 30 E7 A7 83 E9 A1 B6 32 38 E7 81 AB E8 91 AC 33 30 E9 87 8D E7 94 9F E5 BC 82 E4 B8 96 00 00 00 00 00 38 0D 3F 83 73 6A 9C F1 71 7C 10 DC CE F0 03 EA D9 FC 03 D5 87 E1 CD F5 F4 FA 63 37 26 07 17 9F 98 68 06 1A B6 4E 49 0A 14 DE B1 6B E1 32 99 30 29 AB 11 06 28 D9 0E 8A 3C 00 0A 00 00 00 00 06 00 03 00 02 00 01 00 04 00 04 00 00 00 01 00 05 00 04 5D BF EB 82 00 06 00 04 04 08 00 00 00 07 00 04 00 00 85 84 00 09 00 01 01 9F D6 4B F1 00 1A F7 2F 11 00 00 3E 03 3F A2 00 00 53 12 02 7F 00 00 76 E4 B8 DD 00 00 87 73 86 9D 00 00 87 CF 53 7B 00 00 8A 92 D8 1D 00 00 8C D9 1B 93 00 00 8E E0 1A 8A 00 01 9F D6 4B F1 00 00".hexToBytes()
|
||||
.read {
|
||||
decode(UnknownPacketId(0u), 0u, DebugNetworkHandler)
|
||||
}
|
||||
}
|
@ -28,14 +28,6 @@ data class ProtoTest(
|
||||
@UseExperimental(MiraiInternalAPI::class)
|
||||
suspend fun main() {
|
||||
deserializeTest()
|
||||
|
||||
/*
|
||||
intArrayOf(
|
||||
).forEach {
|
||||
println(it.toUShort().toUHexString() + " => " + ProtoFieldId(it.toUInt()))
|
||||
}
|
||||
|
||||
println(ProtoBuf.dump(ProtoTest.serializer(), ProtoTest(1)).toUHexString())*/
|
||||
}
|
||||
|
||||
suspend fun deserializeTest() {
|
||||
@ -43,10 +35,10 @@ suspend fun deserializeTest() {
|
||||
"""
|
||||
|
||||
|
||||
|
||||
00 36 DD C4 A0 01 2D 5C 53 A6 03 3E 03 3F A2 06 B9 DC C0 ED D4 B1 00 30 31 63 35 35 31 34 63 62 36 64 37 39 61 65 61 66 35 66 33 34 35 64 39 63 32 34 64 65 37 32 36 64 39 64 36 39 36 64 66 66 32 38 64 63 38 32 37 36
|
||||
|
||||
|
||||
00 00 00 03 01 01 00 04 01 00 80 01 40 6C 18 F5 DA 02 00 00 27 1B 00 00 00 00 27 1B 01 F4 01 00 00 00 01 00 00 0F 1F 0C 42 69 67 20 63 6F 6E 76 65 6E 65 27 00 00 96 E6 AF 95 E4 B8 9A E4 BA 86 EF BC 8C E5 B8 8C E6 9C 9B E5 A4 A7 E5 AE B6 E8 83 BD E5 A4 9F E5 83 8F E4 BB A5 E5 89 8D E9 82 A3 E6 A0 B7 E5 BC 80 E5 BF 83 EF BC 8C E5 AD A6 E4 B9 A0 E8 BF 9B E6 AD A5 EF BC 8C E5 A4 A9 E5 A4 A9 E5 BF AB E4 B9 90 E3 80 82 E6 AD A4 E7 BE A4 E7 A6 81 E6 AD A2 E9 AA 82 E4 BA BA EF BC 8C E5 88 B7 E5 B1 8F E6 9A B4 E5 8A 9B EF BC 8C E8 BF 9D E8 A7 84 E8 80 85 E7 A6 81 E8 A8 80 EF BC 8C E4 B8 A5 E9 87 8D E8 80 85 E5 B0 B1 76 E8 BF 9B E7 BE A4 E6 97 B6 EF BC 8C E8 AF B7 E4 BF AE E6 94 B9 E6 AD A3 E7 A1 AE E5 A7 93 E5 90 8D E3 80 82 E4 B8 8D E8 83 BD 54 E5 90 8C E5 AD A6 EF BC 8C E5 A4 AA E8 BF 87 E5 88 86 E7 9A 84 54 21 28 E4 BA 92 E8 B5 9E E7 BE A4 EF BC 8C E6 89 8B E6 9C BA E5 9C A8 E7 BA BF E8 81 8A E5 A4 A9 E8 80 85 E5 8F AF E4 BB A5 E4 BA 92 E8 B5 9E E5 AF B9 E6 96 B9 00 38 D9 FD F5 21 A6 1F 8D 61 37 A1 7A 92 91 2A 2C 71 46 A9 B9 1C 45 EB 38 74 4A 74 EA 77 7D 14 DB 12 D0 B0 09 C2 AA 22 16 F1 D0 B9 97 21 F0 5A A0 06 59 A7 3B 2F 32 D2 B8 E3 00 0F 00 00 00 00 06 00 03 00 02 01 01 00 04 00 04 00 00 00 15 00 05 00 04 52 7C C5 7C 00 06 00 04 00 00 00 20 00 07 00 04 00 00 00 00 00 09 00 01 00 C5 15 BE BE 00 1C ED 9F 9B 00 00 26 D0 E1 3A 00 00 2D 5C 53 A6 00 01 2D BD 28 D2 00 00 2E 94 76 3E 00 00 35 F3 BC F2 00 00 37 D6 91 AB 00 00 3A 60 1C 3E 00 80 3A 86 EA A3 00 48 3D 7F E7 70 00 00 3E 03 3F A2 00 09 41 47 0C DD 00 40 41 B6 32 A8 00 80 44 C8 DA 23 00 00 45 3E 1B 6A 00 80 45 C6 59 E9 00 C0 4A BD C6 F9 00 00 4C 67 45 E8 00 00 4E AD C2 C2 00 80 4F A0 F7 EC 00 80 50 CB 11 E8 00 00 58 22 21 90 00 00 59 17 3E 05 00 01 5E 74 48 D9 00 00 5E A2 B5 88 00 00 66 A1 32 9B 00 40 68 07 29 0A 00 00 68 0F EF 4F 00 00 69 8B 14 F3 00 80 6A A5 27 4E 00 00 6C 11 A0 89 00 81 6C 18 F5 DA 00 08 6C 21 F8 E2 00 01 71 F8 F5 18 00 00 72 0B CC B6 00 00 75 53 38 DF 00 00 7A A1 8B 82 00 00 7C 8C 1D 1B 00 00 7C BC D3 C1 00 00 84 2D B8 5F 00 00 88 4C 33 76 00 00 8C C8 0D 43 00 00 90 B8 65 22 00 00 91 54 89 E9 00 00 9C E6 93 A5 00 01 9D 59 6A 36 00 00 9D 63 81 5C 00 00 9E 31 AF AC 00 00 9E 69 86 25 00 80 A1 FD CA 2D 00 00 A5 22 5C 48 00 00 A5 F2 9A B7 00 00 AF 25 74 9E 00 01 B1 50 24 00 00 00 B2 BD 81 A9 00 00 B5 0E B3 DD 00 00 B9 BF 0D BC 00 00 C5 15 BE BE 00 00
|
||||
|
||||
|
||||
|
||||
""".trimIndent().replace("\n", " ").replace("[", "").replace("]", "")
|
||||
.hexToBytes()
|
||||
println(bytes.read { readProtoMap() })
|
||||
|
@ -64,6 +64,13 @@ suspend fun main() {
|
||||
|
||||
"你好" reply "你好!"
|
||||
|
||||
"群资料" reply {
|
||||
if (this is GroupMessage) {
|
||||
group.queryGroupInfo().toString().reply()
|
||||
}
|
||||
""
|
||||
}
|
||||
|
||||
startsWith("profile", removePrefix = true) {
|
||||
val account = it.trim()
|
||||
if (account.isNotEmpty()) {
|
||||
|
Loading…
Reference in New Issue
Block a user