From 0016a04d5e12c87834cc8c5ec12264b3ee47f426 Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Sat, 22 Aug 2020 01:36:22 +0800
Subject: [PATCH] Rename Setting to PluginData for compatiblity issue

---
 PluginDocs/java/source.java                   | 176 -------------
 .../console/codegen/ValueSettingCodegen.kt    |  24 +-
 .../console/codegen/old/JSettingCodegen.kt    |   6 +-
 .../codegen/old/SettingValueUseSiteCodegen.kt |  28 +--
 .../console/codegen/old/ValueImplCodegen.kt   |  26 +-
 .../console/codegen/old/ValuesCodegen.kt      |  16 +-
 .../net/mamoe/mirai/console/MiraiConsole.kt   |  21 +-
 .../console/MiraiConsoleImplementation.kt     |   6 +-
 .../mirai/console/data/AbstractPluginData.kt  |  57 +++++
 .../mamoe/mirai/console/data/PluginConfig.kt  |  17 ++
 .../mamoe/mirai/console/data/PluginData.kt    | 232 ++++++++++++++++++
 .../mirai/console/data/PluginDataHolder.kt    |  84 +++++++
 .../mirai/console/data/PluginDataStorage.kt   | 115 +++++++++
 .../mirai/console/{setting => data}/Value.kt  |  39 +--
 .../MiraiConsoleImplementationBridge.kt       |  10 +-
 .../console/internal/command/internal.kt      |  17 +-
 .../{setting => data}/CompositeValueImpl.kt   |  10 +-
 .../PluginData.value composite impl.kt}       |  12 +-
 .../SettingImpl.kt => data/PluginDataImpl.kt} |  22 +-
 .../PluginDataStorage internal.kt}            |  93 +++----
 .../SemverAsStringSerializer.kt               |   2 +-
 .../_PluginData.value.kt}                     |  69 ++++--
 .../_PrimitiveValueDeclarations.kt            |   5 +-
 .../internal/{setting => data}/asKClass.kt    |  12 +-
 .../{setting => data}/collectionUtil.kt       |   2 +-
 .../{setting => data}/serializerHelper.kt     |   2 +-
 .../{setting => data}/serializerUtil.kt       |   2 +-
 .../internal/plugin/JarPluginLoaderImpl.kt    |   6 +-
 .../internal/plugin/JvmPluginInternal.kt      |  47 +++-
 .../internal/plugin/PluginManagerImpl.kt      |   2 +-
 .../console/internal/utils/BotManagerImpl.kt  |  16 +-
 .../mamoe/mirai/console/plugin/description.kt |   4 +-
 .../console/plugin/jvm/JarPluginLoader.kt     |   6 +-
 .../mirai/console/plugin/jvm/JvmPlugin.kt     |  19 +-
 .../plugin/jvm/JvmPluginDescriptionImpl.kt    |   2 +-
 .../mirai/console/plugin/jvm/KotlinPlugin.kt  |   2 +-
 .../mamoe/mirai/console/setting/Setting.kt    | 206 ----------------
 .../mirai/console/setting/SettingStorage.kt   | 187 --------------
 .../mamoe/mirai/console/TestMiraiConosle.kt   |   8 +-
 .../console/{setting => data}/SettingTest.kt  |  50 ++--
 .../pure/MiraiConsoleImplementationPure.kt    |   8 +-
 .../console/pure/MiraiConsolePureLoader.kt    |  24 ++
 42 files changed, 851 insertions(+), 841 deletions(-)
 delete mode 100644 PluginDocs/java/source.java
 create mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/AbstractPluginData.kt
 create mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginConfig.kt
 create mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginData.kt
 create mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataHolder.kt
 create mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataStorage.kt
 rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/{setting => data}/Value.kt (89%)
 rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting => data}/CompositeValueImpl.kt (94%)
 rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting/Setting.value composite impl.kt => data/PluginData.value composite impl.kt} (92%)
 rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting/SettingImpl.kt => data/PluginDataImpl.kt} (85%)
 rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting/SettingStorage internal.kt => data/PluginDataStorage internal.kt} (59%)
 rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting => data}/SemverAsStringSerializer.kt (95%)
 rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting/_Setting.value.kt => data/_PluginData.value.kt} (69%)
 rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting => data}/_PrimitiveValueDeclarations.kt (99%)
 rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting => data}/asKClass.kt (78%)
 rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting => data}/collectionUtil.kt (99%)
 rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting => data}/serializerHelper.kt (99%)
 rename backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/{setting => data}/serializerUtil.kt (97%)
 delete mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt
 delete mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/SettingStorage.kt
 rename backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/{setting => data}/SettingTest.kt (73%)

diff --git a/PluginDocs/java/source.java b/PluginDocs/java/source.java
deleted file mode 100644
index 7585e5883..000000000
--- a/PluginDocs/java/source.java
+++ /dev/null
@@ -1,176 +0,0 @@
-package net.mamoe.n;
-
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-import net.mamoe.mirai.console.command.*;
-import net.mamoe.mirai.console.plugin.Config;
-import net.mamoe.mirai.console.plugin.ConfigSection;
-import net.mamoe.mirai.console.plugin.ConfigSectionFactory;
-import net.mamoe.mirai.console.plugin.PluginBase;
-import net.mamoe.mirai.console.util.Utils;
-import net.mamoe.mirai.message.GroupMessage;
-import org.jetbrains.annotations.NotNull;
-import org.jsoup.Jsoup;
-
-import java.util.ArrayList;
-import java.util.List;
-
-class PingMyMCServerMain extends PluginBase {
-
-    private String defaultServerName;
-    private ConfigSection serverMap;
-    private Config setting;
-    private String API;
-    private String responseTemplate;
-
-    public void onLoad(){
-        super.onLoad();
-
-        this.setting = this.loadConfig("setting.yml");
-
-        this.setting.setIfAbsent("API","https://api-mping.loliboy.com/ping/{address}/{port}");
-        this.setting.setIfAbsent("ServerList", ConfigSectionFactory.create());
-        this.setting.setIfAbsent("DefaultServerName","");
-        this.setting.setIfAbsent("ResponseTemplate","Ping {serverName}: \nGame: {game}, {version}\nName: {fullName}\nPlayer: {currentPlayers}/{maxPlayers}\nConnected: {connected}\nIP: {address}:{port}");
-
-
-        this.API = this.setting.getString("API");
-        this.defaultServerName = this.setting.getString("DefaultServerName");
-        this.serverMap = this.setting.getConfigSection("ServerList");
-        this.responseTemplate = this.setting.getString("ResponseTemplate");
-    }
-
-    @Override
-    public void onDisable() {
-        super.onDisable();
-        this.setting.set("ServerList",serverMap);
-        this.setting.set("DefaultServerName",defaultServerName);
-        this.setting.save();
-    }
-
-    public void onEnable(){
-        this.getEventListener().subscribeAlways(GroupMessage.class, (GroupMessage event) -> {
-
-            String messageInString = event.getMessage().toString();
-
-            if(!messageInString.contains("ping ")) {
-                return;
-            }
-
-            String serverName = messageInString.replace("ping ", "").toLowerCase().trim();
-
-            if(!this.serverMap.containsKey(serverName)) {
-                serverName = this.defaultServerName;
-            }
-
-            if(!this.serverMap.containsKey(serverName)){
-                event.getSubject().sendMessage("Bot管理员没有设置任何可ping的服务器, 请使用/mcserver 来增加");
-                return;
-            }
-
-            ConfigSection serverInfo = this.serverMap.getConfigSection(serverName);
-
-            final String serverName_ = serverName;
-
-            getScheduler().async(() -> {
-                event.getSubject().sendMessage("正在获取中..");
-                try {
-                    String response = Utils.tryNTimes(2, () ->
-                            Jsoup.connect(API
-                                    .replace("{address}", serverInfo.getString("address"))
-                                    .replace("{port}", serverInfo.getString("port"))
-                            ).ignoreContentType(true).timeout(8000).execute().body()
-                    );
-                    JsonObject resObj = JsonParser.parseString(response).getAsJsonObject();
-                    JsonObject addressObj = resObj.get("rinfo").getAsJsonObject();
-                    event.getSubject().sendMessage(this.responseTemplate
-                            .replace("{connected}",resObj.get("connected").getAsString())
-                            .replace("{currentPlayers}",resObj.get("currentPlayers").getAsString())
-                            .replace("{maxPlayers}",resObj.get("maxPlayers").getAsString())
-                            .replace("{serverName}",serverName_)
-                            .replace("{fullName}",resObj.get("cleanName").getAsString())
-                            .replace("{game}",resObj.get("game").getAsString())
-                            .replace("{version}",resObj.get("version").getAsString())
-                            .replace("{address}",addressObj.get("address").getAsString())
-                            .replace("{port}",addressObj.get("port").getAsString())
-                    );
-                } catch (Exception e) {
-                    event.getSubject().sendMessage("获取失败.." + e.getMessage());
-                    e.printStackTrace();
-                }
-            });
-
-        });
-
-        JCommandManager.getInstance().register(this, new BlockingCommand(
-                "mcserver", new ArrayList<>(),"管理可以ping的MC服务器","/mcserver add/remove"
-        ) {
-            @Override
-            public boolean onCommandBlocking(@NotNull CommandSender commandSender, @NotNull List<String> list) {
-                if(list.size() < 1){
-                    return false;
-                }
-                switch (list.get(0)){
-                    case "add":
-                        if(list.size() < 4){
-                            commandSender.sendMessageBlocking("/mcserver add 服务器名字 IP 端口");
-                            return true;
-                        }
-                        String serverName = list.get(1);
-
-                        String IP = list.get(2);
-
-                        int port = -1;
-                        try {
-                            port = Integer.parseInt(list.get(3));
-                        }catch (Exception e){
-                            commandSender.sendMessageBlocking("无法识别端口号");
-                            return true;
-                        }
-
-                        if(port < 0 || port > 65535){
-                            commandSender.sendMessageBlocking("无法识别端口号[0-65535]");
-                            return true;
-                        }
-                        if(IP.contains(":")){
-                            commandSender.sendMessageBlocking("IP中不应包含端口");
-                            return true;
-                        }
-
-                        ConfigSection data = ConfigSectionFactory.create();
-
-                        data.set("address",IP);
-                        data.set("port",port);
-
-                        if(serverMap.size() == 0){
-                            defaultServerName = serverName;
-                        }
-
-                        serverMap.put(serverName.toLowerCase(),data);
-                        commandSender.sendMessageBlocking("设置成功, 发送ping " + serverName + " 即可");
-
-                        break;
-                    case "remove":
-                        if(list.size() < 2){
-                            commandSender.sendMessageBlocking("/mcserver remove 服务器名字");
-                            return true;
-                        }
-                        String serverNameToRemove = list.get(1).toLowerCase();
-                        if(serverMap.containsKey(serverNameToRemove)){
-                            serverMap.remove(serverNameToRemove);
-                            commandSender.sendMessageBlocking("移除成功");
-                        }else{
-                            commandSender.sendMessageBlocking("没有找到" + list.get(1) + "的数据");
-                        }
-                        break;
-                    default:
-                        return false;
-                }
-                return true;
-            }
-        });
-
-        this.getLogger().info("PingMyMCServer Enabled");
-    }
-
-}
\ No newline at end of file
diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueSettingCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueSettingCodegen.kt
index 54ddc3179..6b2db60ea 100644
--- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueSettingCodegen.kt
+++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/ValueSettingCodegen.kt
@@ -7,7 +7,7 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-@file:Suppress("PRE_RELEASE_CLASS", "ClassName", "RedundantVisibilityModifier")
+@file:Suppress("PRE_RELEASE_CLASS", "ClassName", "RedundantVisibilityModifier", "KDocUnresolvedReference")
 
 package net.mamoe.mirai.console.codegen
 
@@ -15,7 +15,7 @@ import kotlin.reflect.full.functions
 import kotlin.reflect.full.hasAnnotation
 import kotlin.reflect.full.isSubclassOf
 
-internal object ValueSettingCodegen {
+internal object ValuePluginDataCodegen {
     /**
      * The interface
      */
@@ -37,7 +37,7 @@ internal object ValueSettingCodegen {
         }
     }
 
-    object BuiltInSerializerConstantsPrimitivesCodegen : RegionCodegen("_Setting.value.kt"), DefaultInvoke {
+    object BuiltInSerializerConstantsPrimitivesCodegen : RegionCodegen("_PluginData.value.kt"), DefaultInvoke {
         @JvmStatic
         fun main(args: Array<String>) = super.startIndependently()
         override val defaultInvokeArgs: List<KtType> = KtPrimitives + KtString
@@ -99,7 +99,7 @@ internal abstract class ${ktType.standardName}ValueImpl : ${ktType.standardName}
 
     }
 
-    object Setting_value_PrimitivesImplCodegen : RegionCodegen("_Setting.value.kt"), DefaultInvoke {
+    object PluginData_value_PrimitivesImplCodegen : RegionCodegen("_PluginData.value.kt"), DefaultInvoke {
         @JvmStatic
         fun main(args: Array<String>) = super.startIndependently()
         override val defaultInvokeArgs: List<KtType> = KtPrimitives + KtString
@@ -107,12 +107,12 @@ internal abstract class ${ktType.standardName}ValueImpl : ${ktType.standardName}
         override fun StringBuilder.apply(ktType: KtType) {
             appendKCode(
                 """
-internal fun Setting.valueImpl(default: ${ktType.standardName}): SerializerAwareValue<${ktType.standardName}> {
+internal fun PluginData.valueImpl(default: ${ktType.standardName}): SerializerAwareValue<${ktType.standardName}> {
     return object : ${ktType.standardName}ValueImpl(default) {
         override fun onChanged() = this@valueImpl.onValueChanged(this)
     }
 }
-internal fun Setting.${ktType.lowerCaseName}ValueImpl(): SerializerAwareValue<${ktType.standardName}> {
+internal fun PluginData.${ktType.lowerCaseName}ValueImpl(): SerializerAwareValue<${ktType.standardName}> {
     return object : ${ktType.standardName}ValueImpl() {
         override fun onChanged() = this@${ktType.lowerCaseName}ValueImpl.onValueChanged(this)
     }
@@ -122,7 +122,7 @@ internal fun Setting.${ktType.lowerCaseName}ValueImpl(): SerializerAwareValue<${
         }
     }
 
-    object Setting_valueImplPrimitiveCodegen : RegionCodegen("_Setting.value.kt"), DefaultInvoke {
+    object PluginData_valueImplPrimitiveCodegen : RegionCodegen("_PluginData.value.kt"), DefaultInvoke {
         @JvmStatic
         fun main(args: Array<String>) = super.startIndependently()
         override val defaultInvokeArgs: List<KtType> = KtPrimitives + KtString
@@ -136,7 +136,7 @@ internal fun Setting.${ktType.lowerCaseName}ValueImpl(): SerializerAwareValue<${
         }
     }
 
-    object Setting_value_primitivesCodegen : RegionCodegen("Setting.kt"), DefaultInvoke {
+    object PluginData_value_primitivesCodegen : RegionCodegen("PluginData.kt"), DefaultInvoke {
         @JvmStatic
         fun main(args: Array<String>) = super.startIndependently()
         override val defaultInvokeArgs: List<KtType> = KtPrimitives + KtString
@@ -145,9 +145,13 @@ internal fun Setting.${ktType.lowerCaseName}ValueImpl(): SerializerAwareValue<${
             @Suppress("unused")
             appendKCode(
                 """
-                public fun Setting.value(default: ${ktType.standardName}): SerializerAwareValue<${ktType.standardName}> = valueImpl(default)
+                /**
+                 * 创建一个 [${ktType.standardName}] 类型的 [Value], 并设置初始值为 [default]
+                 */
+                public fun PluginData.value(default: ${ktType.standardName}): SerializerAwareValue<${ktType.standardName}> = valueImpl(default)
                 """
             )
+            appendLine()
         }
 
     }
@@ -158,7 +162,7 @@ internal fun Setting.${ktType.lowerCaseName}ValueImpl(): SerializerAwareValue<${
     @OptIn(ExperimentalStdlibApi::class)
     @JvmStatic
     fun main(args: Array<String>) {
-        ValueSettingCodegen::class.nestedClasses
+        ValuePluginDataCodegen::class.nestedClasses
             .filter { it.isSubclassOf(RegionCodegen::class) }
             .associateWith { kClass -> kClass.functions.find { it.name == "main" && it.hasAnnotation<JvmStatic>() } }
             .filter { it.value != null }
diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/JSettingCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/JSettingCodegen.kt
index d9a33b193..54a0ade77 100644
--- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/JSettingCodegen.kt
+++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/JSettingCodegen.kt
@@ -12,7 +12,7 @@
 package net.mamoe.mirai.console.codegen.old
 
 /**
- * used to generate Java Setting
+ * used to generate Java PluginData
  */
 
 
@@ -48,7 +48,7 @@ internal val J_EXTRA = listOf(
 
 fun JClazz.getTemplate(): String = """
         @NotNull default Value<${this.packageName}> $funName(${this.primitiveName} defaultValue){
-            return _SettingKt.value(this,defaultValue);
+            return _PluginDataKt.value(this,defaultValue);
         }
     """
 
@@ -61,7 +61,7 @@ fun main() {
         appendLine()
         appendLine(
             "/**\n" +
-                    " * !!! This file is auto-generated by backend/codegen/src/kotlin/net.mamoe.mirai.console.codegen.JSettingCodegen.kt\n" +
+                    " * !!! This file is auto-generated by backend/codegen/src/kotlin/net.mamoe.mirai.console.codegen.JPluginDataCodegen.kt\n" +
                     " * !!! DO NOT MODIFY THIS FILE MANUALLY\n" +
                     " */\n" +
                     "\"\"\""
diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/SettingValueUseSiteCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/SettingValueUseSiteCodegen.kt
index 68aa3818e..3d81a1d0c 100644
--- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/SettingValueUseSiteCodegen.kt
+++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/SettingValueUseSiteCodegen.kt
@@ -18,7 +18,7 @@ import java.io.File
 fun main() {
     println(File("").absolutePath) // default project base dir
 
-    File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/_Setting.kt").apply {
+    File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/_PluginData.kt").apply {
         createNewFile()
     }.writeText(buildString {
         appendLine(COPYRIGHT)
@@ -39,20 +39,20 @@ fun main() {
 
 private val DO_NOT_MODIFY = """
 /**
- * !!! This file is auto-generated by backend/codegen/src/kotlin/net.mamoe.mirai.console.codegen.SettingValueUseSiteCodegen.kt
+ * !!! This file is auto-generated by backend/codegen/src/kotlin/net.mamoe.mirai.console.codegen.PluginDataValueUseSiteCodegen.kt
  * !!! DO NOT MODIFY THIS FILE MANUALLY
  */
 """.trimIndent()
 
 private val PACKAGE = """
-package net.mamoe.mirai.console.setting
+package net.mamoe.mirai.console.data
 """.trimIndent()
 
 internal val FILE_SUPPRESS = """
 @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "unused")
 """.trimIndent()
 private val IMPORTS = """
-import net.mamoe.mirai.console.setting.internal.valueImpl
+import net.mamoe.mirai.console.data.internal.valueImpl
 import kotlin.internal.LowPriorityInOverloadResolution
 """.trimIndent()
 
@@ -104,7 +104,7 @@ fun genAllValueUseSite(): String = buildString {
             appendln(
                 """
                 @JvmName("valueMutable")
-                fun Setting.value(default: Mutable${collectionName}<${number}>): Mutable${number}${collectionName}Value = valueImpl(default)
+                fun PluginData.value(default: Mutable${collectionName}<${number}>): Mutable${number}${collectionName}Value = valueImpl(default)
             """.trimIndent()
             )
         }
@@ -114,30 +114,30 @@ fun genAllValueUseSite(): String = buildString {
     appendLine()
     appendln(
         """
-            fun <T : Setting> Setting.value(default: T): Value<T> {
+            fun <T : PluginData> PluginData.value(default: T): Value<T> {
                 require(this::class != default::class) {
                     "Recursive nesting is prohibited"
                 }
                 return valueImpl(default).also {
-                    if (default is Setting.NestedSetting) {
+                    if (default is PluginData.NestedPluginData) {
                         default.attachedValue = it
                     }
                 }
             }
 
-            inline fun <T : Setting> Setting.value(default: T, crossinline initializer: T.() -> Unit): Value<T> =
+            inline fun <T : PluginData> PluginData.value(default: T, crossinline initializer: T.() -> Unit): Value<T> =
                 value(default).also { it.value.apply(initializer) }
 
-            inline fun <reified T : Setting> Setting.value(default: List<T>): SettingListValue<T> = valueImpl(default)
+            inline fun <reified T : PluginData> PluginData.value(default: List<T>): PluginDataListValue<T> = valueImpl(default)
 
             @JvmName("valueMutable")
-            inline fun <reified T : Setting> Setting.value(default: MutableList<T>): MutableSettingListValue<T> = valueImpl(default)
+            inline fun <reified T : PluginData> PluginData.value(default: MutableList<T>): MutablePluginDataListValue<T> = valueImpl(default)
 
 
-            inline fun <reified T : Setting> Setting.value(default: Set<T>): SettingSetValue<T> = valueImpl(default)
+            inline fun <reified T : PluginData> PluginData.value(default: Set<T>): PluginDataSetValue<T> = valueImpl(default)
 
             @JvmName("valueMutable")
-            inline fun <reified T : Setting> Setting.value(default: MutableSet<T>): MutableSettingSetValue<T> = valueImpl(default)
+            inline fun <reified T : PluginData> PluginData.value(default: MutableSet<T>): MutablePluginDataSetValue<T> = valueImpl(default)
             
             /**
              * 创建一个只引用对象而不跟踪其属性的值.
@@ -147,7 +147,7 @@ fun genAllValueUseSite(): String = buildString {
             @DangerousReferenceOnlyValue
             @JvmName("valueDynamic")
             @LowPriorityInOverloadResolution
-            inline fun <reified T : Any> Setting.value(default: T): Value<T> = valueImpl(default)
+            inline fun <reified T : Any> PluginData.value(default: T): Value<T> = valueImpl(default)
             
             @RequiresOptIn(
                 ""${'"'}
@@ -164,6 +164,6 @@ fun genAllValueUseSite(): String = buildString {
 
 fun genValueUseSite(kotlinTypeName: String, miraiValueName: String): String =
     """
-        fun Setting.value(default: $kotlinTypeName): ${miraiValueName}Value = valueImpl(default)
+        fun PluginData.value(default: $kotlinTypeName): ${miraiValueName}Value = valueImpl(default)
     """.trimIndent()
 
diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/ValueImplCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/ValueImplCodegen.kt
index a13681156..5d484784f 100644
--- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/ValueImplCodegen.kt
+++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/ValueImplCodegen.kt
@@ -18,7 +18,7 @@ import java.io.File
 fun main() {
     println(File("").absolutePath) // default project base dir
 
-    File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/internal/_ValueImpl.kt").apply {
+    File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/internal/_ValueImpl.kt").apply {
         createNewFile()
     }.writeText(buildString {
         appendLine(COPYRIGHT)
@@ -43,13 +43,13 @@ private val DO_NOT_MODIFY = """
 """.trimIndent()
 
 private val PACKAGE = """
-package net.mamoe.mirai.console.setting.internal
+package net.mamoe.mirai.console.data.internal
 """.trimIndent()
 
 private val IMPORTS = """
 import kotlinx.serialization.*
 import kotlinx.serialization.builtins.*
-import net.mamoe.mirai.console.setting.*
+import net.mamoe.mirai.console.data.*
 """.trimIndent()
 
 fun genAllValueImpl(): String = buildString {
@@ -121,7 +121,7 @@ fun genAllValueImpl(): String = buildString {
             appendln(
                 """
                 @JvmName("valueImplMutable${number}${collectionName}")
-                internal fun Setting.valueImpl(
+                internal fun PluginData.valueImpl(
                     default: Mutable${collectionName}<${number}>
                 ): Mutable${number}${collectionName}Value {
                     var internalValue: Mutable${collectionName}<${number}> = default
@@ -166,8 +166,8 @@ fun genAllValueImpl(): String = buildString {
 
     appendln(
         """
-            internal fun <T : Setting> Setting.valueImpl(default: T): Value<T> {
-                return object : SettingValue<T>() {
+            internal fun <T : PluginData> PluginData.valueImpl(default: T): Value<T> {
+                return object : PluginDataValue<T>() {
                     private var internalValue: T = default
                     override var value: T
                         get() = internalValue
@@ -187,7 +187,7 @@ fun genAllValueImpl(): String = buildString {
                         }
 
                         override fun serialize(encoder: Encoder, value: T) {
-                            internalValue.updaterSerializer.serialize(encoder, SettingSerializerMark)
+                            internalValue.updaterSerializer.serialize(encoder, PluginDataSerializerMark)
                         }
                     }
                 }
@@ -203,20 +203,20 @@ fun genPrimitiveValueImpl(
     isArray: Boolean
 ): String =
     """
-        internal fun Setting.valueImpl(default: ${kotlinTypeName}): ${miraiValueName}Value {
+        internal fun PluginData.valueImpl(default: ${kotlinTypeName}): ${miraiValueName}Value {
             return object : ${miraiValueName}Value() {
                 private var internalValue: $kotlinTypeName = default
                 override var value: $kotlinTypeName
                     get() = internalValue
                     set(new) {
                         ${
-    if (isArray) """
+        if (isArray) """
                         if (!new.contentEquals(internalValue)) {
                             internalValue = new
                             onElementChanged(this)
                         }
     """.trim()
-    else """
+        else """
                         if (new != internalValue) {
                             internalValue = new
                             onElementChanged(this)
@@ -238,7 +238,7 @@ fun genCollectionValueImpl(
     isArray: Boolean
 ): String =
     """
-        internal fun Setting.valueImpl(default: ${kotlinTypeName}): ${miraiValueName}Value {
+        internal fun PluginData.valueImpl(default: ${kotlinTypeName}): ${miraiValueName}Value {
             var internalValue: $kotlinTypeName = default
             val delegt = dynamic$collectionName { internalValue }
             return object : ${miraiValueName}Value(), $kotlinTypeName by delegt {
@@ -246,13 +246,13 @@ fun genCollectionValueImpl(
                     get() = internalValue
                     set(new) {
                         ${
-    if (isArray) """
+        if (isArray) """
                         if (!new.contentEquals(internalValue)) {
                             internalValue = new
                             onElementChanged(this)
                         }
     """.trim()
-    else """
+        else """
                         if (new != internalValue) {
                             internalValue = new
                             onElementChanged(this)
diff --git a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/ValuesCodegen.kt b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/ValuesCodegen.kt
index 9e780e909..dbdd443cc 100644
--- a/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/ValuesCodegen.kt
+++ b/backend/codegen/src/main/kotlin/net/mamoe/mirai/console/codegen/old/ValuesCodegen.kt
@@ -17,7 +17,7 @@ import java.io.File
 fun main() {
     println(File("").absolutePath) // default project base dir
 
-    File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/_Value.kt").apply {
+    File("backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/_Value.kt").apply {
         createNewFile()
     }.writeText(genPublicApi())
 }
@@ -64,7 +64,7 @@ fun genPublicApi() = buildString {
     appendLine()
     appendln(
         """
-            package net.mamoe.mirai.console.setting
+            package net.mamoe.mirai.console.data
 
             import kotlinx.serialization.KSerializer
             import kotlin.properties.ReadWriteProperty
@@ -85,15 +85,15 @@ fun genPublicApi() = buildString {
 
     appendln(
         """
-sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
+sealed class Value<T : Any> : ReadWriteProperty<PluginData, T> {
     abstract var value: T
 
     /**
      * 用于更新 [value] 的序列化器
      */
     abstract val serializer: KSerializer<T>
-    override fun getValue(thisRef: Setting, property: KProperty<*>): T = value
-    override fun setValue(thisRef: Setting, property: KProperty<*>, value: T) {
+    override fun getValue(thisRef: PluginData, property: KProperty<*>): T = value
+    override fun setValue(thisRef: PluginData, property: KProperty<*>, value: T) {
         this.value = value
     }
 
@@ -212,7 +212,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
         // SETTING
         appendln(
             """
-        abstract class Setting${collectionName}Value<T: Setting> internal constructor() : Value<${collectionName}<T>>(), ${collectionName}<T>
+        abstract class PluginData${collectionName}Value<T: PluginData> internal constructor() : Value<${collectionName}<T>>(), ${collectionName}<T>
     """
         )
         appendLine()
@@ -222,7 +222,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
 
     appendln(
         """
-            abstract class SettingValue<T : Setting> internal constructor() : Value<T>()
+            abstract class PluginDataValue<T : PluginData> internal constructor() : Value<T>()
         """
     )
 
@@ -250,7 +250,7 @@ sealed class Value<T : Any> : ReadWriteProperty<Setting, T> {
         // SETTING
         appendln(
             """
-        abstract class MutableSetting${collectionName}Value<T: Setting> internal constructor() : Value<Mutable${collectionName}<T>>(), Mutable${collectionName}<T>
+        abstract class MutablePluginData${collectionName}Value<T: PluginData> internal constructor() : Value<Mutable${collectionName}<T>>(), Mutable${collectionName}<T>
     """
         )
         appendLine()
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt
index 38145751b..fc01c86b7 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt
@@ -14,6 +14,7 @@ package net.mamoe.mirai.console
 
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
+import net.mamoe.mirai.Bot
 import net.mamoe.mirai.console.MiraiConsole.INSTANCE
 import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge
 import net.mamoe.mirai.console.plugin.PluginLoader
@@ -21,6 +22,7 @@ import net.mamoe.mirai.console.plugin.center.PluginCenter
 import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
 import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
 import net.mamoe.mirai.console.util.ConsoleInternalAPI
+import net.mamoe.mirai.utils.BotConfiguration
 import net.mamoe.mirai.utils.MiraiLogger
 import java.io.File
 import java.util.*
@@ -72,7 +74,24 @@ public interface MiraiConsole : CoroutineScope {
          */ // MiraiConsole.INSTANCE.getJob()
         public val job: Job
             get() = MiraiConsole.coroutineContext[Job]
-                ?: error("Internal error: Job not found in MiraiConsole.coroutineContext")
+                ?: throw IllegalMiraiConsoleImplementationError("Internal error: Job not found in MiraiConsole.coroutineContext")
+
+        /**
+         * 添加一个 [Bot] 实例到全局 Bot 列表, 但不登录.
+         *
+         * 调用 [Bot.login] 可登录.
+         *
+         * @see Bot.botInstances 获取现有 [Bot] 实例列表
+         */
+        // don't static
+        @ConsoleExperimentalAPI("This is a low-level API and might be removed in the future.")
+        public fun addBot(id: Long, password: String, configuration: BotConfiguration.() -> Unit = {}): Bot =
+            Bot(id, password) {
+                fileBasedDeviceInfo()
+                this.loginSolver = frontEnd.createLoginSolver()
+                redirectNetworkLogToDirectory()
+                configuration()
+            }
     }
 }
 
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleImplementation.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleImplementation.kt
index 217a86de1..3e4680a8e 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleImplementation.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleImplementation.kt
@@ -15,10 +15,10 @@ import kotlinx.atomicfu.locks.withLock
 import kotlinx.coroutines.CoroutineScope
 import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start
 import net.mamoe.mirai.console.command.ConsoleCommandSender
+import net.mamoe.mirai.console.data.PluginDataStorage
 import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge
 import net.mamoe.mirai.console.plugin.PluginLoader
 import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
-import net.mamoe.mirai.console.setting.SettingStorage
 import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
 import net.mamoe.mirai.utils.MiraiLogger
 import java.io.File
@@ -75,8 +75,8 @@ public interface MiraiConsoleImplementation : CoroutineScope {
 
     public val consoleCommandSender: ConsoleCommandSender
 
-    public val settingStorageForJarPluginLoader: SettingStorage
-    public val settingStorageForBuiltIns: SettingStorage
+    public val dataStorageForJarPluginLoader: PluginDataStorage
+    public val dataStorageForBuiltIns: PluginDataStorage
 
     public companion object {
         internal lateinit var instance: MiraiConsoleImplementation
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/AbstractPluginData.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/AbstractPluginData.kt
new file mode 100644
index 000000000..34797fe68
--- /dev/null
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/AbstractPluginData.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019-2020 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/master/LICENSE
+ */
+
+@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "EXPOSED_SUPER_CLASS", "NOTHING_TO_INLINE")
+
+package net.mamoe.mirai.console.data
+
+import kotlinx.serialization.KSerializer
+import net.mamoe.mirai.console.data.PluginData.ValueNode
+import net.mamoe.mirai.console.internal.data.PluginDataImpl
+import net.mamoe.mirai.console.internal.data.serialName
+import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
+import kotlin.reflect.KProperty
+
+/**
+ * [PluginData] 的默认实现. 支持使用 `by value()` 等委托方法创建 [Value] 并跟踪其改动.
+ *
+ * @see PluginData
+ */
+public abstract class AbstractPluginData : PluginData, PluginDataImpl() {
+    /**
+     * 添加了追踪的 [ValueNode] 列表, 即通过 `by value` 初始化的属性列表.
+     *
+     * 他们的修改会被跟踪, 并触发 [onValueChanged].
+     *
+     * @see provideDelegate
+     */
+    public override val valueNodes: MutableList<ValueNode<*>> = mutableListOf()
+
+    /**
+     * 使用 `by` 时自动调用此方法, 添加对 [Value] 的值修改的跟踪.
+     *
+     * 将会创建一个 [ValueNode] 并添加到 [valueNodes]
+     */
+    public final override operator fun <T> SerializerAwareValue<T>.provideDelegate(
+        thisRef: Any?,
+        property: KProperty<*>
+    ): SerializerAwareValue<T> = apply { valueNodes.add(ValueNode(property.serialName, this, this.serializer)) }
+
+    /**
+     * 值更新序列化器. 仅供内部使用.
+     */
+    @ConsoleExperimentalAPI
+    public final override val updaterSerializer: KSerializer<Unit>
+        get() = super.updaterSerializer
+
+    /**
+     * 当所属于这个 [PluginData] 的 [Value] 的 [值][Value.value] 被修改时被调用.
+     */
+    public abstract override fun onValueChanged(value: Value<*>)
+}
\ No newline at end of file
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginConfig.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginConfig.kt
new file mode 100644
index 000000000..a2a0ec216
--- /dev/null
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginConfig.kt
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2019-2020 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/master/LICENSE
+ */
+
+package net.mamoe.mirai.console.data
+
+/**
+ * 一个插件的配置数据, 用于和用户交互.
+ *
+ * 用户可通过 mirai-console 前端修改这些配置, 修改会自动写入这个对象中.
+ */
+public interface PluginConfig : PluginData
\ No newline at end of file
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginData.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginData.kt
new file mode 100644
index 000000000..73e26021e
--- /dev/null
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginData.kt
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2019-2020 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/master/LICENSE
+ */
+
+@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "EXPOSED_SUPER_CLASS", "NOTHING_TO_INLINE")
+
+package net.mamoe.mirai.console.data
+
+import kotlinx.serialization.KSerializer
+import net.mamoe.mirai.console.internal.data.createInstanceSmart
+import net.mamoe.mirai.console.internal.data.typeOf0
+import net.mamoe.mirai.console.internal.data.valueFromKTypeImpl
+import net.mamoe.mirai.console.internal.data.valueImpl
+import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
+import net.mamoe.mirai.console.plugin.jvm.loadPluginData
+import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
+import kotlin.internal.LowPriorityInOverloadResolution
+import kotlin.reflect.KClass
+import kotlin.reflect.KProperty
+import kotlin.reflect.KType
+
+
+/**
+ * 序列化之后的名称.
+ *
+ * 例:
+ * ```
+ * @SerialName("accounts")
+ * object AccountPluginData : PluginData by ... {
+ *    @SerialName("info")
+ *    val map: Map<String, String> by value("a" to "b")
+ * }
+ * ```
+ *
+ * 将被保存为配置 (YAML 作为示例):
+ * ```yaml
+ * accounts:
+ *   info:
+ *     a: b
+ * ```
+ */
+public typealias SerialName = kotlinx.serialization.SerialName
+
+/**
+ * 一个插件内部的, 对用户隐藏的数据对象. 可包含对多个 [Value] 的值变更的跟踪.
+ *
+ * [PluginData] 不涉及有关数据的存储, 而是只维护数据结构: [属性节点列表][valueNodes].
+ *
+ * 有关存储方案, 请查看 [PluginDataStorage]
+ *
+ * 在 [JvmPlugin] 的典型实现方式:
+ * ```
+ * object PluginMain : KotlinPlugin()
+ *
+ * object AccountPluginData : PluginData by PluginMain.loadPluginData() {
+ *    val map: Map<String, String> by value("a" to "b")
+ * }
+ * ```
+ *
+ * @see JvmPlugin.loadPluginData 通过 [JvmPlugin] 获取指定 [PluginData] 实例.
+ * @see PluginDataStorage [PluginData] 存储仓库
+ */
+public interface PluginData {
+    /**
+     * 添加了追踪的 [ValueNode] 列表 (即使用 `by value()` 委托的属性), 即通过 `by value` 初始化的属性列表.
+     *
+     * 他们的修改会被跟踪, 并触发 [onValueChanged].
+     *
+     * @see provideDelegate
+     */
+    public val valueNodes: MutableList<ValueNode<*>>
+
+    /**
+     * 由 [provideDelegate] 创建, 来自一个通过 `by value` 初始化的属性节点.
+     */
+    public data class ValueNode<T>(
+        /**
+         * 节点名称.
+         *
+         * 如果属性带有 [SerialName], 则使用 [kotlinx.serialization.SerialName.value],
+         * 否则使用 [属性名称][KProperty.name]
+         */
+        val serialName: String,
+        /**
+         * 属性值代理
+         */
+        val value: Value<T>,
+        /**
+         * 属性值更新器
+         *
+         * @suppress 注意, 这是实验性 API.
+         */
+        @ConsoleExperimentalAPI
+        val updaterSerializer: KSerializer<Unit>
+    )
+
+    /**
+     * 使用 `by value()` 时自动调用此方法, 添加对 [Value] 的值修改的跟踪, 并创建 [ValueNode] 加入 [valueNodes]
+     */
+    public operator fun <T> SerializerAwareValue<T>.provideDelegate(
+        thisRef: Any?,
+        property: KProperty<*>
+    ): SerializerAwareValue<T>
+
+    /**
+     * 值更新序列化器. 仅供内部使用
+     *
+     * @suppress 注意, 这是实验性 API.
+     */
+    @ConsoleExperimentalAPI
+    public val updaterSerializer: KSerializer<Unit>
+
+    /**
+     * 当所属于这个 [PluginData] 的 [Value] 的 [值][Value.value] 被修改时被调用.
+     */
+    public fun onValueChanged(value: Value<*>)
+
+    /**
+     * 当这个 [PluginData] 被放入一个 [PluginDataStorage] 时调用
+     */
+    public fun setStorage(storage: PluginDataStorage)
+}
+
+/**
+ * 用于支持属性委托
+ */
+@JvmSynthetic
+public inline operator fun <T> Value<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value
+
+/**
+ * 用于支持属性委托
+ */
+@JvmSynthetic
+public inline operator fun <T> Value<T>.setValue(thisRef: Any?, property: KProperty<*>, value: T) {
+    this.value = value
+}
+
+//// region PluginData_value_primitives CODEGEN ////
+
+/**
+ * 创建一个 [Byte] 类型的 [Value], 并设置初始值为 [default]
+ */
+public fun PluginData.value(default: Byte): SerializerAwareValue<Byte> = valueImpl(default)
+
+/**
+ * 创建一个 [Short] 类型的 [Value], 并设置初始值为 [default]
+ */
+public fun PluginData.value(default: Short): SerializerAwareValue<Short> = valueImpl(default)
+
+/**
+ * 创建一个 [Int] 类型的 [Value], 并设置初始值为 [default]
+ */
+public fun PluginData.value(default: Int): SerializerAwareValue<Int> = valueImpl(default)
+
+/**
+ * 创建一个 [Long] 类型的 [Value], 并设置初始值为 [default]
+ */
+public fun PluginData.value(default: Long): SerializerAwareValue<Long> = valueImpl(default)
+
+/**
+ * 创建一个 [Float] 类型的 [Value], 并设置初始值为 [default]
+ */
+public fun PluginData.value(default: Float): SerializerAwareValue<Float> = valueImpl(default)
+
+/**
+ * 创建一个 [Double] 类型的 [Value], 并设置初始值为 [default]
+ */
+public fun PluginData.value(default: Double): SerializerAwareValue<Double> = valueImpl(default)
+
+/**
+ * 创建一个 [Char] 类型的 [Value], 并设置初始值为 [default]
+ */
+public fun PluginData.value(default: Char): SerializerAwareValue<Char> = valueImpl(default)
+
+/**
+ * 创建一个 [Boolean] 类型的 [Value], 并设置初始值为 [default]
+ */
+public fun PluginData.value(default: Boolean): SerializerAwareValue<Boolean> = valueImpl(default)
+
+/**
+ * 创建一个 [String] 类型的 [Value], 并设置初始值为 [default]
+ */
+public fun PluginData.value(default: String): SerializerAwareValue<String> = valueImpl(default)
+
+//// endregion PluginData_value_primitives CODEGEN ////
+
+
+/**
+ * 通过具体化类型创建一个 [SerializerAwareValue], 并设置初始值.
+ *
+ * @param T 具体化参数类型 T. 仅支持:
+ * - 基础数据类型
+ * - 标准库集合类型 ([List], [Map], [Set])
+ * - 标准库数据类型 ([Map.Entry], [Pair], [Triple])
+ * - 和使用 [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization) 的 [Serializable] 标记的
+ */
+@Suppress("UNCHECKED_CAST")
+@LowPriorityInOverloadResolution
+public inline fun <reified T> PluginData.value(default: T): SerializerAwareValue<T> =
+    valueFromKType(typeOf0<T>(), default)
+
+/**
+ * 通过具体化类型创建一个 [SerializerAwareValue].
+ * @see valueFromKType 查看更多实现信息
+ */
+@LowPriorityInOverloadResolution
+public inline fun <reified T> PluginData.value(): SerializerAwareValue<T> =
+    value(T::class.run { objectInstance ?: createInstanceSmart() } as T)
+
+/**
+ * 通过一个特定的 [KType] 创建 [Value], 并设置初始值.
+ *
+ * 对于 [List], [Map], [Set] 等标准库类型, 这个函数会尝试构造 [LinkedHashMap] 等相关类型.
+ * 而对于自定义数据类型, 本函数只会反射获取 [objectInstance][KClass.objectInstance] 或使用无参构造器构造实例.
+ *
+ * @param T 具体化参数类型 T. 仅支持:
+ * - 基础数据类型
+ * - 标准库集合类型 ([List], [Map], [Set])
+ * - 标准库数据类型 ([Map.Entry], [Pair], [Triple])
+ * - 和使用 [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization) 的 [Serializable] 标记的
+ */
+@Suppress("UNCHECKED_CAST")
+@ConsoleExperimentalAPI
+public fun <T> PluginData.valueFromKType(type: KType, default: T): SerializerAwareValue<T> =
+    (valueFromKTypeImpl(type) as SerializerAwareValue<Any?>).apply { this.value = default } as SerializerAwareValue<T>
+
+// TODO: 2020/6/24 Introduce class TypeToken for compound types for Java.
\ No newline at end of file
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataHolder.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataHolder.kt
new file mode 100644
index 000000000..ef46b3e12
--- /dev/null
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataHolder.kt
@@ -0,0 +1,84 @@
+@file:Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST", "unused")
+
+package net.mamoe.mirai.console.data
+
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import net.mamoe.mirai.console.data.PluginDataStorage.Companion.load
+import net.mamoe.mirai.console.internal.data.AutoSavePluginData
+import net.mamoe.mirai.console.internal.data.cast
+import net.mamoe.mirai.console.internal.data.newPluginDataInstanceUsingReflection
+import net.mamoe.mirai.console.internal.data.typeOf0
+import kotlin.reflect.KClass
+import kotlin.reflect.KType
+import kotlin.reflect.full.createType
+
+/**
+ * 可以持有相关 [PluginData] 实例的对象, 作为 [PluginData] 实例的拥有者.
+ *
+ * @see PluginDataStorage.load
+ * @see PluginDataStorage.store
+ *
+ * @see AutoSavePluginDataHolder 自动保存
+ */
+public interface PluginDataHolder {
+    /**
+     * 保存时使用的分类名
+     */
+    public val name: String
+
+    /**
+     * 创建一个 [PluginData] 实例.
+     *
+     * @see Companion.newPluginDataInstance
+     * @see KClass.createType
+     */
+    @JvmDefault
+    public fun <T : PluginData> newPluginDataInstance(type: KType): T =
+        newPluginDataInstanceUsingReflection<PluginData>(type) as T
+
+    public companion object {
+        /**
+         * 创建一个 [PluginData] 实例.
+         *
+         * @see PluginDataHolder.newPluginDataInstance
+         */
+        @JvmSynthetic
+        public inline fun <reified T : PluginData> PluginDataHolder.newPluginDataInstance(): T {
+            return this.newPluginDataInstance(typeOf0<T>())
+        }
+    }
+}
+
+/**
+ * 可以持有相关 [AutoSavePluginData] 的对象.
+ *
+ * @see net.mamoe.mirai.console.plugin.jvm.JvmPlugin
+ */
+public interface AutoSavePluginDataHolder : PluginDataHolder, CoroutineScope {
+    /**
+     * [AutoSavePluginData] 每次自动保存时间间隔
+     *
+     * - 区间的左端点为最小间隔, 一个 [Value] 被修改后, 若此时间段后无其他修改, 将触发自动保存; 若有, 将重新开始计时.
+     * - 区间的右端点为最大间隔, 一个 [Value] 被修改后, 最多不超过这个时间段后就会被保存.
+     *
+     * 若 [AutoSavePluginDataHolder.coroutineContext] 含有 [Job],
+     * 则 [AutoSavePluginData] 会通过 [Job.invokeOnCompletion] 在 Job 完结时触发自动保存.
+     *
+     * @see LongRange Java 用户使用 [LongRange] 的构造器创建
+     * @see Long.rangeTo Kotlin 用户使用 [Long.rangeTo] 创建, 如 `3000..50000`
+     */
+    public val autoSaveIntervalMillis: LongRange
+
+    /**
+     * 仅支持确切的 [PluginData] 类型
+     */
+    @JvmDefault
+    public override fun <T : PluginData> newPluginDataInstance(type: KType): T {
+        val classifier = type.classifier?.cast<KClass<PluginData>>()
+        require(classifier != null && classifier.java == PluginData::class.java) {
+            "Cannot create PluginData instance. AutoSavePluginDataHolder supports only PluginData type."
+        }
+        return AutoSavePluginData(this, classifier) as T // T is always PluginData
+    }
+}
\ No newline at end of file
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataStorage.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataStorage.kt
new file mode 100644
index 000000000..0782c983a
--- /dev/null
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/PluginDataStorage.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2019-2020 Mamoe Technologies and contributors.
+ *
+ * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证.
+ * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link.
+ *
+ * https://github.com/mamoe/mirai/blob/master/LICENSE
+ */
+
+@file:Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST", "unused")
+
+package net.mamoe.mirai.console.data
+
+import net.mamoe.mirai.console.internal.data.MemoryPluginDataStorageImpl
+import net.mamoe.mirai.console.internal.data.MultiFilePluginDataStorageImpl
+import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
+import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
+import java.io.File
+import kotlin.reflect.KClass
+
+/**
+ * [PluginData] 存储仓库.
+ *
+ * 此为较低层的 API, 一般插件开发者不会接触.
+ *
+ * [JarPluginLoader] 实现一个 [PluginDataStorage], 用于管理所有 [JvmPlugin] 的 [PluginData] 实例.
+ *
+ * @see PluginDataHolder
+ * @see JarPluginLoader.dataStorage
+ */
+public interface PluginDataStorage {
+    /**
+     * 读取一个实例. 在 [T] 实例创建后 [设置 [PluginDataStorage]][PluginData.setStorage]
+     */
+    public fun <T : PluginData> load(holder: PluginDataHolder, dataClass: Class<T>): T
+
+    /**
+     * 保存一个实例
+     */
+    public fun store(holder: PluginDataHolder, pluginData: PluginData)
+
+    public companion object {
+        /**
+         * 读取一个实例. 在 [T] 实例创建后 [设置 [PluginDataStorage]][PluginData.setStorage]
+         */
+        @JvmStatic
+        public fun <T : PluginData> PluginDataStorage.load(holder: PluginDataHolder, dataClass: KClass<T>): T =
+            this.load(holder, dataClass.java)
+
+        /**
+         * 读取一个实例. 在 [T] 实例创建后 [设置 [PluginDataStorage]][PluginData.setStorage]
+         */
+        @JvmSynthetic
+        public inline fun <reified T : PluginData> PluginDataStorage.load(holder: PluginDataHolder): T =
+            this.load(holder, T::class)
+    }
+}
+
+/**
+ * 在内存存储所有 [PluginData] 实例的 [PluginDataStorage]. 在内存数据丢失后相关 [PluginData] 实例也会丢失.
+ * @see PluginDataStorage
+ */
+public interface MemoryPluginDataStorage : PluginDataStorage, Map<Class<out PluginData>, PluginData> {
+    /**
+     * 当任一 [PluginData] 实例拥有的 [Value] 的值被改变后调用的回调函数.
+     */
+    public fun interface OnChangedCallback {
+        public fun onChanged(storage: MemoryPluginDataStorage, value: Value<*>)
+
+        /**
+         * 无任何操作的 [OnChangedCallback]
+         * @see OnChangedCallback
+         */
+        public object NoOp : OnChangedCallback {
+            public override fun onChanged(storage: MemoryPluginDataStorage, value: Value<*>) {
+                // no-op
+            }
+        }
+    }
+
+    public companion object {
+        /**
+         * 创建一个 [MemoryPluginDataStorage] 实例.
+         *
+         * @param onChanged 当任一 [PluginData] 实例拥有的 [Value] 的值被改变后调用的回调函数.
+         */
+        @JvmStatic
+        @JvmName("create")
+        // @JvmOverloads
+        public operator fun invoke(onChanged: OnChangedCallback = OnChangedCallback.NoOp): MemoryPluginDataStorage =
+            MemoryPluginDataStorageImpl(onChanged)
+    }
+}
+
+/**
+ * 用多个文件存储 [PluginData] 实例的 [PluginDataStorage].
+ */
+public interface MultiFilePluginDataStorage : PluginDataStorage {
+    /**
+     * 存放 [PluginData] 的目录.
+     */
+    public val directory: File
+
+    public companion object {
+        /**
+         * 创建一个 [MultiFilePluginDataStorage] 实例.
+         *
+         * @see directory 存放 [PluginData] 的目录.
+         */
+        @JvmStatic
+        @JvmName("create")
+        public operator fun invoke(directory: File): MultiFilePluginDataStorage =
+            MultiFilePluginDataStorageImpl(directory)
+    }
+}
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/Value.kt
similarity index 89%
rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt
rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/Value.kt
index b37bcd6f2..62aa495d8 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Value.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/data/Value.kt
@@ -9,23 +9,24 @@
 
 @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "unused", "NOTHING_TO_INLINE")
 
-package net.mamoe.mirai.console.setting
+package net.mamoe.mirai.console.data
 
 import kotlinx.serialization.BinaryFormat
 import kotlinx.serialization.KSerializer
 import kotlinx.serialization.StringFormat
-import net.mamoe.mirai.console.internal.setting.map
-import net.mamoe.mirai.console.internal.setting.setValueBySerializer
+import net.mamoe.mirai.console.internal.data.map
+import net.mamoe.mirai.console.internal.data.setValueBySerializer
 import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
-import kotlin.reflect.KProperty
 
 /**
- * 表示一个可被观测的, 不可变的值包装.
+ * 表示一个值代理.
  *
- * [Value.value] 可以像 Kotlin 的 `var` 一样被修改, 然而它也可能被用户修改, 如通过 UI 前端.
+ * [Value.value] 可以像 Kotlin 的 `var` 一样被修改, 然而它也可能被用户修改, 如通过 UI 前端, 或通过自动重载.
  *
  * 一些常用的基础类型实现由代码生成创建特性的优化.
  *
+ * @see PluginData 容纳 [Value] 的数据对象
+ *
  * @see PrimitiveValue 基础数据类型实现
  * @see CompositeValue 复合数据类型实现
  */
@@ -39,7 +40,7 @@ public interface Value<T> {
 public class SerializableValue<T>(
     private val delegate: Value<T>,
     /**
-     * The serializer used to update and dump [delegate]
+     * 用于更新和保存 [delegate] 的序列化器
      */
     public override val serializer: KSerializer<Unit>
 ) : Value<T> by delegate, SerializerAwareValue<T> {
@@ -63,7 +64,7 @@ public class SerializableValue<T>(
  * 带有显式 [序列化器][serializer] 的 [Value].
  *
  * @see SerializableValue 简单实现
- * @see Setting.value 创建一个这样的 [SerializerAwareValue]
+ * @see PluginData.value 创建一个这样的 [SerializerAwareValue]
  */
 public interface SerializerAwareValue<T> : Value<T> {
     /**
@@ -109,20 +110,6 @@ public interface SerializerAwareValue<T> : Value<T> {
     }
 }
 
-/**
- * 用于支持属性委托
- */
-@JvmSynthetic
-public inline operator fun <T> Value<T>.getValue(mySetting: Any?, property: KProperty<*>): T = value
-
-/**
- * 用于支持属性委托
- */
-@JvmSynthetic
-public inline operator fun <T> Value<T>.setValue(mySetting: Any?, property: KProperty<*>, value: T) {
-    this.value = value
-}
-
 /**
  * 基础数据类型 [Value]
  *
@@ -144,42 +131,34 @@ public interface PrimitiveValue<T> : Value<T>
  * 表示一个不可空 [Byte] [Value].
  */
 public interface ByteValue : PrimitiveValue<Byte>
-
 /**
  * 表示一个不可空 [Short] [Value].
  */
 public interface ShortValue : PrimitiveValue<Short>
-
 /**
  * 表示一个不可空 [Int] [Value].
  */
 public interface IntValue : PrimitiveValue<Int>
-
 /**
  * 表示一个不可空 [Long] [Value].
  */
 public interface LongValue : PrimitiveValue<Long>
-
 /**
  * 表示一个不可空 [Float] [Value].
  */
 public interface FloatValue : PrimitiveValue<Float>
-
 /**
  * 表示一个不可空 [Double] [Value].
  */
 public interface DoubleValue : PrimitiveValue<Double>
-
 /**
  * 表示一个不可空 [Char] [Value].
  */
 public interface CharValue : PrimitiveValue<Char>
-
 /**
  * 表示一个不可空 [Boolean] [Value].
  */
 public interface BooleanValue : PrimitiveValue<Boolean>
-
 /**
  * 表示一个不可空 [String] [Value].
  */
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/MiraiConsoleImplementationBridge.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/MiraiConsoleImplementationBridge.kt
index 6b41969a9..273ab3744 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/MiraiConsoleImplementationBridge.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/MiraiConsoleImplementationBridge.kt
@@ -22,13 +22,13 @@ import net.mamoe.mirai.console.command.BuiltInCommands
 import net.mamoe.mirai.console.command.Command.Companion.primaryName
 import net.mamoe.mirai.console.command.CommandManagerImpl
 import net.mamoe.mirai.console.command.ConsoleCommandSender
+import net.mamoe.mirai.console.data.PluginDataStorage
 import net.mamoe.mirai.console.internal.plugin.CuiPluginCenter
 import net.mamoe.mirai.console.internal.plugin.PluginManagerImpl
-import net.mamoe.mirai.console.internal.utils.ConsoleBuiltInSettingStorage
+import net.mamoe.mirai.console.internal.utils.ConsoleBuiltInPluginDataStorage
 import net.mamoe.mirai.console.plugin.PluginLoader
 import net.mamoe.mirai.console.plugin.PluginManager
 import net.mamoe.mirai.console.plugin.center.PluginCenter
-import net.mamoe.mirai.console.setting.SettingStorage
 import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
 import net.mamoe.mirai.utils.DefaultLogger
 import net.mamoe.mirai.utils.MiraiLogger
@@ -58,8 +58,8 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI
     override val builtInPluginLoaders: List<PluginLoader<*, *>> get() = instance.builtInPluginLoaders
     override val consoleCommandSender: ConsoleCommandSender get() = instance.consoleCommandSender
 
-    override val settingStorageForJarPluginLoader: SettingStorage get() = instance.settingStorageForJarPluginLoader
-    override val settingStorageForBuiltIns: SettingStorage get() = instance.settingStorageForBuiltIns
+    override val dataStorageForJarPluginLoader: PluginDataStorage get() = instance.dataStorageForJarPluginLoader
+    override val dataStorageForBuiltIns: PluginDataStorage get() = instance.dataStorageForBuiltIns
 
     init {
         DefaultLogger = { identity -> this.newLogger(identity) }
@@ -91,7 +91,7 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI
         mainLogger.info { "${PluginManager.plugins.size} plugin(s) loaded." }
         mainLogger.info { "mirai-console started successfully." }
 
-        ConsoleBuiltInSettingStorage // init
+        ConsoleBuiltInPluginDataStorage // init
         // Only for initialize
     }
 }
\ No newline at end of file
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/command/internal.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/command/internal.kt
index f0aea62fa..d90a3a281 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/command/internal.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/command/internal.kt
@@ -10,8 +10,10 @@
 package net.mamoe.mirai.console.internal.command
 
 import net.mamoe.mirai.console.command.*
+import net.mamoe.mirai.console.command.description.CommandArgumentParserException
 import net.mamoe.mirai.contact.Group
 import net.mamoe.mirai.contact.Member
+import net.mamoe.mirai.contact.nameCardOrNick
 
 
 internal infix fun Array<String>.matchesBeginning(list: List<Any>): Boolean {
@@ -61,9 +63,6 @@ internal inline fun <T : Any> Collection<T>.fuzzySearch(
     target: String,
     index: (T) -> String
 ): T? {
-    if (this.isEmpty()) {
-        return null
-    }
     var potential: T? = null
     var rate = 0.0
     this.forEach {
@@ -90,9 +89,6 @@ internal inline fun <T : Any> Collection<T>.fuzzySearchOnly(
     target: String,
     index: (T) -> String
 ): T? {
-    if (this.isEmpty()) {
-        return null
-    }
     var potential: T? = null
     var rate = 0.0
     var collide = 0
@@ -115,9 +111,7 @@ internal inline fun <T : Any> Collection<T>.fuzzySearchOnly(
 
 
 internal fun Group.fuzzySearchMember(nameCardTarget: String): Member? {
-    return this.members.fuzzySearchOnly(nameCardTarget) {
-        it.nameCard
-    }
+    return this.members.fuzzySearch(nameCardTarget) { it.nameCardOrNick }
 }
 
 
@@ -159,7 +153,10 @@ internal suspend inline fun CommandSender.executeCommandInternal(
     kotlin.runCatching {
         command.onCommand(this, args)
     }.onFailure {
-        throw CommandExecutionException(command, commandName, it)
+        catchExecutionException(it)
+        if (it !is CommandArgumentParserException) {
+            throw CommandExecutionException(command, commandName, it)
+        }
     }
 }
 
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/CompositeValueImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/CompositeValueImpl.kt
similarity index 94%
rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/CompositeValueImpl.kt
rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/CompositeValueImpl.kt
index cc3f308e7..b7df66e71 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/CompositeValueImpl.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/CompositeValueImpl.kt
@@ -9,13 +9,13 @@
 
 @file:Suppress("unused")
 
-package net.mamoe.mirai.console.internal.setting
+package net.mamoe.mirai.console.internal.data
 
-import net.mamoe.mirai.console.setting.*
+import net.mamoe.mirai.console.data.*
 
 
 // type inference bug
-internal fun <T> Setting.createCompositeSetValueImpl(tToValue: (T) -> Value<T>): CompositeSetValueImpl<T> {
+internal fun <T> PluginData.createCompositeSetValueImpl(tToValue: (T) -> Value<T>): CompositeSetValueImpl<T> {
     return object : CompositeSetValueImpl<T>(tToValue) {
         override fun onChanged() {
             this@createCompositeSetValueImpl.onValueChanged(this)
@@ -62,7 +62,7 @@ internal abstract class CompositeSetValueImpl<T>(
 
 
 // type inference bug
-internal fun <T> Setting.createCompositeListValueImpl(tToValue: (T) -> Value<T>): CompositeListValueImpl<T> {
+internal fun <T> PluginData.createCompositeListValueImpl(tToValue: (T) -> Value<T>): CompositeListValueImpl<T> {
     return object : CompositeListValueImpl<T>(tToValue) {
         override fun onChanged() {
             this@createCompositeListValueImpl.onValueChanged(this)
@@ -108,7 +108,7 @@ internal abstract class CompositeListValueImpl<T>(
 }
 
 // workaround to a type inference bug
-internal fun <K, V> Setting.createCompositeMapValueImpl(
+internal fun <K, V> PluginData.createCompositeMapValueImpl(
     kToValue: (K) -> Value<K>,
     vToValue: (V) -> Value<V>
 ): CompositeMapValueImpl<K, V> {
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/Setting.value composite impl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/PluginData.value composite impl.kt
similarity index 92%
rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/Setting.value composite impl.kt
rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/PluginData.value composite impl.kt
index 990e778f0..4bfb9ed43 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/Setting.value composite impl.kt	
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/PluginData.value composite impl.kt	
@@ -9,13 +9,13 @@
 
 @file:Suppress("NOTHING_TO_INLINE", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
 
-package net.mamoe.mirai.console.internal.setting
+package net.mamoe.mirai.console.internal.data
 
 import kotlinx.serialization.KSerializer
-import net.mamoe.mirai.console.setting.SerializableValue.Companion.serializableValueWith
-import net.mamoe.mirai.console.setting.SerializerAwareValue
-import net.mamoe.mirai.console.setting.Setting
-import net.mamoe.mirai.console.setting.valueFromKType
+import net.mamoe.mirai.console.data.PluginData
+import net.mamoe.mirai.console.data.SerializableValue.Companion.serializableValueWith
+import net.mamoe.mirai.console.data.SerializerAwareValue
+import net.mamoe.mirai.console.data.valueFromKType
 import kotlin.reflect.KClass
 import kotlin.reflect.KType
 import kotlin.reflect.full.createInstance as createInstanceKotlin
@@ -30,7 +30,7 @@ internal inline fun <reified T> typeOf0(): KType = kotlin.reflect.typeOf<T>()
 
 @PublishedApi
 @Suppress("UnsafeCall", "SMARTCAST_IMPOSSIBLE", "UNCHECKED_CAST")
-internal fun Setting.valueFromKTypeImpl(type: KType): SerializerAwareValue<*> {
+internal fun PluginData.valueFromKTypeImpl(type: KType): SerializerAwareValue<*> {
     val classifier = type.classifier
     require(classifier is KClass<*>)
 
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/SettingImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/PluginDataImpl.kt
similarity index 85%
rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/SettingImpl.kt
rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/PluginDataImpl.kt
index 6afe1b203..88eb0b3cf 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/SettingImpl.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/PluginDataImpl.kt
@@ -9,7 +9,7 @@
 
 @file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "EXPOSED_SUPER_CLASS")
 
-package net.mamoe.mirai.console.internal.setting
+package net.mamoe.mirai.console.internal.data
 
 import kotlinx.serialization.KSerializer
 import kotlinx.serialization.SerialName
@@ -19,9 +19,9 @@ import kotlinx.serialization.descriptors.SerialDescriptor
 import kotlinx.serialization.encoding.CompositeDecoder
 import kotlinx.serialization.encoding.Decoder
 import kotlinx.serialization.encoding.Encoder
-import net.mamoe.mirai.console.setting.AbstractSetting.ValueNode
-import net.mamoe.mirai.console.setting.Setting
-import net.mamoe.mirai.console.setting.Value
+import net.mamoe.mirai.console.data.PluginData
+import net.mamoe.mirai.console.data.PluginData.ValueNode
+import net.mamoe.mirai.console.data.Value
 import net.mamoe.yamlkt.YamlNullableDynamicSerializer
 import kotlin.reflect.KProperty
 import kotlin.reflect.full.findAnnotation
@@ -29,17 +29,17 @@ import kotlin.reflect.full.findAnnotation
 internal val KProperty<*>.serialName: String get() = this.findAnnotation<SerialName>()?.value ?: this.name
 
 /**
- * Internal implementation for [Setting] including:
+ * Internal implementation for [PluginData] including:
  * - Reflection on Kotlin properties and Java fields
  * - Auto-saving
  */
-internal abstract class SettingImpl {
+internal abstract class PluginDataImpl {
     internal fun findNodeInstance(name: String): ValueNode<*>? = valueNodes.firstOrNull { it.serialName == name }
 
     internal abstract val valueNodes: MutableList<ValueNode<*>>
 
     internal open val updaterSerializer: KSerializer<Unit> = object : KSerializer<Unit> {
-        override val descriptor: SerialDescriptor get() = settingUpdaterSerializerDescriptor
+        override val descriptor: SerialDescriptor get() = dataUpdaterSerializerDescriptor
 
         @Suppress("UNCHECKED_CAST")
         override fun deserialize(decoder: Decoder) {
@@ -96,7 +96,7 @@ internal abstract class SettingImpl {
             with(encoder.beginCollection(descriptor, valueNodes.size)) {
                 var index = 0
 
-                // val vSerializer = settingUpdaterSerializerTypeArguments[1] as KSerializer<Any?>
+                // val vSerializer = dataUpdaterSerializerTypeArguments[1] as KSerializer<Any?>
                 valueNodes.forEach { (serialName, _, valueSerializer) ->
                     encodeSerializableElement(descriptor, index++, String.serializer(), serialName)
                     encodeSerializableElement(descriptor, index++, valueSerializer, Unit)
@@ -113,8 +113,8 @@ internal abstract class SettingImpl {
     abstract fun onValueChanged(value: Value<*>)
 
     companion object {
-        private val settingUpdaterSerializerTypeArguments = arrayOf(String.serializer(), YamlNullableDynamicSerializer)
-        private val settingUpdaterSerializerDescriptor =
-            MapSerializer(settingUpdaterSerializerTypeArguments[0], settingUpdaterSerializerTypeArguments[1]).descriptor
+        private val dataUpdaterSerializerTypeArguments = arrayOf(String.serializer(), YamlNullableDynamicSerializer)
+        private val dataUpdaterSerializerDescriptor =
+            MapSerializer(dataUpdaterSerializerTypeArguments[0], dataUpdaterSerializerTypeArguments[1]).descriptor
     }
 }
\ No newline at end of file
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/SettingStorage internal.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/PluginDataStorage internal.kt
similarity index 59%
rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/SettingStorage internal.kt
rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/PluginDataStorage internal.kt
index 04e4fcf31..b83886b02 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/SettingStorage internal.kt	
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/PluginDataStorage internal.kt	
@@ -7,14 +7,14 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.console.internal.setting
+package net.mamoe.mirai.console.internal.data
 
 import kotlinx.atomicfu.atomic
 import kotlinx.coroutines.*
+import net.mamoe.mirai.console.data.*
 import net.mamoe.mirai.console.internal.command.qualifiedNameOrTip
 import net.mamoe.mirai.console.internal.plugin.updateWhen
-import net.mamoe.mirai.console.plugin.jvm.loadSetting
-import net.mamoe.mirai.console.setting.*
+import net.mamoe.mirai.console.plugin.jvm.loadPluginData
 import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
 import net.mamoe.mirai.console.util.ConsoleInternalAPI
 import net.mamoe.mirai.utils.currentTimeMillis
@@ -26,21 +26,21 @@ import kotlin.reflect.full.findAnnotation
 
 
 /**
- * 链接自动保存的 [Setting].
+ * 链接自动保存的 [PluginData].
  * 当任一相关 [Value] 的值被修改时, 将在一段时间无其他修改时保存
  *
- * 若 [AutoSaveSettingHolder.coroutineContext] 含有 [Job], 则 [AutoSaveSetting] 会通过 [Job.invokeOnCompletion] 在 Job 完结时触发自动保存.
+ * 若 [AutoSavePluginDataHolder.coroutineContext] 含有 [Job], 则 [AutoSavePluginData] 会通过 [Job.invokeOnCompletion] 在 Job 完结时触发自动保存.
  *
- * @see loadSetting
+ * @see loadPluginData
  */
-internal open class AutoSaveSetting(
-    private val owner: AutoSaveSettingHolder,
-    internal val originSettingClass: KClass<out Setting>
+internal open class AutoSavePluginData(
+    private val owner: AutoSavePluginDataHolder,
+    internal val originPluginDataClass: KClass<out PluginData>
 ) :
-    AbstractSetting() {
-    private lateinit var storage: SettingStorage
+    AbstractPluginData() {
+    private lateinit var storage: PluginDataStorage
 
-    override fun setStorage(storage: SettingStorage) {
+    override fun setStorage(storage: PluginDataStorage) {
         check(!this::storage.isInitialized) { "storage is already initialized" }
         this.storage = storage
     }
@@ -82,71 +82,71 @@ internal open class AutoSaveSetting(
     private fun doSave() = storage.store(owner, this)
 }
 
-internal class MemorySettingStorageImpl(
-    private val onChanged: MemorySettingStorage.OnChangedCallback
-) : SettingStorage, MemorySettingStorage,
-    MutableMap<Class<out Setting>, Setting> by mutableMapOf() {
+internal class MemoryPluginDataStorageImpl(
+    private val onChanged: MemoryPluginDataStorage.OnChangedCallback
+) : PluginDataStorage, MemoryPluginDataStorage,
+    MutableMap<Class<out PluginData>, PluginData> by mutableMapOf() {
 
-    internal inner class MemorySettingImpl : AbstractSetting() {
+    internal inner class MemoryPluginDataImpl : AbstractPluginData() {
         @ConsoleInternalAPI
         override fun onValueChanged(value: Value<*>) {
-            onChanged.onChanged(this@MemorySettingStorageImpl, value)
+            onChanged.onChanged(this@MemoryPluginDataStorageImpl, value)
         }
 
-        override fun setStorage(storage: SettingStorage) {
-            check(storage is MemorySettingStorageImpl) { "storage is not MemorySettingStorageImpl" }
+        override fun setStorage(storage: PluginDataStorage) {
+            check(storage is MemoryPluginDataStorageImpl) { "storage is not MemoryPluginDataStorageImpl" }
         }
     }
 
     @Suppress("UNCHECKED_CAST")
-    override fun <T : Setting> load(holder: SettingHolder, settingClass: Class<T>): T = (synchronized(this) {
-        this.getOrPut(settingClass) {
-            settingClass.kotlin.run {
+    override fun <T : PluginData> load(holder: PluginDataHolder, dataClass: Class<T>): T = (synchronized(this) {
+        this.getOrPut(dataClass) {
+            dataClass.kotlin.run {
                 objectInstance ?: createInstanceOrNull() ?: kotlin.run {
-                    if (settingClass != Setting::class.java) {
+                    if (dataClass != PluginData::class.java) {
                         throw IllegalArgumentException(
-                            "Cannot create Setting instance. Make sure settingClass is Setting::class.java or a Kotlin's object, " +
+                            "Cannot create PluginData instance. Make sure dataClass is PluginData::class.java or a Kotlin's object, " +
                                     "or has a constructor which either has no parameters or all parameters of which are optional"
                         )
                     }
-                    MemorySettingImpl()
+                    MemoryPluginDataImpl()
                 }
             }
         }
     } as T).also { it.setStorage(this) }
 
-    override fun store(holder: SettingHolder, setting: Setting) {
+    override fun store(holder: PluginDataHolder, pluginData: PluginData) {
         synchronized(this) {
-            this[setting::class.java] = setting
+            this[pluginData::class.java] = pluginData
         }
     }
 }
 
 @Suppress("RedundantVisibilityModifier") // might be public in the future
-internal open class MultiFileSettingStorageImpl(
+internal open class MultiFilePluginDataStorageImpl(
     public final override val directory: File
-) : SettingStorage, MultiFileSettingStorage {
+) : PluginDataStorage, MultiFilePluginDataStorage {
     init {
         directory.mkdir()
     }
 
-    public override fun <T : Setting> load(holder: SettingHolder, settingClass: Class<T>): T =
-        with(settingClass.kotlin) {
+    public override fun <T : PluginData> load(holder: PluginDataHolder, dataClass: Class<T>): T =
+        with(dataClass.kotlin) {
             @Suppress("UNCHECKED_CAST")
             val instance = objectInstance ?: this.createInstanceOrNull() ?: kotlin.run {
-                require(settingClass == Setting::class.java) {
-                    "Cannot create Setting instance. Make sure settingClass is Setting::class.java or a Kotlin's object, " +
+                require(dataClass == PluginData::class.java) {
+                    "Cannot create PluginData instance. Make sure dataClass is PluginData::class.java or a Kotlin's object, " +
                             "or has a constructor which either has no parameters or all parameters of which are optional"
                 }
-                if (holder is AutoSaveSettingHolder) {
-                    AutoSaveSetting(holder, this) as T?
+                if (holder is AutoSavePluginDataHolder) {
+                    AutoSavePluginData(holder, this) as T?
                 } else null
             } ?: throw IllegalArgumentException(
-                "Cannot create Setting instance. Make sure 'holder' is a AutoSaveSettingHolder, " +
-                        "or 'setting' is an object or has a constructor which either has no parameters or all parameters of which are optional"
+                "Cannot create PluginData instance. Make sure 'holder' is a AutoSavePluginDataHolder, " +
+                        "or 'data' is an object or has a constructor which either has no parameters or all parameters of which are optional"
             )
 
-            val file = getSettingFile(holder, this)
+            val file = getPluginDataFile(holder, this)
             file.createNewFile()
             check(file.exists() && file.isFile && file.canRead()) { "${file.absolutePath} cannot be read" }
             val text = file.readText()
@@ -156,29 +156,32 @@ internal open class MultiFileSettingStorageImpl(
             instance
         }.also { it.setStorage(this) }
 
-    protected open fun getSettingFile(holder: SettingHolder, clazz: KClass<*>): File = with(clazz) {
+    protected open fun getPluginDataFile(holder: PluginDataHolder, clazz: KClass<*>): File = with(clazz) {
         val name = findASerialName()
 
         val dir = File(directory, holder.name)
         if (dir.isFile) {
-            error("Target directory ${dir.path} for holder $holder is occupied by a file therefore setting $qualifiedNameOrTip can't be saved.")
+            error("Target directory ${dir.path} for holder $holder is occupied by a file therefore data $qualifiedNameOrTip can't be saved.")
         }
         dir.mkdir()
 
         val file = File(directory, name)
         if (file.isDirectory) {
-            error("Target file $file is occupied by a directory therefore setting $qualifiedNameOrTip can't be saved.")
+            error("Target file $file is occupied by a directory therefore data $qualifiedNameOrTip can't be saved.")
         }
         return file
     }
 
     @ConsoleExperimentalAPI
-    public override fun store(holder: SettingHolder, setting: Setting) {
+    public override fun store(holder: PluginDataHolder, pluginData: PluginData) {
         val file =
-            getSettingFile(holder, if (setting is AutoSaveSetting) setting.originSettingClass else setting::class)
+            getPluginDataFile(
+                holder,
+                if (pluginData is AutoSavePluginData) pluginData.originPluginDataClass else pluginData::class
+            )
 
         if (file.exists() && file.isFile && file.canRead()) {
-            file.writeText(Yaml.default.encodeToString(setting.updaterSerializer, Unit))
+            file.writeText(Yaml.default.encodeToString(pluginData.updaterSerializer, Unit))
         }
     }
 }
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/SemverAsStringSerializer.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/SemverAsStringSerializer.kt
similarity index 95%
rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/SemverAsStringSerializer.kt
rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/SemverAsStringSerializer.kt
index 39fe0f637..f319a7a0a 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/SemverAsStringSerializer.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/SemverAsStringSerializer.kt
@@ -7,7 +7,7 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.console.internal.setting
+package net.mamoe.mirai.console.internal.data
 
 import com.vdurmont.semver4j.Semver
 import kotlinx.serialization.KSerializer
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/_Setting.value.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/_PluginData.value.kt
similarity index 69%
rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/_Setting.value.kt
rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/_PluginData.value.kt
index abf3b6c04..d8b5aa213 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/_Setting.value.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/_PluginData.value.kt
@@ -7,11 +7,11 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.console.internal.setting
+package net.mamoe.mirai.console.internal.data
 
 import kotlinx.serialization.builtins.serializer
-import net.mamoe.mirai.console.setting.SerializerAwareValue
-import net.mamoe.mirai.console.setting.Setting
+import net.mamoe.mirai.console.data.PluginData
+import net.mamoe.mirai.console.data.SerializerAwareValue
 import kotlin.reflect.KClass
 
 
@@ -49,9 +49,9 @@ internal object BuiltInSerializerConstants {
 }
 
 @Suppress("UNCHECKED_CAST")
-internal fun <T : Any> Setting.valueImplPrimitive(kClass: KClass<T>): SerializerAwareValue<T>? {
+internal fun <T : Any> PluginData.valueImplPrimitive(kClass: KClass<T>): SerializerAwareValue<T>? {
     return when (kClass) {
-        //// region Setting_valueImplPrimitive CODEGEN ////
+        //// region PluginData_valueImplPrimitive CODEGEN ////
 
         Byte::class -> byteValueImpl()
         Short::class -> shortValueImpl()
@@ -63,103 +63,120 @@ internal fun <T : Any> Setting.valueImplPrimitive(kClass: KClass<T>): Serializer
         Boolean::class -> booleanValueImpl()
         String::class -> stringValueImpl()
 
-        //// endregion Setting_valueImplPrimitive CODEGEN ////
+        //// endregion PluginData_valueImplPrimitive CODEGEN ////
         else -> error("Internal error: unexpected type passed: ${kClass.qualifiedName}")
     } as SerializerAwareValue<T>?
 }
 
 
-//// region Setting_value_PrimitivesImpl CODEGEN ////
+//// region PluginData_value_PrimitivesImpl CODEGEN ////
 
-internal fun Setting.valueImpl(default: Byte): SerializerAwareValue<Byte> {
+internal fun PluginData.valueImpl(default: Byte): SerializerAwareValue<Byte> {
     return object : ByteValueImpl(default) {
         override fun onChanged() = this@valueImpl.onValueChanged(this)
     }
 }
-internal fun Setting.byteValueImpl(): SerializerAwareValue<Byte> {
+
+internal fun PluginData.byteValueImpl(): SerializerAwareValue<Byte> {
     return object : ByteValueImpl() {
         override fun onChanged() = this@byteValueImpl.onValueChanged(this)
     }
 }
-internal fun Setting.valueImpl(default: Short): SerializerAwareValue<Short> {
+
+internal fun PluginData.valueImpl(default: Short): SerializerAwareValue<Short> {
     return object : ShortValueImpl(default) {
         override fun onChanged() = this@valueImpl.onValueChanged(this)
     }
 }
-internal fun Setting.shortValueImpl(): SerializerAwareValue<Short> {
+
+internal fun PluginData.shortValueImpl(): SerializerAwareValue<Short> {
     return object : ShortValueImpl() {
         override fun onChanged() = this@shortValueImpl.onValueChanged(this)
     }
 }
-internal fun Setting.valueImpl(default: Int): SerializerAwareValue<Int> {
+
+internal fun PluginData.valueImpl(default: Int): SerializerAwareValue<Int> {
     return object : IntValueImpl(default) {
         override fun onChanged() = this@valueImpl.onValueChanged(this)
     }
 }
-internal fun Setting.intValueImpl(): SerializerAwareValue<Int> {
+
+internal fun PluginData.intValueImpl(): SerializerAwareValue<Int> {
     return object : IntValueImpl() {
         override fun onChanged() = this@intValueImpl.onValueChanged(this)
     }
 }
-internal fun Setting.valueImpl(default: Long): SerializerAwareValue<Long> {
+
+internal fun PluginData.valueImpl(default: Long): SerializerAwareValue<Long> {
     return object : LongValueImpl(default) {
         override fun onChanged() = this@valueImpl.onValueChanged(this)
     }
 }
-internal fun Setting.longValueImpl(): SerializerAwareValue<Long> {
+
+internal fun PluginData.longValueImpl(): SerializerAwareValue<Long> {
     return object : LongValueImpl() {
         override fun onChanged() = this@longValueImpl.onValueChanged(this)
     }
 }
-internal fun Setting.valueImpl(default: Float): SerializerAwareValue<Float> {
+
+internal fun PluginData.valueImpl(default: Float): SerializerAwareValue<Float> {
     return object : FloatValueImpl(default) {
         override fun onChanged() = this@valueImpl.onValueChanged(this)
     }
 }
-internal fun Setting.floatValueImpl(): SerializerAwareValue<Float> {
+
+internal fun PluginData.floatValueImpl(): SerializerAwareValue<Float> {
     return object : FloatValueImpl() {
         override fun onChanged() = this@floatValueImpl.onValueChanged(this)
     }
 }
-internal fun Setting.valueImpl(default: Double): SerializerAwareValue<Double> {
+
+internal fun PluginData.valueImpl(default: Double): SerializerAwareValue<Double> {
     return object : DoubleValueImpl(default) {
         override fun onChanged() = this@valueImpl.onValueChanged(this)
     }
 }
-internal fun Setting.doubleValueImpl(): SerializerAwareValue<Double> {
+
+internal fun PluginData.doubleValueImpl(): SerializerAwareValue<Double> {
     return object : DoubleValueImpl() {
         override fun onChanged() = this@doubleValueImpl.onValueChanged(this)
     }
 }
-internal fun Setting.valueImpl(default: Char): SerializerAwareValue<Char> {
+
+internal fun PluginData.valueImpl(default: Char): SerializerAwareValue<Char> {
     return object : CharValueImpl(default) {
         override fun onChanged() = this@valueImpl.onValueChanged(this)
     }
 }
-internal fun Setting.charValueImpl(): SerializerAwareValue<Char> {
+
+internal fun PluginData.charValueImpl(): SerializerAwareValue<Char> {
     return object : CharValueImpl() {
         override fun onChanged() = this@charValueImpl.onValueChanged(this)
     }
 }
-internal fun Setting.valueImpl(default: Boolean): SerializerAwareValue<Boolean> {
+
+internal fun PluginData.valueImpl(default: Boolean): SerializerAwareValue<Boolean> {
     return object : BooleanValueImpl(default) {
         override fun onChanged() = this@valueImpl.onValueChanged(this)
     }
 }
-internal fun Setting.booleanValueImpl(): SerializerAwareValue<Boolean> {
+
+internal fun PluginData.booleanValueImpl(): SerializerAwareValue<Boolean> {
     return object : BooleanValueImpl() {
         override fun onChanged() = this@booleanValueImpl.onValueChanged(this)
     }
 }
-internal fun Setting.valueImpl(default: String): SerializerAwareValue<String> {
+
+internal fun PluginData.valueImpl(default: String): SerializerAwareValue<String> {
     return object : StringValueImpl(default) {
         override fun onChanged() = this@valueImpl.onValueChanged(this)
     }
 }
-internal fun Setting.stringValueImpl(): SerializerAwareValue<String> {
+
+internal fun PluginData.stringValueImpl(): SerializerAwareValue<String> {
     return object : StringValueImpl() {
         override fun onChanged() = this@stringValueImpl.onValueChanged(this)
     }
 }
 
-//// endregion Setting_value_PrimitivesImpl CODEGEN ////
+//// endregion PluginData_value_PrimitivesImpl CODEGEN ////
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/_PrimitiveValueDeclarations.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/_PrimitiveValueDeclarations.kt
similarity index 99%
rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/_PrimitiveValueDeclarations.kt
rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/_PrimitiveValueDeclarations.kt
index 81dee4d8a..df89a4931 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/_PrimitiveValueDeclarations.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/_PrimitiveValueDeclarations.kt
@@ -7,14 +7,14 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.console.internal.setting
+package net.mamoe.mirai.console.internal.data
 
 import kotlinx.serialization.KSerializer
 import kotlinx.serialization.builtins.serializer
 import kotlinx.serialization.descriptors.SerialDescriptor
 import kotlinx.serialization.encoding.Decoder
 import kotlinx.serialization.encoding.Encoder
-import net.mamoe.mirai.console.setting.*
+import net.mamoe.mirai.console.data.*
 
 /**
  * The super class to all ValueImpl s
@@ -98,7 +98,6 @@ internal abstract class ShortValueImpl : ShortValue, SerializerAwareValue<Short>
         else value.hashCode() * 31
     }
 }
-
 internal abstract class IntValueImpl : IntValue, SerializerAwareValue<Int>, KSerializer<Unit>, AbstractValueImpl<Int> {
     constructor()
     constructor(default: Int) {
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/asKClass.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/asKClass.kt
similarity index 78%
rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/asKClass.kt
rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/asKClass.kt
index 0e0ab2e2d..1ea34d799 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/asKClass.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/asKClass.kt
@@ -7,10 +7,10 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.console.internal.setting
+package net.mamoe.mirai.console.internal.data
 
+import net.mamoe.mirai.console.data.PluginData
 import net.mamoe.mirai.console.internal.command.qualifiedNameOrTip
-import net.mamoe.mirai.console.setting.Setting
 import kotlin.reflect.KClass
 import kotlin.reflect.KType
 import kotlin.reflect.full.isSubclassOf
@@ -29,16 +29,16 @@ internal inline fun <reified T : Any> KType.asKClass(): KClass<out T> {
     return clazz
 }
 
-internal inline fun <reified T : Setting> newSettingInstanceUsingReflection(type: KType): T {
+internal inline fun <reified T : PluginData> newPluginDataInstanceUsingReflection(type: KType): T {
     val classifier = type.asKClass<T>()
 
     return with(classifier) {
         objectInstance
             ?: createInstanceOrNull()
             ?: throw IllegalArgumentException(
-                "Cannot create Setting instance. " +
-                        "SettingHolder supports Settings implemented as an object " +
-                        "or the ones with a constructor which either has no parameters or all parameters of which are optional, by default newSettingInstance implementation."
+                "Cannot create PluginData instance. " +
+                        "PluginDataHolder supports PluginDatas implemented as an object " +
+                        "or the ones with a constructor which either has no parameters or all parameters of which are optional, by default newPluginDataInstance implementation."
             )
     }
 }
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/collectionUtil.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/collectionUtil.kt
similarity index 99%
rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/collectionUtil.kt
rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/collectionUtil.kt
index 528293c23..571138e53 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/collectionUtil.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/collectionUtil.kt
@@ -9,7 +9,7 @@
 
 @file:Suppress("DuplicatedCode")
 
-package net.mamoe.mirai.console.internal.setting
+package net.mamoe.mirai.console.internal.data
 
 import kotlinx.serialization.InternalSerializationApi
 import kotlinx.serialization.serializer
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/serializerHelper.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/serializerHelper.kt
similarity index 99%
rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/serializerHelper.kt
rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/serializerHelper.kt
index c74954ab7..8a5afe07c 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/serializerHelper.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/serializerHelper.kt
@@ -7,7 +7,7 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.console.internal.setting
+package net.mamoe.mirai.console.internal.data
 
 import kotlinx.serialization.ExperimentalSerializationApi
 import kotlinx.serialization.InternalSerializationApi
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/serializerUtil.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/serializerUtil.kt
similarity index 97%
rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/serializerUtil.kt
rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/serializerUtil.kt
index 342777ccd..1800eafe6 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/setting/serializerUtil.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/serializerUtil.kt
@@ -7,7 +7,7 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.console.internal.setting
+package net.mamoe.mirai.console.internal.data
 
 import kotlinx.serialization.KSerializer
 import kotlinx.serialization.SerialName
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JarPluginLoaderImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JarPluginLoaderImpl.kt
index 45b4ea85a..6bb33be26 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JarPluginLoaderImpl.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JarPluginLoaderImpl.kt
@@ -11,6 +11,7 @@ package net.mamoe.mirai.console.internal.plugin
 
 import kotlinx.coroutines.*
 import net.mamoe.mirai.console.MiraiConsole
+import net.mamoe.mirai.console.data.PluginDataStorage
 import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge
 import net.mamoe.mirai.console.plugin.AbstractFilePluginLoader
 import net.mamoe.mirai.console.plugin.PluginLoadException
@@ -18,7 +19,6 @@ import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
 import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
 import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
 import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescriptionImpl
-import net.mamoe.mirai.console.setting.SettingStorage
 import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
 import net.mamoe.mirai.utils.MiraiLogger
 import net.mamoe.yamlkt.Yaml
@@ -35,8 +35,8 @@ internal object JarPluginLoaderImpl :
     private val logger: MiraiLogger = MiraiConsole.newLogger(JarPluginLoader::class.simpleName!!)
 
     @ConsoleExperimentalAPI
-    override val settingStorage: SettingStorage
-        get() = MiraiConsoleImplementationBridge.settingStorageForJarPluginLoader
+    override val dataStorage: PluginDataStorage
+        get() = MiraiConsoleImplementationBridge.dataStorageForJarPluginLoader
 
     override val coroutineContext: CoroutineContext =
         MiraiConsole.coroutineContext +
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JvmPluginInternal.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JvmPluginInternal.kt
index 575969f86..d9f90f98b 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JvmPluginInternal.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JvmPluginInternal.kt
@@ -17,6 +17,7 @@ import net.mamoe.mirai.console.plugin.Plugin
 import net.mamoe.mirai.console.plugin.PluginManager
 import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
 import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
+import net.mamoe.mirai.console.plugin.safeLoader
 import net.mamoe.mirai.console.util.ResourceContainer.Companion.asResourceContainer
 import net.mamoe.mirai.utils.MiraiLogger
 import java.io.File
@@ -65,17 +66,36 @@ internal abstract class JvmPluginInternal(
 
     internal fun internalOnDisable() {
         firstRun = false
-        this.onDisable()
-        this.cancel(CancellationException("plugin disabled"))
+        kotlin.runCatching {
+            onLoad()
+        }.fold(
+            onSuccess = {
+                cancel(CancellationException("plugin disabled"))
+            },
+            onFailure = {
+                cancel(CancellationException("Exception while enabling plugin", it))
+            }
+        )
     }
 
-    internal fun internalOnLoad() {
-        this.onLoad()
+    @Throws(Throwable::class)
+    internal fun internalOnLoad() { // propagate exceptions
+        onLoad()
     }
 
-    internal fun internalOnEnable() {
+    internal fun internalOnEnable(): Boolean {
         if (!firstRun) refreshCoroutineContext()
-        this.onEnable()
+        kotlin.runCatching {
+            onEnable()
+        }.fold(
+            onSuccess = {
+                return true
+            },
+            onFailure = {
+                cancel(CancellationException("Exception while enabling plugin", it))
+                return false
+            }
+        )
     }
 
     // endregion
@@ -85,18 +105,25 @@ internal abstract class JvmPluginInternal(
     // for future use
     @Suppress("PropertyName")
     @JvmField
-    internal var _intrinsicCoroutineContext: CoroutineContext =
-        EmptyCoroutineContext
+    internal var _intrinsicCoroutineContext: CoroutineContext = EmptyCoroutineContext
 
     @JvmField
     internal val coroutineContextInitializer = {
         CoroutineExceptionHandler { _, throwable -> logger.error(throwable) }
             .plus(parentCoroutineContext)
-            .plus(SupervisorJob(parentCoroutineContext[Job])) + _intrinsicCoroutineContext
+            .plus(SupervisorJob(parentCoroutineContext[Job]))
+            .plus(_intrinsicCoroutineContext)
     }
 
     private fun refreshCoroutineContext(): CoroutineContext {
-        return coroutineContextInitializer().also { _coroutineContext = it }
+        return coroutineContextInitializer().also { _coroutineContext = it }.also {
+            job.invokeOnCompletion { e ->
+                if (e != null) {
+                    logger.error(e)
+                    safeLoader.disable(this)
+                }
+            }
+        }
     }
 
     private val contextUpdateLock: ReentrantLock =
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/PluginManagerImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/PluginManagerImpl.kt
index 303996e27..6cc295f1e 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/PluginManagerImpl.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/PluginManagerImpl.kt
@@ -15,7 +15,7 @@ import kotlinx.atomicfu.locks.withLock
 import kotlinx.coroutines.InternalCoroutinesApi
 import kotlinx.coroutines.Job
 import net.mamoe.mirai.console.MiraiConsole
-import net.mamoe.mirai.console.internal.setting.cast
+import net.mamoe.mirai.console.internal.data.cast
 import net.mamoe.mirai.console.plugin.*
 import net.mamoe.mirai.utils.info
 import java.io.File
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/utils/BotManagerImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/utils/BotManagerImpl.kt
index e4d0c06c5..85b6347b3 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/utils/BotManagerImpl.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/utils/BotManagerImpl.kt
@@ -16,9 +16,9 @@ import kotlinx.coroutines.Job
 import kotlinx.coroutines.SupervisorJob
 import net.mamoe.mirai.Bot
 import net.mamoe.mirai.console.MiraiConsole
+import net.mamoe.mirai.console.data.*
+import net.mamoe.mirai.console.data.PluginDataStorage.Companion.load
 import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge
-import net.mamoe.mirai.console.setting.*
-import net.mamoe.mirai.console.setting.SettingStorage.Companion.load
 import net.mamoe.mirai.console.util.BotManager
 import net.mamoe.mirai.contact.User
 import net.mamoe.mirai.utils.minutesToMillis
@@ -29,7 +29,7 @@ internal object BotManagerImpl : BotManager {
     /**
      * 判断此用户是否为 console 管理员
      */
-    override val User.isManager: Boolean get() = this.id in this.bot.managers
+    override val User.isManager: Boolean get() = this.id in ManagersConfig[this.bot]
 
     override fun Bot.removeManager(id: Long): Boolean {
         return ManagersConfig[this].remove(id)
@@ -43,7 +43,7 @@ internal object BotManagerImpl : BotManager {
     }
 }
 
-internal object ManagersConfig : Setting by ConsoleBuiltInSettingStorage.load() {
+internal object ManagersConfig : PluginData by ConsoleBuiltInPluginDataStorage.load() {
     private val managers: MutableMap<Long, MutableSet<Long>> by value()
 
     internal operator fun get(bot: Bot): MutableSet<Long> = managers.getOrPut(bot.id, ::mutableSetOf)
@@ -54,14 +54,14 @@ internal fun CoroutineContext.overrideWithSupervisorJob(): CoroutineContext = th
 internal fun CoroutineScope.childScope(context: CoroutineContext = EmptyCoroutineContext): CoroutineScope =
     CoroutineScope(this.coroutineContext.overrideWithSupervisorJob() + context)
 
-internal object ConsoleBuiltInSettingHolder : AutoSaveSettingHolder,
+internal object ConsoleBuiltInPluginDataHolder : AutoSavePluginDataHolder,
     CoroutineScope by MiraiConsole.childScope() {
     override val autoSaveIntervalMillis: LongRange = 30.minutesToMillis..60.minutesToMillis
     override val name: String get() = "ConsoleBuiltIns"
 }
 
-internal object ConsoleBuiltInSettingStorage :
-    SettingStorage by MiraiConsoleImplementationBridge.settingStorageForJarPluginLoader {
+internal object ConsoleBuiltInPluginDataStorage :
+    PluginDataStorage by MiraiConsoleImplementationBridge.dataStorageForBuiltIns {
 
-    inline fun <reified T : Setting> load(): T = load(ConsoleBuiltInSettingHolder)
+    inline fun <reified T : PluginData> load(): T = load(ConsoleBuiltInPluginDataHolder)
 }
\ No newline at end of file
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description.kt
index f7ef9c8c0..9029e8d15 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/description.kt
@@ -14,8 +14,8 @@ import kotlinx.serialization.KSerializer
 import kotlinx.serialization.Serializable
 import kotlinx.serialization.builtins.serializer
 import kotlinx.serialization.encodeToString
-import net.mamoe.mirai.console.internal.setting.SemverAsStringSerializerIvy
-import net.mamoe.mirai.console.internal.setting.map
+import net.mamoe.mirai.console.internal.data.SemverAsStringSerializerIvy
+import net.mamoe.mirai.console.internal.data.map
 import net.mamoe.yamlkt.Yaml
 import net.mamoe.yamlkt.YamlDynamicSerializer
 import java.io.File
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JarPluginLoader.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JarPluginLoader.kt
index 5ac08034c..134b2d018 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JarPluginLoader.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JarPluginLoader.kt
@@ -10,9 +10,9 @@
 package net.mamoe.mirai.console.plugin.jvm
 
 import kotlinx.coroutines.CoroutineScope
+import net.mamoe.mirai.console.data.PluginDataStorage
 import net.mamoe.mirai.console.internal.plugin.JarPluginLoaderImpl
 import net.mamoe.mirai.console.plugin.FilePluginLoader
-import net.mamoe.mirai.console.setting.SettingStorage
 import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
 
 /**
@@ -20,10 +20,10 @@ import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
  */
 public interface JarPluginLoader : CoroutineScope, FilePluginLoader<JvmPlugin, JvmPluginDescription> {
     /**
-     * [JvmPlugin.loadSetting] 默认使用的实例
+     * [JvmPlugin.loadPluginData] 默认使用的实例
      */
     @ConsoleExperimentalAPI
-    public val settingStorage: SettingStorage
+    public val dataStorage: PluginDataStorage
 
     public companion object INSTANCE : JarPluginLoader by JarPluginLoaderImpl {
         @Suppress("EXTENSION_SHADOWED_BY_MEMBER")
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt
index d11003d5d..867b4002a 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt
@@ -12,10 +12,10 @@
 package net.mamoe.mirai.console.plugin.jvm
 
 import kotlinx.coroutines.CoroutineScope
+import net.mamoe.mirai.console.data.AutoSavePluginDataHolder
+import net.mamoe.mirai.console.data.PluginData
 import net.mamoe.mirai.console.plugin.Plugin
 import net.mamoe.mirai.console.plugin.PluginFileExtensions
-import net.mamoe.mirai.console.setting.AutoSaveSettingHolder
-import net.mamoe.mirai.console.setting.Setting
 import net.mamoe.mirai.console.util.ResourceContainer
 import net.mamoe.mirai.utils.MiraiLogger
 import kotlin.reflect.KClass
@@ -36,7 +36,7 @@ import kotlin.reflect.KClass
  * @see ResourceContainer 支持资源获取 (如 Jar 中的资源文件)
  */
 public interface JvmPlugin : Plugin, CoroutineScope,
-    PluginFileExtensions, ResourceContainer, AutoSaveSettingHolder {
+    PluginFileExtensions, ResourceContainer, AutoSavePluginDataHolder {
     /** 日志 */
     public val logger: MiraiLogger
 
@@ -49,10 +49,10 @@ public interface JvmPlugin : Plugin, CoroutineScope,
         get() = JarPluginLoader
 
     /**
-     * 从 [JarPluginLoader.settingStorage] 获取一个 [Setting] 实例
+     * 从 [JarPluginLoader.dataStorage] 获取一个 [PluginData] 实例
      */
     @JvmDefault
-    public fun <T : Setting> loadSetting(clazz: Class<T>): T = loader.settingStorage.load(this, clazz)
+    public fun <T : PluginData> loadPluginData(clazz: Class<T>): T = loader.dataStorage.load(this, clazz)
 
     /**
      * 在插件被加载时调用. 只会被调用一次.
@@ -77,7 +77,12 @@ public interface JvmPlugin : Plugin, CoroutineScope,
 }
 
 @JvmSynthetic
-public inline fun <T : Setting> JvmPlugin.loadSetting(clazz: KClass<T>): T = this.loadSetting(clazz.java)
+public inline fun <T : PluginData> JvmPlugin.loadPluginData(clazz: KClass<T>): T = this.loadPluginData(clazz.java)
 
+/**
+ * 读取一个插件数据.
+ *
+ * 插件数据
+ */
 @JvmSynthetic
-public inline fun <reified T : Setting> JvmPlugin.loadSetting(): T = this.loadSetting(T::class)
\ No newline at end of file
+public inline fun <reified T : PluginData> JvmPlugin.loadPluginData(): T = this.loadPluginData(T::class)
\ No newline at end of file
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginDescriptionImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginDescriptionImpl.kt
index 100e48294..32d834527 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginDescriptionImpl.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPluginDescriptionImpl.kt
@@ -13,7 +13,7 @@ import com.vdurmont.semver4j.Semver
 import kotlinx.serialization.SerialName
 import kotlinx.serialization.Serializable
 import kotlinx.serialization.Transient
-import net.mamoe.mirai.console.internal.setting.SemverAsStringSerializerLoose
+import net.mamoe.mirai.console.internal.data.SemverAsStringSerializerLoose
 import net.mamoe.mirai.console.plugin.PluginDependency
 import net.mamoe.mirai.console.plugin.PluginDescription
 import net.mamoe.mirai.console.plugin.PluginKind
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/KotlinPlugin.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/KotlinPlugin.kt
index b26d1d2e6..3199b6236 100644
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/KotlinPlugin.kt
+++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/KotlinPlugin.kt
@@ -48,7 +48,7 @@ public abstract class KotlinMemoryPlugin @JvmOverloads constructor(
 
 public object MyPlugin : KotlinPlugin()
 
-public object AccountSetting : Setting by MyPlugin.getSetting() {
+public object AccountPluginData : PluginData by MyPlugin.getPluginData() {
     public val s by value(1)
 }
 */
\ No newline at end of file
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt
deleted file mode 100644
index f780b7752..000000000
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/Setting.kt
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright 2019-2020 Mamoe Technologies and contributors.
- *
- * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证.
- * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link.
- *
- * https://github.com/mamoe/mirai/blob/master/LICENSE
- */
-
-@file:Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "EXPOSED_SUPER_CLASS")
-
-package net.mamoe.mirai.console.setting
-
-import kotlinx.serialization.KSerializer
-import net.mamoe.mirai.console.internal.setting.*
-import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
-import net.mamoe.mirai.console.plugin.jvm.loadSetting
-import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
-import kotlin.internal.LowPriorityInOverloadResolution
-import kotlin.reflect.KClass
-import kotlin.reflect.KProperty
-import kotlin.reflect.KType
-
-
-/**
- * 序列化之后的名称.
- *
- * 例:
- * ```
- * @SerialName("accounts")
- * object AccountSettings : Setting by ... {
- *    @SerialName("info")
- *    val map: Map<String, String> by value("a" to "b")
- * }
- * ```
- *
- * 将被保存为配置 (YAML 作为示例):
- * ```yaml
- * accounts:
- *   info:
- *     a: b
- * ```
- */
-public typealias SerialName = kotlinx.serialization.SerialName
-
-/**
- * [Setting] 的默认实现. 支持使用 `by value()` 等委托方法创建 [Value] 并跟踪其改动.
- *
- * @see Setting
- */
-public abstract class AbstractSetting : Setting, SettingImpl() {
-    /**
-     * 添加了追踪的 [ValueNode] 列表, 即通过 `by value` 初始化的属性列表.
-     *
-     * 他们的修改会被跟踪, 并触发 [onValueChanged].
-     *
-     * @see provideDelegate
-     */
-    public override val valueNodes: MutableList<ValueNode<*>> = mutableListOf()
-
-    /**
-     * 由 [provideDelegate] 创建, 来自一个通过 `by value` 初始化的属性.
-     */
-    public data class ValueNode<T>(
-        val serialName: String,
-        val value: Value<T>,
-        @ConsoleExperimentalAPI
-        val updaterSerializer: KSerializer<Unit>
-    )
-
-    /**
-     * 使用 `by` 时自动调用此方法, 添加对 [Value] 的值修改的跟踪.
-     *
-     * 将会创建一个 [ValueNode] 并添加到 [valueNodes]
-     */
-    public final override operator fun <T> SerializerAwareValue<T>.provideDelegate(
-        thisRef: Any?,
-        property: KProperty<*>
-    ): SerializerAwareValue<T> {
-        val name = property.serialName
-        valueNodes.add(ValueNode(name, this, this.serializer))
-        return this
-    }
-
-    /**
-     * 值更新序列化器. 仅供内部使用.
-     */
-    @ConsoleExperimentalAPI
-    public final override val updaterSerializer: KSerializer<Unit>
-        get() = super.updaterSerializer
-
-    /**
-     * 当所属于这个 [Setting] 的 [Value] 的 [值][Value.value] 被修改时被调用.
-     */
-    public abstract override fun onValueChanged(value: Value<*>)
-}
-
-/**
- * 一个配置对象. 可包含对多个 [Value] 的值变更的跟踪.
- *
- * 在 [JvmPlugin] 的典型实现方式:
- * ```
- * object PluginMain : KotlinPlugin()
- *
- * object AccountSettings : Setting by PluginMain.loadSetting() {
- *    val map: Map<String, String> by value("a" to "b")
- * }
- * ```
- *
- * @see JvmPlugin.loadSetting 通过 [JvmPlugin] 获取指定 [Setting] 实例.
- */
-public interface Setting : ExperimentalSettingExtensions {
-    /**
-     * 使用 `by` 时自动调用此方法, 添加对 [Value] 的值修改的跟踪.
-     */
-    public operator fun <T> SerializerAwareValue<T>.provideDelegate(
-        thisRef: Any?,
-        property: KProperty<*>
-    ): SerializerAwareValue<T>
-
-    /**
-     * 值更新序列化器. 仅供内部使用
-     */
-    @ConsoleExperimentalAPI
-    public val updaterSerializer: KSerializer<Unit>
-
-    /**
-     * 当所属于这个 [Setting] 的 [Value] 的 [值][Value.value] 被修改时被调用.
-     */
-    public fun onValueChanged(value: Value<*>)
-
-    /**
-     * 当这个 [Setting] 被放入一个 [SettingStorage] 时调用
-     */
-    public fun setStorage(storage: SettingStorage)
-}
-
-@ConsoleExperimentalAPI("")
-public interface ExperimentalSettingExtensions {
-    public fun <E, V, K> MutableMap<E, V>.shadowMap(
-        eToK: (E) -> K,
-        kToE: (K) -> E
-    ): MutableMap<K, V> {
-        return this.shadowMap(
-            kTransform = eToK,
-            kTransformBack = kToE,
-            vTransform = { it },
-            vTransformBack = { it }
-        )
-    }
-}
-
-//// region Setting_value_primitives CODEGEN ////
-
-public fun Setting.value(default: Byte): SerializerAwareValue<Byte> = valueImpl(default)
-public fun Setting.value(default: Short): SerializerAwareValue<Short> = valueImpl(default)
-public fun Setting.value(default: Int): SerializerAwareValue<Int> = valueImpl(default)
-public fun Setting.value(default: Long): SerializerAwareValue<Long> = valueImpl(default)
-public fun Setting.value(default: Float): SerializerAwareValue<Float> = valueImpl(default)
-public fun Setting.value(default: Double): SerializerAwareValue<Double> = valueImpl(default)
-public fun Setting.value(default: Char): SerializerAwareValue<Char> = valueImpl(default)
-public fun Setting.value(default: Boolean): SerializerAwareValue<Boolean> = valueImpl(default)
-public fun Setting.value(default: String): SerializerAwareValue<String> = valueImpl(default)
-
-//// endregion Setting_value_primitives CODEGEN ////
-
-
-/**
- * 通过具体化类型创建一个 [SerializerAwareValue], 并设置初始值.
- *
- * @param T 具体化参数类型 T. 仅支持:
- * - 基础数据类型
- * - 标准库集合类型 ([List], [Map], [Set])
- * - 标准库数据类型 ([Map.Entry], [Pair], [Triple])
- * - 和使用 [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization) 的 [Serializable] 标记的
- */
-@Suppress("UNCHECKED_CAST")
-@LowPriorityInOverloadResolution
-public inline fun <reified T> Setting.value(default: T): SerializerAwareValue<T> = valueFromKType(typeOf0<T>(), default)
-
-/**
- * 通过具体化类型创建一个 [SerializerAwareValue].
- * @see valueFromKType 查看更多实现信息
- */
-@LowPriorityInOverloadResolution
-public inline fun <reified T> Setting.value(): SerializerAwareValue<T> =
-    value(T::class.run { objectInstance ?: createInstanceSmart() } as T)
-
-/**
- * 通过一个特定的 [KType] 创建 [Value], 并设置初始值.
- *
- * 对于 [List], [Map], [Set] 等标准库类型, 这个函数会尝试构造 [LinkedHashMap] 等相关类型.
- * 而对于自定义数据类型, 本函数只会反射获取 [objectInstance][KClass.objectInstance] 或使用无参构造器构造实例.
- *
- * @param T 具体化参数类型 T. 仅支持:
- * - 基础数据类型
- * - 标准库集合类型 ([List], [Map], [Set])
- * - 标准库数据类型 ([Map.Entry], [Pair], [Triple])
- * - 和使用 [kotlinx.serialization](https://github.com/Kotlin/kotlinx.serialization) 的 [Serializable] 标记的
- */
-@Suppress("UNCHECKED_CAST")
-@ConsoleExperimentalAPI
-public fun <T> Setting.valueFromKType(type: KType, default: T): SerializerAwareValue<T> =
-    (valueFromKTypeImpl(type) as SerializerAwareValue<Any?>).apply { this.value = default } as SerializerAwareValue<T>
-
-// TODO: 2020/6/24 Introduce class TypeToken for compound types for Java.
\ No newline at end of file
diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/SettingStorage.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/SettingStorage.kt
deleted file mode 100644
index c24ed9900..000000000
--- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/setting/SettingStorage.kt
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright 2019-2020 Mamoe Technologies and contributors.
- *
- * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions 许可证的约束, 可以在以下链接找到该许可证.
- * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 with Mamoe Exceptions license that can be found via the following link.
- *
- * https://github.com/mamoe/mirai/blob/master/LICENSE
- */
-
-@file:Suppress("NOTHING_TO_INLINE", "UNCHECKED_CAST", "unused")
-
-package net.mamoe.mirai.console.setting
-
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Job
-import net.mamoe.mirai.console.internal.setting.*
-import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
-import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
-import net.mamoe.mirai.console.setting.SettingStorage.Companion.load
-import java.io.File
-import kotlin.reflect.KClass
-import kotlin.reflect.KType
-import kotlin.reflect.full.createType
-
-/**
- * [Setting] 存储容器.
- *
- * 此为较低层的 API, 一般插件开发者不会接触.
- *
- * [JarPluginLoader] 实现一个 [SettingStorage], 用于管理所有 [JvmPlugin] 的 [Setting] 实例.
- *
- * @see SettingHolder
- * @see JarPluginLoader.settingStorage
- */
-public interface SettingStorage {
-    /**
-     * 读取一个实例. 在 [T] 实例创建后 [设置 [SettingStorage]][Setting.setStorage]
-     */
-    public fun <T : Setting> load(holder: SettingHolder, settingClass: Class<T>): T
-
-    /**
-     * 保存一个实例
-     */
-    public fun store(holder: SettingHolder, setting: Setting)
-
-    public companion object {
-        /**
-         * 读取一个实例. 在 [T] 实例创建后 [设置 [SettingStorage]][Setting.setStorage]
-         */
-        @JvmStatic
-        public fun <T : Setting> SettingStorage.load(holder: SettingHolder, settingClass: KClass<T>): T =
-            this.load(holder, settingClass.java)
-
-        /**
-         * 读取一个实例. 在 [T] 实例创建后 [设置 [SettingStorage]][Setting.setStorage]
-         */
-        @JvmSynthetic
-        public inline fun <reified T : Setting> SettingStorage.load(holder: SettingHolder): T =
-            this.load(holder, T::class)
-    }
-}
-
-/**
- * 在内存存储所有 [Setting] 实例的 [SettingStorage]. 在内存数据丢失后相关 [Setting] 实例也会丢失.
- */
-public interface MemorySettingStorage : SettingStorage, Map<Class<out Setting>, Setting> {
-    /**
-     * 当任一 [Setting] 实例拥有的 [Value] 的值被改变后调用的回调函数.
-     */
-    public fun interface OnChangedCallback {
-        public fun onChanged(storage: MemorySettingStorage, value: Value<*>)
-
-        /**
-         * 无任何操作的 [OnChangedCallback]
-         * @see OnChangedCallback
-         */
-        public object NoOp : OnChangedCallback {
-            public override fun onChanged(storage: MemorySettingStorage, value: Value<*>) {
-                // no-op
-            }
-        }
-    }
-
-    public companion object {
-        /**
-         * 创建一个 [MemorySettingStorage] 实例.
-         *
-         * @param onChanged 当任一 [Setting] 实例拥有的 [Value] 的值被改变后调用的回调函数.
-         */
-        @JvmStatic
-        @JvmName("create")
-        // @JvmOverloads
-        public operator fun invoke(onChanged: OnChangedCallback = OnChangedCallback.NoOp): MemorySettingStorage =
-            MemorySettingStorageImpl(onChanged)
-    }
-}
-
-/**
- * 用多个文件存储 [Setting] 实例的 [SettingStorage].
- */
-public interface MultiFileSettingStorage : SettingStorage {
-    /**
-     * 存放 [Setting] 的目录.
-     */
-    public val directory: File
-
-    public companion object {
-        /**
-         * 创建一个 [MultiFileSettingStorage] 实例.
-         *
-         * @see directory 存放 [Setting] 的目录.
-         */
-        @JvmStatic
-        @JvmName("create")
-        public operator fun invoke(directory: File): MultiFileSettingStorage = MultiFileSettingStorageImpl(directory)
-    }
-}
-
-/**
- * 可以持有相关 [Setting] 实例的对象, 作为 [Setting] 实例的拥有者.
- *
- * @see SettingStorage.load
- * @see SettingStorage.store
- *
- * @see AutoSaveSettingHolder 自动保存
- */
-public interface SettingHolder {
-    /**
-     * 保存时使用的分类名
-     */
-    public val name: String
-
-    /**
-     * 创建一个 [Setting] 实例.
-     *
-     * @see Companion.newSettingInstance
-     * @see KClass.createType
-     */
-    @JvmDefault
-    public fun <T : Setting> newSettingInstance(type: KType): T =
-        newSettingInstanceUsingReflection<Setting>(type) as T
-
-    public companion object {
-        /**
-         * 创建一个 [Setting] 实例.
-         *
-         * @see SettingHolder.newSettingInstance
-         */
-        @JvmSynthetic
-        public inline fun <reified T : Setting> SettingHolder.newSettingInstance(): T {
-            return this.newSettingInstance(typeOf0<T>())
-        }
-    }
-}
-
-/**
- * 可以持有相关 [AutoSaveSetting] 的对象.
- *
- * @see net.mamoe.mirai.console.plugin.jvm.JvmPlugin
- */
-public interface AutoSaveSettingHolder : SettingHolder, CoroutineScope {
-    /**
-     * [AutoSaveSetting] 每次自动保存时间间隔
-     *
-     * - 区间的左端点为最小间隔, 一个 [Value] 被修改后, 若此时间段后无其他修改, 将触发自动保存; 若有, 将重新开始计时.
-     * - 区间的右端点为最大间隔, 一个 [Value] 被修改后, 最多不超过这个时间段后就会被保存.
-     *
-     * 若 [AutoSaveSettingHolder.coroutineContext] 含有 [Job],
-     * 则 [AutoSaveSetting] 会通过 [Job.invokeOnCompletion] 在 Job 完结时触发自动保存.
-     *
-     * @see LongRange Java 用户使用 [LongRange] 的构造器创建
-     * @see Long.rangeTo Kotlin 用户使用 [Long.rangeTo] 创建, 如 `3000..50000`
-     */
-    public val autoSaveIntervalMillis: LongRange
-
-    /**
-     * 仅支持确切的 [Setting] 类型
-     */
-    @JvmDefault
-    public override fun <T : Setting> newSettingInstance(type: KType): T {
-        val classifier = type.classifier?.cast<KClass<Setting>>()
-        require(classifier != null && classifier.java == Setting::class.java) {
-            "Cannot create Setting instance. AutoSaveSettingHolder supports only Setting type."
-        }
-        return AutoSaveSetting(this, classifier) as T // T is always Setting
-    }
-}
\ No newline at end of file
diff --git a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/TestMiraiConosle.kt b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/TestMiraiConosle.kt
index 8242e9b2a..8dd4fc9ef 100644
--- a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/TestMiraiConosle.kt
+++ b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/TestMiraiConosle.kt
@@ -17,11 +17,11 @@ import net.mamoe.mirai.Bot
 import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start
 import net.mamoe.mirai.console.command.CommandManager
 import net.mamoe.mirai.console.command.ConsoleCommandSender
+import net.mamoe.mirai.console.data.MemoryPluginDataStorage
+import net.mamoe.mirai.console.data.PluginDataStorage
 import net.mamoe.mirai.console.plugin.DeferredPluginLoader
 import net.mamoe.mirai.console.plugin.PluginLoader
 import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
-import net.mamoe.mirai.console.setting.MemorySettingStorage
-import net.mamoe.mirai.console.setting.SettingStorage
 import net.mamoe.mirai.console.util.ConsoleInternalAPI
 import net.mamoe.mirai.message.data.Message
 import net.mamoe.mirai.utils.DefaultLogger
@@ -51,8 +51,8 @@ fun initTestEnvironment() {
         override val consoleCommandSender: ConsoleCommandSender = object : ConsoleCommandSender() {
             override suspend fun sendMessage(message: Message) = println(message)
         }
-        override val settingStorageForJarPluginLoader: SettingStorage get() = MemorySettingStorage()
-        override val settingStorageForBuiltIns: SettingStorage get() = MemorySettingStorage()
+        override val dataStorageForJarPluginLoader: PluginDataStorage get() = MemoryPluginDataStorage()
+        override val dataStorageForBuiltIns: PluginDataStorage get() = MemoryPluginDataStorage()
         override val coroutineContext: CoroutineContext = SupervisorJob()
     }.start()
     CommandManager
diff --git a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/data/SettingTest.kt
similarity index 73%
rename from backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt
rename to backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/data/SettingTest.kt
index 5ca8a5c14..be874cbfe 100644
--- a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/setting/SettingTest.kt
+++ b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/data/SettingTest.kt
@@ -7,7 +7,7 @@
  * https://github.com/mamoe/mirai/blob/master/LICENSE
  */
 
-package net.mamoe.mirai.console.setting
+package net.mamoe.mirai.console.data
 
 import kotlinx.serialization.json.Json
 import net.mamoe.mirai.console.util.ConsoleInternalAPI
@@ -16,9 +16,9 @@ import kotlin.test.assertEquals
 import kotlin.test.assertSame
 
 @OptIn(ConsoleInternalAPI::class)
-internal class SettingTest {
+internal class PluginDataTest {
 
-    class MySetting : AbstractSetting() {
+    class MyPluginData : AbstractPluginData() {
         var int by value(1)
         val map by value<MutableMap<String, String>>()
         val map2 by value<MutableMap<String, MutableMap<String, String>>>()
@@ -28,7 +28,7 @@ internal class SettingTest {
 
         }
 
-        override fun setStorage(storage: SettingStorage) {
+        override fun setStorage(storage: PluginDataStorage) {
         }
     }
 
@@ -37,45 +37,45 @@ internal class SettingTest {
 
     @Test
     fun testStringify() {
-        val setting = MySetting()
+        val data = MyPluginData()
 
-        var string = json.encodeToString(setting.updaterSerializer, Unit)
+        var string = json.encodeToString(data.updaterSerializer, Unit)
         assertEquals("""{"int":1,"map":{},"map2":{}}""", string)
 
-        setting.int = 2
+        data.int = 2
 
-        string = json.encodeToString(setting.updaterSerializer, Unit)
+        string = json.encodeToString(data.updaterSerializer, Unit)
         assertEquals("""{"int":2,"map":{},"map2":{}}""", string)
     }
 
     @Test
     fun testParseUpdate() {
-        val setting = MySetting()
+        val data = MyPluginData()
 
-        assertEquals(1, setting.int)
+        assertEquals(1, data.int)
 
         json.decodeFromString(
-            setting.updaterSerializer, """
+            data.updaterSerializer, """
                 {"int":3,"map":{},"map2":{}}
             """.trimIndent()
         )
 
-        assertEquals(3, setting.int)
+        assertEquals(3, data.int)
     }
 
     @Test
     fun testNestedParseUpdate() {
-        val setting = MySetting()
+        val data = MyPluginData()
 
-        fun delegation() = setting.map
+        fun delegation() = data.map
 
-        val refBefore = setting.map
+        val refBefore = data.map
         fun reference() = refBefore
 
         assertEquals(mutableMapOf(), delegation()) // delegation
 
         json.decodeFromString(
-            setting.updaterSerializer, """
+            data.updaterSerializer, """
                 {"int":1,"map":{"t":"test"},"map2":{}}
             """.trimIndent()
         )
@@ -88,17 +88,17 @@ internal class SettingTest {
 
     @Test
     fun testDeepNestedParseUpdate() {
-        val setting = MySetting()
+        val data = MyPluginData()
 
-        fun delegation() = setting.map2
+        fun delegation() = data.map2
 
-        val refBefore = setting.map2
+        val refBefore = data.map2
         fun reference() = refBefore
 
         assertEquals(mutableMapOf(), delegation()) // delegation
 
         json.decodeFromString(
-            setting.updaterSerializer, """
+            data.updaterSerializer, """
                 {"int":1,"map":{},"map2":{"t":{"f":"test"}}}
             """.trimIndent()
         )
@@ -111,19 +111,19 @@ internal class SettingTest {
 
     @Test
     fun testDeepNestedTrackingParseUpdate() {
-        val setting = MySetting()
+        val data = MyPluginData()
 
-        setting.map2["t"] = mutableMapOf()
+        data.map2["t"] = mutableMapOf()
 
-        fun delegation() = setting.map2["t"]!!
+        fun delegation() = data.map2["t"]!!
 
-        val refBefore = setting.map2["t"]!!
+        val refBefore = data.map2["t"]!!
         fun reference() = refBefore
 
         assertEquals(mutableMapOf(), delegation()) // delegation
 
         json.decodeFromString(
-            setting.updaterSerializer, """
+            data.updaterSerializer, """
                 {"int":1,"map":{},"map2":{"t":{"f":"test"}}}
             """.trimIndent()
         )
diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleImplementationPure.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleImplementationPure.kt
index c59bf10b1..b259e3a31 100644
--- a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleImplementationPure.kt
+++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleImplementationPure.kt
@@ -28,11 +28,11 @@ import net.mamoe.mirai.console.ConsoleFrontEndImplementation
 import net.mamoe.mirai.console.MiraiConsoleFrontEnd
 import net.mamoe.mirai.console.MiraiConsoleImplementation
 import net.mamoe.mirai.console.command.ConsoleCommandSender
+import net.mamoe.mirai.console.data.MultiFilePluginDataStorage
+import net.mamoe.mirai.console.data.PluginDataStorage
 import net.mamoe.mirai.console.plugin.DeferredPluginLoader
 import net.mamoe.mirai.console.plugin.PluginLoader
 import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader
-import net.mamoe.mirai.console.setting.MultiFileSettingStorage
-import net.mamoe.mirai.console.setting.SettingStorage
 import net.mamoe.mirai.console.util.ConsoleInternalAPI
 import net.mamoe.mirai.utils.MiraiLogger
 import java.io.File
@@ -53,8 +53,8 @@ class MiraiConsoleImplementationPure
     override val frontEnd: MiraiConsoleFrontEnd = MiraiConsoleFrontEndPure,
     override val mainLogger: MiraiLogger = frontEnd.loggerFor("main"),
     override val consoleCommandSender: ConsoleCommandSender = ConsoleCommandSenderImpl,
-    override val settingStorageForJarPluginLoader: SettingStorage = MultiFileSettingStorage(File(rootDir, "data")),
-    override val settingStorageForBuiltIns: SettingStorage = MultiFileSettingStorage(File(rootDir, "data"))
+    override val dataStorageForJarPluginLoader: PluginDataStorage = MultiFilePluginDataStorage(File(rootDir, "data")),
+    override val dataStorageForBuiltIns: PluginDataStorage = MultiFilePluginDataStorage(File(rootDir, "data"))
 ) : MiraiConsoleImplementation, CoroutineScope by CoroutineScope(SupervisorJob()) {
     init {
         rootDir.mkdir()
diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt
index 9e1d2e269..e81c4342d 100644
--- a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt
+++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt
@@ -20,9 +20,18 @@
 
 package net.mamoe.mirai.console.pure
 
+import kotlinx.coroutines.runBlocking
+import net.mamoe.mirai.alsoLogin
+import net.mamoe.mirai.console.MiraiConsole
 import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start
+import net.mamoe.mirai.console.command.CommandManager.INSTANCE.register
+import net.mamoe.mirai.console.command.CommandPermission
+import net.mamoe.mirai.console.command.CommandSender
 import net.mamoe.mirai.console.command.ConsoleCommandSender
+import net.mamoe.mirai.console.command.SimpleCommand
 import net.mamoe.mirai.console.util.ConsoleInternalAPI
+import net.mamoe.mirai.contact.Member
+import net.mamoe.mirai.contact.nameCardOrNick
 import net.mamoe.mirai.message.data.Message
 import net.mamoe.mirai.message.data.content
 import net.mamoe.mirai.utils.DefaultLogger
@@ -35,9 +44,24 @@ object MiraiConsolePureLoader {
     @JvmStatic
     fun main(args: Array<String>?) {
         startup()
+        YellowCommand.register()
+        runBlocking { MiraiConsole.addBot(1994701021, "Asd123456789asd").alsoLogin() }
     }
 }
 
+object YellowCommand : SimpleCommand(
+    net.mamoe.mirai.console.command.ConsoleCommandOwner, "睡", "sleep",
+    prefixOptional = true,
+    description = "睡一个人",
+    permission = CommandPermission.Any
+) {
+    @Handler
+    suspend fun CommandSender.handle(target: Member) {
+        target.mute(1)
+
+        sendMessage("${this.name} 睡了 ${target.nameCardOrNick}")
+    }
+}
 
 internal fun startup() {
     DefaultLogger = { MiraiConsoleFrontEndPure.loggerFor(it) }