diff --git a/mirai-core-api/src/commonMain/kotlin/contact/Group.kt b/mirai-core-api/src/commonMain/kotlin/contact/Group.kt
index 1fd79770a..eba77e242 100644
--- a/mirai-core-api/src/commonMain/kotlin/contact/Group.kt
+++ b/mirai-core-api/src/commonMain/kotlin/contact/Group.kt
@@ -14,13 +14,14 @@ package net.mamoe.mirai.contact
 import kotlinx.coroutines.CoroutineScope
 import net.mamoe.kjbb.JvmBlockingBridge
 import net.mamoe.mirai.Bot
-import net.mamoe.mirai.LowLevelApi
-import net.mamoe.mirai.data.MemberInfo
 import net.mamoe.mirai.event.events.*
 import net.mamoe.mirai.message.MessageReceipt
 import net.mamoe.mirai.message.MessageReceipt.Companion.recall
 import net.mamoe.mirai.message.data.*
-import net.mamoe.mirai.utils.*
+import net.mamoe.mirai.utils.ExternalImage
+import net.mamoe.mirai.utils.MiraiExperimentalApi
+import net.mamoe.mirai.utils.OverFileSizeMaxException
+import net.mamoe.mirai.utils.PlannedRemoval
 import java.io.InputStream
 
 /**
@@ -66,7 +67,7 @@ public interface Group : Contact, CoroutineScope {
      * @see BotMuteEvent 机器人被禁言事件
      * @see isBotMuted 判断机器人是否正在被禁言
      */
-    public val botMuteRemaining: Int
+    public val botMuteRemaining: Int get() = botAsMember.muteTimeRemaining
 
     /**
      * 机器人在这个群里的权限
@@ -75,7 +76,7 @@ public interface Group : Contact, CoroutineScope {
      *
      * @see BotGroupPermissionChangeEvent 机器人群员修改
      */
-    public val botPermission: MemberPermission
+    public val botPermission: MemberPermission get() = botAsMember.permission
 
     /**
      * 群头像下载链接.
@@ -135,14 +136,6 @@ public interface Group : Contact, CoroutineScope {
     @JvmBlockingBridge
     public suspend fun quit(): Boolean
 
-    /**
-     * 构造一个 [Member].
-     * 非特殊情况请不要使用这个函数. 优先使用 [get].
-     */
-    @LowLevelApi
-    @MiraiExperimentalApi("dangerous")
-    public fun newMember(memberInfo: MemberInfo): Member
-
     /**
      * 向这个对象发送消息.
      *
diff --git a/mirai-core-api/src/commonMain/kotlin/event/events/group.kt b/mirai-core-api/src/commonMain/kotlin/event/events/group.kt
index a88927f8e..59726646d 100644
--- a/mirai-core-api/src/commonMain/kotlin/event/events/group.kt
+++ b/mirai-core-api/src/commonMain/kotlin/event/events/group.kt
@@ -22,6 +22,7 @@ import net.mamoe.mirai.event.BroadcastControllable
 import net.mamoe.mirai.internal.network.Packet
 import net.mamoe.mirai.message.action.Nudge
 import net.mamoe.mirai.utils.MiraiExperimentalApi
+import net.mamoe.mirai.utils.MiraiInternalApi
 import java.util.concurrent.atomic.AtomicBoolean
 
 /**
@@ -34,7 +35,7 @@ public sealed class BotLeaveEvent : BotEvent, Packet, AbstractEvent() {
      * 机器人主动退出一个群.
      */
     @MiraiExperimentalApi("目前此事件类型不一定正确. 部分被踢出情况也会广播此事件.")
-    public data class Active internal constructor(
+    public data class Active @MiraiInternalApi constructor(
         public override val group: Group
     ) : BotLeaveEvent() {
         public override fun toString(): String = "BotLeaveEvent.Active(group=${group.id})"
@@ -44,7 +45,7 @@ public sealed class BotLeaveEvent : BotEvent, Packet, AbstractEvent() {
      * 机器人被管理员或群主踢出群.
      */
     @MiraiExperimentalApi("BotLeaveEvent 的子类可能在将来改动. 使用 BotLeaveEvent 以保证兼容性.")
-    public data class Kick internal constructor(
+    public data class Kick @MiraiInternalApi constructor(
         public override val operator: Member
     ) : BotLeaveEvent(),
         GroupOperableEvent {
@@ -59,7 +60,7 @@ public sealed class BotLeaveEvent : BotEvent, Packet, AbstractEvent() {
 /**
  * Bot 在群里的权限被改变. 操作人一定是群主
  */
-public data class BotGroupPermissionChangeEvent internal constructor(
+public data class BotGroupPermissionChangeEvent @MiraiInternalApi constructor(
     public override val group: Group,
     public val origin: MemberPermission,
     public val new: MemberPermission
@@ -68,7 +69,7 @@ public data class BotGroupPermissionChangeEvent internal constructor(
 /**
  * Bot 被禁言
  */
-public data class BotMuteEvent internal constructor(
+public data class BotMuteEvent @MiraiInternalApi constructor(
     public val durationSeconds: Int,
     /**
      * 操作人.
@@ -82,7 +83,7 @@ public data class BotMuteEvent internal constructor(
 /**
  * Bot 被取消禁言
  */
-public data class BotUnmuteEvent internal constructor(
+public data class BotUnmuteEvent @MiraiInternalApi constructor(
     /**
      * 操作人.
      */
@@ -102,7 +103,7 @@ public sealed class BotJoinGroupEvent : GroupEvent, BotPassiveEvent, Packet, Abs
      * 不确定. 可能是主动加入
      */
     @MiraiExperimentalApi
-    public data class Active internal constructor(
+    public data class Active @MiraiInternalApi constructor(
         public override val group: Group
     ) : BotJoinGroupEvent() {
         public override fun toString(): String = "BotJoinGroupEvent.Active(group=$group)"
@@ -114,7 +115,7 @@ public sealed class BotJoinGroupEvent : GroupEvent, BotPassiveEvent, Packet, Abs
      * 此时服务器基于 Bot 的 QQ 设置自动同意了请求.
      */
     @MiraiExperimentalApi
-    public data class Invite internal constructor(
+    public data class Invite @MiraiInternalApi constructor(
         /**
          * 邀请人
          */
@@ -132,7 +133,7 @@ public sealed class BotJoinGroupEvent : GroupEvent, BotPassiveEvent, Packet, Abs
      * [Bot] 是原群主
      */
     @MiraiExperimentalApi
-    public data class Retrieve internal constructor(
+    public data class Retrieve @MiraiInternalApi constructor(
         public override val group: Group
     ) : BotJoinGroupEvent() {
         override fun toString(): String = "BotJoinGroupEvent.Retrieve(group=${group.id})"
@@ -155,7 +156,7 @@ public interface GroupSettingChangeEvent<T> : GroupEvent, BotPassiveEvent, Broad
 /**
  * 群名改变. 此事件广播前修改就已经完成.
  */
-public data class GroupNameChangeEvent internal constructor(
+public data class GroupNameChangeEvent @MiraiInternalApi constructor(
     public override val origin: String,
     public override val new: String,
     public override val group: Group,
@@ -168,7 +169,7 @@ public data class GroupNameChangeEvent internal constructor(
 /**
  * 入群公告改变. 此事件广播前修改就已经完成.
  */
-public data class GroupEntranceAnnouncementChangeEvent internal constructor(
+public data class GroupEntranceAnnouncementChangeEvent @MiraiInternalApi constructor(
     public override val origin: String,
     public override val new: String,
     public override val group: Group,
@@ -182,7 +183,7 @@ public data class GroupEntranceAnnouncementChangeEvent internal constructor(
 /**
  * 群 "全员禁言" 功能状态改变. 此事件广播前修改就已经完成.
  */
-public data class GroupMuteAllEvent internal constructor(
+public data class GroupMuteAllEvent @MiraiInternalApi constructor(
     public override val origin: Boolean,
     public override val new: Boolean,
     public override val group: Group,
@@ -196,7 +197,7 @@ public data class GroupMuteAllEvent internal constructor(
 /**
  * 群 "匿名聊天" 功能状态改变. 此事件广播前修改就已经完成.
  */
-public data class GroupAllowAnonymousChatEvent internal constructor(
+public data class GroupAllowAnonymousChatEvent @MiraiInternalApi constructor(
     public override val origin: Boolean,
     public override val new: Boolean,
     public override val group: Group,
@@ -210,7 +211,7 @@ public data class GroupAllowAnonymousChatEvent internal constructor(
 /**
  * 群 "坦白说" 功能状态改变. 此事件广播前修改就已经完成.
  */
-public data class GroupAllowConfessTalkEvent internal constructor(
+public data class GroupAllowConfessTalkEvent @MiraiInternalApi constructor(
     public override val origin: Boolean,
     public override val new: Boolean,
     public override val group: Group,
@@ -220,7 +221,7 @@ public data class GroupAllowConfessTalkEvent internal constructor(
 /**
  * 群 "允许群员邀请好友加群" 功能状态改变. 此事件广播前修改就已经完成.
  */
-public data class GroupAllowMemberInviteEvent internal constructor(
+public data class GroupAllowMemberInviteEvent @MiraiInternalApi constructor(
     public override val origin: Boolean,
     public override val new: Boolean,
     public override val group: Group,
@@ -248,7 +249,7 @@ public sealed class MemberJoinEvent(
     /**
      * 被邀请加入群
      */
-    public data class Invite internal constructor(
+    public data class Invite @MiraiInternalApi constructor(
         public override val member: NormalMember
     ) : MemberJoinEvent(member) {
         public override fun toString(): String = "MemberJoinEvent.Invite(member=${member.id})"
@@ -257,7 +258,7 @@ public sealed class MemberJoinEvent(
     /**
      * 成员主动加入群
      */
-    public data class Active internal constructor(
+    public data class Active @MiraiInternalApi constructor(
         public override val member: NormalMember
     ) : MemberJoinEvent(member) {
         public override fun toString(): String = "MemberJoinEvent.Active(member=${member.id})"
@@ -267,7 +268,7 @@ public sealed class MemberJoinEvent(
      * 原群主通过 https://huifu.qq.com/ 恢复原来群主身份并入群,
      * 此时 [member] 的 [Member.permission] 肯定是 [MemberPermission.OWNER]
      */
-    public data class Retrieve internal constructor(
+    public data class Retrieve @MiraiInternalApi constructor(
         public override val member: NormalMember
     ) : MemberJoinEvent(member) {
         override fun toString(): String = "MemberJoinEvent.Retrieve(member=${member.id})"
@@ -305,7 +306,7 @@ public sealed class MemberLeaveEvent : GroupMemberEvent, AbstractEvent() {
  * [Bot] 被邀请加入一个群.
  */
 @Suppress("DEPRECATION")
-public data class BotInvitedJoinGroupRequestEvent internal constructor(
+public data class BotInvitedJoinGroupRequestEvent @MiraiInternalApi constructor(
     public override val bot: Bot,
     /**
      * 事件唯一识别号
@@ -341,7 +342,7 @@ public data class BotInvitedJoinGroupRequestEvent internal constructor(
  * 一个账号请求加入群事件, [Bot] 在此群中是管理员或群主.
  */
 @Suppress("DEPRECATION")
-public data class MemberJoinRequestEvent internal constructor(
+public data class MemberJoinRequestEvent @MiraiInternalApi constructor(
     override val bot: Bot,
     /**
      * 事件唯一识别号
@@ -401,7 +402,7 @@ public data class MemberJoinRequestEvent internal constructor(
  *
  * 由于服务器并不会告知名片变动, 此事件只能由 mirai 在发现变动时才广播. 不要依赖于这个事件.
  */
-public data class MemberCardChangeEvent internal constructor(
+public data class MemberCardChangeEvent @MiraiInternalApi constructor(
     /**
      * 修改前
      */
@@ -418,7 +419,7 @@ public data class MemberCardChangeEvent internal constructor(
 /**
  * 成员群头衔改动. 一定为群主操作
  */
-public data class MemberSpecialTitleChangeEvent internal constructor(
+public data class MemberSpecialTitleChangeEvent @MiraiInternalApi constructor(
     /**
      * 修改前
      */
@@ -447,7 +448,7 @@ public data class MemberSpecialTitleChangeEvent internal constructor(
 /**
  * 成员权限改变的事件. 成员不可能是机器人自己.
  */
-public data class MemberPermissionChangeEvent internal constructor(
+public data class MemberPermissionChangeEvent @MiraiInternalApi constructor(
     public override val member: Member,
     public val origin: MemberPermission,
     public val new: MemberPermission
@@ -463,7 +464,7 @@ public data class MemberPermissionChangeEvent internal constructor(
  *
  * @see BotMuteEvent 机器人被禁言的事件
  */
-public data class MemberMuteEvent internal constructor(
+public data class MemberMuteEvent @MiraiInternalApi constructor(
     public override val member: Member,
     public val durationSeconds: Int,
     /**
@@ -477,7 +478,7 @@ public data class MemberMuteEvent internal constructor(
  *
  * @see BotUnmuteEvent 机器人被取消禁言的事件
  */
-public data class MemberUnmuteEvent internal constructor(
+public data class MemberUnmuteEvent @MiraiInternalApi constructor(
     public override val member: Member,
     /**
      * 操作人. 为 null 则为机器人操作
@@ -494,7 +495,7 @@ public data class MemberUnmuteEvent internal constructor(
  * [Member] 被 [戳][Nudge] 的事件.
  */
 @MiraiExperimentalApi
-public data class MemberNudgedEvent internal constructor(
+public data class MemberNudgedEvent @MiraiInternalApi constructor(
     /**
      * 戳一戳的发起人, 不可能是 bot
      */
diff --git a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt
index 3bd2e5d0d..4143dd71c 100644
--- a/mirai-core/src/commonMain/kotlin/MiraiImpl.kt
+++ b/mirai-core/src/commonMain/kotlin/MiraiImpl.kt
@@ -20,10 +20,7 @@ import net.mamoe.mirai.data.*
 import net.mamoe.mirai.event.events.BotInvitedJoinGroupRequestEvent
 import net.mamoe.mirai.event.events.MemberJoinRequestEvent
 import net.mamoe.mirai.event.events.NewFriendRequestEvent
-import net.mamoe.mirai.internal.contact.FriendImpl
-import net.mamoe.mirai.internal.contact.GroupImpl
-import net.mamoe.mirai.internal.contact.MemberInfoImpl
-import net.mamoe.mirai.internal.contact.checkIsGroupImpl
+import net.mamoe.mirai.internal.contact.*
 import net.mamoe.mirai.internal.message.*
 import net.mamoe.mirai.internal.network.highway.HighwayHelper
 import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
@@ -709,17 +706,17 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
         }
 
         if (accept ?: return@run)
-            groups[groupId]?.apply {
-                members.delegate.add(newMember(object : MemberInfo {
-                    override val nameCard: String get() = ""
-                    override val permission: MemberPermission get() = MemberPermission.MEMBER
-                    override val specialTitle: String get() = ""
-                    override val muteTimestamp: Int get() = 0
-                    override val uin: Long get() = fromId
-                    override val nick: String get() = fromNick
-                    override val remark: String
-                        get() = ""
-                }).cast())
+            groups[groupId]?.run {
+                members.delegate.add(
+                    newMember(
+                        MemberInfoImpl(
+                            uin = fromId,
+                            nick = fromNick,
+                            permission = MemberPermission.MEMBER,
+                            "", "", "", 0, null
+                        )
+                    ).cast()
+                )
             }
     }
 
diff --git a/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt b/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt
index 3d8a3484f..e1ba52f65 100644
--- a/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt
+++ b/mirai-core/src/commonMain/kotlin/contact/GroupImpl.kt
@@ -12,7 +12,6 @@
 
 package net.mamoe.mirai.internal.contact
 
-import kotlinx.coroutines.launch
 import net.mamoe.mirai.LowLevelApi
 import net.mamoe.mirai.contact.*
 import net.mamoe.mirai.data.GroupInfo
@@ -26,7 +25,6 @@ import net.mamoe.mirai.internal.message.OfflineGroupImage
 import net.mamoe.mirai.internal.message.ensureSequenceIdAvailable
 import net.mamoe.mirai.internal.message.firstIsInstanceOrNull
 import net.mamoe.mirai.internal.network.highway.HighwayHelper
-import net.mamoe.mirai.internal.network.protocol.packet.chat.TroopManagement
 import net.mamoe.mirai.internal.network.protocol.packet.chat.image.ImgStore
 import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.MessageSvcPbSendMsg
 import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.createToGroup
@@ -46,16 +44,12 @@ import kotlin.coroutines.CoroutineContext
 import kotlin.time.ExperimentalTime
 
 internal fun GroupImpl.Companion.checkIsInstance(instance: Group) {
-    contract {
-        returns() implies (instance is GroupImpl)
-    }
+    contract { returns() implies (instance is GroupImpl) }
     check(instance is GroupImpl) { "group is not an instanceof GroupImpl!! DO NOT interlace two or more protocol implementations!!" }
 }
 
 internal fun Group.checkIsGroupImpl() {
-    contract {
-        returns() implies (this@checkIsGroupImpl is GroupImpl)
-    }
+    contract { returns() implies (this@checkIsGroupImpl is GroupImpl) }
     GroupImpl.checkIsInstance(this)
 }
 
@@ -69,20 +63,14 @@ internal class GroupImpl(
 ) : Group, AbstractContact(bot, coroutineContext) {
     companion object
 
-    val groupPkgMsgParsingCache = GroupPkgMsgParsingCache()
-
     val uin: Long = groupInfo.uin
+    override val settings: GroupSettingsImpl = GroupSettingsImpl(this, groupInfo)
+    override var name: String by settings::name
 
     override lateinit var owner: NormalMember
-
     override lateinit var botAsMember: NormalMember
 
-    override val botPermission: MemberPermission get() = botAsMember.permission
-
-    // e.g. 600
-    override val botMuteRemaining: Int get() = botAsMember.muteTimeRemaining
-
-    override val members: ContactList<NormalMember> = ContactList(members.mapNotNull {
+    override val members: ContactList<NormalMember> = ContactList(members.mapNotNullTo(ConcurrentLinkedQueue()) {
         if (it.uin == bot.id) {
             botAsMember = newMember(it).cast()
             if (it.permission == MemberPermission.OWNER) {
@@ -94,115 +82,9 @@ internal class GroupImpl(
                 owner = member
             }
         }
-    }.mapTo(ConcurrentLinkedQueue()) { it })
+    })
 
-    internal var _name: String = groupInfo.name
-    private var _announcement: String = groupInfo.memo
-    private var _allowMemberInvite: Boolean = groupInfo.allowMemberInvite
-    internal var _confessTalk: Boolean = groupInfo.confessTalk
-    internal var _muteAll: Boolean = groupInfo.muteAll
-    private var _autoApprove: Boolean = groupInfo.autoApprove
-    internal var _anonymousChat: Boolean = groupInfo.allowAnonymousChat
-
-    override var name: String
-        get() = _name
-        set(newValue) {
-
-            checkBotPermission(MemberPermission.ADMINISTRATOR)
-            if (_name != newValue) {
-                val oldValue = _name
-                _name = newValue
-                launch {
-                    bot.network.run {
-                        TroopManagement.GroupOperation.name(
-                            client = bot.client,
-                            groupCode = id,
-                            newName = newValue
-                        ).sendWithoutExpect()
-                    }
-                    GroupNameChangeEvent(oldValue, newValue, this@GroupImpl, null).broadcast()
-                }
-            }
-        }
-
-    override val settings: GroupSettings = object : GroupSettings {
-
-        override var entranceAnnouncement: String
-            get() = _announcement
-            set(newValue) {
-                checkBotPermission(MemberPermission.ADMINISTRATOR)
-                //if (_announcement != newValue) {
-                val oldValue = _announcement
-                _announcement = newValue
-                launch {
-                    bot.network.run {
-                        TroopManagement.GroupOperation.memo(
-                            client = bot.client,
-                            groupCode = id,
-                            newMemo = newValue
-                        ).sendWithoutExpect()
-                    }
-                    GroupEntranceAnnouncementChangeEvent(oldValue, newValue, this@GroupImpl, null).broadcast()
-                }
-                //}
-            }
-
-
-        override var isAllowMemberInvite: Boolean
-            get() = _allowMemberInvite
-            set(newValue) {
-                checkBotPermission(MemberPermission.ADMINISTRATOR)
-                //if (_allowMemberInvite != newValue) {
-                val oldValue = _allowMemberInvite
-                _allowMemberInvite = newValue
-                launch {
-                    bot.network.run {
-                        TroopManagement.GroupOperation.allowMemberInvite(
-                            client = bot.client,
-                            groupCode = id,
-                            switch = newValue
-                        ).sendWithoutExpect()
-                    }
-                    GroupAllowMemberInviteEvent(oldValue, newValue, this@GroupImpl, null).broadcast()
-                }
-                //}
-            }
-
-        override var isAnonymousChatEnabled: Boolean
-            get() = _anonymousChat
-            @Suppress("UNUSED_PARAMETER")
-            set(newValue) {
-                TODO()
-            }
-
-        override var isAutoApproveEnabled: Boolean
-            get() = _autoApprove
-            @Suppress("UNUSED_PARAMETER")
-            set(newValue) {
-                TODO()
-            }
-
-
-        override var isMuteAll: Boolean
-            get() = _muteAll
-            set(newValue) {
-                checkBotPermission(MemberPermission.ADMINISTRATOR)
-                //if (_muteAll != newValue) {
-                val oldValue = _muteAll
-                _muteAll = newValue
-                launch {
-                    bot.network.run {
-                        TroopManagement.GroupOperation.muteAll(
-                            client = bot.client,
-                            groupCode = id,
-                            switch = newValue
-                        ).sendWithoutExpect()
-                    }
-                    GroupMuteAllEvent(oldValue, newValue, this@GroupImpl, null).broadcast()
-                }
-                //}
-            }
-    }
+    val groupPkgMsgParsingCache = GroupPkgMsgParsingCache()
 
     override suspend fun quit(): Boolean {
         check(botPermission != MemberPermission.OWNER) { "An owner cannot quit from a owning group" }
@@ -225,33 +107,6 @@ internal class GroupImpl(
         return true
     }
 
-    override fun newMember(memberInfo: MemberInfo): Member {
-        memberInfo.anonymousId?.let { anId ->
-            return AnonymousMemberImpl(
-                this, this.coroutineContext,
-                memberInfo, anId
-            )
-        }
-        return MemberImpl(
-            this,
-            this.coroutineContext,
-            memberInfo
-        )
-    }
-
-    internal fun newAnonymous(name: String, id: String): Member = newMember(
-        object : MemberInfo {
-            override val nameCard = name
-            override val permission = MemberPermission.MEMBER
-            override val specialTitle = "匿名"
-            override val muteTimestamp = 0
-            override val uin = 80000000L
-            override val nick = name
-            override val remark: String = "匿名"
-            override val anonymousId: String get() = id
-        }
-    )
-
     override operator fun get(id: Long): NormalMember? {
         if (id == bot.id) {
             return botAsMember
@@ -460,6 +315,33 @@ internal class GroupImpl(
 
     }
 
-
     override fun toString(): String = "Group($id)"
 }
+
+internal fun Group.newMember(memberInfo: MemberInfo): Member {
+    this.checkIsGroupImpl()
+    memberInfo.anonymousId?.let { anId ->
+        return AnonymousMemberImpl(
+            this, this.coroutineContext,
+            memberInfo, anId
+        )
+    }
+    return NormalMemberImpl(
+        this,
+        this.coroutineContext,
+        memberInfo
+    )
+}
+
+internal fun GroupImpl.newAnonymous(name: String, id: String): Member = newMember(
+    MemberInfoImpl(
+        uin = 80000000L,
+        nick = name,
+        permission = MemberPermission.MEMBER,
+        remark = "匿名",
+        nameCard = name,
+        specialTitle = "匿名",
+        muteTimestamp = 0,
+        anonymousId = id,
+    )
+)
diff --git a/mirai-core/src/commonMain/kotlin/contact/GroupSettingsImpl.kt b/mirai-core/src/commonMain/kotlin/contact/GroupSettingsImpl.kt
new file mode 100644
index 000000000..a685d5e8d
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/contact/GroupSettingsImpl.kt
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2019-2020 Mamoe Technologies and contributors.
+ *
+ *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ *  https://github.com/mamoe/mirai/blob/master/LICENSE
+ */
+
+package net.mamoe.mirai.internal.contact
+
+import kotlinx.coroutines.launch
+import net.mamoe.mirai.contact.GroupSettings
+import net.mamoe.mirai.contact.MemberPermission
+import net.mamoe.mirai.contact.checkBotPermission
+import net.mamoe.mirai.data.GroupInfo
+import net.mamoe.mirai.event.broadcast
+import net.mamoe.mirai.event.events.GroupAllowMemberInviteEvent
+import net.mamoe.mirai.event.events.GroupEntranceAnnouncementChangeEvent
+import net.mamoe.mirai.event.events.GroupMuteAllEvent
+import net.mamoe.mirai.event.events.GroupNameChangeEvent
+import net.mamoe.mirai.internal.network.protocol.packet.chat.TroopManagement
+
+@Suppress("SetterBackingFieldAssignment")
+internal class GroupSettingsImpl(
+    private val group: GroupImpl,
+    groupInfo: GroupInfo,
+) : GroupSettings {
+
+    internal var nameField: String = groupInfo.name
+    var name: String
+        get() = nameField
+        set(newValue) = with(group) {
+            checkBotPermission(MemberPermission.ADMINISTRATOR)
+            if (nameField != newValue) {
+                val oldValue = nameField
+                nameField = newValue
+                launch {
+                    bot.network.run {
+                        TroopManagement.GroupOperation.name(
+                            client = bot.client,
+                            groupCode = id,
+                            newName = newValue
+                        ).sendWithoutExpect()
+                    }
+                    GroupNameChangeEvent(oldValue, newValue, group, null).broadcast()
+                }
+            }
+        }
+
+
+    private var _entranceAnnouncement: String = groupInfo.memo
+
+    @Deprecated("Don't use public var internally", level = DeprecationLevel.HIDDEN)
+    override var entranceAnnouncement: String
+        get() = _entranceAnnouncement
+        set(newValue) = with(group) {
+            checkBotPermission(MemberPermission.ADMINISTRATOR)
+            //if (_announcement != newValue) {
+            val oldValue = _entranceAnnouncement
+            _entranceAnnouncement = newValue
+            launch {
+                bot.network.run {
+                    TroopManagement.GroupOperation.memo(
+                        client = bot.client,
+                        groupCode = id,
+                        newMemo = newValue
+                    ).sendWithoutExpect()
+                }
+                GroupEntranceAnnouncementChangeEvent(oldValue, newValue, group, null).broadcast()
+            }
+            //}
+        }
+
+    @Deprecated("Don't use public var internally", level = DeprecationLevel.HIDDEN)
+    override var isAllowMemberInvite: Boolean = groupInfo.allowMemberInvite
+        set(newValue) = with(group) {
+            checkBotPermission(MemberPermission.ADMINISTRATOR)
+            //if (_allowMemberInvite != newValue) {
+            val oldValue = field
+            field = newValue
+            launch {
+                bot.network.run {
+                    TroopManagement.GroupOperation.allowMemberInvite(
+                        client = bot.client,
+                        groupCode = id,
+                        switch = newValue
+                    ).sendWithoutExpect()
+                }
+                GroupAllowMemberInviteEvent(oldValue, newValue, group, null).broadcast()
+            }
+            //}
+        }
+
+    internal var isAnonymousChatEnabledField: Boolean = groupInfo.allowAnonymousChat
+
+    @Deprecated("Don't use public var internally", level = DeprecationLevel.HIDDEN)
+    override var isAnonymousChatEnabled: Boolean
+        get() = isAnonymousChatEnabledField
+        @Suppress("UNUSED_PARAMETER")
+        set(newValue) {
+            throw UnsupportedOperationException()
+        }
+
+    @Deprecated("Don't use public var internally", level = DeprecationLevel.HIDDEN)
+    override var isAutoApproveEnabled: Boolean = groupInfo.autoApprove
+        @Suppress("UNUSED_PARAMETER")
+        set(newValue) {
+            throw UnsupportedOperationException()
+        }
+
+
+    internal var isMuteAllField: Boolean = groupInfo.muteAll
+
+    @Deprecated("Don't use public var internally", level = DeprecationLevel.HIDDEN)
+    override var isMuteAll: Boolean
+        get() = isMuteAllField
+        set(newValue) = with(group) {
+            checkBotPermission(MemberPermission.ADMINISTRATOR)
+            //if (_muteAll != newValue) {
+            val oldValue = isMuteAllField
+            isMuteAllField = newValue
+            launch {
+                bot.network.run {
+                    TroopManagement.GroupOperation.muteAll(
+                        client = bot.client,
+                        groupCode = id,
+                        switch = newValue
+                    ).sendWithoutExpect()
+                }
+                GroupMuteAllEvent(oldValue, newValue, group, null).broadcast()
+            }
+            //}
+        }
+}
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/contact/MemberInfoImpl.kt b/mirai-core/src/commonMain/kotlin/contact/MemberInfoImpl.kt
new file mode 100644
index 000000000..8f4f917d0
--- /dev/null
+++ b/mirai-core/src/commonMain/kotlin/contact/MemberInfoImpl.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019-2020 Mamoe Technologies and contributors.
+ *
+ *  此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
+ *  Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
+ *
+ *  https://github.com/mamoe/mirai/blob/master/LICENSE
+ */
+
+package net.mamoe.mirai.internal.contact
+
+import net.mamoe.mirai.contact.MemberPermission
+import net.mamoe.mirai.data.MemberInfo
+import net.mamoe.mirai.internal.network.protocol.data.jce.StTroopMemberInfo
+
+internal class MemberInfoImpl(
+    override val uin: Long,
+    override var nick: String,
+    override val permission: MemberPermission,
+    override val remark: String,
+    override val nameCard: String,
+    override val specialTitle: String,
+    override val muteTimestamp: Int,
+    override val anonymousId: String?,
+) : MemberInfo {
+    constructor(
+        jceInfo: StTroopMemberInfo,
+        groupOwnerId: Long
+    ) : this(
+        uin = jceInfo.memberUin,
+        nick = jceInfo.nick,
+        permission = when {
+            jceInfo.memberUin == groupOwnerId -> MemberPermission.OWNER
+            jceInfo.dwFlag == 1L -> MemberPermission.ADMINISTRATOR
+            else -> MemberPermission.MEMBER
+        },
+        remark = jceInfo.autoRemark.orEmpty(),
+        nameCard = jceInfo.sName.orEmpty(),
+        specialTitle = jceInfo.sSpecialTitle.orEmpty(),
+        muteTimestamp = jceInfo.dwShutupTimestap?.toInt() ?: 0,
+        anonymousId = null,
+    )
+}
\ No newline at end of file
diff --git a/mirai-core/src/commonMain/kotlin/contact/MemberImpl.kt b/mirai-core/src/commonMain/kotlin/contact/NormalMemberImpl.kt
similarity index 79%
rename from mirai-core/src/commonMain/kotlin/contact/MemberImpl.kt
rename to mirai-core/src/commonMain/kotlin/contact/NormalMemberImpl.kt
index 9faacaccf..af4db31c9 100644
--- a/mirai-core/src/commonMain/kotlin/contact/MemberImpl.kt
+++ b/mirai-core/src/commonMain/kotlin/contact/NormalMemberImpl.kt
@@ -22,7 +22,6 @@ import net.mamoe.mirai.event.events.*
 import net.mamoe.mirai.internal.message.MessageSourceToTempImpl
 import net.mamoe.mirai.internal.message.ensureSequenceIdAvailable
 import net.mamoe.mirai.internal.message.firstIsInstanceOrNull
-import net.mamoe.mirai.internal.network.protocol.data.jce.StTroopMemberInfo
 import net.mamoe.mirai.internal.network.protocol.packet.chat.TroopManagement
 import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.MessageSvcPbSendMsg
 import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.createToTemp
@@ -37,7 +36,7 @@ import kotlin.coroutines.CoroutineContext
 
 @OptIn(LowLevelApi::class)
 @Suppress("MemberVisibilityCanBePrivate")
-internal class MemberImpl constructor(
+internal class NormalMemberImpl constructor(
     group: GroupImpl,
     coroutineContext: CoroutineContext,
     memberInfo: MemberInfo
@@ -80,7 +79,7 @@ internal class MemberImpl constructor(
             val source: MessageSourceToTempImpl
             MessageSvcPbSendMsg.createToTemp(
                 bot.client,
-                this@MemberImpl,
+                this@NormalMemberImpl,
                 chain
             ) {
                 source = it
@@ -89,7 +88,7 @@ internal class MemberImpl constructor(
                     "Send temp message failed: $it"
                 }
             }
-            MessageReceipt(source, this@MemberImpl)
+            MessageReceipt(source, this@NormalMemberImpl)
         }
 
         result.fold(
@@ -138,11 +137,11 @@ internal class MemberImpl constructor(
                     bot.network.run {
                         TroopManagement.EditGroupNametag(
                             bot.client,
-                            this@MemberImpl,
+                            this@NormalMemberImpl,
                             newValue
                         ).sendWithoutExpect()
                     }
-                    MemberCardChangeEvent(oldValue, newValue, this@MemberImpl).broadcast()
+                    MemberCardChangeEvent(oldValue, newValue, this@NormalMemberImpl).broadcast()
                 }
             }
         }
@@ -158,16 +157,15 @@ internal class MemberImpl constructor(
                     bot.network.run {
                         TroopManagement.EditSpecialTitle(
                             bot.client,
-                            this@MemberImpl,
+                            this@NormalMemberImpl,
                             newValue
                         ).sendWithoutExpect()
                     }
-                    MemberSpecialTitleChangeEvent(oldValue, newValue, this@MemberImpl, null).broadcast()
+                    MemberSpecialTitleChangeEvent(oldValue, newValue, this@NormalMemberImpl, null).broadcast()
                 }
             }
         }
 
-    @JvmSynthetic
     override suspend fun mute(durationSeconds: Int) {
         check(this.id != bot.id) {
             "A bot can't mute itself."
@@ -177,32 +175,30 @@ internal class MemberImpl constructor(
             TroopManagement.Mute(
                 client = bot.client,
                 groupCode = group.id,
-                memberUin = this@MemberImpl.id,
+                memberUin = this@NormalMemberImpl.id,
                 timeInSecond = durationSeconds
             ).sendAndExpect<TroopManagement.Mute.Response>()
         }
 
         @Suppress("RemoveRedundantQualifierName") // or unresolved reference
-        net.mamoe.mirai.event.events.MemberMuteEvent(this@MemberImpl, durationSeconds, null).broadcast()
+        net.mamoe.mirai.event.events.MemberMuteEvent(this@NormalMemberImpl, durationSeconds, null).broadcast()
     }
 
-    @JvmSynthetic
     override suspend fun unmute() {
         checkBotPermissionHigherThanThis("unmute")
         bot.network.run {
             TroopManagement.Mute(
                 client = bot.client,
                 groupCode = group.id,
-                memberUin = this@MemberImpl.id,
+                memberUin = this@NormalMemberImpl.id,
                 timeInSecond = 0
             ).sendAndExpect<TroopManagement.Mute.Response>()
         }
 
         @Suppress("RemoveRedundantQualifierName") // or unresolved reference
-        net.mamoe.mirai.event.events.MemberUnmuteEvent(this@MemberImpl, null).broadcast()
+        net.mamoe.mirai.event.events.MemberUnmuteEvent(this@NormalMemberImpl, null).broadcast()
     }
 
-    @JvmSynthetic
     override suspend fun kick(message: String) {
         checkBotPermissionHigherThanThis("kick")
         check(group.members[this.id] != null) {
@@ -211,16 +207,16 @@ internal class MemberImpl constructor(
         bot.network.run {
             val response: TroopManagement.Kick.Response = TroopManagement.Kick(
                 client = bot.client,
-                member = this@MemberImpl,
+                member = this@NormalMemberImpl,
                 message = message
             ).sendAndExpect()
 
             check(response.success) { "kick failed: ${response.ret}" }
 
             @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
-            group.members.delegate.removeIf { it.id == this@MemberImpl.id }
-            this@MemberImpl.cancel(CancellationException("Kicked by bot"))
-            MemberLeaveEvent.Kick(this@MemberImpl, null).broadcast()
+            group.members.delegate.removeIf { it.id == this@NormalMemberImpl.id }
+            this@NormalMemberImpl.cancel(CancellationException("Kicked by bot"))
+            MemberLeaveEvent.Kick(this@NormalMemberImpl, null).broadcast()
         }
     }
 }
@@ -235,29 +231,11 @@ internal fun Member.checkBotPermissionHigherThanThis(operationName: String) {
 }
 
 @OptIn(ExperimentalContracts::class)
-internal fun Member.checkIsMemberImpl(): MemberImpl {
+internal fun Member.checkIsMemberImpl(): NormalMemberImpl {
     contract {
-        returns() implies (this@checkIsMemberImpl is MemberImpl)
+        returns() implies (this@checkIsMemberImpl is NormalMemberImpl)
     }
-    check(this is MemberImpl) { "A Member instance is not instance of MemberImpl. Don't interlace two protocol implementations together!" }
+    check(this is NormalMemberImpl) { "A Member instance is not instance of MemberImpl. Don't interlace two protocol implementations together!" }
     return this
 }
 
-@OptIn(LowLevelApi::class)
-internal class MemberInfoImpl(
-    jceInfo: StTroopMemberInfo,
-    groupOwnerId: Long
-) : MemberInfo {
-    override val uin: Long = jceInfo.memberUin
-    override val nameCard: String = jceInfo.sName ?: ""
-    internal var _nick: String = jceInfo.nick
-    override val nick: String get() = _nick
-    override val permission: MemberPermission = when {
-        jceInfo.memberUin == groupOwnerId -> MemberPermission.OWNER
-        jceInfo.dwFlag == 1L -> MemberPermission.ADMINISTRATOR
-        else -> MemberPermission.MEMBER
-    }
-    override val specialTitle: String = jceInfo.sSpecialTitle ?: ""
-    override val muteTimestamp: Int = jceInfo.dwShutupTimestap?.toInt() ?: 0
-    override val remark: String = jceInfo.autoRemark ?: ""
-}
diff --git a/mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt b/mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt
index d238bc506..44dea1c5d 100644
--- a/mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt
+++ b/mirai-core/src/commonMain/kotlin/message/incomingSourceImpl.kt
@@ -15,6 +15,7 @@ import net.mamoe.mirai.Bot
 import net.mamoe.mirai.contact.Friend
 import net.mamoe.mirai.contact.Member
 import net.mamoe.mirai.internal.contact.GroupImpl
+import net.mamoe.mirai.internal.contact.newAnonymous
 import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
 import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
 import net.mamoe.mirai.internal.network.protocol.data.proto.SourceMsg
diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.PbPushGroupMsg.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.PbPushGroupMsg.kt
index 62ee0cfd0..2b727104f 100644
--- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.PbPushGroupMsg.kt
+++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.PbPushGroupMsg.kt
@@ -23,7 +23,8 @@ import net.mamoe.mirai.event.events.GroupMessageSyncEvent
 import net.mamoe.mirai.event.events.MemberCardChangeEvent
 import net.mamoe.mirai.internal.QQAndroidBot
 import net.mamoe.mirai.internal.contact.GroupImpl
-import net.mamoe.mirai.internal.contact.MemberImpl
+import net.mamoe.mirai.internal.contact.NormalMemberImpl
+import net.mamoe.mirai.internal.contact.newAnonymous
 import net.mamoe.mirai.internal.message.toMessageChain
 import net.mamoe.mirai.internal.network.Packet
 import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
@@ -101,7 +102,7 @@ internal object OnlinePushPbPushGroupMsg : IncomingPacketFactory<Packet?>("Onlin
             sender = group.newAnonymous(anonymous.anonNick.encodeToString(), anonymous.anonId.encodeToBase64())
             name = sender.nameCard
         } else { // normal member chat
-            sender = group[msgHead.fromUin] as MemberImpl
+            sender = group[msgHead.fromUin] as NormalMemberImpl
             name = findSenderName(extraInfo, msgHead.groupInfo) ?: sender.nameCardOrNick
         }
 
@@ -129,7 +130,7 @@ internal object OnlinePushPbPushGroupMsg : IncomingPacketFactory<Packet?>("Onlin
 
     private suspend inline fun broadcastNameCardChangedEventIfNecessary(sender: Member, name: String) {
         val currentNameCard = sender.nameCard
-        if (sender is MemberImpl && name != currentNameCard) {
+        if (sender is NormalMemberImpl && name != currentNameCard) {
             sender._nameCard = name
             MemberCardChangeEvent(currentNameCard, name, sender).broadcast()
         }
diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.PbPushTransMsg.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.PbPushTransMsg.kt
index b23ad28c3..573f29fb9 100644
--- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.PbPushTransMsg.kt
+++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.PbPushTransMsg.kt
@@ -24,8 +24,9 @@ import net.mamoe.mirai.data.MemberInfo
 import net.mamoe.mirai.event.events.*
 import net.mamoe.mirai.internal.QQAndroidBot
 import net.mamoe.mirai.internal.contact.GroupImpl
-import net.mamoe.mirai.internal.contact.MemberImpl
+import net.mamoe.mirai.internal.contact.NormalMemberImpl
 import net.mamoe.mirai.internal.contact.checkIsMemberImpl
+import net.mamoe.mirai.internal.contact.newMember
 import net.mamoe.mirai.internal.message.contextualBugReportException
 import net.mamoe.mirai.internal.network.MultiPacketByIterable
 import net.mamoe.mirai.internal.network.Packet
@@ -100,7 +101,7 @@ internal object OnlinePushPbPushTransMsg :
                                         )
                                     )
                             } else {
-                                val member = group[from] as MemberImpl
+                                val member = group[from] as NormalMemberImpl
                                 if (member.permission != MemberPermission.MEMBER) {
                                     results.add(
                                         MemberPermissionChangeEvent(
@@ -186,7 +187,7 @@ internal object OnlinePushPbPushTransMsg :
                                         newPermission
                                     )
                                 } else {
-                                    val member = group[target] as MemberImpl
+                                    val member = group[target] as NormalMemberImpl
                                     if (member.permission == newPermission) {
                                         return null
                                     }
@@ -230,7 +231,7 @@ internal object OnlinePushPbPushTransMsg :
                                     bot.groups.delegate.remove(group)
                                 }
                             } else {
-                                val member = group.get(target) as? MemberImpl ?: return null
+                                val member = group.get(target) as? NormalMemberImpl ?: return null
                                 return MemberLeaveEvent.Quit(member.also {
                                     member.cancel(CancellationException("Leaved actively"))
                                     group.members.delegate.remove(member)
@@ -245,7 +246,7 @@ internal object OnlinePushPbPushTransMsg :
                                     bot.groups.delegate.remove(group)
                                 }
                             } else {
-                                val member = group.get(target) as? MemberImpl ?: return null
+                                val member = group.get(target) as? NormalMemberImpl ?: return null
                                 return MemberLeaveEvent.Kick(member.also {
                                     member.cancel(CancellationException("Being kicked"))
                                     group.members.delegate.remove(member)
diff --git a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.ReqPush.kt b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.ReqPush.kt
index e6b6cfc23..307f7a6ee 100644
--- a/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.ReqPush.kt
+++ b/mirai-core/src/commonMain/kotlin/network/protocol/packet/chat/receive/OnlinePush.ReqPush.kt
@@ -45,13 +45,9 @@ import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacketFactory
 import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
 import net.mamoe.mirai.internal.network.protocol.packet.buildResponseUniPacket
 import net.mamoe.mirai.internal.utils.*
-import net.mamoe.mirai.internal.utils._miraiContentToString
-import net.mamoe.mirai.internal.utils.encodeToString
 import net.mamoe.mirai.internal.utils.io.ProtoBuf
 import net.mamoe.mirai.internal.utils.io.readString
 import net.mamoe.mirai.internal.utils.io.serialization.*
-import net.mamoe.mirai.internal.utils.read
-import net.mamoe.mirai.internal.utils.toUHexString
 import net.mamoe.mirai.utils.currentTimeSeconds
 import net.mamoe.mirai.utils.debug
 import net.mamoe.mirai.utils.mapToIntArray
@@ -89,7 +85,7 @@ internal object OnlinePushReqPush : IncomingPacketFactory<OnlinePushReqPush.ReqP
                     val group = bot.getGroup(readUInt().toLong())
                         ?: return@deco emptySequence() // group has not been initialized
 
-                    GroupImpl.checkIsInstance(group)
+                    group.checkIsGroupImpl()
 
                     val internalType = readByte().toInt()
                     discardExact(1)
@@ -191,10 +187,10 @@ private object Transformers732 : Map<Int, Lambda732> by mapOf(
 
         if (target == 0L) {
             val new = timeSeconds != 0
-            if (group.settings.isMuteAll == new) {
+            if (group.settings.isMuteAllField == new) {
                 return@lambda732 emptySequence()
             }
-            group._muteAll = new
+            group.settings.isMuteAllField = new
             return@lambda732 sequenceOf(GroupMuteAllEvent(!new, new, group, operator))
         }
 
@@ -230,11 +226,11 @@ private object Transformers732 : Map<Int, Lambda732> by mapOf(
         // 匿名
         val operator = group[readUInt().toLong()] ?: return@lambda732 emptySequence()
         val new = readInt() == 0
-        if (group.settings.isAnonymousChatEnabled == new) {
+        if (group.settings.isAnonymousChatEnabledField == new) {
             return@lambda732 emptySequence()
         }
 
-        group._anonymousChat = new
+        group.settings.isAnonymousChatEnabledField = new
         return@lambda732 sequenceOf(GroupAllowAnonymousChatEvent(!new, new, group, operator))
     },
 
@@ -409,6 +405,7 @@ internal inline fun lambda528(crossinline block: MsgType0x210.(QQAndroidBot, Msg
 /**
  * @see MsgType0x210
  */
+@OptIn(ExperimentalStdlibApi::class)
 internal object Transformers528 : Map<Long, Lambda528> by mapOf(
 
     0x8AL to lambda528 { bot ->
@@ -606,7 +603,7 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
                         val operator = if (this.cmdUin == bot.id) null
                         else group[this.cmdUin] ?: return@mapNotNull null
 
-                        group._name = new
+                        group.settings.nameField = new
 
                         return@mapNotNull GroupNameChangeEvent(old, new, group, operator)
                     }
@@ -688,57 +685,46 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
             return sequenceOf(FriendAvatarChangedEvent(friend))
         }
 
-        fun ModProfile.transform(bot: QQAndroidBot): Sequence<Packet> {
-            return ArrayList<Packet>().apply {
-                var containsUnknown = false
-                msgProfileInfos.forEach { modified ->
-                    when (modified.field) {
-                        20002 -> { // 昵称修改
-                            val value = modified.value
-                            val to = value.encodeToString()
-                            if (uin == bot.id) {
-                                val from = bot.nick
-                                if (from != to) {
-                                    bot.nick = to
-                                    add(BotNickChangedEvent(bot, from, to))
-                                }
-                            } else {
-                                val friend = (bot.getFriend(uin) ?: return@forEach) as FriendImpl
-                                val info = friend.friendInfo
-                                val from = info.nick
-                                when (info) {
-                                    is FriendInfoImpl -> {
-                                        info.nick = to
-                                    }
-                                    is MemberInfoImpl -> {
-                                        info._nick = to
-                                    }
-                                    else -> {
-                                        bot.network.logger.debug {
-                                            "Unknown how to update nick for $info"
-                                        }
-                                    }
-                                }
-                                add(
-                                    FriendNickChangedEvent(
-                                        friend, from, to
-                                    )
-                                )
+        fun ModProfile.transform(bot: QQAndroidBot): Sequence<Packet> = buildList<Packet> {
+            var containsUnknown = false
+            msgProfileInfos.forEach { modified ->
+                when (modified.field) {
+                    20002 -> { // 昵称修改
+                        val value = modified.value
+                        val to = value.encodeToString()
+                        if (uin == bot.id) {
+                            val from = bot.nick
+                            if (from != to) {
+                                bot.nick = to
+                                add(BotNickChangedEvent(bot, from, to))
                             }
-                        }
-                        else -> {
-                            containsUnknown = true
+                        } else {
+                            val friend = (bot.getFriend(uin) ?: return@forEach) as FriendImpl
+                            val info = friend.friendInfo
+                            val from = info.nick
+                            when (info) {
+                                is FriendInfoImpl -> info.nick = to
+                                is MemberInfoImpl -> info.nick = to
+                                else -> {
+                                    bot.network.logger.debug {
+                                        "Unknown how to update nick for $info"
+                                    }
+                                }
+                            }
+                            add(FriendNickChangedEvent(friend, from, to))
                         }
                     }
-                }
-                if (msgProfileInfos.isEmpty() || containsUnknown) {
-                    bot.network.logger.debug {
-                        "Transformers528 0x27L: new data: ${_miraiContentToString()}"
+                    else -> {
+                        containsUnknown = true
                     }
                 }
-            }.asSequence()
-
-        }
+            }
+            if (msgProfileInfos.isEmpty() || containsUnknown) {
+                bot.network.logger.debug {
+                    "Transformers528 0x27L: new data: ${_miraiContentToString()}"
+                }
+            }
+        }.asSequence()
 
         return@lambda528 vProtobuf.loadAs(SubMsgType0x27MsgBody.serializer()).msgModInfos.asSequence()
             .flatMap {