From 086f04e1f508b5364f44d39f76bf9b729924e73f Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Thu, 20 Feb 2020 22:36:19 +0800 Subject: [PATCH] Add member.muteTimeRemaining --- .../net/mamoe/mirai/qqandroid/ContactImpl.kt | 18 +++++++-- .../packet/chat/receive/OnlinePush.kt | 22 +++++----- .../kotlin/net.mamoe.mirai/contact/Member.kt | 40 ++++++++++++++++--- .../kotlin/net.mamoe.mirai/data/MemberInfo.kt | 2 + .../net.mamoe.mirai/event/events/BotEvents.kt | 9 ++++- 5 files changed, 71 insertions(+), 20 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt index af1977697..708a07064 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt @@ -180,6 +180,15 @@ internal class MemberImpl( internal var _nameCard: String = memberInfo.nameCard internal var _specialTitle: String = memberInfo.specialTitle + var _muteTimestamp: Int = memberInfo.muteTimestamp + + override val muteTimeRemaining: Int = + if (_muteTimestamp == 0 || _muteTimestamp == 0xFFFFFFFF.toInt()) { + 0 + } else { + _muteTimestamp - currentTimeSeconds.toInt() - bot.client.timeDifference.toInt() + } + override var nameCard: String get() = _nameCard set(newValue) { @@ -215,7 +224,7 @@ internal class MemberImpl( newValue ).sendWithoutExpect() } - MemberSpecialTitleChangeEvent(oldValue, newValue, this@MemberImpl).broadcast() + MemberSpecialTitleChangeEvent(oldValue, newValue, this@MemberImpl, null).broadcast() } } } @@ -293,6 +302,7 @@ internal class MemberInfoImpl( else -> MemberPermission.MEMBER } override val specialTitle: String get() = jceInfo.sSpecialTitle ?: "" + override val muteTimestamp: Int get() = jceInfo.dwShutupTimestap?.toInt() ?: 0 } /** @@ -315,13 +325,13 @@ internal class GroupImpl( @UseExperimental(MiraiExperimentalAPI::class) override lateinit var botPermission: MemberPermission - var _botMuteRemaining: Int = groupInfo.botMuteRemaining + var _botMuteTimestamp: Int = groupInfo.botMuteRemaining override val botMuteRemaining: Int = - if (_botMuteRemaining == 0 || _botMuteRemaining == 0xFFFFFFFF.toInt()) { + if (_botMuteTimestamp == 0 || _botMuteTimestamp == 0xFFFFFFFF.toInt()) { 0 } else { - _botMuteRemaining - currentTimeSeconds.toInt() - bot.client.timeDifference.toInt() + _botMuteTimestamp - currentTimeSeconds.toInt() - bot.client.timeDifference.toInt() } override val members: ContactList<Member> = ContactList(members.mapNotNull { diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt index 4aa8a4439..117b1601e 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt @@ -181,12 +181,12 @@ internal class OnlinePush { } } else { if (target == bot.uin) { - if (group._botMuteRemaining != time) { + if (group._botMuteTimestamp != time) { if (time == 0) { - group._botMuteRemaining = 0 + group._botMuteTimestamp = 0 return@mapNotNull BotUnmuteEvent(operator) as Packet } else { - group._botMuteRemaining = time + group._botMuteTimestamp = time return@mapNotNull BotMuteEvent(durationSeconds = time, operator = operator) as Packet } } else { @@ -194,11 +194,17 @@ internal class OnlinePush { } } else { val member = group[target] - // TODO: 2020/2/20 检查是否重复 - return@mapNotNull if (time == 0) { - MemberUnmuteEvent(operator = operator, member = member) + member as MemberImpl + if (member._muteTimestamp != time) { + if (time == 0) { + member._muteTimestamp = 0 + return@mapNotNull MemberUnmuteEvent(member, operator) as Packet + } else { + member._muteTimestamp = time + return@mapNotNull MemberMuteEvent(member, time, operator) as Packet + } } else { - MemberMuteEvent(operator = operator, member = member, durationSeconds = time) as Packet + return@mapNotNull null } } } @@ -261,7 +267,6 @@ internal class OnlinePush { return@mapNotNull null } } - return@mapNotNull null } msgInfo.shMsgType.toInt() == 528 -> { bot.network.logger.debug { "unknown shtype ${msgInfo.shMsgType.toInt()}" } @@ -274,7 +279,6 @@ internal class OnlinePush { return@mapNotNull null } } - return@mapNotNull null } } return MultiPacket(packets) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt index d21bf9b1d..74f0a1431 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt @@ -1,7 +1,7 @@ /* * Copyright 2020 Mamoe Technologies and contributors. * - * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * 此源代码的使用受 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 @@ -29,33 +29,50 @@ interface Member : QQ, Contact { /** * 成员的权限, 动态更新. + * + * @see MemberPermissionChangeEvent 权限变更事件. 由群主或机器人的操作触发. */ val permission: MemberPermission /** - * 群名片. 可能为空. 修改时将会触发事件 + * 群名片. 可能为空. + * + * 管理员和群主都可修改任何人(包括群主)的群名片. * * 在修改时将会异步上传至服务器. * * @see [nameCardOrNick] 获取非空群名片或昵称 * - * @see MemberCardChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件 + * @see MemberCardChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件. 修改时也会触发此事件. * @throws PermissionDeniedException 无权限修改时 */ var nameCard: String /** - * 群头衔 + * 群头衔. + * + * 仅群主可以修改群头衔. * * 在修改时将会异步上传至服务器. * - * @see MemberSpecialTitleChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件 + * @see MemberSpecialTitleChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件. 修改时也会触发此事件. * @throws PermissionDeniedException 无权限修改时 */ var specialTitle: String /** - * 禁言 + * 被禁言剩余时长. 单位为秒. + * + * @see isMuted 判断改成员是否处于禁言状态 + * @see mute 设置禁言 + * @see unmute 取消禁言 + */ + val muteTimeRemaining: Int + + /** + * 禁言. + * + * 管理员可禁言成员, 群主可禁言管理员和群员. * * @param durationSeconds 持续时间. 精确到秒. 范围区间表示为 `(0s, 30days]`. 超过范围则会抛出异常. * @return 机器人无权限时返回 `false` @@ -72,6 +89,8 @@ interface Member : QQ, Contact { /** * 解除禁言. * + * 管理员可解除成员的禁言, 群主可解除管理员和群员的禁言. + * * @see MemberUnmuteEvent 成员被取消禁言事件. * @throws PermissionDeniedException 无权限修改时 */ @@ -80,6 +99,8 @@ interface Member : QQ, Contact { /** * 踢出该成员. * + * 管理员可踢出成员, 群主可踢出管理员和群员. + * * @see MemberLeaveEvent.Kick 成员被踢出事件. * @throws PermissionDeniedException 无权限修改时 */ @@ -98,6 +119,13 @@ interface Member : QQ, Contact { */ val Member.nameCardOrNick: String get() = this.nameCard.takeIf { it.isNotEmpty() } ?: this.nick +/** + * 判断改成员是否处于禁言状态. + */ +fun Member.isMuted(): Boolean { + return muteTimeRemaining != 0 && muteTimeRemaining != 0xFFFFFFFF.toInt() +} + @ExperimentalTime suspend inline fun Member.mute(duration: Duration) { require(duration.inDays <= 30) { "duration must be at most 1 month" } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/MemberInfo.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/MemberInfo.kt index 3ed39ef10..37e6ba4b0 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/MemberInfo.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/MemberInfo.kt @@ -17,4 +17,6 @@ interface MemberInfo : FriendInfo { val permission: MemberPermission val specialTitle: String + + val muteTimestamp: Int } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt index 0deab64d0..c9ad80052 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt @@ -333,7 +333,14 @@ data class MemberSpecialTitleChangeEvent( */ val new: String, - override val member: Member + override val member: Member, + + /** + * 操作人. + * 不为 null 时一定为群主. 可能与 [member] 引用相同, 此时为群员自己修改. + * 为 null 时则是机器人操作. + */ + val operator: Member? ) : GroupMemberEvent // endregion