diff --git a/mirai-api/pom.xml b/mirai-api/pom.xml
index 116fae742..d21f6f18e 100644
--- a/mirai-api/pom.xml
+++ b/mirai-api/pom.xml
@@ -22,6 +22,14 @@
             <version>1.0</version>
             <scope>compile</scope>
         </dependency>
+
+
+        <dependency>
+            <groupId>net.mamoe</groupId>
+            <artifactId>mirai-console</artifactId>
+            <version>1.0</version>
+            <scope>compile</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/mirai-console/pom.xml b/mirai-console/pom.xml
index 35ba0a785..a30e768dc 100644
--- a/mirai-console/pom.xml
+++ b/mirai-console/pom.xml
@@ -18,7 +18,7 @@
 
         <dependency>
             <groupId>net.mamoe</groupId>
-            <artifactId>mirai-api</artifactId>
+            <artifactId>mirai-core</artifactId>
             <version>1.0</version>
             <scope>compile</scope>
         </dependency>
diff --git a/mirai-console/src/main/java/net/mamoe/mirai/MiraiConsole.java b/mirai-console/src/main/java/net/mamoe/mirai/MiraiConsole.java
index 4146bd06b..cc91a0203 100644
--- a/mirai-console/src/main/java/net/mamoe/mirai/MiraiConsole.java
+++ b/mirai-console/src/main/java/net/mamoe/mirai/MiraiConsole.java
@@ -1,13 +1,11 @@
 package net.mamoe.mirai;
 
-import java.util.Scanner;
-
 public class MiraiConsole {
 
 
     public static void main(String[] args){
         System.out.println(">>> starting Mirai");
-        MiraiAPI.startMirai(args);
+        // MiraiAPI.startMirai(args);
     }
 
     public static void processCommand(String command){
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/MiraiMain.java b/mirai-console/src/main/java/net/mamoe/mirai/MiraiMain.java
similarity index 100%
rename from mirai-core/src/main/java/net/mamoe/mirai/MiraiMain.java
rename to mirai-console/src/main/java/net/mamoe/mirai/MiraiMain.java
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java b/mirai-console/src/main/java/net/mamoe/mirai/MiraiServer.java
similarity index 98%
rename from mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java
rename to mirai-console/src/main/java/net/mamoe/mirai/MiraiServer.java
index a0dfc68f1..5819ca254 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/MiraiServer.java
+++ b/mirai-console/src/main/java/net/mamoe/mirai/MiraiServer.java
@@ -17,7 +17,6 @@ import net.mamoe.mirai.utils.setting.MiraiSettings;
 
 import java.io.File;
 import java.io.IOException;
-import java.util.List;
 import java.util.concurrent.ExecutionException;
 
 /**
@@ -197,12 +196,12 @@ public final class MiraiServer {
 
 
     String qqList =
-            "3034551466----zxcvbnm\n";
+            "1683921395----bb22222\n";
 
     private Bot getAvailableBot() throws ExecutionException, InterruptedException {
         for (String it : qqList.split("\n")) {
             var strings = it.split("----");
-            var bot = new Bot(new BotAccount(Long.parseLong(strings[0]), strings[1]), List.of());
+            var bot = new Bot(new BotAccount(Long.parseLong(strings[0]), strings[1]));
 
             if (bot.network.tryLogin(200).get() == LoginState.SUCCESS) {
                 MiraiLoggerKt.success(bot, "Login succeed");
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/Bot.java b/mirai-core/src/main/java/net/mamoe/mirai/Bot.java
index beda974d4..fe36237e2 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/Bot.java
+++ b/mirai-core/src/main/java/net/mamoe/mirai/Bot.java
@@ -1,17 +1,18 @@
 package net.mamoe.mirai;
 
-import lombok.Getter;
 import net.mamoe.mirai.contact.Group;
 import net.mamoe.mirai.contact.QQ;
 import net.mamoe.mirai.network.BotNetworkHandler;
 import net.mamoe.mirai.network.BotNetworkHandlerImpl;
 import net.mamoe.mirai.utils.BotAccount;
 import net.mamoe.mirai.utils.ContactList;
-import net.mamoe.mirai.utils.config.MiraiConfigSection;
 import org.jetbrains.annotations.NotNull;
 
 import java.io.Closeable;
-import java.util.*;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -58,7 +59,7 @@ public final class Bot implements Closeable {
 
     @Override
     public String toString() {
-        return String.format("Bot{id=%d,qq=%d}", id, this.account.qqNumber);
+        return String.format("Bot{id=%d,qq=%d}", id, this.account.getQqNumber());
     }
 
     /**
@@ -93,32 +94,9 @@ public final class Bot implements Closeable {
         }
     }
 
-
-    /**
-     * Ref list
-     */
-    @Getter
-    private final List<String> owners;
-
-    public boolean isOwnBy(String ownerName) {
-        return owners.contains(ownerName);
-    }
-
-    public Bot(MiraiConfigSection<Object> data) throws Throwable {
-        this(
-                new BotAccount(
-                        data.getLongOrThrow("account", () -> new IllegalArgumentException("account")),
-                        data.getStringOrThrow("password", () -> new IllegalArgumentException("password"))
-                ),
-                data.getAsOrDefault("owners", ArrayList::new)
-        );
-    }
-
-    public Bot(@NotNull BotAccount account, @NotNull List<String> owners) {
+    public Bot(@NotNull BotAccount account) {
         Objects.requireNonNull(account);
-        Objects.requireNonNull(owners);
         this.account = account;
-        this.owners = Collections.unmodifiableList(owners);
         this.network = new BotNetworkHandlerImpl(this);
     }
 
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/BotKt.kt b/mirai-core/src/main/java/net/mamoe/mirai/BotKt.kt
new file mode 100644
index 000000000..098c38b12
--- /dev/null
+++ b/mirai-core/src/main/java/net/mamoe/mirai/BotKt.kt
@@ -0,0 +1,29 @@
+package net.mamoe.mirai
+
+import net.mamoe.mirai.contact.Group
+import net.mamoe.mirai.contact.QQ
+import net.mamoe.mirai.network.packet.ClientPacket
+
+/**
+ * The mirror of functions in inner classes of [Bot]
+ *
+ * @author Him188moe
+ */
+
+//Contacts
+fun Bot.getQQ(number: Long): QQ = this.contacts.getQQ(number)
+
+fun Bot.getGroupByNumber(number: Long): Group = this.contacts.getGroupByNumber(number)
+
+fun Bot.getGroupById(number: Long): Group = this.contacts.getGroupById(number)
+
+
+//NetworkHandler
+suspend fun Bot.sendPacket(packet: ClientPacket) {
+    this.network.socket.sendPacket(packet)
+}
+
+
+//BotAccount
+
+fun Bot.getBotQQ(): Long = this.account.qqNumber
\ No newline at end of file
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 dcbb16107..774e089c3 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
@@ -38,6 +38,10 @@ abstract class Contact internal constructor(val bot: Bot, val number: Long) {
         this.sendMessage(PlainText(message))
     }
 
+    suspend fun sendMessage(message: List<Message>) {
+        this.sendMessage(MessageChain(message))
+    }
+
     /**
      * Async
      */
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManagerKt.kt b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManagerKt.kt
index 8acbb81c6..055cc60bb 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManagerKt.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/event/MiraiEventManagerKt.kt
@@ -3,6 +3,7 @@
 package net.mamoe.mirai.event
 
 import kotlinx.coroutines.runBlocking
+import net.mamoe.mirai.Bot
 import kotlin.reflect.KClass
 
 /**
@@ -19,7 +20,7 @@ object EventManager : MiraiEventManager()
 /**
  * 每次事件触发时都会调用 hook
  */
-fun <C : Class<E>, E : MiraiEvent> C.hookAlways(hook: suspend (E) -> Unit) {
+fun <C : Class<E>, E : MiraiEvent> C.hookAlways(bot: Bot? = null, hook: suspend (E) -> Unit) {
     MiraiEventManager.getInstance().hookAlways(MiraiEventHook<E>(this) {
         runBlocking {
             hook(it)
@@ -30,7 +31,8 @@ fun <C : Class<E>, E : MiraiEvent> C.hookAlways(hook: suspend (E) -> Unit) {
 /**
  * 当下一次事件触发时调用 hook
  */
-fun <C : Class<E>, E : MiraiEvent> C.hookOnce(hook: suspend (E) -> Unit) {
+fun <C : Class<E>, E : MiraiEvent> C.hookOnce(bot: Bot? = null, hook: suspend (E) -> Unit) {
+    //todo bot 限制 实现. 或重写 hook
     MiraiEventManager.getInstance().hookOnce(MiraiEventHook<E>(this) {
         runBlocking {
             hook(it)
@@ -41,30 +43,32 @@ fun <C : Class<E>, E : MiraiEvent> C.hookOnce(hook: suspend (E) -> Unit) {
 /**
  * 每次事件触发时都会调用 hook, 直到 hook 返回 false 时停止 hook
  */
-fun <C : Class<E>, E : MiraiEvent> C.hookWhile(hook: suspend (E) -> Boolean) {
+fun <C : Class<E>, E : MiraiEvent> C.hookWhile(bot: Bot? = null, hook: suspend (E) -> Boolean) {
     MiraiEventManager.getInstance().hookAlways(MiraiEventHookSimple(this, hook))
 }
 
 
 /**
  * 每次事件触发时都会调用 hook
+ *
+ * @param bot 指定仅限于某个 [Bot] 的事件.
  */
-fun <C : KClass<E>, E : MiraiEvent> C.hookAlways(hook: suspend (E) -> Unit) {
-    this.java.hookAlways(hook)
+fun <C : KClass<E>, E : MiraiEvent> C.hookAlways(bot: Bot? = null, hook: suspend (E) -> Unit) {
+    this.java.hookAlways(bot, hook)
 }
 
 /**
  * 当下一次事件触发时调用 hook
  */
-fun <C : KClass<E>, E : MiraiEvent> C.hookOnce(hook: suspend (E) -> Unit) {
-    this.java.hookOnce(hook)
+fun <C : KClass<E>, E : MiraiEvent> C.hookOnce(bot: Bot? = null, hook: suspend (E) -> Unit) {
+    this.java.hookOnce(bot, hook)
 }
 
 /**
  * 每次事件触发时都会调用 hook, 直到 hook 返回 false 时停止 hook
  */
-fun <C : KClass<E>, E : MiraiEvent> C.hookWhile(hook: suspend (E) -> Boolean) {
-    this.java.hookWhile(hook)
+fun <C : KClass<E>, E : MiraiEvent> C.hookWhile(bot: Bot? = null, hook: suspend (E) -> Boolean) {
+    this.java.hookWhile(bot, hook)
 }
 
 
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/Message.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/Message.kt
index 244b6a8e0..bb7a5c445 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/message/Message.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/message/Message.kt
@@ -15,8 +15,8 @@ import java.util.*
  * #### 在 Kotlin 使用 [Message]
  *  这与使用 [String] 的使用非常类似.
  *
- *  比较 [Message] 与 [String] (使用 infix [Message.valueEquals]):
- *  `if(message valueEquals "你好") qq.sendMessage(message)`
+ *  比较 [Message] 与 [String] (使用 infix [Message.eq]):
+ *  `if(message eq "你好") qq.sendMessage(message)`
  *
  *  连接 [Message] 与 [Message], [String], [BufferedImage] (使用 operator [Message.plus]):
  *  ```
@@ -28,7 +28,7 @@ import java.util.*
  * @see Contact.sendMessage
  */
 abstract class Message {
-    internal abstract val type: Int
+    internal abstract val type: MessageKey
 
     private var toStringCache: String? = null
     private val cacheLock = object : Any() {}
@@ -76,12 +76,17 @@ abstract class Message {
      * - [PlainText] 比较 [PlainText.text]
      * - [Image] 比较 [Image.imageId]
      */
-    abstract infix fun valueEquals(another: Message): Boolean
+    abstract infix fun eq(another: Message): Boolean
 
     /**
      * 将这个消息的 [toString] 与 [another] 比较
      */
-    infix fun valueEquals(another: String): Boolean = this.toString() == another
+    infix fun eq(another: String): Boolean = this.toString() == another
+
+    /**
+     * 判断 [sub] 是否存在于本消息中
+     */
+    abstract operator fun contains(sub: String): Boolean
 
     /**
      * 把这个消息连接到另一个消息的头部. 相当于字符串相加
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/MessageKey.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/MessageKey.kt
new file mode 100644
index 000000000..d42560334
--- /dev/null
+++ b/mirai-core/src/main/java/net/mamoe/mirai/message/MessageKey.kt
@@ -0,0 +1,8 @@
+package net.mamoe.mirai.message
+
+/**
+ * @author Him188moe
+ */
+open class MessageKey(
+        val intValue: Int
+)
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.kt
index 904e474cf..95796949e 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/At.kt
@@ -2,7 +2,7 @@ package net.mamoe.mirai.message.defaults
 
 import net.mamoe.mirai.contact.QQ
 import net.mamoe.mirai.message.Message
-import net.mamoe.mirai.message.MessageId
+import net.mamoe.mirai.message.MessageKey
 
 /**
  * At 一个人
@@ -10,7 +10,9 @@ import net.mamoe.mirai.message.MessageId
  * @author Him188moe
  */
 class At(val target: Long) : Message() {
-    override val type: Int = MessageId.AT
+    companion object Key : MessageKey(0x06)
+
+    override val type: MessageKey = Key
 
     constructor(target: QQ) : this(target.number)
 
@@ -20,7 +22,9 @@ class At(val target: Long) : Message() {
         TODO()
     }
 
-    override fun valueEquals(another: Message): Boolean {
+    override operator fun contains(sub: String): Boolean = false
+
+    override fun eq(another: Message): Boolean {
         if (another !is At) {
             return false
         }
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.kt
index a3edd2f3d..227f9111f 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Face.kt
@@ -2,7 +2,7 @@ package net.mamoe.mirai.message.defaults
 
 import net.mamoe.mirai.message.FaceID
 import net.mamoe.mirai.message.Message
-import net.mamoe.mirai.message.MessageId
+import net.mamoe.mirai.message.MessageKey
 import net.mamoe.mirai.network.packet.readLVNumber
 import net.mamoe.mirai.network.packet.writeHex
 import net.mamoe.mirai.network.packet.writeLVByteArray
@@ -15,14 +15,16 @@ import net.mamoe.mirai.utils.lazyEncode
  * @author Him188moe
  */
 class Face(val id: FaceID) : Message() {
-    override val type: Int = MessageId.FACE
+    companion object Key : MessageKey(0x02)
+
+    override val type: MessageKey = Key
 
     override fun toStringImpl(): String {
         return String.format("[face%d]", id.id)
     }
 
     override fun toByteArray(): ByteArray = lazyEncode { section ->
-        section.writeByte(this.type)
+        section.writeByte(this.type.intValue)
 
         section.writeLVByteArray(lazyEncode { child ->
             child.writeShort(1)
@@ -37,14 +39,16 @@ class Face(val id: FaceID) : Message() {
     }
 
 
-    override fun valueEquals(another: Message): Boolean {
+    override fun eq(another: Message): Boolean {
         if (another !is Face) {
             return false
         }
         return this.id == another.id
     }
 
-    companion object {
+    override operator fun contains(sub: String): Boolean = false
+
+    internal object PacketHelper {
         fun ofByteArray(data: ByteArray): Face = lazyDecode(data) {
             //00  01  AF  0B  00  08  00  01  00  04  52  CC  F5  D0  FF  00  02  14  F0
             //00  01  0C  0B  00  08  00  01  00  04  52  CC  F5  D0  FF  00  02  14  4D
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Image.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Image.kt
index c50cbcc7d..5b4e3be87 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Image.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/Image.kt
@@ -2,6 +2,7 @@ package net.mamoe.mirai.message.defaults
 
 import net.mamoe.mirai.message.Message
 import net.mamoe.mirai.message.MessageId
+import net.mamoe.mirai.message.MessageKey
 import net.mamoe.mirai.network.packet.*
 import net.mamoe.mirai.utils.lazyDecode
 import net.mamoe.mirai.utils.lazyEncode
@@ -16,8 +17,10 @@ import net.mamoe.mirai.utils.toUHexString
  *
  * @author Him188moe
  */
-open class Image internal constructor(val imageId: String) : Message() {
-    override val type: Int = MessageId.IMAGE
+open class Image(val imageId: String) : Message() {
+    companion object Key : MessageKey(0x03)
+
+    override val type: MessageKey = Key
 
     override fun toStringImpl(): String {
         return imageId
@@ -43,7 +46,7 @@ open class Image internal constructor(val imageId: String) : Message() {
         })
     }
 
-    override fun valueEquals(another: Message): Boolean {
+    override fun eq(another: Message): Boolean {
         if (another is Image) {
             return this.imageId == another.imageId
         }
@@ -51,7 +54,9 @@ open class Image internal constructor(val imageId: String) : Message() {
         return false
     }
 
-    companion object {
+    override operator fun contains(sub: String): Boolean = false //No string can be contained in a image
+
+    internal object PacketHelper {
         @JvmStatic
         fun ofByteArray0x06(data: ByteArray): Image = lazyDecode(data) {
             it.skip(1)
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.kt
index 27e9042fb..cbbbc87ce 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/MessageChain.kt
@@ -1,15 +1,17 @@
 package net.mamoe.mirai.message.defaults
 
 import net.mamoe.mirai.message.Message
-import net.mamoe.mirai.message.MessageId
+import net.mamoe.mirai.message.MessageKey
 import net.mamoe.mirai.utils.lazyEncode
-import org.intellij.lang.annotations.MagicConstant
 import java.util.*
 import java.util.stream.Collectors
 import java.util.stream.Stream
+import kotlin.reflect.KClass
 
 class MessageChain : Message {
-    override val type: Int = MessageId.CHAIN
+    companion object Key : MessageKey(0xff)//only used to compare
+
+    override val type: MessageKey = Key
 
     /**
      * Elements will not be instances of [MessageChain]
@@ -35,18 +37,19 @@ class MessageChain : Message {
 
     constructor()
 
+    /**
+     * 获取第一个这个类型的消息
+     */
+    operator fun get(type: MessageKey): Message? = list.firstOrNull { it.type == type }
+
     fun size(): Int {
         return list.size
     }
 
-    fun containsType(@MagicConstant(valuesFromClass = MessageId::class) type: Int): Boolean {
-        for (message in list) {
-            if (message.type == type) {
-                return true
-            }
-        }
-        return false
-    }
+    fun containsType(clazz: KClass<out Message>): Boolean = list.any { clazz.isInstance(it) }
+    fun containsType(clazz: Class<out Message>): Boolean = list.any { clazz.isInstance(it) }
+    operator fun contains(sub: KClass<out Message>): Boolean = containsType(sub)
+    operator fun contains(sub: Class<out Message>): Boolean = containsType(sub)
 
     fun stream(): Stream<Message> {
         return list.stream()
@@ -80,10 +83,16 @@ class MessageChain : Message {
         }
     }
 
-    override fun valueEquals(another: Message): Boolean {
+    override fun eq(another: Message): Boolean {
         if (another !is MessageChain) {
             return false
         }
         return this.list == another.list
     }
+
+    override operator fun contains(sub: String): Boolean = list.any { it.contains(sub) }
+
+    operator fun component1(): Message = this.list[0]
+    operator fun component2(): Message = this.list[1]
+    operator fun component3(): Message = this.list[2]
 }
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/PlainText.kt b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/PlainText.kt
index a6d089dbd..927a771c5 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/PlainText.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/message/defaults/PlainText.kt
@@ -1,7 +1,7 @@
 package net.mamoe.mirai.message.defaults
 
 import net.mamoe.mirai.message.Message
-import net.mamoe.mirai.message.MessageId
+import net.mamoe.mirai.message.MessageKey
 import net.mamoe.mirai.network.packet.readLVString
 import net.mamoe.mirai.network.packet.writeLVByteArray
 import net.mamoe.mirai.network.packet.writeLVString
@@ -12,14 +12,16 @@ import net.mamoe.mirai.utils.lazyEncode
  * @author Him188moe
  */
 class PlainText(private val text: String) : Message() {
-    override val type: Int = MessageId.TEXT
+    companion object Key : MessageKey(0x01)
+
+    override val type: MessageKey = Key
 
     override fun toStringImpl(): String {
         return text
     }
 
     override fun toByteArray(): ByteArray = lazyEncode { section ->
-        section.writeByte(this.type)
+        section.writeByte(this.type.intValue)
 
         section.writeLVByteArray(lazyEncode { child ->
             child.writeByte(0x01)
@@ -27,14 +29,16 @@ class PlainText(private val text: String) : Message() {
         })
     }
 
-    override fun valueEquals(another: Message): Boolean {
+    override fun eq(another: Message): Boolean {
         if (another !is PlainText) {
             return false
         }
         return this.text == another.text
     }
 
-    companion object {
+    override operator fun contains(sub: String): Boolean = this.toString().contains(sub)
+
+    internal object PacketHelper {
         fun ofByteArray(data: ByteArray): PlainText = lazyDecode(data) {
             it.skip(1)
             PlainText(it.readLVString())
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/BotNetworkHandlerImpl.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/BotNetworkHandlerImpl.kt
index cea484d44..5b3bcf282 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/BotNetworkHandlerImpl.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/BotNetworkHandlerImpl.kt
@@ -2,7 +2,6 @@ package net.mamoe.mirai.network
 
 import kotlinx.coroutines.*
 import net.mamoe.mirai.Bot
-import net.mamoe.mirai.MiraiServer
 import net.mamoe.mirai.event.events.bot.BotLoginSucceedEvent
 import net.mamoe.mirai.event.events.network.BeforePacketSendEvent
 import net.mamoe.mirai.event.events.network.PacketSentEvent
@@ -13,6 +12,7 @@ import net.mamoe.mirai.network.packet.login.*
 import net.mamoe.mirai.task.MiraiThreadPool
 import net.mamoe.mirai.utils.*
 import java.io.Closeable
+import java.io.File
 import java.net.DatagramPacket
 import java.net.DatagramSocket
 import java.net.InetSocketAddress
@@ -160,23 +160,23 @@ internal class BotNetworkHandlerImpl(private val bot: Bot) : BotNetworkHandler {
             socket?.close()
             socket = DatagramSocket(0)
             socket!!.connect(InetSocketAddress(serverIP, 8000))
-            Thread {
-                while (socket!!.isConnected) {
+            GlobalScope.launch {
+                while (socket?.isConnected == true) {
                     val packet = DatagramPacket(ByteArray(2048), 2048)
                     kotlin.runCatching { socket?.receive(packet) }
                             .onSuccess {
-                                GlobalScope.launch {
+                                NetworkScope.launch {
                                     distributePacket(ServerPacket.ofByteArray(packet.data.removeZeroTail()))
                                 }
                             }.onFailure {
                                 if (it.message == "Socket closed" || it.message == "socket closed") {
-                                    return@Thread
+                                    return@launch
                                 }
                                 it.printStackTrace()
                             }
 
                 }
-            }.start()
+            }
         }
 
 
@@ -323,11 +323,12 @@ internal class BotNetworkHandlerImpl(private val bot: Bot) : BotNetworkHandler {
                         }
                         bot.notice("需要验证码登录, 验证码为 4 字母")
                         try {
-                            (MiraiServer.getInstance().parentFolder + "VerificationCode.png").writeBytes(this.captchaCache!!)
-                            bot.notice("若看不清字符图片, 请查看 Mirai 根目录下 VerificationCode.png")
+                            File(System.getProperty("user.dir") + "/temp/Captcha.png").writeBytes(this.captchaCache!!)
+                            bot.notice("若看不清字符图片, 请查看 Mirai 目录下 /temp/Captcha.png")
                         } catch (e: Exception) {
                             bot.notice("无法写出验证码文件, 请尝试查看以上字符图片")
                         }
+                        this.captchaCache = null
                         bot.notice("若要更换验证码, 请直接回车")
                         val code = Scanner(System.`in`).nextLine()
                         if (code.isEmpty() || code.length != 4) {
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/network/handler/MessagePacketHandler.kt b/mirai-core/src/main/java/net/mamoe/mirai/network/handler/MessagePacketHandler.kt
index 796d50750..2520d0a54 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/network/handler/MessagePacketHandler.kt
+++ b/mirai-core/src/main/java/net/mamoe/mirai/network/handler/MessagePacketHandler.kt
@@ -4,10 +4,7 @@ import net.mamoe.mirai.contact.Group
 import net.mamoe.mirai.contact.QQ
 import net.mamoe.mirai.event.events.group.GroupMessageEvent
 import net.mamoe.mirai.event.events.qq.FriendMessageEvent
-import net.mamoe.mirai.event.hookWhile
-import net.mamoe.mirai.message.defaults.Image
 import net.mamoe.mirai.message.defaults.MessageChain
-import net.mamoe.mirai.message.defaults.PlainText
 import net.mamoe.mirai.network.LoginSession
 import net.mamoe.mirai.network.packet.ServerFriendMessageEventPacket
 import net.mamoe.mirai.network.packet.ServerGroupMessageEventPacket
@@ -27,47 +24,6 @@ import net.mamoe.mirai.network.packet.action.ServerSendGroupMessageResponsePacke
 class MessagePacketHandler(session: LoginSession) : PacketHandler(session) {
     internal var ignoreMessage: Boolean = true
 
-    init {
-        //todo for test
-        FriendMessageEvent::class.hookWhile {
-            if (session.socket.isClosed()) {
-                return@hookWhile false
-            }
-            when {
-                it.message valueEquals "你好" -> it.sender.sendMessage("你好!")
-                it.message.toString().startsWith("复读") -> it.sender.sendMessage(it.message())
-                it.message.toString().startsWith("发群") -> {
-                    it.message().list.toMutableList().let { messages ->
-                        messages.removeAt(0)
-                        sendGroupMessage(Group(session.bot, 580266363), MessageChain(messages))
-                    }
-                }
-                /*it.message valueEquals "发图片群" -> sendGroupMessage(Group(session.bot, 580266363), PlainText("test") + UnsolvedImage(File("C:\\Users\\Him18\\Desktop\\faceImage_1559564477775.jpg")).also { image ->
-                        image.upload(session, Group(session.bot, 580266363)).get()
-                    })*/
-                it.message valueEquals "发图片群2" -> sendGroupMessage(Group(session.bot, 580266363), Image("{7AA4B3AA-8C3C-0F45-2D9B-7F302A0ACEAA}.jpg").toChain())
-                /* it.message valueEquals "发图片" -> sendFriendMessage(it.sender, PlainText("test") + UnsolvedImage(File("C:\\Users\\Him18\\Desktop\\faceImage_1559564477775.jpg")).also { image ->
-                         image.upload(session, it.sender).get()
-                     })*/
-                it.message valueEquals "发图片2" -> sendFriendMessage(it.sender, PlainText("test") + Image("{7AA4B3AA-8C3C-0F45-2D9B-7F302A0ACEAA}.jpg"))
-            }
-
-            return@hookWhile true
-        }
-
-        GroupMessageEvent::class.hookWhile {
-            if (session.socket.isClosed()) {
-                return@hookWhile false
-            }
-
-            when {
-                it.message.contains("复读") -> it.group.sendMessage(it.chain)
-            }
-
-            return@hookWhile true
-        }
-    }
-
     override suspend fun onPacketReceived(packet: ServerPacket) {
         when (packet) {
             is ServerGroupUploadFileEventPacket -> {
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 fea131438..3579bd131 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
@@ -263,10 +263,10 @@ private fun DataInputStream.readSection(): Message? {
     val sectionLength = this.readShort().toLong()//sectionLength: short
     val sectionData = this.readNBytes(sectionLength)
     return when (messageType) {
-        0x01 -> PlainText.ofByteArray(sectionData)
-        0x02 -> Face.ofByteArray(sectionData)
-        0x03 -> Image.ofByteArray0x03(sectionData)
-        0x06 -> Image.ofByteArray0x06(sectionData)
+        0x01 -> PlainText.PacketHelper.ofByteArray(sectionData)
+        0x02 -> Face.PacketHelper.ofByteArray(sectionData)
+        0x03 -> Image.PacketHelper.ofByteArray0x03(sectionData)
+        0x06 -> Image.PacketHelper.ofByteArray0x06(sectionData)
 
 
         0x19 -> {//长文本
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/BotAccount.java b/mirai-core/src/main/java/net/mamoe/mirai/utils/BotAccount.java
deleted file mode 100644
index 5965a4178..000000000
--- a/mirai-core/src/main/java/net/mamoe/mirai/utils/BotAccount.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package net.mamoe.mirai.utils;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-
-@Data
-@AllArgsConstructor
-public class BotAccount {
-    public final long qqNumber;
-    public final String password;
-}
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/BotAccount.kt b/mirai-core/src/main/java/net/mamoe/mirai/utils/BotAccount.kt
new file mode 100644
index 000000000..bc7186e6a
--- /dev/null
+++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/BotAccount.kt
@@ -0,0 +1,9 @@
+package net.mamoe.mirai.utils
+
+/**
+ * @author Him188moe
+ */
+data class BotAccount(
+        val qqNumber: Long,
+        val password: String
+)
\ No newline at end of file
diff --git a/mirai-core/src/main/java/net/mamoe/mirai/utils/config/MiraiConfig.java b/mirai-core/src/main/java/net/mamoe/mirai/utils/config/MiraiConfig.java
index 106615e6f..d6bc415e7 100644
--- a/mirai-core/src/main/java/net/mamoe/mirai/utils/config/MiraiConfig.java
+++ b/mirai-core/src/main/java/net/mamoe/mirai/utils/config/MiraiConfig.java
@@ -1,7 +1,6 @@
 package net.mamoe.mirai.utils.config;
 
 import kotlin.io.FilesKt;
-import net.mamoe.mirai.MiraiServer;
 import org.jetbrains.annotations.NotNull;
 import org.yaml.snakeyaml.DumperOptions;
 import org.yaml.snakeyaml.Yaml;
@@ -24,10 +23,6 @@ public class MiraiConfig extends MiraiConfigSection<Object> {
 
     private final File root;
 
-    public MiraiConfig(@NotNull String configName) {
-        this(new File(MiraiServer.getInstance().getParentFolder(), Objects.requireNonNull(configName)));
-    }
-
     public MiraiConfig(@NotNull File file) {
         super(parse(Objects.requireNonNull(file)));
         this.root = file;
@@ -47,9 +42,10 @@ public class MiraiConfig extends MiraiConfigSection<Object> {
 
     @SuppressWarnings("unchecked")
     private static LinkedHashMap<String,Object> parse(File file) {
+        /*
         if (!file.toURI().getPath().contains(MiraiServer.getInstance().getParentFolder().getPath())) {
             file = new File(MiraiServer.getInstance().getParentFolder().getPath(), file.getName());
-        }
+        }*/
         if (!file.exists()) {
             try {
                 if (!file.createNewFile()) {
diff --git a/mirai-core/src/test/java/BadQQFilter.kt b/mirai-core/src/test/java/BadQQFilter.kt
index ed738dac8..27c992f5e 100644
--- a/mirai-core/src/test/java/BadQQFilter.kt
+++ b/mirai-core/src/test/java/BadQQFilter.kt
@@ -74,7 +74,7 @@ fun main() {
                     return@let password.substring(0, password.length - 1)
                 }
                 return@let password
-            }), listOf())
+            }))
 
             bot.network.tryLogin().whenComplete { state, _ ->
                 if (!(state == LoginState.BLOCKED || state == LoginState.DEVICE_LOCK || state == LoginState.WRONG_PASSWORD)) {
diff --git a/mirai-core/src/test/java/ConfigTest.java b/mirai-core/src/test/java/ConfigTest.java
deleted file mode 100644
index d8e883600..000000000
--- a/mirai-core/src/test/java/ConfigTest.java
+++ /dev/null
@@ -1,8 +0,0 @@
-import net.mamoe.mirai.MiraiServer;
-import net.mamoe.mirai.utils.config.MiraiConfig;
-
-public class ConfigTest {
-    public static void main(String[] args){
-        MiraiConfig config = new MiraiConfig("QQ.yml");
-    }
-}
diff --git a/mirai-demos/mirai-demo-1/pom.xml b/mirai-demos/mirai-demo-1/pom.xml
new file mode 100644
index 000000000..1928168a8
--- /dev/null
+++ b/mirai-demos/mirai-demo-1/pom.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>net.mamoe</groupId>
+        <artifactId>mirai-demos</artifactId>
+        <version>1.0</version>
+    </parent>
+
+    <artifactId>mirai-demo-1</artifactId>
+    <version>1.0</version>
+
+    <build>
+        <resources>
+            <resource>
+                <directory>/src/main/resources</directory>
+
+                <includes>
+                    <include>**/*.*</include>
+                </includes>
+            </resource>
+        </resources>
+
+        <plugins>
+
+            <plugin>
+                <groupId>org.jetbrains.kotlin</groupId>
+                <artifactId>kotlin-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>compile</id>
+                        <phase>compile</phase>
+                        <goals>
+                            <goal>compile</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jetbrains.kotlinx</groupId>
+            <artifactId>kotlinx-coroutines-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.jetbrains.kotlin</groupId>
+            <artifactId>kotlin-stdlib</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt b/mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt
new file mode 100644
index 000000000..e1a0f5a2a
--- /dev/null
+++ b/mirai-demos/mirai-demo-1/src/main/java/demo1/Main.kt
@@ -0,0 +1,65 @@
+package demo1
+
+import net.mamoe.mirai.Bot
+import net.mamoe.mirai.contact.Group
+import net.mamoe.mirai.event.events.group.GroupMessageEvent
+import net.mamoe.mirai.event.events.qq.FriendMessageEvent
+import net.mamoe.mirai.event.hookAlways
+import net.mamoe.mirai.message.defaults.Image
+import net.mamoe.mirai.message.defaults.PlainText
+import net.mamoe.mirai.network.packet.login.LoginState
+import net.mamoe.mirai.utils.BotAccount
+
+/**
+ * @author Him188moe
+ */
+fun main() {
+    val bot = Bot(BotAccount(
+            qqNumber = 1683921395,
+            password = "bb22222"
+    ))
+
+    bot.network.tryLogin().get().let {
+        check(it == LoginState.SUCCESS) { "Login failed: " + it.name }
+    }
+
+    //监听事件:
+    FriendMessageEvent::class.hookAlways {
+        //获取第一个纯文本消息
+        val firstText = it.message[PlainText]
+
+        //获取第一个图片
+        val firstImage = it.message[Image]
+
+        when {
+            it.message eq "你好" -> it.sender.sendMessage("你好!")
+
+            "复读" in it.message -> it.sender.sendMessage(it.message())
+
+            "发群" in it.message -> {
+                it.message().list.toMutableList().let { messages ->
+                    messages.removeAt(0)
+                    Group(bot, 580266363).sendMessage(messages)
+                }
+            }
+
+            /*it.message eq "发图片群" -> sendGroupMessage(Group(session.bot, 580266363), PlainText("test") + UnsolvedImage(File("C:\\Users\\Him18\\Desktop\\faceImage_1559564477775.jpg")).also { image ->
+                    image.upload(session, Group(session.bot, 580266363)).get()
+                })*/
+
+            it.message eq "发图片群2" -> Group(bot, 580266363).sendMessage(Image("{7AA4B3AA-8C3C-0F45-2D9B-7F302A0ACEAA}.jpg"))
+
+            /* it.message eq "发图片" -> sendFriendMessage(it.sender, PlainText("test") + UnsolvedImage(File("C:\\Users\\Him18\\Desktop\\faceImage_1559564477775.jpg")).also { image ->
+                     image.upload(session, it.sender).get()
+                 })*/
+
+            it.message eq "发图片2" -> it.sender.sendMessage(PlainText("test") + Image("{7AA4B3AA-8C3C-0F45-2D9B-7F302A0ACEAA}.jpg"))
+        }
+    }
+
+    GroupMessageEvent::class.hookAlways {
+        when {
+            it.message.contains("复读") -> it.group.sendMessage(it.chain)
+        }
+    }
+}
\ No newline at end of file
diff --git a/mirai-demos/pom.xml b/mirai-demos/pom.xml
new file mode 100644
index 000000000..74df657ee
--- /dev/null
+++ b/mirai-demos/pom.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>net.mamoe</groupId>
+        <artifactId>mirai</artifactId>
+        <version>1.0</version>
+    </parent>
+
+    <artifactId>mirai-demos</artifactId>
+    <version>1.0</version>
+
+    <modules>
+        <module>mirai-demo-1</module>
+    </modules>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>net.mamoe</groupId>
+            <artifactId>mirai-core</artifactId>
+            <version>1.0</version>
+            <scope>compile</scope>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 1e2441ae9..9da74c037 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,6 +14,7 @@
         <module>mirai-ui</module>
         <module>mirai-console</module>
         <module>mirai-api</module>
+        <module>mirai-demos</module>
     </modules>
 
     <repositories>