From 0b01fd7b3634e4bd1b5bc1e789baa99061cd0fe2 Mon Sep 17 00:00:00 2001
From: "jiahua.liu" <n@mamoe.net>
Date: Fri, 31 Jan 2020 18:06:23 +0800
Subject: [PATCH 1/2] troop List

---
 .../network/QQAndroidBotNetworkHandler.kt     | 11 ++-
 .../qqandroid/network/http/HttpRequest.kt     | 81 +++++++++++++++++++
 .../network/protocol/packet/PacketFactory.kt  |  2 +-
 .../protocol/packet/list/FriendListPacket.kt  |  7 +-
 .../androidPacketTests/clientToServer.kt      |  3 +
 .../androidPacketTests/serverToClient.kt      |  3 +
 6 files changed, 99 insertions(+), 8 deletions(-)
 create mode 100644 mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/http/HttpRequest.kt

diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
index 8bb5551f5..bca5c7436 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
@@ -1,5 +1,6 @@
 package net.mamoe.mirai.qqandroid.network
 
+import io.ktor.client.HttpClient
 import kotlinx.atomicfu.AtomicRef
 import kotlinx.atomicfu.atomic
 import kotlinx.coroutines.*
@@ -98,6 +99,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
         suspend fun doInit() {
             //start updating friend/group list
             bot.logger.info("Start updating friend/group list")
+
             /*
             val data = FriendList.GetFriendGroupList(
                 bot.client,
@@ -106,11 +108,14 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
                 0,
                 2
             ).sendAndExpect<FriendList.GetFriendGroupList.Response>()
-             */
-            val data = FriendList.GetTroopList(
+            */
+
+            val data = FriendList.GetTroopListSimplify(
                 bot.client
-            ).sendAndExpect<FriendList.GetFriendGroupList.Response>()
+            ).sendAndExpect<FriendList.GetTroopListSimplify.Response>(100000)
             println(data.contentToString())
+
+
         }
 
         doLogin()
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/http/HttpRequest.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/http/HttpRequest.kt
new file mode 100644
index 000000000..b74ac1501
--- /dev/null
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/http/HttpRequest.kt
@@ -0,0 +1,81 @@
+package net.mamoe.mirai.qqandroid.network.http
+
+import io.ktor.client.HttpClient
+import io.ktor.client.request.*
+import io.ktor.client.response.HttpResponse
+import io.ktor.http.ContentType
+import io.ktor.http.URLProtocol
+import io.ktor.http.setCookie
+import io.ktor.http.userAgent
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.io.readRemaining
+import kotlinx.coroutines.withContext
+import net.mamoe.mirai.qqandroid.QQAndroidBot
+import net.mamoe.mirai.qqandroid.network.QQAndroidClient
+import net.mamoe.mirai.utils.cryptor.contentToString
+import net.mamoe.mirai.utils.currentTimeMillis
+import net.mamoe.mirai.utils.io.readRemainingBytes
+import net.mamoe.mirai.utils.io.toUHexString
+
+/**
+ * 好像不需要了
+ */
+object HttpRequest {
+    private lateinit var cookie: String
+}
+
+
+internal suspend fun HttpClient.getPTLoginCookies(
+    client: QQAndroidClient
+): String {
+    //$"https://ssl.ptlogin2.qq.com/jump?pt_clientver=5593&pt_src=1&keyindex=9&ptlang=2052&clientuin={QQ}&clientkey={Util.ToHex(TXProtocol.BufServiceTicketHttp, "", "{0}")}&u1=https:%2F%2Fuser.qzone.qq.com%2F417085811%3FADUIN=417085811%26ADSESSION={Util.GetTimeMillis(DateTime.Now)}%26ADTAG=CLIENT.QQ.5593_MyTip.0%26ADPUBNO=26841&source=namecardhoverstar"
+    // "https://ssl.ptlogin2.qq.com/jump?pt_clientver=5509&pt_src=1&keyindex=9&clientuin={0}&clientkey={1}&u1=http%3A%2F%2Fqun.qq.com%2Fmember.html%23gid%3D168209441",
+    val res = post<HttpResponse> {
+        println(client.wLoginSigInfo.userStWebSig.data.toUHexString().replace(" ", "").toLowerCase())
+        url {
+            protocol = URLProtocol.HTTPS
+            host = "ssl.ptlogin2.qq.com"
+            path(
+                "/jump?pt_clientver=5509&pt_src=1&keyindex=9&clientuin=${client.uin}&clientkey=${client.wLoginSigInfo.userStWebSig.data.toUHexString().replace(
+                    " ",
+                    ""
+                )}&u1=http%3A%2F%2Fqun.qq.com%2Fmember.html%23gid%3D168209441&FADUIN=417085811&ADSESSION=${currentTimeMillis}&source=namecardhoverstar"
+            )
+        }
+        headers {
+            userAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36")
+        }
+    }
+
+    println(res.status)
+    println(res.setCookie())
+    println(res.content.readRemaining().readRemainingBytes().toUHexString())
+    return "done";
+}
+
+
+internal suspend fun HttpClient.getGroupList(
+    client: QQAndroidClient
+): String {
+    // "https://ssl.ptlogin2.qq.com/jump?pt_clientver=5509&pt_src=1&keyindex=9&clientuin={0}&clientkey={1}&u1=http%3A%2F%2Fqun.qq.com%2Fmember.html%23gid%3D168209441",
+    val res = get<HttpResponse> {
+        url {
+            protocol = URLProtocol.HTTPS
+            host = "ssl.ptlogin2.qq.com"
+            path("jump")
+            parameters["pt_clientver"] = "5509"
+            parameters["pt_src"] = "1"
+            parameters["keyindex"] = "9"
+            parameters["u1"] = "http%3A%2F%2Fqun.qq.com%2Fmember.html%23gid%3D168209441"
+            parameters["clientuin"] = client.uin.toString()
+            parameters["clientkey"] = client.wLoginSigInfo.userStWebSig.data.toUHexString()
+        }
+        headers {
+            userAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36")
+        }
+    }
+
+    println(res.status)
+    println(res.setCookie())
+    return "done";
+}
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
index a68e3778b..acf2834df 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
@@ -67,7 +67,7 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf(
     MessageSvc.PushForceOffline,
     MessageSvc.PbSendMsg,
     FriendList.GetFriendGroupList,
-    FriendList.GetTroopList
+    FriendList.GetTroopListSimplify
 ) {
     // SvcReqMSFLoginNotify 自己的其他设备上限
     // MessageSvc.PushReaded 电脑阅读了别人的消息, 告知手机
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendListPacket.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendListPacket.kt
index c62de6ef3..f3354ff3b 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendListPacket.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendListPacket.kt
@@ -15,7 +15,6 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
 import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
 import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
 import net.mamoe.mirai.utils.cryptor.contentToString
-import net.mamoe.mirai.utils.io.debugPrint
 import net.mamoe.mirai.utils.io.discardExact
 import net.mamoe.mirai.utils.io.readRemainingBytes
 import net.mamoe.mirai.utils.io.toUHexString
@@ -23,8 +22,9 @@ import net.mamoe.mirai.utils.io.toUHexString
 
 internal class FriendList {
 
-    internal object GetTroopList : PacketFactory<GetTroopList.Response>("friendlist.GetTroopListReqV2") {
-        override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GetTroopList.Response {
+    internal object GetTroopListSimplify :
+        PacketFactory<GetTroopListSimplify.Response>("friendlist.GetTroopListReqV2") {
+        override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GetTroopListSimplify.Response {
             println("获取到了GetTroopList的回信")
             println(this.readRemainingBytes().toUHexString())
             return Response()
@@ -65,7 +65,6 @@ internal class FriendList {
             }
         }
     }
-
     internal object GetFriendGroupList : PacketFactory<GetFriendGroupList.Response>("friendlist.getFriendGroupList") {
 
         class Response : Packet {
diff --git a/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt b/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt
index 4bdaff37a..07958c3cd 100644
--- a/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt
+++ b/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt
@@ -276,6 +276,9 @@ fun ByteReadPacket.decodeUni() {
     //return
     readBytes(readInt() - 4).debugPrint("head").toReadPacket().apply {
         val commandName = readString(readInt() - 4).also { PacketLogger.warning("commandName=$it") }
+        if(commandName.contains("GetTroopList")){
+            println("!\n".repeat(100))
+        }
         println(commandName)
         println("  unknown4Bytes=" + readBytes(readInt() - 4).toUHexString())
         // 00 00 00 1A 43 6F 6E 66 69 67 50 75 73 68 53 76 63 2E 50 75 73 68 52 65 73 70
diff --git a/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/serverToClient.kt b/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/serverToClient.kt
index 77ca2dbfe..be316f9f5 100644
--- a/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/serverToClient.kt
+++ b/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/serverToClient.kt
@@ -219,6 +219,9 @@ private fun parseSsoFrame(input: ByteReadPacket): KnownPacketFactories.IncomingP
 
         commandName = readString(readInt() - 4)
         DebugLogger.warning("commandName=$commandName")
+        if(commandName.contains("GetTroopList")){
+            println("!\n".repeat(100))
+        }
         val unknown = readBytes(readInt() - 4)
         //if (unknown.toInt() != 0x02B05B8B) DebugLogger.debug("got new unknown: ${unknown.toUHexString()}")
 

From 192a83de0cf39ab306e2631be58e2ec8b6577068 Mon Sep 17 00:00:00 2001
From: "jiahua.liu" <n@mamoe.net>
Date: Fri, 31 Jan 2020 21:17:53 +0800
Subject: [PATCH 2/2] troop List

---
 .../network/QQAndroidBotNetworkHandler.kt     | 15 +++-
 .../network/protocol/data/jce/TroopList.kt    | 81 +++++++++++++++++++
 .../network/protocol/packet/PacketFactory.kt  |  2 +-
 .../protocol/packet/list/FriendListPacket.kt  | 44 +++++++---
 4 files changed, 125 insertions(+), 17 deletions(-)

diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
index fb51a07b2..550414e09 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
@@ -102,19 +102,26 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
     override suspend fun init() {
         //start updating friend/group list
         bot.logger.info("Start updating friend/group list")
+
         /*
         val data = FriendList.GetFriendGroupList(
             bot.client,
             0,
-            1,
+            20,
             0,
-            2
+            0
         ).sendAndExpect<FriendList.GetFriendGroupList.Response>()
-         */
+
+
+        println(data.contentToString())
+        */
+
         val data = FriendList.GetTroopList(
             bot.client
-        ).sendAndExpect<FriendList.GetTroopList.Response>()
+        ).sendAndExpect<FriendList.GetTroopList.Response>(100000)
         println(data.contentToString())
+
+
     }
 
 
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/TroopList.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/TroopList.kt
index 296d4c133..63f465d9e 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/TroopList.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/TroopList.kt
@@ -24,3 +24,84 @@ internal class stTroopNumSimplify(
     @SerialId(2) val dwGroupFlagExt: Long? = null,
     @SerialId(3) val dwGroupRankSeq: Long? = null
 ) : JceStruct
+
+
+@Serializable
+internal class GetTroopListRespV2(
+    @SerialId(0) val uin: Long,
+    @SerialId(1) val troopcount: Short,
+    @SerialId(2) val result: Int,
+    @SerialId(3) val errorCode: Short? = null,
+    @SerialId(4) val vecCookies: ByteArray? = null,
+    @SerialId(5) val vecTroopList: List<stTroopNum>? = null,
+    @SerialId(6) val vecTroopListDel: List<stTroopNum>? = null,
+    @SerialId(7) val vecTroopRank: List<stGroupRankInfo>? = null,
+    @SerialId(8) val vecFavGroup: List<stFavoriteGroup>? = null,
+    @SerialId(9) val vecTroopListExt: List<stTroopNum>? = null
+) : JceStruct
+
+
+@Serializable
+internal class stTroopNum(
+    @SerialId(0) val groupUin: Long,
+    @SerialId(1) val groupCode: Long,
+    @SerialId(2) val flag: Byte? = null,
+    @SerialId(3) val dwGroupInfoSeq: Long? = null,
+    @SerialId(4) val groupName: String? = "",
+    @SerialId(5) val groupMemo: String? = "",
+    @SerialId(6) val dwGroupFlagExt: Long? = null,
+    @SerialId(7) val dwGroupRankSeq: Long? = null,
+    @SerialId(8) val dwCertificationType: Long? = null,
+    @SerialId(9) val dwShutupTimestamp: Long? = null,
+    @SerialId(10) val dwMyShutupTimestamp: Long? = null,
+    @SerialId(11) val dwCmdUinUinFlag: Long? = null,
+    @SerialId(12) val dwAdditionalFlag: Long? = null,
+    @SerialId(13) val dwGroupTypeFlag: Long? = null,
+    @SerialId(14) val dwGroupSecType: Long? = null,
+    @SerialId(15) val dwGroupSecTypeInfo: Long? = null,
+    @SerialId(16) val dwGroupClassExt: Long? = null,
+    @SerialId(17) val dwAppPrivilegeFlag: Long? = null,
+    @SerialId(18) val dwSubscriptionUin: Long? = null,
+    @SerialId(19) val dwMemberNum: Long? = null,
+    @SerialId(20) val dwMemberNumSeq: Long? = null,
+    @SerialId(21) val dwMemberCardSeq: Long? = null,
+    @SerialId(22) val dwGroupFlagExt3: Long? = null,
+    @SerialId(23) val dwGroupOwnerUin: Long? = null,
+    @SerialId(24) val isConfGroup: Byte? = null,
+    @SerialId(25) val isModifyConfGroupFace: Byte? = null,
+    @SerialId(26) val isModifyConfGroupName: Byte? = null,
+    @SerialId(27) val dwCmduinJoinTime: Long? = null,
+    @SerialId(28) val ulCompanyId: Long? = null,
+    @SerialId(29) val dwMaxGroupMemberNum: Long? = null,
+    @SerialId(30) val dwCmdUinGroupMask: Long? = null,
+    @SerialId(31) val udwHLGuildAppid: Long? = null,
+    @SerialId(32) val udwHLGuildSubType: Long? = null,
+    @SerialId(33) val udwCmdUinRingtoneID: Long? = null,
+    @SerialId(34) val udwCmdUinFlagEx2: Long? = null
+) : JceStruct
+
+@Serializable
+internal class stGroupRankInfo(
+    @SerialId(0) val dwGroupCode: Long,
+    @SerialId(1) val groupRankSysFlag: Byte? = null,
+    @SerialId(2) val groupRankUserFlag: Byte? = null,
+    @SerialId(3) val vecRankMap: List<stLevelRankPair>? = null,
+    @SerialId(4) val dwGroupRankSeq: Long? = null,
+    @SerialId(5) val ownerName: String? = "",
+    @SerialId(6) val adminName: String? = "",
+    @SerialId(7) val dwOfficeMode: Long? = null
+) : JceStruct
+
+@Serializable
+internal class stFavoriteGroup(
+    @SerialId(0) val dwGroupCode: Long,
+    @SerialId(1) val dwTimestamp: Long? = null,
+    @SerialId(2) val dwSnsFlag: Long? = 1L,
+    @SerialId(3) val dwOpenTimestamp: Long? = null
+) : JceStruct
+
+@Serializable
+internal class stLevelRankPair(
+    @SerialId(0) val dwLevel: Long? = null,
+    @SerialId(1) val rank: String? = ""
+) : JceStruct
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
index acf2834df..a68e3778b 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt
@@ -67,7 +67,7 @@ internal object KnownPacketFactories : List<PacketFactory<*>> by mutableListOf(
     MessageSvc.PushForceOffline,
     MessageSvc.PbSendMsg,
     FriendList.GetFriendGroupList,
-    FriendList.GetTroopListSimplify
+    FriendList.GetTroopList
 ) {
     // SvcReqMSFLoginNotify 自己的其他设备上限
     // MessageSvc.PushReaded 电脑阅读了别人的消息, 告知手机
diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendListPacket.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendListPacket.kt
index 6369b5642..43f8ab69c 100644
--- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendListPacket.kt
+++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/list/FriendListPacket.kt
@@ -8,16 +8,20 @@ import net.mamoe.mirai.qqandroid.io.serialization.jceRequestSBuffer
 import net.mamoe.mirai.qqandroid.io.serialization.toByteArray
 import net.mamoe.mirai.qqandroid.io.serialization.writeJceStruct
 import net.mamoe.mirai.qqandroid.network.QQAndroidClient
+import net.mamoe.mirai.qqandroid.network.protocol.data.jce.*
 import net.mamoe.mirai.qqandroid.network.protocol.data.jce.GetFriendListReq
 import net.mamoe.mirai.qqandroid.network.protocol.data.jce.GetFriendListResp
 import net.mamoe.mirai.qqandroid.network.protocol.data.jce.GetTroopListReqV2Simplify
+import net.mamoe.mirai.qqandroid.network.protocol.data.jce.GroupInfo
 import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPacket
 import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Vec0xd50
 import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
 import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
 import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
 import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
+import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList.GetFriendGroupList.decode
 import net.mamoe.mirai.utils.cryptor.contentToString
+import net.mamoe.mirai.utils.io.debugPrint
 import net.mamoe.mirai.utils.io.discardExact
 import net.mamoe.mirai.utils.io.readRemainingBytes
 import net.mamoe.mirai.utils.io.toUHexString
@@ -25,15 +29,28 @@ import net.mamoe.mirai.utils.io.toUHexString
 
 internal class FriendList {
 
-    internal object GetTroopListSimplify :
-        PacketFactory<GetTroopListSimplify.Response>("friendlist.GetTroopListReqV2") {
-        override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GetTroopListSimplify.Response {
-            println("获取到了GetTroopList的回信")
-            println(this.readRemainingBytes().toUHexString())
-            return Response()
+    /**
+     * Get Troop List不一定会得到服务器的回应 据推测与群数量有关
+     * 因此 应对timeout方法做出处理
+     * timeout时间应不小于 8s?
+     *
+     */
+    internal object GetTroopList :
+        PacketFactory<GetTroopList.Response>("friendlist.GetTroopListReqV2") {
+        override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GetTroopList.Response {
+            debugPrint()
+            this.discardExact(4)
+            val res = this.decodeUniPacket(GetTroopListRespV2.serializer())
+            println(res.contentToString())
+            return Response(
+
+            )
+
         }
 
-        class Response : Packet {
+        class Response(
+
+        ) : Packet {
             override fun toString(): String = "FriendList.GetFriendGroupList.Response"
         }
 
@@ -49,7 +66,6 @@ internal class FriendList {
                         iVersion = 3,
                         cPacketType = 0x00,
                         iMessageType = 0x00000,
-                        iRequestId = 1921334513,
                         sBuffer = jceRequestSBuffer(
                             "GetTroopListReqV2Simplify",
                             GetTroopListReqV2Simplify.serializer(),
@@ -69,16 +85,20 @@ internal class FriendList {
         }
     }
     internal object GetFriendGroupList : PacketFactory<GetFriendGroupList.Response>("friendlist.getFriendGroupList") {
-
-        class Response : Packet {
+        class Response(
+            val totalFriendCount: Short,
+            val friendList: List<FriendInfo>
+        ) : Packet {
             override fun toString(): String = "FriendList.GetFriendGroupList.Response"
         }
 
         override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
             this.discardExact(4)
             val res = this.decodeUniPacket(GetFriendListResp.serializer())
-            println(res.contentToString())
-            return Response()
+            return Response(
+                res.totoalFriendCount,
+                res.vecFriendInfo.orEmpty()
+            )
         }
 
         operator fun invoke(