Add GroupInfo

This commit is contained in:
Him188 2019-11-27 23:14:34 +08:00
parent 95f4f9d45a
commit d171073dc5
15 changed files with 322 additions and 51 deletions

View File

@ -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

View File

@ -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() }
}

View File

@ -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].

View File

@ -10,6 +10,11 @@ interface Member : QQ, Contact {
* 所在的群
*/
val group: Group
/**
* 权限
*/
val permission: MemberPermission
}
/**

View File

@ -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)"
}

View File

@ -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 查询 "新朋友" 记录

View File

@ -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()
}
}
}

View File

@ -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> {

View File

@ -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

View File

@ -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()) }

View File

@ -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

View File

@ -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(

View 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)
}
}

View File

@ -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() })

View File

@ -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()) {