Re-design Member interfaces #725

This commit is contained in:
Karlatemp 2020-12-18 20:31:24 +08:00
parent 17a223d9ce
commit 2340486db8
No known key found for this signature in database
GPG Key ID: 21FBDDF664FF06F8
10 changed files with 276 additions and 151 deletions

View File

@ -0,0 +1,32 @@
/*
* 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.contact
import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.utils.MemberDeprecatedApi
/**
* 匿名
*
* 代表匿名群成员
*/
public interface AnonymousMember : Member {
/** 该匿名群成员 ID */
public val anonymousId: String
@MemberDeprecatedApi(message = "无法发送信息至 AnonymousMember")
@Deprecated(level = DeprecationLevel.ERROR, message = "无法发送信息至 AnonymousMember")
public override suspend fun sendMessage(message: Message): Nothing
@Deprecated(level = DeprecationLevel.ERROR, message = "无法发送信息至 AnonymousMember")
@MemberDeprecatedApi(message = "无法发送信息至 AnonymousMember")
public override suspend fun sendMessage(message: String): Nothing
}

View File

@ -53,13 +53,13 @@ public interface Group : Contact, CoroutineScope {
*
* @return 若机器人是群主, 返回 [botAsMember]. 否则返回相应的成员
*/
public val owner: Member
public val owner: NormalMember
/**
* [Bot] 在群内的 [Member] 实例
*/
@MiraiExperimentalApi
public val botAsMember: Member
public val botAsMember: NormalMember
/**
* 机器人被禁言还剩余多少秒
@ -89,14 +89,14 @@ public interface Group : Contact, CoroutineScope {
*
* [Group] 实例创建的时候查询一次. 并与事件同步事件更新.
*/
public val members: ContactList<Member>
public val members: ContactList<NormalMember>
/**
* 获取群成员实例. 不存在时返回 `null`.
*
* [id] [Bot.id] 时返回 [botAsMember].
*/
public operator fun get(id: Long): Member?
public operator fun get(id: Long): NormalMember?
@Deprecated("Use get", ReplaceWith("get(id)"))
@PlannedRemoval("2.0-M2")
@ -104,14 +104,14 @@ public interface Group : Contact, CoroutineScope {
* 获取群成员实例, 不存在则 null
* [id] [Bot.id] 时返回 [botAsMember]
*/
public fun getOrNull(id: Long): Member? = get(id)
public fun getOrNull(id: Long): NormalMember? = get(id)
/**
* 获取群成员实例. 不存在时抛出 [kotlin.NoSuchElementException].
*
* [id] [Bot.id] 时返回 [botAsMember].
*/
public fun getOrFail(id: Long): Member =
public fun getOrFail(id: Long): NormalMember =
get(id) ?: throw NoSuchElementException("member $id not found in group ${this.id}")
@ -125,7 +125,7 @@ public interface Group : Contact, CoroutineScope {
/**
* [member] 是本群成员时返回 `true`. 将同时成员 [所属群][Member.group]. 同一个用户在不同群内的 [Member] 对象不相等.
*/
public operator fun contains(member: Member): Boolean = member in members
public operator fun contains(member: NormalMember): Boolean = member in members
/**

View File

@ -12,30 +12,28 @@
package net.mamoe.mirai.contact
import net.mamoe.kjbb.JvmBlockingBridge
import net.mamoe.mirai.Bot
import net.mamoe.mirai.JavaFriendlyAPI
import net.mamoe.mirai.event.events.*
import net.mamoe.mirai.event.events.MemberMuteEvent
import net.mamoe.mirai.event.events.MemberPermissionChangeEvent
import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.MessageReceipt.Companion.recall
import net.mamoe.mirai.message.action.MemberNudge
import net.mamoe.mirai.message.action.Nudge
import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.message.data.isContentEmpty
import net.mamoe.mirai.message.data.toPlainText
import net.mamoe.mirai.utils.MemberDeprecatedApi
import net.mamoe.mirai.utils.MiraiExperimentalApi
import net.mamoe.mirai.utils.PlannedRemoval
import net.mamoe.mirai.utils.WeakRefProperty
import kotlin.time.Duration
import kotlin.time.ExperimentalTime
/**
* 代表一位群成员.
*
* 群成员可能是匿名群成员 [AnonymousMember]
* 群成员可能也是好友, 但他们在对象类型上不同.
* 群成员可以通过 [asFriend] 得到相关好友对象.
*
* ## 与好友相关的操作
* ## 相关的操作
* [Member.isFriend] 判断此成员是否为好友
* [Member.isAnonymous] 判断此成员是否为匿名群成员
* [Member.isNormal] 判断此成员是否为正常群成员
*/
@Suppress("INAPPLICABLE_JVM_NAME", "EXPOSED_SUPER_CLASS")
@OptIn(JavaFriendlyAPI::class)
@ -56,36 +54,22 @@ public interface Member : User {
/**
* 群名片. 可能为空.
*
* 管理员和群主都可修改任何人包括群主的群名片.
*
* 在修改时将会异步上传至服务器.
*
* @see [nameCardOrNick] 获取非空群名片或昵称
*
* @see MemberCardChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件. 修改时也会触发此事件.
* @throws PermissionDeniedException 无权限修改时
* @see [NormalMember.nameCard]
* @see [AnonymousMember.nameCard]
*/
public var nameCard: String
public val nameCard: String
/**
* 群头衔.
*
* 仅群主可以修改群头衔.
* [AnonymousMember] 时一定是 `"匿名"`
*
* 在修改时将会异步上传至服务器.
*
* @see MemberSpecialTitleChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件. 修改时也会触发此事件.
* @throws PermissionDeniedException 无权限修改时
* @see [NormalMember.specialTitle]
*/
public var specialTitle: String
public val specialTitle: String
/**
* 被禁言剩余时长. 单位为秒.
*
* @see isMuted 判断改成员是否处于禁言状态
* @see mute 设置禁言
* @see unmute 取消禁言
*/
@MemberDeprecatedApi("仅 NormalMember 支持 muteTimeRemaining")
@PlannedRemoval("2.0-M2")
public val muteTimeRemaining: Int
/**
@ -99,8 +83,8 @@ public interface Member : User {
* @param durationSeconds 持续时间. 精确到秒. 范围区间表示为 `(0s, 30days]`. 超过范围则会抛出异常.
* @return 机器人无权限时返回 `false`
*
* @see Member.isMuted 判断此成员是否正处于禁言状态中
* @see unmute 取消禁言此成员
* @see NormalMember.isMuted 判断此成员是否正处于禁言状态中
* @see NormalMember.unmute 取消禁言此成员
*
* @see Int.minutesToSeconds
* @see Int.hoursToSeconds
@ -113,68 +97,24 @@ public interface Member : User {
@JvmBlockingBridge
public suspend fun mute(durationSeconds: Int)
/**
* 解除禁言.
*
* 管理员可解除成员的禁言, 群主可解除管理员和群员的禁言.
*
* @see Member.isMuted 判断此成员是否正处于禁言状态中
*
* @see MemberUnmuteEvent 成员被取消禁言事件
*
* @throws PermissionDeniedException 无权限修改时抛出
*/
@JvmBlockingBridge
@MemberDeprecatedApi("仅 NormalMember 支持 unmute")
@PlannedRemoval("2.0-M2")
public suspend fun unmute()
/**
* 踢出该成员.
*
* 管理员可踢出成员, 群主可踢出管理员和群员.
*
* @see MemberLeaveEvent.Kick 成员被踢出事件.
* @throws PermissionDeniedException 无权限修改时
*/
@JvmBlockingBridge
@MemberDeprecatedApi("仅 NormalMember 支持 kick")
@PlannedRemoval("2.0-M2")
public suspend fun kick(message: String = "")
/**
* 向群成员发送消息.
* 若群成员同时是好友, 则会发送好友消息. 否则发送临时会话消息.
*
* 单条消息最大可发送 4500 字符或 50 张图片.
*
* @see FriendMessagePreSendEvent 当此成员是好友时发送消息前事件
* @see FriendMessagePostSendEvent 当此成员是好友时发送消息后事件
*
* @see TempMessagePreSendEvent 当此成员不是好友时发送消息前事件
* @see TempMessagePostSendEvent 当此成员不是好友时发送消息后事件
*
* @throws EventCancelledException 当发送消息事件被取消时抛出
* @throws BotIsBeingMutedException 发送群消息时若 [Bot] 被禁言抛出
* @throws MessageTooLargeException 当消息过长时抛出
* @throws IllegalArgumentException 当消息内容为空时抛出 (详见 [Message.isContentEmpty])
*
* @return 消息回执. 可进行撤回 ([MessageReceipt.recall])
*/
@JvmBlockingBridge
@MemberDeprecatedApi("仅 NormalMember 支持 sendMessage")
public override suspend fun sendMessage(message: Message): MessageReceipt<Member>
/**
* 发送纯文本消息
* @see sendMessage
*/
@JvmBlockingBridge
public override suspend fun sendMessage(message: String): MessageReceipt<Member> =
this.sendMessage(message.toPlainText())
@MemberDeprecatedApi("仅 NormalMember 支持 sendMessage")
public override suspend fun sendMessage(message: String): MessageReceipt<Member>
/**
* 创建一个 "戳一戳" 消息
*
* @see Nudge.sendTo 发送这个戳一戳消息
*/
@MemberDeprecatedApi("仅 NormalMember 支持 nudge")
@PlannedRemoval("2.0-M2")
@MiraiExperimentalApi
public override fun nudge(): MemberNudge = MemberNudge(this)
public override fun nudge(): MemberNudge
}
/**
@ -213,39 +153,5 @@ public inline fun <R> Member.takeIfIsFriend(block: (Friend) -> R): R? {
* [群名片][Member.nameCard] 不为空则返回群名片, 为空则返回 [User.nick]
*/
public val Member.nameCardOrNick: String get() = this.nameCard.takeIf { it.isNotEmpty() } ?: this.nick
/**
* 获取非空群名片或昵称.
*
* @return [User] [Member] 时返回 [Member.nameCardOrNick]
*
* 否则返回 [Member.nick]
*/
public val User.nameCardOrNick: String
get() = when (this) {
is Member -> this.nameCardOrNick
else -> this.nick
}
/**
* 判断群成员是否处于禁言状态.
*/
public val Member.isMuted: Boolean
get() = muteTimeRemaining != 0 && muteTimeRemaining != 0xFFFFFFFF.toInt()
/**
* @see Member.mute
*/
@ExperimentalTime
public suspend inline fun Member.mute(duration: Duration) {
require(duration.inDays <= 30) { "duration must be at most 1 month" }
require(duration.inSeconds > 0) { "duration must be greater than 0 second" }
this.mute(duration.inSeconds.toInt())
}
/**
* @see Member.mute
*/
@Deprecated("Convert duration to int manually.", ReplaceWith("this.mute(durationSeconds.toInt())"))
@PlannedRemoval("2.0-M2")
public suspend inline fun Member.mute(durationSeconds: Long): Unit = this.mute(durationSeconds.toInt())
public val Member.isNormal: Boolean get() = this is NormalMember
public val Member.isAnonymous: Boolean get() = this is AnonymousMember

View File

@ -0,0 +1,173 @@
/*
* 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.contact
import net.mamoe.kjbb.JvmBlockingBridge
import net.mamoe.mirai.Bot
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.action.MemberNudge
import net.mamoe.mirai.message.action.Nudge
import net.mamoe.mirai.message.data.Message
import net.mamoe.mirai.message.data.isContentEmpty
import net.mamoe.mirai.message.data.toPlainText
import net.mamoe.mirai.utils.MemberDeprecatedApi
import net.mamoe.mirai.utils.MiraiExperimentalApi
import net.mamoe.mirai.utils.PlannedRemoval
import kotlin.time.Duration
import kotlin.time.ExperimentalTime
/**
* 代表一位正常的群成员.
*
* 群成员可能也是好友, 但他们在对象类型上不同.
* 群成员可以通过 [asFriend] 得到相关好友对象.
*
* ## 相关的操作
* [Member.isFriend] 判断此成员是否为好友
*/
@OptIn(MemberDeprecatedApi::class)
public interface NormalMember : Member {
/**
* 群名片. 可能为空.
*
* 管理员和群主都可修改任何人包括群主的群名片.
*
* 在修改时将会异步上传至服务器.
*
* @see [nameCardOrNick] 获取非空群名片或昵称
*
* @see MemberCardChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件. 修改时也会触发此事件.
* @throws PermissionDeniedException 无权限修改时
*/
public override var nameCard: String
/**
* 群头衔.
*
* 仅群主可以修改群头衔.
*
* 在修改时将会异步上传至服务器.
*
* @see MemberSpecialTitleChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件. 修改时也会触发此事件.
* @throws PermissionDeniedException 无权限修改时
*/
public override var specialTitle: String
/**
* 被禁言剩余时长. 单位为秒.
*
* @see isMuted 判断改成员是否处于禁言状态
* @see mute 设置禁言
* @see unmute 取消禁言
*/
public override val muteTimeRemaining: Int
/**
* 解除禁言.
*
* 管理员可解除成员的禁言, 群主可解除管理员和群员的禁言.
*
* @see Member.isMuted 判断此成员是否正处于禁言状态中
*
* @see MemberUnmuteEvent 成员被取消禁言事件
*
* @throws PermissionDeniedException 无权限修改时抛出
*/
@JvmBlockingBridge
public override suspend fun unmute()
/**
* 踢出该成员.
*
* 管理员可踢出成员, 群主可踢出管理员和群员.
*
* @see MemberLeaveEvent.Kick 成员被踢出事件.
* @throws PermissionDeniedException 无权限修改时
*/
@JvmBlockingBridge
public override suspend fun kick(message: String)
/**
* 向群成员发送消息.
* 若群成员同时是好友, 则会发送好友消息. 否则发送临时会话消息.
*
* 单条消息最大可发送 4500 字符或 50 张图片.
*
* @see FriendMessagePreSendEvent 当此成员是好友时发送消息前事件
* @see FriendMessagePostSendEvent 当此成员是好友时发送消息后事件
*
* @see TempMessagePreSendEvent 当此成员不是好友时发送消息前事件
* @see TempMessagePostSendEvent 当此成员不是好友时发送消息后事件
*
* @throws EventCancelledException 当发送消息事件被取消时抛出
* @throws BotIsBeingMutedException 发送群消息时若 [Bot] 被禁言抛出
* @throws MessageTooLargeException 当消息过长时抛出
* @throws IllegalArgumentException 当消息内容为空时抛出 (详见 [Message.isContentEmpty])
*
* @return 消息回执. 可进行撤回 ([MessageReceipt.recall])
*/
@JvmBlockingBridge
public override suspend fun sendMessage(message: Message): MessageReceipt<Member>
/**
* 发送纯文本消息
* @see sendMessage
*/
@JvmBlockingBridge
public override suspend fun sendMessage(message: String): MessageReceipt<Member> =
this.sendMessage(message.toPlainText())
/**
* 创建一个 "戳一戳" 消息
*
* @see Nudge.sendTo 发送这个戳一戳消息
*/
@MiraiExperimentalApi
public override fun nudge(): MemberNudge = MemberNudge(this)
}
/**
* 获取非空群名片或昵称.
*
* @return [User] [Member] 时返回 [Member.nameCardOrNick]
*
* 否则返回 [Member.nick]
*/
public val User.nameCardOrNick: String
get() = when (this) {
is NormalMember -> this.nameCardOrNick
else -> this.nick
}
/**
* 判断群成员是否处于禁言状态.
*/
public val NormalMember.isMuted: Boolean
get() = muteTimeRemaining != 0 && muteTimeRemaining != 0xFFFFFFFF.toInt()
/**
* @see Member.mute
*/
@ExperimentalTime
public suspend inline fun NormalMember.mute(duration: Duration) {
require(duration.inDays <= 30) { "duration must be at most 1 month" }
require(duration.inSeconds > 0) { "duration must be greater than 0 second" }
this.mute(duration.inSeconds.toInt())
}
/**
* @see Member.mute
*/
@Deprecated("Convert duration to int manually.", ReplaceWith("this.mute(durationSeconds.toInt())"))
@PlannedRemoval("2.0-M2")
public suspend inline fun NormalMember.mute(durationSeconds: Long): Unit = this.mute(durationSeconds.toInt())

View File

@ -16,10 +16,7 @@ package net.mamoe.mirai.event.events
import net.mamoe.kjbb.JvmBlockingBridge
import net.mamoe.mirai.Bot
import net.mamoe.mirai.Mirai
import net.mamoe.mirai.contact.Friend
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.Member
import net.mamoe.mirai.contact.MemberPermission
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.event.AbstractEvent
import net.mamoe.mirai.event.BroadcastControllable
import net.mamoe.mirai.internal.network.Packet
@ -245,14 +242,14 @@ public data class GroupAllowMemberInviteEvent internal constructor(
* 成员已经加入群的事件
*/
public sealed class MemberJoinEvent(
public override val member: Member
public override val member: NormalMember
) : GroupMemberEvent, BotPassiveEvent, Packet,
AbstractEvent() {
/**
* 被邀请加入群
*/
public data class Invite internal constructor(
public override val member: Member
public override val member: NormalMember
) : MemberJoinEvent(member) {
public override fun toString(): String = "MemberJoinEvent.Invite(member=${member.id})"
}
@ -261,7 +258,7 @@ public sealed class MemberJoinEvent(
* 成员主动加入群
*/
public data class Active internal constructor(
public override val member: Member
public override val member: NormalMember
) : MemberJoinEvent(member) {
public override fun toString(): String = "MemberJoinEvent.Active(member=${member.id})"
}
@ -271,7 +268,7 @@ public sealed class MemberJoinEvent(
* 此时 [member] [Member.permission] 肯定是 [MemberPermission.OWNER]
*/
public data class Retrieve internal constructor(
public override val member: Member
public override val member: NormalMember
) : MemberJoinEvent(member) {
override fun toString(): String = "MemberJoinEvent.Retrieve(member=${member.id})"
}
@ -285,11 +282,11 @@ public sealed class MemberLeaveEvent : GroupMemberEvent, AbstractEvent() {
* 成员被踢出群. 成员不可能是机器人自己.
*/
public data class Kick(
public override val member: Member,
public override val member: NormalMember,
/**
* 操作人. null 则是机器人操作.
*/
public override val operator: Member?
public override val operator: NormalMember?
) : MemberLeaveEvent(), Packet, GroupOperableEvent {
public override fun toString(): String = "MemberLeaveEvent.Kick(member=${member.id}, operator=${operator?.id})"
}
@ -298,7 +295,7 @@ public sealed class MemberLeaveEvent : GroupMemberEvent, AbstractEvent() {
* 成员主动离开
*/
public data class Quit(
public override val member: Member
public override val member: NormalMember
) : MemberLeaveEvent(), Packet {
public override fun toString(): String = "MemberLeaveEvent.Quit(member=${member.id})"
}
@ -439,7 +436,7 @@ public data class MemberSpecialTitleChangeEvent internal constructor(
* 不为 null 时一定为群主. 可能与 [member] 引用相同, 此时为群员自己修改.
* null 时则是机器人操作.
*/
public override val operator: Member?
public override val operator: NormalMember?
) : GroupMemberEvent, GroupOperableEvent, AbstractEvent()
// endregion

View File

@ -48,4 +48,16 @@ public annotation class MiraiExperimentalApi(
@Target(CLASS, PROPERTY, FIELD, CONSTRUCTOR, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, TYPEALIAS)
@Retention(AnnotationRetention.SOURCE)
@MustBeDocumented
internal annotation class PlannedRemoval(val version: String)
internal annotation class PlannedRemoval(val version: String)
/**
* 标记已过时的 Member API
*/
@Target(CLASS, PROPERTY, FIELD, CONSTRUCTOR, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, TYPEALIAS)
@Retention(AnnotationRetention.SOURCE)
@RequiresOptIn(level = RequiresOptIn.Level.ERROR)
@MustBeDocumented
@PlannedRemoval("2.0-M2")
internal annotation class MemberDeprecatedApi(val message: String)

View File

@ -46,6 +46,7 @@ import net.mamoe.mirai.message.data.Image.Key.FRIEND_IMAGE_ID_REGEX_2
import net.mamoe.mirai.message.data.Image.Key.GROUP_IMAGE_ID_REGEX
import net.mamoe.mirai.utils.BotConfiguration
import net.mamoe.mirai.utils.MiraiExperimentalApi
import net.mamoe.mirai.utils.cast
import net.mamoe.mirai.utils.currentTimeSeconds
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.math.absoluteValue
@ -733,7 +734,7 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
override val nick: String get() = fromNick
override val remark: String
get() = ""
}))
}).cast())
}
}

View File

@ -77,23 +77,23 @@ internal class GroupImpl(
val uin: Long = groupInfo.uin
override lateinit var owner: Member
override lateinit var owner: NormalMember
override lateinit var botAsMember: Member
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<Member> = ContactList(members.mapNotNull {
override val members: ContactList<NormalMember> = ContactList(members.mapNotNull {
if (it.uin == bot.id) {
botAsMember = newMember(it)
botAsMember = newMember(it).cast()
if (it.permission == MemberPermission.OWNER) {
owner = botAsMember
}
null
} else newMember(it).also { member ->
} else newMember(it).cast<NormalMember>().also { member ->
if (member.permission == MemberPermission.OWNER) {
owner = member
}
@ -250,7 +250,7 @@ internal class GroupImpl(
}
)
override operator fun get(id: Long): Member? {
override operator fun get(id: Long): NormalMember? {
if (id == bot.id) {
return botAsMember
}

View File

@ -44,7 +44,7 @@ internal class MemberImpl constructor(
group: GroupImpl,
coroutineContext: CoroutineContext,
memberInfo: MemberInfo
) : Member {
) : NormalMember {
override val group: GroupImpl by group.unsafeWeakRef()
override val coroutineContext: CoroutineContext = coroutineContext + SupervisorJob(coroutineContext[Job])

View File

@ -22,6 +22,7 @@ import kotlinx.io.core.discardExact
import net.mamoe.mirai.Mirai
import net.mamoe.mirai.contact.Group
import net.mamoe.mirai.contact.MemberPermission
import net.mamoe.mirai.contact.NormalMember
import net.mamoe.mirai.data.MemberInfo
import net.mamoe.mirai.event.AbstractEvent
import net.mamoe.mirai.event.Event
@ -51,6 +52,7 @@ import net.mamoe.mirai.internal.utils.io.serialization.writeProtoBuf
import net.mamoe.mirai.internal.utils.read
import net.mamoe.mirai.internal.utils.toInt
import net.mamoe.mirai.internal.utils.toUHexString
import net.mamoe.mirai.utils.cast
import net.mamoe.mirai.utils.debug
import net.mamoe.mirai.utils.warning
import kotlin.random.Random
@ -235,10 +237,12 @@ internal object MessageSvcPbGetMsg : OutgoingPacketFactory<MessageSvcPbGetMsg.Re
readByte().toInt().and(0xff)
} == 0x83) {
return@mapNotNull MemberJoinEvent.Invite(group.newMember(msg.getNewMemberInfo())
.cast<NormalMember>()
.also { group.members.delegate.add(it) })
}
return@mapNotNull MemberJoinEvent.Active(group.newMember(msg.getNewMemberInfo())
.cast<NormalMember>()
.also { group.members.delegate.add(it) })
}
}