From 7ca62bb0c89a38db186a05e83a1904b6d30f04e3 Mon Sep 17 00:00:00 2001
From: Him188moe <Him188>
Date: Mon, 2 Sep 2019 22:33:23 +0800
Subject: [PATCH] Updated verification code processing

---
 .../main/java/net/mamoe/mirai/MiraiMain.java  |  18 +--
 .../java/net/mamoe/mirai/MiraiServer.java     |  70 ++-------
 .../src/main/java/net/mamoe/mirai/Robot.java  |  17 ++-
 .../java/net/mamoe/mirai/contact/Contact.kt   |   2 +-
 .../java/net/mamoe/mirai/contact/Group.kt     |  86 ++++++-----
 .../main/java/net/mamoe/mirai/contact/Lazy.kt |  17 ---
 .../main/java/net/mamoe/mirai/contact/QQ.kt   |   5 +-
 .../net/mamoe/mirai/message/defaults/At.java  |   6 +-
 .../mirai/network/RobotNetworkHandler.kt      | 117 ++++++++-------
 .../mamoe/mirai/network/packet/AccountInfo.kt |   2 +-
 .../mirai/network/packet/ClientPacket.kt      |  31 +++-
 .../mamoe/mirai/network/packet/Heartbeat.kt   |   2 +-
 .../mirai/network/packet/MessageEvent.kt      |   2 +-
 .../net/mamoe/mirai/network/packet/SKey.kt    |   4 +-
 .../mamoe/mirai/network/packet/ServerEvent.kt |  20 ++-
 .../mirai/network/packet/ServerPacket.kt      |  10 +-
 .../net/mamoe/mirai/network/packet/Session.kt |   2 +-
 .../net/mamoe/mirai/network/packet/Touch.kt   |   4 +-
 .../mirai/network/packet/VerificationCode.kt  |  98 +++++++++++++
 .../network/packet/login/ClientLoginPacket.kt |  15 +-
 .../packet/login/ClientLoginStatusPacket.kt   |   2 +-
 .../ClientLoginVerificationCodePacket.kt      |  41 ------
 ...oginResponseVerificationCodeInitPacket.kt} |  13 +-
 .../message/ClientSendFriendMessagePacket.kt  |  10 +-
 .../message/ClientSendGroupMessagePacket.kt   |   6 +-
 .../ServerVerificationCodePacket.kt           |  44 ------
 .../net/mamoe/mirai/utils/ContactList.java    |   2 +-
 .../main/java/net/mamoe/mirai/utils/Utils.kt  |   2 +
 .../utils/config/MiraiConfigSection.java      |   4 +-
 mirai-core/src/test/java/HexComparator.java   | 133 +++++++++++++-----
 mirai-core/src/test/java/TestKt.kt            |   8 ++
 31 files changed, 435 insertions(+), 358 deletions(-)
 delete mode 100644 mirai-core/src/main/java/net/mamoe/mirai/contact/Lazy.kt
 create mode 100644 mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt
 delete mode 100644 mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginVerificationCodePacket.kt
 rename mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/{ServerLoginResponseVerificationCodePacket.kt => ServerLoginResponseVerificationCodeInitPacket.kt} (61%)
 delete mode 100644 mirai-core/src/main/java/net/mamoe/mirai/network/packet/verification/ServerVerificationCodePacket.kt
 create mode 100644 mirai-core/src/test/java/TestKt.kt

diff --git a/mirai-core/src/main/java/net/mamoe/mirai/MiraiMain.java b/mirai-core/src/main/java/net/mamoe/mirai/MiraiMain.java
index 77c77cbfd..d959f504a 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/MiraiMain.java
+++ b/mirai-core/src/main/java/net/mamoe/mirai/MiraiMain.java
@@ -1,28 +1,14 @@
 package net.mamoe.mirai;
 
 
-import net.mamoe.mirai.utils.config.MiraiConfig;
-import net.mamoe.mirai.utils.config.MiraiConfigSection;
-
 /**
  * @author Him188moe
  */
 public final class MiraiMain {
     private static MiraiServer server;
+
     public static void main(String[] args) {
         server = new MiraiServer();
-        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
-            server.shutdown();
-        }));
-        MiraiConfig config = new MiraiConfig("QQ.yml");
-        MiraiConfigSection<Object> data = config.getSection("123123");
-        data.put("account","123123a");
-        try {
-            Robot robot = new Robot(data);
-        } catch (Throwable throwable) {
-            throwable.printStackTrace();
-        }
-
-
+        Runtime.getRuntime().addShutdownHook(new Thread(() -> server.shutdown()));
     }
 }
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java b/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java
index 6ba54eb76..a768ff60f 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java
+++ b/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java
@@ -5,7 +5,6 @@ import net.mamoe.mirai.event.MiraiEventManager;
 import net.mamoe.mirai.event.events.server.ServerDisableEvent;
 import net.mamoe.mirai.event.events.server.ServerEnableEvent;
 import net.mamoe.mirai.network.RobotNetworkHandler;
-import net.mamoe.mirai.network.packet.ClientTouchPacket;
 import net.mamoe.mirai.task.MiraiTaskManager;
 import net.mamoe.mirai.utils.LoggerTextFormat;
 import net.mamoe.mirai.utils.MiraiLogger;
@@ -17,7 +16,6 @@ import net.mamoe.mirai.utils.setting.MiraiSettingMapSection;
 
 import java.io.File;
 import java.io.IOException;
-import java.util.LinkedList;
 import java.util.Scanner;
 
 public class MiraiServer {
@@ -119,62 +117,20 @@ public class MiraiServer {
         getLogger().info("ready to connect");
 
 
-        /*
-        MiraiConfigSection section = new MiraiConfigSection<MiraiConfigSection<String>>(){{
-            put("1",new MiraiConfigSection<>(){{
-                put("1","0");
-            }});
-        }};
+        this.qqs.keySet().stream().map(key -> this.qqs.getSection(key)).forEach(section -> {
+            try {
+                Robot robot = new Robot(section);
+                RobotNetworkHandler robotNetworkHandler = robot.getHandler();
+                robotNetworkHandler.setServerIP("14.116.136.106");
+                robotNetworkHandler.touch$mirai_core();
 
-        this.qqs.put("test",section);
-        this.qqs.save();
-        */
-
-
-        MiraiConfigSection<MiraiConfigSection> x = this.qqs.getTypedSection("test");
-        //System.out.println(x.getSection("1").getInt("1"));
-
-        /*
-        System.out.println(v);
-
-        System.out.println(v.get("1111"));
-        */
-
-
-        Robot robot = new Robot(1994701021, "xiaoqqq", new LinkedList<>());
-        RobotNetworkHandler robotNetworkHandler = robot.getHandler();
-        try {
-            //System.out.println(Protocol.Companion.getSERVER_IP().get(3));
-            //System.out.println(Protocol.Companion.getSERVER_IP().toString());
-
-            robotNetworkHandler.setServerIP("14.116.136.106");
-            robotNetworkHandler.sendPacket(new ClientTouchPacket(1994701021, "14.116.136.106"));
-            while (true) ;
-            //robotNetworkHandler.connect("14.116.136.106");
-            //robotNetworkHandler.connect(Protocol.Companion.getSERVER_IP().get(2));
-            //robotNetworkHandler.connect("125.39.132.242");
-        } catch (Exception e) {
-            e.printStackTrace();
-            System.exit(1);
-        }
-/*
-        System.out.println("network test");
-        try {
-
-
-            MiraiUDPServer server = new MiraiUDPServer();
-            MiraiUDPClient client = new MiraiUDPClient(InetAddress.getLocalHost(),9999,MiraiNetwork.getAvailablePort());
-            this.getTaskManager().repeatingTask(() -> {
-                byte[] sendInfo = "test test".getBytes(StandardCharsets.UTF_8);
-                try {
-                    client.send(new DatagramPacket(sendInfo,sendInfo.length));
-                } catch (IOException e) {
-                    e.printStackTrace();
-                }
-            },300);
-        } catch (IOException e) {
-            e.printStackTrace();
-        }*/
+                Robot.instances.add(robot);
+            } catch (Throwable e) {
+                e.printStackTrace();
+                getLogger().error("Could not load QQ robots config!");
+                System.exit(1);
+            }
+        });
     }
 
     private void initSetting(File setting) {
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/Robot.java b/mirai-core/src/main/java/net/mamoe/mirai/Robot.java
index fa6d90e37..20b6c922a 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/Robot.java
+++ b/mirai-core/src/main/java/net/mamoe/mirai/Robot.java
@@ -9,11 +9,13 @@ import net.mamoe.mirai.utils.config.MiraiConfigSection;
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.LinkedList;
 import java.util.List;
 
 public class Robot {
+    public static final List<Robot> instances = Collections.synchronizedList(new LinkedList<>());
 
-    private final int qqNumber;
+    private final long qqNumber;
     private final String password;
     @Getter
     private final RobotNetworkHandler handler;
@@ -31,38 +33,41 @@ public class Robot {
         return owners.contains(ownerName);
     }
 
+    public long getQQNumber() {
+        return qqNumber;
+    }
 
     public Robot(MiraiConfigSection<Object> data) throws Throwable {
         this(
-                data.getIntOrThrow("account", () -> new IllegalArgumentException("account")),
+                data.getLongOrThrow("account", () -> new IllegalArgumentException("account")),
                 data.getStringOrThrow("password", () -> new IllegalArgumentException("password")),
                 data.getAsOrDefault("owners", ArrayList::new)
         );
 
     }
 
-    public Robot(int qqNumber, String password, List<String> owners) {
+    public Robot(long qqNumber, String password, List<String> owners) {
         this.qqNumber = qqNumber;
         this.password = password;
         this.owners = Collections.unmodifiableList(owners);
         this.handler = new RobotNetworkHandler(this, this.qqNumber, this.password);
     }
 
-    public QQ getQQ(int qqNumber) {
+    public QQ getQQ(long qqNumber) {
         if (!this.qqs.containsKey(qqNumber)) {
             this.qqs.put(qqNumber, new QQ(qqNumber));
         }
         return this.qqs.get(qqNumber);
     }
 
-    public Group getGroup(int groupNumber) {
+    public Group getGroup(long groupNumber) {
         if (!this.groups.containsKey(groupNumber)) {
             this.groups.put(groupNumber, new Group(groupNumber));
         }
         return groups.get(groupNumber);
     }
 
-    public Group getGroupByGroupId(int groupId) {
+    public Group getGroupByGroupId(long groupId) {
         return getGroup(Group.Companion.groupIdToNumber(groupId));
     }
 }
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt
index 844c5c050..fa1a475c1 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/Contact.kt
@@ -8,7 +8,7 @@ import net.mamoe.mirai.message.defaults.PlainText
  *
  * @author Him188moe
  */
-abstract class Contact(val number: Int) {
+abstract class Contact(val number: Long) {
 
     /**
      * Async
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt
index 835a1b0a2..2d8677058 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/Group.kt
@@ -3,14 +3,10 @@ package net.mamoe.mirai.contact
 import net.mamoe.mirai.message.Message
 import net.mamoe.mirai.utils.ContactList
 
-class Group(number: Int) : Contact(number) {
+class Group(number: Long) : Contact(number) {
     val groupId = groupNumberToId(number)
     val members = ContactList<QQ>()
 
-    init {
-        Instances.groups.add(this)
-    }
-
     override fun sendMessage(message: Message) {
 
     }
@@ -20,38 +16,38 @@ class Group(number: Int) : Contact(number) {
     }
 
     companion object {
-        fun groupNumberToId(number: Int): Int {
-            val left: Int = number.toString().let {
+        fun groupNumberToId(number: Long): Long {
+            val left: Long = number.toString().let {
                 if (it.length < 6) {
                     return@groupNumberToId number
                 }
-                it.substring(0, it.length - 6).toInt()
+                it.substring(0, it.length - 6).toLong()
             }
-            val right: Int = number.toString().let {
-                it.substring(it.length - 6).toInt()
+            val right: Long = number.toString().let {
+                it.substring(it.length - 6).toLong()
             }
 
             return when (left) {
                 in 1..10 -> {
-                    ((left + 202).toString() + right.toString()).toInt()
+                    ((left + 202).toString() + right.toString()).toLong()
                 }
                 in 11..19 -> {
-                    ((left + 469).toString() + right.toString()).toInt()
+                    ((left + 469).toString() + right.toString()).toLong()
                 }
                 in 20..66 -> {
-                    ((left + 208).toString() + right.toString()).toInt()
+                    ((left + 208).toString() + right.toString()).toLong()
                 }
                 in 67..156 -> {
-                    ((left + 1943).toString() + right.toString()).toInt()
+                    ((left + 1943).toString() + right.toString()).toLong()
                 }
                 in 157..209 -> {
-                    ((left + 199).toString() + right.toString()).toInt()
+                    ((left + 199).toString() + right.toString()).toLong()
                 }
                 in 210..309 -> {
-                    ((left + 389).toString() + right.toString()).toInt()
+                    ((left + 389).toString() + right.toString()).toLong()
                 }
                 in 310..499 -> {
-                    ((left + 349).toString() + right.toString()).toInt()
+                    ((left + 349).toString() + right.toString()).toLong()
                 }
                 else -> number
             }
@@ -62,60 +58,60 @@ class Group(number: Int) : Contact(number) {
             groupNumberToId(580266363)
         }
 
-        fun groupIdToNumber(id: Int): Int {
-            var left: Int = id.toString().let {
+        fun groupIdToNumber(id: Long): Long {
+            var left: Long = id.toString().let {
                 if (it.length < 6) {
                     return@groupIdToNumber id
                 }
-                it.substring(0 until it.length - 6).toInt()
+                it.substring(0 until it.length - 6).toLong()
             }
 
             return when (left) {
                 in 203..212 -> {
-                    val right: Int = id.toString().let {
-                        it.substring(it.length - 6).toInt()
+                    val right: Long = id.toString().let {
+                        it.substring(it.length - 6).toLong()
                     }
-                    ((left - 202).toString() + right.toString()).toInt()
+                    ((left - 202).toString() + right.toString()).toLong()
                 }
                 in 480..488 -> {
-                    val right: Int = id.toString().let {
-                        it.substring(it.length - 6).toInt()
+                    val right: Long = id.toString().let {
+                        it.substring(it.length - 6).toLong()
                     }
-                    ((left - 469).toString() + right.toString()).toInt()
+                    ((left - 469).toString() + right.toString()).toLong()
                 }
                 in 2100..2146 -> {
-                    val right: Int = id.toString().let {
-                        it.substring(it.length - 7).toInt()
+                    val right: Long = id.toString().let {
+                        it.substring(it.length - 7).toLong()
                     }
-                    left = left.toString().substring(0 until 3).toInt()
-                    ((left - 208).toString() + right.toString()).toInt()
+                    left = left.toString().substring(0 until 3).toLong()
+                    ((left - 208).toString() + right.toString()).toLong()
                 }
                 in 2010..2099 -> {
-                    val right: Int = id.toString().let {
-                        it.substring(it.length - 6).toInt()
+                    val right: Long = id.toString().let {
+                        it.substring(it.length - 6).toLong()
                     }
-                    ((left - 1943).toString() + right.toString()).toInt()
+                    ((left - 1943).toString() + right.toString()).toLong()
                 }
                 in 2147..2199 -> {
-                    val right: Int = id.toString().let {
-                        it.substring(it.length - 7).toInt()
+                    val right: Long = id.toString().let {
+                        it.substring(it.length - 7).toLong()
                     }
-                    left = left.toString().substring(0 until 3).toInt()
-                    ((left - 199).toString() + right.toString()).toInt()
+                    left = left.toString().substring(0 until 3).toLong()
+                    ((left - 199).toString() + right.toString()).toLong()
                 }
                 in 4100..4199 -> {
-                    val right: Int = id.toString().let {
-                        it.substring(it.length - 7).toInt()
+                    val right: Long = id.toString().let {
+                        it.substring(it.length - 7).toLong()
                     }
-                    left = left.toString().substring(0 until 3).toInt()
-                    ((left - 389).toString() + right.toString()).toInt()
+                    left = left.toString().substring(0 until 3).toLong()
+                    ((left - 389).toString() + right.toString()).toLong()
                 }
                 in 3800..3989 -> {
-                    val right: Int = id.toString().let {
-                        it.substring(it.length - 7).toInt()
+                    val right: Long = id.toString().let {
+                        it.substring(it.length - 7).toLong()
                     }
-                    left = left.toString().substring(0 until 3).toInt()
-                    ((left - 349).toString() + right.toString()).toInt()
+                    left = left.toString().substring(0 until 3).toLong()
+                    ((left - 349).toString() + right.toString()).toLong()
                 }
                 else -> id
             }
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/Lazy.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/Lazy.kt
deleted file mode 100644
index cecd6001c..000000000
--- a/mirai-core/src/main/java/net/mamoe/mirai/contact/Lazy.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package net.mamoe.mirai.contact
-
-
-fun Int.asQQ(): QQ = Instances.qqs.stream().filter { t: QQ? -> t?.number?.equals(this)!! }.findAny().orElse(QQ(this))!!
-
-fun Int.asGroup(): Group = Instances.groups.stream().filter { t: Group? -> t?.number?.equals(this)!! }.findAny().orElse(Group(this))!!
-
-fun String.withImage(id: String, type: String) = "{$id}.$type"
-
-fun String.withAt(qq: Int) = qq.asQQ().at()
-
-fun String.withAt(qq: QQ) = qq.at()
-
-object Instances {
-    var qqs = arrayListOf<QQ>()
-    var groups = arrayListOf<Group>()
-}
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt b/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt
index 5638a2de2..e7a0cf537 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/contact/QQ.kt
@@ -6,10 +6,7 @@ import net.mamoe.mirai.message.defaults.At
 /**
  * @author Him188moe
  */
-class QQ(number: Int) : Contact(number) {
-    init {
-        Instances.qqs.add(this)
-    }
+class QQ(number: Long) : Contact(number) {
 
     override fun sendMessage(message: Message) {
 
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java
index 088a98a30..003d40850 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java
+++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.java
@@ -10,17 +10,17 @@ import java.util.Objects;
  * @author Him188moe
  */
 public final class At extends Message {
-    private final int target;
+    private final long target;
 
     public At(@NotNull QQ target) {
         this(Objects.requireNonNull(target).getNumber());
     }
 
-    public At(int target) {
+    public At(long target) {
         this.target = target;
     }
 
-    public int getTarget() {
+    public long getTarget() {
         return target;
     }
 
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt
index 7d28047fc..0db821a4f 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/RobotNetworkHandler.kt
@@ -1,6 +1,5 @@
 package net.mamoe.mirai.network
 
-import net.mamoe.mirai.MiraiServer
 import net.mamoe.mirai.Robot
 import net.mamoe.mirai.contact.Group
 import net.mamoe.mirai.event.events.qq.FriendMessageEvent
@@ -10,12 +9,8 @@ import net.mamoe.mirai.network.packet.login.*
 import net.mamoe.mirai.network.packet.message.ClientSendGroupMessagePacket
 import net.mamoe.mirai.network.packet.message.ServerSendFriendMessageResponsePacket
 import net.mamoe.mirai.network.packet.message.ServerSendGroupMessageResponsePacket
-import net.mamoe.mirai.network.packet.verification.ServerVerificationCodePacket
-import net.mamoe.mirai.network.packet.verification.ServerVerificationCodePacketEncrypted
 import net.mamoe.mirai.task.MiraiThreadPool
 import net.mamoe.mirai.utils.*
-import java.io.ByteArrayInputStream
-import java.io.FileOutputStream
 import java.net.DatagramPacket
 import java.net.DatagramSocket
 import java.net.InetSocketAddress
@@ -28,9 +23,7 @@ import java.util.concurrent.TimeUnit
  * @author Him188moe
  */
 @ExperimentalUnsignedTypes
-class RobotNetworkHandler(val robot: Robot, val number: Int, private val password: String) {
-
-    private var sequence: Int = 0
+class RobotNetworkHandler(val robot: Robot, val number: Long, private val password: String) {
 
     var socket: DatagramSocket = DatagramSocket((15314 + Math.random() * 100).toInt())
 
@@ -39,33 +32,7 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
             serverAddress = InetSocketAddress(value, 8000)
             field = value
 
-            socket.close()
-            socket = DatagramSocket((15314 + Math.random() * 100).toInt())
-            socket.connect(this.serverAddress)
-            val zeroByte: Byte = 0
-            Thread {
-                while (true) {
-                    val dp1 = DatagramPacket(ByteArray(2048), 2048)
-                    try {
-                        socket.receive(dp1)
-                    } catch (e: Exception) {
-                        if (e.message == "socket closed") {
-                            return@Thread
-                        }
-                    }
-                    MiraiThreadPool.getInstance().submit {
-                        var i = dp1.data.size - 1;
-                        while (dp1.data[i] == zeroByte) {
-                            --i
-                        }
-                        try {
-                            onPacketReceived(ServerPacket.ofByteArray(dp1.data.copyOfRange(0, i + 1)))
-                        } catch (e: Exception) {
-                            e.printStackTrace()
-                        }
-                    }
-                }
-            }.start()
+            restartSocket()
         }
 
     private lateinit var serverAddress: InetSocketAddress
@@ -78,6 +45,10 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
     private var tlv0105: ByteArray
     private lateinit var _0828_rec_decr_key: ByteArray
 
+    private var verificationCodeSequence: Int = 0//这两个验证码使用
+    private var verificationCodeCache: ByteArray? = null//每次包只发一部分验证码来
+    private var verificationCodeCacheCount: Int = 0//
+    private lateinit var verificationToken: ByteArray
 
     private lateinit var sessionKey: ByteArray//这两个是登录成功后得到的
     private lateinit var sKey: String
@@ -104,6 +75,40 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
     private var md5_32: ByteArray = getRandomKey(32)
 
 
+    internal fun touch() {
+        this.sendPacket(ClientTouchPacket(this.number, this.serverIP))
+    }
+
+    private fun restartSocket() {
+        socket.close()
+        socket = DatagramSocket((15314 + Math.random() * 100).toInt())
+        socket.connect(this.serverAddress)
+        val zeroByte: Byte = 0
+        Thread {
+            while (true) {
+                val dp1 = DatagramPacket(ByteArray(2048), 2048)
+                try {
+                    socket.receive(dp1)
+                } catch (e: Exception) {
+                    if (e.message == "socket closed") {
+                        return@Thread
+                    }
+                }
+                MiraiThreadPool.getInstance().submit {
+                    var i = dp1.data.size - 1;
+                    while (dp1.data[i] == zeroByte) {
+                        --i
+                    }
+                    try {
+                        onPacketReceived(ServerPacket.ofByteArray(dp1.data.copyOfRange(0, i + 1)))
+                    } catch (e: Exception) {
+                        e.printStackTrace()
+                    }
+                }
+            }
+        }.start()
+    }
+
     @ExperimentalUnsignedTypes
     internal fun onPacketReceived(packet: ServerPacket) {
         packet.decode()
@@ -131,22 +136,44 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
                 return
             }
 
-            is ServerLoginResponseVerificationCodePacket -> {
+            is ServerLoginResponseVerificationCodeInitPacket -> {
                 //[token00BA]来源之一: 验证码
                 this.token00BA = packet.token00BA
+                this.verificationCodeCache = packet.verifyCodePart1
 
-                with(MiraiServer.getInstance().parentFolder + "verifyCode.png") {
-                    ByteArrayInputStream(packet.verifyCode).transferTo(FileOutputStream(this))
-                    println("验证码已写入到 " + this.path)
-                }
 
                 if (packet.unknownBoolean != null && packet.unknownBoolean!!) {
-                    this.sequence = 1
-                    sendPacket(ClientLoginVerificationCodePacket(this.number, this.token0825, this.sequence, this.token00BA))
+                    this.verificationCodeSequence = 1
+                    sendPacket(ClientVerificationCodeTransmissionRequestPacket(1, this.number, this.token0825, this.verificationCodeSequence, this.token00BA))
                 }
 
             }
 
+            is ServerVerificationCodeRepeatPacket -> {//todo 这个名字正确么
+                this.tgtgtKey = packet.tgtgtKeyUpdate
+                this.token00BA = packet.token00BA
+                sendPacket(ClientLoginResendPacket3105(this.number, this.password, this.loginTime, this.loginIP, this.tgtgtKey!!, this.token0825, this.token00BA))
+            }
+
+            is ServerVerificationCodeTransmissionPacket -> {
+                this.verificationCodeSequence = 0
+                this.verificationCodeCache = this.verificationCodeCache!! + packet.verificationCodePart2
+
+                this.verificationToken = packet.verificationToken
+                this.verificationCodeCacheCount = packet.count
+
+                this.token00BA = packet.token00BA
+                this.verificationCodeCache
+
+
+                if (packet.transmissionCompleted) {
+                    this.verificationCodeCache
+                    TODO("验证码好了")
+                } else {
+                    sendPacket(ClientVerificationCodeTransmissionRequestPacket(packet.count, this.number, this.token0825, this.verificationCodeSequence, this.token00BA))
+                }
+            }
+
             is ServerLoginResponseSuccessPacket -> {
                 this._0828_rec_decr_key = packet._0828_rec_decr_key
                 sendPacket(ClientSessionRequestPacket(this.number, this.serverIP, this.loginIP, this.md5_32, packet.token38, packet.token88, packet.encryptionKey, this.tlv0105))
@@ -190,10 +217,6 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
                 }
             }
 
-            is ServerVerificationCodePacket -> {
-                this.sequence++
-
-            }
 
             is ServerSessionKeyResponsePacket -> {
                 this.sessionKey = packet.sessionKey
@@ -267,7 +290,7 @@ class RobotNetworkHandler(val robot: Robot, val number: Int, private val passwor
 
             is ServerMessageEventPacketRaw -> onPacketReceived(packet.analyze())
 
-            is ServerVerificationCodePacketEncrypted -> onPacketReceived(packet.decrypt(this.token00BA))
+            is ServerVerificationCodePacketEncrypted -> onPacketReceived(packet.decrypt())
             is ServerLoginResponseVerificationCodePacketEncrypted -> onPacketReceived(packet.decrypt())
             is ServerLoginResponseResendPacketEncrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!))
             is ServerLoginResponseSuccessPacketEncrypted -> onPacketReceived(packet.decrypt(this.tgtgtKey!!))
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt
index 85ffc41dc..90d50c89e 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/AccountInfo.kt
@@ -12,7 +12,7 @@ import java.io.DataInputStream
 @ExperimentalUnsignedTypes
 @PacketId("00 5C")
 class ClientAccountInfoRequestPacket(
-        private val qq: Int,
+        private val qq: Long,
         private val sessionKey: ByteArray
 ) : ClientPacket() {
     override fun encode() {
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt
index 29682026d..6c18807e8 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ClientPacket.kt
@@ -119,13 +119,18 @@ fun DataOutputStream.encryptAndWrite(key: ByteArray, encoder: (ByteArrayDataOutp
     this.write(TEACryptor.encrypt(ByteArrayDataOutputStream().let { encoder(it); it.toByteArray() }, key))
 }
 
+@ExperimentalUnsignedTypes
+fun DataOutputStream.encryptAndWrite(keyHex: String, encoder: (ByteArrayDataOutputStream) -> Unit) {
+    this.encryptAndWrite(keyHex.hexToBytes(), encoder)
+}
+
 fun DataOutputStream.encryptAndWrite(cryptor: TEACryptor, encoder: (ByteArrayDataOutputStream) -> Unit) {
     this.write(cryptor.encrypt(ByteArrayDataOutputStream().let { encoder(it); it.toByteArray() }))
 }
 
 @ExperimentalUnsignedTypes
 @Throws(IOException::class)
-fun DataOutputStream.writeTLV0006(qq: Int, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray) {
+fun DataOutputStream.writeTLV0006(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray) {
     ByteArrayDataOutputStream().let {
         it.writeHex("12 12 12 12")//it.writeRandom(4) todo
         it.writeHex("00 02")
@@ -134,7 +139,7 @@ fun DataOutputStream.writeTLV0006(qq: Int, password: String, loginTime: Int, log
         it.writeHex("00 00 01")
 
         val md5_1 = md5(password);
-        val md5_2 = md5(md5_1 + "00 00 00 00".hexToBytes() + qq.toByteArray())
+        val md5_2 = md5(md5_1 + "00 00 00 00".hexToBytes() + qq.toUInt().toByteArray())
         println(md5_1.toUByteArray().toUHexString())
         println(md5_2.toUByteArray().toUHexString())
         it.write(md5_1)
@@ -193,6 +198,17 @@ fun Int.toByteArray(): ByteArray = byteArrayOf(
         (this.ushr(0) and 0xFF).toByte()
 )
 
+/**
+ * 255u -> 00 00 00 FF
+ */
+@ExperimentalUnsignedTypes
+fun UInt.toByteArray(): ByteArray = byteArrayOf(
+        (this.shr(24) and 255u).toByte(),
+        (this.shr(16) and 255u).toByte(),
+        (this.shr(8) and 255u).toByte(),
+        (this.shr(0) and 255u).toByte()
+)
+
 /**
  * 255 -> FF 00 00 00
  */
@@ -225,7 +241,14 @@ fun DataOutputStream.writeRandom(length: Int) {
     }
 }
 
+@ExperimentalUnsignedTypes
 @Throws(IOException::class)
-fun DataOutputStream.writeQQ(qq: Int) {
-    this.writeInt(qq)
+fun DataOutputStream.writeQQ(qq: Long) {
+    this.write(qq.toUInt().toByteArray())
+}
+
+@ExperimentalUnsignedTypes
+@Throws(IOException::class)
+fun DataOutputStream.writeGroup(groupIdOrGroupNumber: Long) {
+    this.write(groupIdOrGroupNumber.toUInt().toByteArray())
 }
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt
index 8a40a441d..d8b1b8040 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Heartbeat.kt
@@ -10,7 +10,7 @@ import java.io.IOException
 @ExperimentalUnsignedTypes
 @PacketId("00 58")
 class ClientHeartbeatPacket(
-        private val qq: Int,
+        private val qq: Long,
         private val sessionKey: ByteArray
 ) : ClientPacket() {
     @Throws(IOException::class)
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/MessageEvent.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/MessageEvent.kt
index 2657662ee..001cf7571 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/MessageEvent.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/MessageEvent.kt
@@ -12,7 +12,7 @@ import java.io.DataInputStream
 @PacketId("")//随后写入
 @ExperimentalUnsignedTypes
 class ClientMessageResponsePacket(
-        private val qq: Int,
+        private val qq: Long,
         private val packetIdFromServer: ByteArray,
         private val sessionKey: ByteArray,
         private val eventIdentity: ByteArray
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt
index c5a1d4905..76b181fca 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/SKey.kt
@@ -11,7 +11,7 @@ import java.io.DataInputStream
 @ExperimentalUnsignedTypes
 @PacketId("00 1D")
 class ClientSKeyRequestPacket(
-        private val qq: Int,
+        private val qq: Long,
         private val sessionKey: ByteArray
 ) : ClientPacket() {
     override fun encode() {
@@ -31,7 +31,7 @@ class ClientSKeyRequestPacket(
 @PacketId("00 1D")
 @ExperimentalUnsignedTypes
 class ClientSKeyRefreshmentRequestPacket(
-        private val qq: Int,
+        private val qq: Long,
         private val sessionKey: ByteArray
 ) : ClientPacket() {
     override fun encode() {
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt
index 8d73cc493..02fcfc719 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerEvent.kt
@@ -39,8 +39,8 @@ class ServerGroupUploadFileEventPacket(input: DataInputStream, packetId: ByteArr
 }
 
 class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) {
-    var groupNumber: Int = 0
-    var qq: Int = 0
+    var groupNumber: Long = 0
+    var qq: Long = 0
     lateinit var message: String
     lateinit var messageType: MessageType
 
@@ -58,9 +58,10 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray,
         OTHER,
     }
 
+    @ExperimentalUnsignedTypes
     override fun decode() {
-        groupNumber = this.input.goto(51).readInt()
-        qq = this.input.goto(56).readInt()
+        groupNumber = this.input.goto(51).readInt().toLong()
+        qq = this.input.goto(56).readLong().toUInt().toLong()
         val fontLength = this.input.goto(108).readShort()
         //println(this.input.goto(110 + fontLength).readNBytesAt(2).toUHexString())//always 00 00
 
@@ -142,7 +143,7 @@ class ServerGroupMessageEventPacket(input: DataInputStream, packetId: ByteArray,
 }
 
 class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) {
-    var qq: Int = 0
+    var qq: Long = 0
     lateinit var message: MessageChain
 
 
@@ -153,7 +154,7 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
         println(input.readAllBytes().toUHexString())
         input.goto(0)
 
-        qq = input.readIntAt(0)
+        qq = input.readIntAt(0).toLong()
         val msgLength = input.readShortAt(22)
         val fontLength = input.readShortAt(93 + msgLength)
         val offset = msgLength + fontLength
@@ -164,6 +165,11 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
     }
 
 }
+/*
+3E 03 3F A2 76 E4 B8 DD 00 09 7C 3F 64 5C 2A 60 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 02 38 03 3E 03 3F A2 76 E4 B8 DD 01 10 9D D6 12 EA BC 07 91 EF DC 29 75 67 A9 1E 00 0B 2F E4 5D 6B A8 F6 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 6B A8 F6 08 7E 90 CE 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
+3E 03 3F A2 76 E4 B8 DD 00 03 5F 85 64 5C 2A A4 1F 40 00 A6 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 02 38 03 3E 03 3F A2 76 E4 B8 DD 01 10 9D D6 12 EA BC 07 91 EF DC 29 75 67 A9 1E 00 0B 2F E5 5D 6B A9 16 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D 6B A9 17 1B B3 4D D7 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E7 89 9B E9 80 BC 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
+
+ */
 
 /*
 
@@ -171,7 +177,7 @@ class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray
 backup
 
 class ServerFriendMessageEventPacket(input: DataInputStream, packetId: ByteArray, eventIdentity: ByteArray) : ServerEventPacket(input, packetId, eventIdentity) {
-    var qq: Int = 0
+    var qq: Long = 0
     lateinit var message: String
 
 
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt
index c3e0e2e3a..ced9db2b2 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/ServerPacket.kt
@@ -3,7 +3,6 @@ package net.mamoe.mirai.network.packet
 import net.mamoe.mirai.network.packet.login.*
 import net.mamoe.mirai.network.packet.message.ServerSendFriendMessageResponsePacket
 import net.mamoe.mirai.network.packet.message.ServerSendGroupMessageResponsePacket
-import net.mamoe.mirai.network.packet.verification.ServerVerificationCodePacketEncrypted
 import net.mamoe.mirai.utils.getAllDeclaredFields
 import net.mamoe.mirai.utils.hexToBytes
 import net.mamoe.mirai.utils.toUHexString
@@ -150,6 +149,15 @@ fun <N : Number> DataInputStream.readNBytesAt(position: N, length: Int): ByteArr
     return this.readNBytes(length)
 }
 
+fun <N : Number> DataInputStream.readNBytes(length: N): ByteArray {
+    return this.readNBytes(length.toInt())
+}
+
+fun DataInputStream.readNBytesIn(range: IntRange): ByteArray {
+    this.goto(range.first)
+    return this.readNBytes(range.last - range.first + 1)
+}
+
 fun <N : Number> DataInputStream.readIntAt(position: N): Int {
     this.goto(position)
     return this.readInt();
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt
index a6eb7bf81..4f55c4e88 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Session.kt
@@ -14,7 +14,7 @@ import java.net.InetAddress
 @ExperimentalUnsignedTypes
 @PacketId("08 28 04 34")
 class ClientSessionRequestPacket(
-        private val qq: Int,
+        private val qq: Long,
         private val serverIp: String,
         private val loginIP: String,
         private val md5_32: ByteArray,
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt
index 5654f791c..bf3624e84 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/Touch.kt
@@ -76,7 +76,7 @@ class ServerTouchResponsePacketEncrypted(private val type: ServerTouchResponsePa
  */
 @ExperimentalUnsignedTypes
 @PacketId("08 25 31 01")
-class ClientTouchPacket(val qq: Int, val serverIp: String) : ClientPacket() {
+class ClientTouchPacket(val qq: Long, val serverIp: String) : ClientPacket() {
     @ExperimentalUnsignedTypes
     @Throws(IOException::class)
     override fun encode() {
@@ -108,7 +108,7 @@ class ClientTouchPacket(val qq: Int, val serverIp: String) : ClientPacket() {
  */
 @ExperimentalUnsignedTypes
 @PacketId("08 25 31 02")
-class ClientServerRedirectionPacket(private val serverIP: String, private val qq: Int) : ClientPacket() {
+class ClientServerRedirectionPacket(private val serverIP: String, private val qq: Long) : ClientPacket() {
     @ExperimentalUnsignedTypes
     override fun encode() {
         this.writeQQ(qq)
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt
new file mode 100644
index 000000000..4684f356b
--- /dev/null
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/VerificationCode.kt
@@ -0,0 +1,98 @@
+package net.mamoe.mirai.network.packet
+
+import net.mamoe.mirai.network.Protocol
+import net.mamoe.mirai.utils.*
+import java.io.DataInputStream
+
+
+@ExperimentalUnsignedTypes
+@PacketId("00 BA 31")
+class ClientVerificationCodeTransmissionRequestPacket(//todo 这个包可能有问题.
+        private val count: Int,
+        private val qq: Long,
+        private val token0825: ByteArray,
+        private val verificationSequence: Int,
+        private val token00BA: ByteArray
+) : ClientPacket() {
+    override fun encode() {
+        this.writeByte(count)//part of packet id
+
+        this.writeQQ(qq)
+        this.writeHex(Protocol._fixVer)
+        this.writeHex(Protocol._00BaKey)
+        this.encryptAndWrite(Protocol._00BaKey) {
+            it.writeHex("00 02 00 00 08 04 01 E0")
+            it.writeHex(Protocol._0825data2)
+            it.writeHex("00 00 38")
+            it.write(token0825)
+            it.writeHex("01 03 00 19")
+            it.writeHex(Protocol.publicKey)
+            it.writeHex("13 00 05 00 00 00 00")
+            it.writeByte(verificationSequence)
+            it.writeHex("00 28")
+            it.write(token00BA)
+            it.writeHex("00 10")
+            it.writeHex(Protocol._00BaFixKey)
+        }
+    }
+}
+
+/**
+ * @author Him188moe
+ */
+class ServerVerificationCodeTransmissionPacket(input: DataInputStream, val dataSize: Int, val packetId: ByteArray) : ServerVerificationCodePacket(input) {
+
+    lateinit var verificationCodePart2: ByteArray
+    lateinit var verificationToken: ByteArray//56bytes
+    var transmissionCompleted: Boolean = false//验证码是否已经传输完成
+    lateinit var token00BA: ByteArray//40 bytes
+    var count: Int = 0
+
+    @ExperimentalUnsignedTypes
+    override fun decode() {
+        this.verificationToken = this.input.readNBytesAt(10, 56)
+
+        val length = this.input.readShortAt(66)
+        this.verificationCodePart2 = this.input.readNBytes(length)
+
+        this.input.skip(2)
+        this.transmissionCompleted = this.input.readBoolean()
+
+        this.token00BA = this.input.readNBytesAt(dataSize - 57, 40)
+        this.count = byteArrayOf(0, 0, packetId[2], packetId[3]).toUHexString().hexToInt()
+    }
+}
+
+/**
+ * @author Him188moe
+ */
+class ServerVerificationCodeRepeatPacket(input: DataInputStream) : ServerVerificationCodePacket(input) {
+
+    lateinit var token00BA: ByteArray//56 bytes
+    lateinit var tgtgtKeyUpdate: ByteArray
+
+    @ExperimentalUnsignedTypes
+    override fun decode() {
+        token00BA = this.input.readNBytesAt(10, 56)
+        tgtgtKeyUpdate = getRandomKey(16)
+    }
+}
+
+abstract class ServerVerificationCodePacket(input: DataInputStream) : ServerPacket(input)
+
+class ServerVerificationCodePacketEncrypted(input: DataInputStream) : ServerPacket(input) {
+    override fun decode() {
+
+    }
+
+    @ExperimentalUnsignedTypes
+    fun decrypt(): ServerVerificationCodePacket {
+        this.input goto 14
+        val data = TEACryptor.decrypt(Protocol._00BaKey.hexToBytes(), this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) })
+        return if (data.size == 95) {
+            ServerVerificationCodeRepeatPacket(data.dataInputStream())
+        } else {
+            ServerVerificationCodeTransmissionPacket(data.dataInputStream(), data.size, this.input.readNBytesAt(3, 4))
+        }
+    }
+}
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginPacket.kt
index c58e1c6d4..2330c1d30 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginPacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginPacket.kt
@@ -18,7 +18,7 @@ import java.io.DataOutputStream
 @ExperimentalUnsignedTypes
 @TestedSuccessfully
 class ClientPasswordSubmissionPacket(
-        private val qq: Int,
+        private val qq: Long,
         private val password: String,
         private val loginTime: Int,
         private val loginIP: String,
@@ -43,17 +43,22 @@ class ClientPasswordSubmissionPacket(
 
 @PacketId("08 36 31 04")
 @ExperimentalUnsignedTypes
-class ClientLoginResendPacket3104(qq: Int, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv_0006_encr: ByteArray? = null)
+class ClientLoginResendPacket3104(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv_0006_encr: ByteArray? = null)
     : ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, tlv_0006_encr)
 
+@PacketId("08 36 31 05")
+@ExperimentalUnsignedTypes
+class ClientLoginResendPacket3105(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray)
+    : ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, null)
+
 @PacketId("08 36 31 06")
 @ExperimentalUnsignedTypes
-class ClientLoginResendPacket3106(qq: Int, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv_0006_encr: ByteArray? = null)
+class ClientLoginResendPacket3106(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, token00BA: ByteArray, tlv_0006_encr: ByteArray? = null)
     : ClientLoginResendPacket(qq, password, loginTime, loginIP, tgtgtKey, token0825, token00BA, tlv_0006_encr)
 
 @ExperimentalUnsignedTypes
 open class ClientLoginResendPacket internal constructor(
-        val qq: Int,
+        val qq: Long,
         val password: String,
         val loginTime: Int,
         val loginIP: String,
@@ -91,7 +96,7 @@ open class ClientLoginResendPacket internal constructor(
  * @author Him188moe
  */
 @ExperimentalUnsignedTypes
-private fun DataOutputStream.writePart1(qq: Int, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, tlv_0006_encr: ByteArray? = null) {
+private fun DataOutputStream.writePart1(qq: Long, password: String, loginTime: Int, loginIP: String, tgtgtKey: ByteArray, token0825: ByteArray, tlv_0006_encr: ByteArray? = null) {
 
     //this.writeInt(System.currentTimeMillis().toInt())
     this.writeHex("01 12")//tag
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginStatusPacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginStatusPacket.kt
index e73b228d5..7c2b2eae3 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginStatusPacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginStatusPacket.kt
@@ -10,7 +10,7 @@ import net.mamoe.mirai.utils.ClientLoginStatus
 @ExperimentalUnsignedTypes
 @PacketId("00 EC")
 class ClientLoginStatusPacket(
-        private val qq: Int,
+        private val qq: Long,
         private val sessionKey: ByteArray,
         private val loginStatus: ClientLoginStatus
 
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginVerificationCodePacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginVerificationCodePacket.kt
deleted file mode 100644
index 751fa07bf..000000000
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ClientLoginVerificationCodePacket.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-package net.mamoe.mirai.network.packet.login
-
-import net.mamoe.mirai.network.Protocol
-import net.mamoe.mirai.network.packet.*
-import net.mamoe.mirai.utils.ByteArrayDataOutputStream
-import net.mamoe.mirai.utils.TEACryptor
-
-/**
- * @author Him188moe
- */
-@PacketId("00 BA 31 01")
-@ExperimentalUnsignedTypes
-class ClientLoginVerificationCodePacket(
-        private val qq: Int,
-        private val token0825: ByteArray,
-        private val sequence: Int,
-        private val token00BA: ByteArray
-) : ClientPacket() {
-    override fun encode() {
-        this.writeQQ(qq)
-        this.writeHex(Protocol.fixVer)
-        this.writeHex(Protocol._00BaKey)
-        this.write(TEACryptor.CRYPTOR_00BAKEY.encrypt(object : ByteArrayDataOutputStream() {
-            override fun toByteArray(): ByteArray {
-                this.writeHex("00 02 00 00 08 04 01 E0")
-                this.writeHex(Protocol._0825data2)
-                this.writeHex("00 00 38")
-                this.write(token0825)
-                this.writeHex("01 03 00 19")
-                this.writeHex(Protocol.publicKey)
-                this.writeHex("13 00 05 00 00 00 00")
-                this.writeVarInt(sequence.toUInt())
-                this.writeHex("00 28")
-                this.write(token00BA)
-                this.writeHex("00 10")
-                this.writeHex(Protocol._00BaFixKey)
-                return super.toByteArray()
-            }
-        }.toByteArray()))
-    }
-}
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodePacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt
similarity index 61%
rename from mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodePacket.kt
rename to mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt
index 540b23f5a..1d6428c63 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodePacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/login/ServerLoginResponseVerificationCodeInitPacket.kt
@@ -7,19 +7,22 @@ import net.mamoe.mirai.utils.TEACryptor
 import java.io.DataInputStream
 
 /**
+ * 收到这个包意味着需要验证码登录, 并且能得到验证码图片文件的一半
+ *
  * @author Him188moe
  */
-class ServerLoginResponseVerificationCodePacket(input: DataInputStream, private val packetLength: Int) : ServerPacket(input) {
+class ServerLoginResponseVerificationCodeInitPacket(input: DataInputStream, private val packetLength: Int) : ServerPacket(input) {
 
-    lateinit var verifyCode: ByteArray
+    lateinit var verifyCodePart1: ByteArray
     lateinit var token00BA: ByteArray
     var unknownBoolean: Boolean? = null
+//todo 也有可能这个包有问题, 也有可能 ClientVerificationCodeTransmissionRequestPacket. 检查
 
 
     @ExperimentalUnsignedTypes
     override fun decode() {
         val verifyCodeLength = this.input.goto(78).readShort()//2bytes
-        this.verifyCode = this.input.readNBytes(verifyCodeLength.toInt())
+        this.verifyCodePart1 = this.input.readNBytes(verifyCodeLength.toInt())
 
         this.input.skip(1)
 
@@ -34,9 +37,9 @@ class ServerLoginResponseVerificationCodePacketEncrypted(input: DataInputStream)
 
     }
 
-    fun decrypt(): ServerLoginResponseVerificationCodePacket {
+    fun decrypt(): ServerLoginResponseVerificationCodeInitPacket {
         this.input goto 14
         val data = TEACryptor.CRYPTOR_SHARE_KEY.decrypt(this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) });
-        return ServerLoginResponseVerificationCodePacket(data.dataInputStream(), data.size)
+        return ServerLoginResponseVerificationCodeInitPacket(data.dataInputStream(), data.size)
     }
 }
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendFriendMessagePacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendFriendMessagePacket.kt
index 905d3fd9b..6fa63d04d 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendFriendMessagePacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendFriendMessagePacket.kt
@@ -11,10 +11,10 @@ import java.io.DataInputStream
 @PacketId("00 CD")
 @ExperimentalUnsignedTypes
 class ClientSendFriendMessagePacket(
-        val robotQQ: Int,
-        val targetQQ: Int,
-        val sessionKey: ByteArray,
-        val message: String
+        private val robotQQ: Long,
+        private val targetQQ: Long,
+        private val sessionKey: ByteArray,
+        private val message: String
 ) : ClientPacket() {
     override fun encode() {
         this.writeRandom(2)//part of packet id
@@ -52,7 +52,7 @@ class ClientSendFriendMessagePacket(
                 it.writeByte(0x01)
                 it.writeShort(bytes.size)
                 it.write(bytes)
-            }//todo check
+            }
         }
     }
 }
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendGroupMessagePacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendGroupMessagePacket.kt
index 315814a29..2ef2a85cc 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendGroupMessagePacket.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/message/ClientSendGroupMessagePacket.kt
@@ -12,8 +12,8 @@ import java.io.DataInputStream
 @PacketId("00 02")
 @ExperimentalUnsignedTypes
 class ClientSendGroupMessagePacket(
-        private val groupId: Int,//不是 number
-        private val qq: Int,
+        private val groupId: Long,//不是 number
+        private val qq: Long,
         private val sessionKey: ByteArray,
         private val message: String
 ) : ClientPacket() {
@@ -25,7 +25,7 @@ class ClientSendGroupMessagePacket(
         this.encryptAndWrite(sessionKey) {
             val bytes = message.toByteArray()
             it.writeByte(0x2A)
-            it.writeInt(groupId)
+            it.writeGroup(groupId)
             it.writeShort(56 + bytes.size)
 
             it.writeHex("00 01 01 00 00 00 00 00 00 00 4D 53 47 00 00 00 00 00")
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/verification/ServerVerificationCodePacket.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/packet/verification/ServerVerificationCodePacket.kt
deleted file mode 100644
index 710c1c2a0..000000000
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/packet/verification/ServerVerificationCodePacket.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-package net.mamoe.mirai.network.packet.verification
-
-import net.mamoe.mirai.network.packet.ServerPacket
-import net.mamoe.mirai.network.packet.dataInputStream
-import net.mamoe.mirai.network.packet.goto
-import net.mamoe.mirai.utils.TEACryptor
-import java.io.DataInputStream
-
-/**
- * @author Him188moe
- */
-class ServerVerificationCodePacket(input: DataInputStream) : ServerPacket(input) {
-
-    lateinit var verifyCode: ByteArray
-    lateinit var verifyToken: ByteArray
-    var unknownBoolean: Boolean? = null
-    lateinit var token00BA: ByteArray
-    var count: Int = 0
-
-    @ExperimentalUnsignedTypes
-    override fun decode() {
-        TODO()
-        val verifyCodeLength = this.input.goto(78).readShort()//2bytes
-        this.verifyCode = this.input.readNBytes(verifyCodeLength.toInt())
-
-        this.input.skip(1)
-
-        this.unknownBoolean = this.input.readByte().toInt() == 1
-
-        //this.token00BA = this.input.goto(packetLength - 60).readNBytesAt(40)
-    }
-}
-
-class ServerVerificationCodePacketEncrypted(input: DataInputStream) : ServerPacket(input) {
-    override fun decode() {
-
-    }
-
-    fun decrypt(token00BA: ByteArray): ServerVerificationCodePacket {
-        this.input goto 14
-        val data = TEACryptor.decrypt(token00BA, this.input.readAllBytes().let { it.copyOfRange(0, it.size - 1) });
-        return ServerVerificationCodePacket(data.dataInputStream())
-    }
-}
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/ContactList.java b/mirai-core/src/main/java/net/mamoe/mirai/utils/ContactList.java
index 2729890f2..6cfde9c52 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/utils/ContactList.java
+++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/ContactList.java
@@ -6,5 +6,5 @@ import net.mamoe.mirai.utils.config.MiraiSynchronizedLinkedListMap;
 /**
  * @author Him188moe
  */
-public class ContactList<C extends Contact> extends MiraiSynchronizedLinkedListMap<Integer, C> {
+public class ContactList<C extends Contact> extends MiraiSynchronizedLinkedListMap<Long, C> {
 }
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt b/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt
index 3fac69b21..72ceb4c1a 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/Utils.kt
@@ -20,6 +20,8 @@ fun ByteArray.toHexString(separator: String = " "): String = this.joinToString(s
 @ExperimentalUnsignedTypes
 fun ByteArray.toUHexString(separator: String = " "): String = this.toUByteArray().toUHexString(separator)
 
+fun ByteArray.__toUHexString(separator: String = " "): String = this.toUByteArray().toUHexString(separator)
+
 @ExperimentalUnsignedTypes
 fun ByteArray.toUHexString(): String = this.toUByteArray().toUHexString()
 
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/config/MiraiConfigSection.java b/mirai-core/src/main/java/net/mamoe/mirai/utils/config/MiraiConfigSection.java
index 196ddd59a..7005b3f59 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/utils/config/MiraiConfigSection.java
+++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/config/MiraiConfigSection.java
@@ -126,10 +126,10 @@ public class MiraiConfigSection<T> extends MiraiSynchronizedLinkedListMap<String
         return result==null?defaultV:result.toString();
     }
 
-    public String getStringOrThrow(String key, Callable<Throwable> throwableCallable) throws Throwable {
+    public String getStringOrThrow(String key, Supplier<Throwable> exceptionSupplier) throws Throwable {
         Object result = this.getOrDefault(key, null);
         if(result == null){
-            throw throwableCallable.call();
+            throw exceptionSupplier.get();
         }
         return result.toString();
     }
diff --git a/mirai-core/src/test/java/HexComparator.java b/mirai-core/src/test/java/HexComparator.java
index cabaeba5d..e3a1571ca 100644
--- a/mirai-core/src/test/java/HexComparator.java
+++ b/mirai-core/src/test/java/HexComparator.java
@@ -3,11 +3,17 @@ import lombok.AllArgsConstructor;
 import lombok.Getter;
 import lombok.ToString;
 import net.mamoe.mirai.network.Protocol;
+import net.mamoe.mirai.network.packet.ClientPacketKt;
+import net.mamoe.mirai.utils.UtilsKt;
 
+import java.awt.*;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
 import java.lang.reflect.Field;
 import java.util.Arrays;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Scanner;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.BiConsumer;
@@ -32,15 +38,24 @@ public class HexComparator {
 
     private static final String BLUE = "\033[34m";
 
-    public static final List<HexReader> consts  = new LinkedList<>(){{
+    public static final List<HexReader> consts = new LinkedList<>() {{
         add(new HexReader("90 5E 39 DF 00 02 76 E4 B8 DD 00"));
     }};
 
     private static class ConstMatcher {
         private static final List<Field> CONST_FIELDS = new LinkedList<>() {{
             List.of(Protocol.class).forEach(aClass -> Arrays.stream(aClass.getDeclaredFields()).peek(this::add).forEach(Field::trySetAccessible));
+            List.of(TestConsts.class).forEach(aClass -> Arrays.stream(aClass.getDeclaredFields()).peek(this::add).forEach(Field::trySetAccessible));
         }};
 
+        @SuppressWarnings({"unused", "NonAsciiCharacters"})
+        private static class TestConsts {
+            private static final String 牛逼 = UtilsKt.__toUHexString("牛逼".getBytes(), " ");
+            private static final String _1994701021 = ClientPacketKt.toHexString(1994701021, " ");
+            private static final String _1040400290 = ClientPacketKt.toHexString(1040400290, " ");
+            private static final String _580266363 = ClientPacketKt.toHexString(580266363, " ");
+        }
+
         private final List<Match> matches = new LinkedList<>();
 
         private ConstMatcher(String hex) {
@@ -89,6 +104,23 @@ public class HexComparator {
         }
     }
 
+    private static void buildConstNameChain(int length, ConstMatcher constMatcher, StringBuilder constNameBuilder) {
+        for (int i = 0; i < length; i++) {
+            constNameBuilder.append(" ");
+            String match = constMatcher.getMatchedConstName(i / 4);
+            if (match != null) {
+                int appendedNameLength = match.length();
+                constNameBuilder.append(match);
+                while (constMatcher.getMatchedConstName(i++ / 4) != null) {
+                    if (appendedNameLength-- <= 0) {
+                        constNameBuilder.append(" ");
+                    }
+                }
+
+            }
+        }
+    }
+
     private static String compare(String hex1s, String hex2s) {
         StringBuilder builder = new StringBuilder();
 
@@ -105,10 +137,17 @@ public class HexComparator {
 
 
         StringBuilder numberLine = new StringBuilder();
+        StringBuilder hex1ConstName = new StringBuilder();
         StringBuilder hex1b = new StringBuilder();
         StringBuilder hex2b = new StringBuilder();
+        StringBuilder hex2ConstName = new StringBuilder();
         int dif = 0;
 
+        int length = Math.max(hex1.length, hex2.length) * 4;
+        buildConstNameChain(length, constMatcher1, hex1ConstName);
+        buildConstNameChain(length, constMatcher2, hex2ConstName);
+
+
         for (int i = 0; i < Math.max(hex1.length, hex2.length); ++i) {
             String h1 = null;
             String h2 = null;
@@ -152,7 +191,7 @@ public class HexComparator {
                 }
             }
 
-            numberLine.append(UNKNOWN).append(getNumber(i)).append(" ");
+            numberLine.append(UNKNOWN).append(getFixedNumber(i)).append(" ");
             hex1b.append(" ").append(h1).append(" ");
             hex2b.append(" ").append(h2).append(" ");
             if (isDif) {
@@ -165,42 +204,46 @@ public class HexComparator {
 
         return (builder.append(" ").append(dif).append(" 个不同").append("\n")
                 .append(numberLine).append("\n")
+                .append(hex1ConstName).append("\n")
                 .append(hex1b).append("\n")
-                .append(hex2b))
+                .append(hex2b).append("\n")
+                .append(hex2ConstName).append("\n")
+        )
                 .toString();
 
 
     }
 
 
-    private static void doConstReplacement(StringBuilder builder){
+    private static void doConstReplacement(StringBuilder builder) {
         String mirror = builder.toString();
         HexReader hexs = new HexReader(mirror);
-        for (AtomicInteger i=new AtomicInteger(0);i.get()<builder.length();i.addAndGet(1)){
+        for (AtomicInteger i = new AtomicInteger(0); i.get() < builder.length(); i.addAndGet(1)) {
             hexs.setTo(i.get());
             consts.forEach(a -> {
                 hexs.setTo(i.get());
                 List<Integer> posToPlaceColor = new LinkedList<>();
                 AtomicBoolean is = new AtomicBoolean(false);
 
-                a.readFully((c,d) -> {
-                    if(c.equals(hexs.readHex())){
+                a.readFully((c, d) -> {
+                    if (c.equals(hexs.readHex())) {
                         posToPlaceColor.add(d);
-                    }else{
+                    } else {
                         is.set(false);
                     }
                 });
 
-                if(is.get()){
+                if (is.get()) {
                     AtomicInteger adder = new AtomicInteger();
                     posToPlaceColor.forEach(e -> {
-                        builder.insert(e + adder.getAndAdd(BLUE.length()),BLUE);
+                        builder.insert(e + adder.getAndAdd(BLUE.length()), BLUE);
                     });
                 }
             });
         }
     }
-    private static String getNumber(int number) {
+
+    private static String getFixedNumber(int number) {
         if (number < 10) {
             return "00" + number;
         }
@@ -210,8 +253,31 @@ public class HexComparator {
         return String.valueOf(number);
     }
 
-    public static void main(String[] args) {
+    private static String getClipboardString() {
+        Transferable trans = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null);
+        if (trans.isDataFlavorSupported(DataFlavor.stringFlavor)) {
+            try {
+                return (String) trans.getTransferData(DataFlavor.stringFlavor);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
 
+        return null;
+    }
+
+    public static void main(String[] args) {
+        Scanner scanner = new Scanner(System.in);
+        while (true) {
+            System.out.println("Hex1: ");
+            var hex1 = scanner.nextLine();
+            System.out.println("Hex2: ");
+            var hex2 = scanner.nextLine();
+            System.out.println("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
+            System.out.println(HexComparator.compare(hex1, hex2));
+            System.out.println();
+        }
+/*
         System.out.println(HexComparator.compare(
                 //mirai
 
@@ -230,66 +296,63 @@ public class HexComparator {
                 "6F 0B DF 92 00 02 76 E4 B8 DD 00 00 04 53 00 00 00 01 00 00 15 85 00 00 01 55 35 05 8E C9 BA 16 D0 01 63 5B 59 4B 59 52 31 01 B9 00 00 00 00 00 00 00 00 00 00 00 00 00 E9 E9 E9 E9 00 00 00 00 00 00 00 00 00 10 15 74 C4 89 85 7A 19 F5 5E A9 C9 A3 5E 8A 5A 9B AA BB CC DD EE FF AA BB CC\n\n\n"
         ));*/
     }
-
-
 }
 
-class HexReader{
+class HexReader {
     private String s;
     private int pos = 0;
     private int lastHaxPos = 0;
 
 
-    public HexReader(String s){
+    public HexReader(String s) {
         this.s = s;
     }
 
-    public String readHex(){
+    public String readHex() {
         boolean isStr = false;
         String next = "";
-        for (;pos<s.length()-2;++pos){
+        for (; pos < s.length() - 2; ++pos) {
 
             char s1 = ' ';
-            if(pos != 0){
+            if (pos != 0) {
                 s1 = this.s.charAt(0);
             }
-            char s2 = this.s.charAt(pos+1);
-            char s3 = this.s.charAt(pos+2);
+            char s2 = this.s.charAt(pos + 1);
+            char s3 = this.s.charAt(pos + 2);
             char s4 = ' ';
-            if(this.s.length() != (this.pos+3)){
-                s4 = this.s.charAt(pos+3);
+            if (this.s.length() != (this.pos + 3)) {
+                s4 = this.s.charAt(pos + 3);
             }
-            if(
+            if (
                     Character.isSpaceChar(s1) && Character.isSpaceChar(s4)
-                    &&
+                            &&
                             (Character.isDigit(s2) || Character.isAlphabetic(s2))
                             &&
                             (Character.isDigit(s3) || Character.isAlphabetic(s3))
-            ){
-                this.pos+=2;
-                this.lastHaxPos = this.pos+1;
-                return String.valueOf(s2) + String.valueOf(s3);
+            ) {
+                this.pos += 2;
+                this.lastHaxPos = this.pos + 1;
+                return String.valueOf(s2) + s3;
             }
         }
         return "";
     }
 
-    public void readFully(BiConsumer<String, Integer> processor){
+    public void readFully(BiConsumer<String, Integer> processor) {
         this.reset();
         String nextHax = this.readHex();
-        while (!nextHax.equals(" ")){
-            processor.accept(nextHax,this.lastHaxPos);
+        while (!nextHax.equals(" ")) {
+            processor.accept(nextHax, this.lastHaxPos);
             nextHax = this.readHex();
         }
     }
 
-    public void setTo(int pos){
+    public void setTo(int pos) {
         this.pos = pos;
     }
 
-    public void reset(){
+    public void reset() {
         this.pos = 0;
     }
-
 }
 
diff --git a/mirai-core/src/test/java/TestKt.kt b/mirai-core/src/test/java/TestKt.kt
new file mode 100644
index 000000000..42878b5dc
--- /dev/null
+++ b/mirai-core/src/test/java/TestKt.kt
@@ -0,0 +1,8 @@
+import net.mamoe.mirai.utils.toUHexString
+
+/**
+ * @author Him188moe
+ */
+fun main() {
+    println("牛逼".toByteArray().toUHexString())
+}
\ No newline at end of file