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 {